@dmsdc-ai/aigentry-telepty 0.1.65 → 0.1.67
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 +24 -3
- package/daemon.js +82 -26
- package/package.json +1 -1
- package/tui.js +1 -1
package/cli.js
CHANGED
|
@@ -691,12 +691,27 @@ async function main() {
|
|
|
691
691
|
|
|
692
692
|
await ensureDaemonRunning({ requiredCapabilities: ['wrapped-sessions'] });
|
|
693
693
|
|
|
694
|
+
// Detect terminal backend for session registration
|
|
695
|
+
function findKittySocketCli() {
|
|
696
|
+
try {
|
|
697
|
+
const files = require('fs').readdirSync('/tmp').filter(f => f.startsWith('kitty-sock'));
|
|
698
|
+
return files.length > 0;
|
|
699
|
+
} catch { return false; }
|
|
700
|
+
}
|
|
701
|
+
const detectedBackend = process.env.CMUX_WORKSPACE_ID ? 'cmux' : (findKittySocketCli() ? 'kitty' : 'pty');
|
|
702
|
+
|
|
694
703
|
// Register session with daemon
|
|
695
704
|
try {
|
|
696
705
|
const res = await fetchWithAuth(`${DAEMON_URL}/api/sessions/register`, {
|
|
697
706
|
method: 'POST',
|
|
698
707
|
headers: { 'Content-Type': 'application/json' },
|
|
699
|
-
body: JSON.stringify({
|
|
708
|
+
body: JSON.stringify({
|
|
709
|
+
session_id: sessionId,
|
|
710
|
+
command,
|
|
711
|
+
cwd: process.cwd(),
|
|
712
|
+
backend: detectedBackend,
|
|
713
|
+
cmux_workspace_id: process.env.CMUX_WORKSPACE_ID || null
|
|
714
|
+
})
|
|
700
715
|
});
|
|
701
716
|
const data = await res.json();
|
|
702
717
|
if (!res.ok) {
|
|
@@ -769,7 +784,13 @@ async function main() {
|
|
|
769
784
|
await fetchWithAuth(`${DAEMON_URL}/api/sessions/register`, {
|
|
770
785
|
method: 'POST',
|
|
771
786
|
headers: { 'Content-Type': 'application/json' },
|
|
772
|
-
body: JSON.stringify({
|
|
787
|
+
body: JSON.stringify({
|
|
788
|
+
session_id: sessionId,
|
|
789
|
+
command,
|
|
790
|
+
cwd: process.cwd(),
|
|
791
|
+
backend: detectedBackend,
|
|
792
|
+
cmux_workspace_id: process.env.CMUX_WORKSPACE_ID || null
|
|
793
|
+
})
|
|
773
794
|
});
|
|
774
795
|
} catch (e) {
|
|
775
796
|
// Registration may fail if session already exists or daemon not ready
|
|
@@ -1186,7 +1207,7 @@ async function main() {
|
|
|
1186
1207
|
const configArg = args.find(a => a.startsWith('--config='));
|
|
1187
1208
|
const configPath = configArg ? configArg.split('=').slice(1).join('=') : null;
|
|
1188
1209
|
const cliArg = args.find(a => a.startsWith('--cli='));
|
|
1189
|
-
const cli = cliArg ? cliArg.split('=')[1] : 'claude --dangerously-skip-permissions';
|
|
1210
|
+
const cli = cliArg ? cliArg.split('=')[1] : 'claude --dangerously-skip-permissions --continue';
|
|
1190
1211
|
const projectsDir = args.find(a => a.startsWith('--dir=')) ? args.find(a => a.startsWith('--dir=')).split('=')[1] : process.cwd();
|
|
1191
1212
|
|
|
1192
1213
|
// Discover project folders (subdirectories with .git)
|
package/daemon.js
CHANGED
|
@@ -19,7 +19,7 @@ function persistSessions() {
|
|
|
19
19
|
try {
|
|
20
20
|
const data = {};
|
|
21
21
|
for (const [id, s] of Object.entries(sessions)) {
|
|
22
|
-
data[id] = { id, type: s.type, command: s.command, cwd: s.cwd, createdAt: s.createdAt, lastActivityAt: s.lastActivityAt || null };
|
|
22
|
+
data[id] = { id, type: s.type, command: s.command, cwd: s.cwd, backend: s.backend || null, cmuxWorkspaceId: s.cmuxWorkspaceId || null, createdAt: s.createdAt, lastActivityAt: s.lastActivityAt || null };
|
|
23
23
|
}
|
|
24
24
|
fs.mkdirSync(require('path').dirname(SESSION_PERSIST_PATH), { recursive: true });
|
|
25
25
|
fs.writeFileSync(SESSION_PERSIST_PATH, JSON.stringify(data, null, 2));
|
|
@@ -306,7 +306,7 @@ app.post('/api/sessions/spawn', (req, res) => {
|
|
|
306
306
|
});
|
|
307
307
|
|
|
308
308
|
app.post('/api/sessions/register', (req, res) => {
|
|
309
|
-
const { session_id, command, cwd = process.cwd() } = req.body;
|
|
309
|
+
const { session_id, command, cwd = process.cwd(), backend, cmux_workspace_id } = req.body;
|
|
310
310
|
if (!session_id) return res.status(400).json({ error: 'session_id is required' });
|
|
311
311
|
// Entitlement: check session limit for new registrations
|
|
312
312
|
if (!sessions[session_id]) {
|
|
@@ -322,6 +322,8 @@ app.post('/api/sessions/register', (req, res) => {
|
|
|
322
322
|
const existing = sessions[session_id];
|
|
323
323
|
if (command) existing.command = command;
|
|
324
324
|
if (cwd) existing.cwd = cwd;
|
|
325
|
+
if (backend) existing.backend = backend;
|
|
326
|
+
if (cmux_workspace_id) existing.cmuxWorkspaceId = cmux_workspace_id;
|
|
325
327
|
console.log(`[REGISTER] Re-registered session ${session_id} (updated metadata)`);
|
|
326
328
|
return res.status(200).json({ session_id, type: 'wrapped', command: existing.command, cwd: existing.cwd, reregistered: true });
|
|
327
329
|
}
|
|
@@ -333,6 +335,8 @@ app.post('/api/sessions/register', (req, res) => {
|
|
|
333
335
|
ownerWs: null,
|
|
334
336
|
command: command || 'wrapped',
|
|
335
337
|
cwd,
|
|
338
|
+
backend: backend || 'kitty',
|
|
339
|
+
cmuxWorkspaceId: cmux_workspace_id || null,
|
|
336
340
|
createdAt: new Date().toISOString(),
|
|
337
341
|
lastActivityAt: new Date().toISOString(),
|
|
338
342
|
clients: new Set(),
|
|
@@ -389,6 +393,8 @@ app.get('/api/sessions', (req, res) => {
|
|
|
389
393
|
type: session.type || 'spawned',
|
|
390
394
|
command: session.command,
|
|
391
395
|
cwd: session.cwd,
|
|
396
|
+
backend: session.backend || 'kitty',
|
|
397
|
+
cmuxWorkspaceId: session.cmuxWorkspaceId || null,
|
|
392
398
|
createdAt: session.createdAt,
|
|
393
399
|
lastActivityAt: session.lastActivityAt || null,
|
|
394
400
|
idleSeconds,
|
|
@@ -452,11 +458,13 @@ app.post('/api/sessions/multicast/inject', (req, res) => {
|
|
|
452
458
|
if (session.ownerWs && session.ownerWs.readyState === 1) {
|
|
453
459
|
session.ownerWs.send(JSON.stringify({ type: 'inject', data: prompt }));
|
|
454
460
|
setTimeout(() => {
|
|
455
|
-
if (session.
|
|
461
|
+
if (session.backend === 'cmux' && session.cmuxWorkspaceId) {
|
|
462
|
+
submitViaCmux(id);
|
|
463
|
+
} else if (session.ownerWs && session.ownerWs.readyState === 1) {
|
|
456
464
|
session.ownerWs.send(JSON.stringify({ type: 'inject', data: '\r' }));
|
|
457
465
|
}
|
|
458
466
|
}, 300);
|
|
459
|
-
results.successful.push({ id, strategy: 'split_cr' });
|
|
467
|
+
results.successful.push({ id, strategy: session.backend === 'cmux' ? 'cmux_split_cr' : 'split_cr' });
|
|
460
468
|
} else {
|
|
461
469
|
results.failed.push({ id, error: 'Wrap process not connected' });
|
|
462
470
|
}
|
|
@@ -502,11 +510,13 @@ app.post('/api/sessions/broadcast/inject', (req, res) => {
|
|
|
502
510
|
if (session.ownerWs && session.ownerWs.readyState === 1) {
|
|
503
511
|
session.ownerWs.send(JSON.stringify({ type: 'inject', data: prompt }));
|
|
504
512
|
setTimeout(() => {
|
|
505
|
-
if (session.
|
|
513
|
+
if (session.backend === 'cmux' && session.cmuxWorkspaceId) {
|
|
514
|
+
submitViaCmux(id);
|
|
515
|
+
} else if (session.ownerWs && session.ownerWs.readyState === 1) {
|
|
506
516
|
session.ownerWs.send(JSON.stringify({ type: 'inject', data: '\r' }));
|
|
507
517
|
}
|
|
508
518
|
}, 300);
|
|
509
|
-
results.successful.push({ id, strategy: 'split_cr' });
|
|
519
|
+
results.successful.push({ id, strategy: session.backend === 'cmux' ? 'cmux_split_cr' : 'split_cr' });
|
|
510
520
|
} else {
|
|
511
521
|
results.failed.push({ id, error: 'Wrap process not connected' });
|
|
512
522
|
}
|
|
@@ -680,6 +690,22 @@ function submitViaOsascript(sessionId, keyCombo) {
|
|
|
680
690
|
}
|
|
681
691
|
}
|
|
682
692
|
|
|
693
|
+
function submitViaCmux(sessionId) {
|
|
694
|
+
const { execSync } = require('child_process');
|
|
695
|
+
const session = sessions[sessionId];
|
|
696
|
+
if (!session || !session.cmuxWorkspaceId) return false;
|
|
697
|
+
try {
|
|
698
|
+
execSync(`cmux send-key --workspace ${session.cmuxWorkspaceId} return`, {
|
|
699
|
+
timeout: 5000, stdio: ['pipe', 'pipe', 'pipe']
|
|
700
|
+
});
|
|
701
|
+
console.log(`[SUBMIT] cmux send-key return for ${sessionId} (workspace ${session.cmuxWorkspaceId})`);
|
|
702
|
+
return true;
|
|
703
|
+
} catch (err) {
|
|
704
|
+
console.error(`[SUBMIT] cmux send-key failed for ${sessionId}:`, err.message);
|
|
705
|
+
return false;
|
|
706
|
+
}
|
|
707
|
+
}
|
|
708
|
+
|
|
683
709
|
// POST /api/sessions/:id/submit — CLI-aware submit
|
|
684
710
|
app.post('/api/sessions/:id/submit', (req, res) => {
|
|
685
711
|
const requestedId = req.params.id;
|
|
@@ -692,12 +718,18 @@ app.post('/api/sessions/:id/submit', (req, res) => {
|
|
|
692
718
|
console.log(`[SUBMIT] Session ${id} (${session.command}) using strategy: ${strategy}`);
|
|
693
719
|
|
|
694
720
|
let success = false;
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
721
|
+
// cmux backend takes priority
|
|
722
|
+
if (session.backend === 'cmux' && session.cmuxWorkspaceId) {
|
|
723
|
+
success = submitViaCmux(id);
|
|
724
|
+
}
|
|
725
|
+
if (!success) {
|
|
726
|
+
if (strategy === 'pty_cr') {
|
|
727
|
+
success = submitViaPty(session);
|
|
728
|
+
} else if (strategy === 'osascript_cmd_enter') {
|
|
729
|
+
success = submitViaOsascript(id, 'cmd_enter');
|
|
730
|
+
} else {
|
|
731
|
+
success = submitViaPty(session); // fallback
|
|
732
|
+
}
|
|
701
733
|
}
|
|
702
734
|
|
|
703
735
|
if (success) {
|
|
@@ -725,10 +757,16 @@ app.post('/api/sessions/submit-all', (req, res) => {
|
|
|
725
757
|
const strategy = getSubmitStrategy(session.command);
|
|
726
758
|
let success = false;
|
|
727
759
|
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
760
|
+
// cmux backend takes priority
|
|
761
|
+
if (session.backend === 'cmux' && session.cmuxWorkspaceId) {
|
|
762
|
+
success = submitViaCmux(id);
|
|
763
|
+
}
|
|
764
|
+
if (!success) {
|
|
765
|
+
if (strategy === 'pty_cr') {
|
|
766
|
+
success = submitViaPty(session);
|
|
767
|
+
} else if (strategy === 'osascript_cmd_enter') {
|
|
768
|
+
success = submitViaOsascript(id, 'cmd_enter');
|
|
769
|
+
}
|
|
732
770
|
}
|
|
733
771
|
|
|
734
772
|
if (success) {
|
|
@@ -818,14 +856,24 @@ app.post('/api/sessions/:id/inject', (req, res) => {
|
|
|
818
856
|
|
|
819
857
|
if (!no_enter) {
|
|
820
858
|
setTimeout(() => {
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
859
|
+
let submitted = false;
|
|
860
|
+
|
|
861
|
+
// 1. cmux backend: use cmux send-key
|
|
862
|
+
if (session.backend === 'cmux' && session.cmuxWorkspaceId) {
|
|
863
|
+
submitted = submitViaCmux(id);
|
|
864
|
+
if (submitted) console.log(`[INJECT] cmux submit for ${id}`);
|
|
865
|
+
}
|
|
866
|
+
|
|
867
|
+
// 2. kitty/default backend: osascript primary
|
|
868
|
+
if (!submitted) {
|
|
869
|
+
const submitStrategy = getSubmitStrategy(session.command);
|
|
870
|
+
const keyCombo = submitStrategy === 'osascript_cmd_enter' ? 'cmd_enter' : 'return_key';
|
|
871
|
+
submitted = submitViaOsascript(id, keyCombo);
|
|
872
|
+
}
|
|
873
|
+
|
|
874
|
+
// 3. Fallback: kitty send-text → WS
|
|
875
|
+
if (!submitted) {
|
|
876
|
+
console.log(`[INJECT] submit fallback for ${id}`);
|
|
829
877
|
if (wid && sock) {
|
|
830
878
|
try {
|
|
831
879
|
require('child_process').execSync(`kitty @ --to unix:${sock} send-text --match id:${wid} $'\\r'`, {
|
|
@@ -839,7 +887,7 @@ app.post('/api/sessions/:id/inject', (req, res) => {
|
|
|
839
887
|
}
|
|
840
888
|
}
|
|
841
889
|
|
|
842
|
-
// Update tab title
|
|
890
|
+
// Update tab title (kitty-specific, safe to fail)
|
|
843
891
|
if (wid && sock) {
|
|
844
892
|
try {
|
|
845
893
|
require('child_process').execSync(`kitty @ --to unix:${sock} set-tab-title --match id:${wid} '⚡ telepty :: ${id}'`, {
|
|
@@ -848,7 +896,7 @@ app.post('/api/sessions/:id/inject', (req, res) => {
|
|
|
848
896
|
} catch {}
|
|
849
897
|
}
|
|
850
898
|
}, 500);
|
|
851
|
-
submitResult = { deferred: true, strategy: 'osascript_with_fallback' };
|
|
899
|
+
submitResult = { deferred: true, strategy: session.backend === 'cmux' ? 'cmux_with_fallback' : 'osascript_with_fallback' };
|
|
852
900
|
}
|
|
853
901
|
} else {
|
|
854
902
|
// Spawned sessions: direct PTY write
|
|
@@ -1023,6 +1071,14 @@ function busAutoRoute(msg) {
|
|
|
1023
1071
|
delivered = true;
|
|
1024
1072
|
} catch {}
|
|
1025
1073
|
}
|
|
1074
|
+
// cmux backend: use WS for text, cmux send-key for enter
|
|
1075
|
+
if (!delivered && targetSession.backend === 'cmux' && targetSession.cmuxWorkspaceId) {
|
|
1076
|
+
if (targetSession.type === 'wrapped' && targetSession.ownerWs && targetSession.ownerWs.readyState === 1) {
|
|
1077
|
+
targetSession.ownerWs.send(JSON.stringify({ type: 'inject', data: prompt }));
|
|
1078
|
+
setTimeout(() => submitViaCmux(targetId), 500);
|
|
1079
|
+
delivered = true;
|
|
1080
|
+
}
|
|
1081
|
+
}
|
|
1026
1082
|
if (!delivered) {
|
|
1027
1083
|
if (targetSession.type === 'wrapped' && targetSession.ownerWs && targetSession.ownerWs.readyState === 1) {
|
|
1028
1084
|
targetSession.ownerWs.send(JSON.stringify({ type: 'inject', data: prompt }));
|
package/package.json
CHANGED
package/tui.js
CHANGED
|
@@ -12,7 +12,7 @@ const DAEMON_URL = `http://localhost:${PORT}`;
|
|
|
12
12
|
const POLL_INTERVAL = 2000;
|
|
13
13
|
const STALE_THRESHOLD = 120; // seconds idle before "stale"
|
|
14
14
|
const PROJECTS_DIR = path.join(os.homedir(), 'projects');
|
|
15
|
-
const DEFAULT_CLI = 'claude --dangerously-skip-permissions';
|
|
15
|
+
const DEFAULT_CLI = 'claude --dangerously-skip-permissions --continue';
|
|
16
16
|
|
|
17
17
|
class TuiDashboard {
|
|
18
18
|
constructor() {
|