@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.
Files changed (4) hide show
  1. package/cli.js +24 -3
  2. package/daemon.js +82 -26
  3. package/package.json +1 -1
  4. 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({ session_id: sessionId, command, cwd: process.cwd() })
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({ session_id: sessionId, command, cwd: process.cwd() })
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.ownerWs && session.ownerWs.readyState === 1) {
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.ownerWs && session.ownerWs.readyState === 1) {
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
- if (strategy === 'pty_cr') {
696
- success = submitViaPty(session);
697
- } else if (strategy === 'osascript_cmd_enter') {
698
- success = submitViaOsascript(id, 'cmd_enter');
699
- } else {
700
- success = submitViaPty(session); // fallback
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
- if (strategy === 'pty_cr') {
729
- success = submitViaPty(session);
730
- } else if (strategy === 'osascript_cmd_enter') {
731
- success = submitViaOsascript(id, 'cmd_enter');
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
- // Primary: osascript keystroke (reliable across all CLIs)
822
- const submitStrategy = getSubmitStrategy(session.command);
823
- const keyCombo = submitStrategy === 'osascript_cmd_enter' ? 'cmd_enter' : 'return_key';
824
- const osascriptOk = submitViaOsascript(id, keyCombo);
825
-
826
- if (!osascriptOk) {
827
- // Fallback: kitty send-text → WS
828
- console.log(`[INJECT] osascript submit failed for ${id}, trying fallback`);
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 regardless of submit method
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dmsdc-ai/aigentry-telepty",
3
- "version": "0.1.65",
3
+ "version": "0.1.67",
4
4
  "main": "daemon.js",
5
5
  "bin": {
6
6
  "aigentry-telepty": "install.js",
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() {