@dmsdc-ai/aigentry-telepty 0.1.80 → 0.1.82

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/README.md +113 -54
  2. package/cli.js +93 -37
  3. package/daemon.js +10 -8
  4. package/package.json +25 -4
package/README.md CHANGED
@@ -1,92 +1,151 @@
1
- # @dmsdc-ai/aigentry-telepty
1
+ # telepty
2
2
 
3
- **Cross-machine PTY-based remote prompt injection daemon for AI CLIs.**
3
+ **Connect any terminal to any terminal, any machine.**
4
4
 
5
- `telepty` (Tele-Prompt) is a lightweight background daemon that bridges the gap between the network and interactive AI command-line interfaces. It allows you to seamlessly share, attach to, and inject commands into terminal sessions across different machines.
5
+ telepty is a lightweight PTY multiplexer and session bridge. It lets you spawn, attach to, and inject commands into terminal sessions — locally or across machines via Tailscale.
6
6
 
7
- Its primary user experience is prompt-driven operation inside LLM CLIs and the built-in TUI. Raw `telepty ...` commands are the lower-level control surface.
7
+ Built for AI CLI workflows (Claude Code, Codex, Gemini CLI), but works with any interactive terminal program.
8
8
 
9
- ## One-Click Installation & Update
9
+ ## Install
10
10
 
11
- To install or update `telepty` on any machine (macOS, Linux, or Windows), just run the command for your OS. (Node.js will be automatically installed if you don't have it).
12
-
13
- ### For macOS and Linux (Ubuntu, CentOS, etc.)
14
- Open your terminal and run:
15
11
  ```bash
12
+ # macOS / Linux
16
13
  curl -fsSL https://raw.githubusercontent.com/dmsdc-ai/aigentry-telepty/main/install.sh | bash
17
- ```
18
14
 
19
- ### For Windows (PowerShell)
20
- Open PowerShell as Administrator and run:
21
- ```powershell
15
+ # Windows (PowerShell as Admin)
22
16
  iwr -useb https://raw.githubusercontent.com/dmsdc-ai/aigentry-telepty/main/install.ps1 | iex
17
+
18
+ # Or via npm
19
+ npm install -g @dmsdc-ai/aigentry-telepty
23
20
  ```
24
21
 
25
- You can also launch the installer through npm without downloading the script first:
22
+ The installer sets up telepty as a background service (`launchd` on macOS, `systemd` on Linux, detached process on Windows).
23
+
24
+ ## Quick Start
26
25
 
27
26
  ```bash
28
- npx --yes @dmsdc-ai/aigentry-telepty@latest
29
- ```
27
+ # 1. Start the daemon
28
+ telepty daemon
29
+
30
+ # 2. Wrap an existing CLI session for remote control
31
+ telepty allow --id my-session claude
32
+
33
+ # 3. List active sessions (local + Tailnet)
34
+ telepty list
30
35
 
31
- *These single commands will install the package globally and automatically configure it to run as a background service specific to your OS (`systemd` for Linux, `launchd` for macOS, or a detached background process for Windows).*
32
- The installer now stops older local telepty daemons before starting the new one, so updates do not leave duplicate background processes behind.
36
+ # 4. Inject a prompt into a session
37
+ telepty inject my-session "explain this codebase"
33
38
 
34
- ## Seamless Usage
39
+ # 5. Attach to a session interactively
40
+ telepty attach my-session
35
41
 
36
- 1. **Start a background session:**
37
- ```bash
38
- telepty spawn --id "my-session" bash
39
- ```
42
+ # 6. Broadcast to all sessions
43
+ telepty broadcast "status report"
44
+ ```
40
45
 
41
- 2. **Attach to a session (Local or Remote):**
42
- ```bash
43
- telepty attach
44
- ```
45
- *telepty will automatically discover active sessions on your local machine and across your Tailscale network!*
46
+ ## Core Commands
47
+
48
+ | Command | Description |
49
+ |---------|-------------|
50
+ | `telepty daemon` | Start the background daemon (port 3848) |
51
+ | `telepty allow --id <name> <cmd>` | Wrap a CLI for inject control |
52
+ | `telepty spawn --id <name> <cmd>` | Spawn a new background session |
53
+ | `telepty list [--json]` | List sessions across all discovered hosts |
54
+ | `telepty attach [id[@host]]` | Attach to a session (interactive picker if no ID) |
55
+ | `telepty inject <id[@host]> "text"` | Inject text into a session |
56
+ | `telepty enter <id[@host]>` | Send Enter/Return to a session |
57
+ | `telepty multicast <id1,id2> "text"` | Inject into multiple sessions |
58
+ | `telepty broadcast "text"` | Inject into ALL sessions |
59
+ | `telepty rename <old> <new>` | Rename a session |
60
+ | `telepty read-screen <id> [--lines N]` | Read session screen buffer |
61
+ | `telepty reply "text"` | Reply to the last injector |
62
+ | `telepty monitor` | Real-time event billboard |
63
+ | `telepty listen` | Stream event bus as JSON |
64
+ | `telepty tui` | Full TUI dashboard |
65
+ | `telepty layout [grid\|tall\|stack]` | Arrange kitty windows |
66
+ | `telepty update` | Update to latest version |
67
+
68
+ ## Cross-Machine Sessions
69
+
70
+ telepty auto-discovers sessions across your Tailnet. All commands (`list`, `attach`, `inject`, `rename`, `multicast`, `broadcast`) work seamlessly across machines.
71
+
72
+ When the same session ID exists on multiple hosts, disambiguate with `session_id@host`:
46
73
 
47
- 3. **Inject commands remotely:**
48
- ```bash
49
- telepty inject my-session "echo 'Hello from nowhere!'"
50
- ```
74
+ ```bash
75
+ telepty inject my-session@macbook "hello"
76
+ telepty attach worker@server-01
77
+ ```
51
78
 
52
- 4. **Universal CLI submit (split_cr):**
79
+ ## How It Works
53
80
 
54
- All AI CLIs (Claude, Codex, Gemini) submit reliably via the `split_cr` strategy — text is injected first, then `\r` is sent separately after a 300ms delay. This works universally across all CLIs without any per-CLI workarounds.
81
+ ```
82
+ CLI (telepty) ──> HTTP/WS ──> Daemon (:3848)
83
+ ├── Session WebSocket (/api/sessions/:id)
84
+ ├── Event Bus WebSocket (/api/bus)
85
+ └── REST API (/api/sessions/*)
86
+ ```
55
87
 
56
- ```bash
57
- # The inject API handles split_cr automatically
58
- curl -X POST http://127.0.0.1:3848/api/sessions/my-session/inject \
59
- -H "Content-Type: application/json" \
60
- -d '{"prompt": "your command here"}'
61
- ```
88
+ - **`allow`** wraps a CLI process in a PTY bridge, enabling remote inject
89
+ - **`inject`** delivers text via the fastest available path: kitty terminal API, WebSocket, or UDS (Unix Domain Socket for embedded integrations)
90
+ - **`submit`** is handled separately from text injection for reliability across all AI CLIs
62
91
 
63
- CLI commands such as `list`, `attach`, `inject`, `rename`, `multicast`, and `broadcast` now auto-discover sessions across your Tailnet by default. If the same session ID exists on multiple hosts, disambiguate with `session_id@host`.
92
+ ## Inject Delivery Paths
64
93
 
65
- ## Testing
94
+ | Priority | Method | When |
95
+ |----------|--------|------|
96
+ | 1 | `kitty @ send-text` | Terminal supports kitty protocol |
97
+ | 2 | UDS (Unix Domain Socket) | Embedded IPC sessions (e.g. aterm) |
98
+ | 3 | WebSocket PTY write | Wrapped sessions via allow-bridge |
99
+
100
+ ## AI CLI Integration
66
101
 
67
- Run the full regression suite locally:
102
+ telepty works as a session bridge for AI CLIs. Use `allow` to wrap any CLI:
68
103
 
69
104
  ```bash
70
- npm test
105
+ # Claude Code
106
+ telepty allow --id claude-main claude
107
+
108
+ # Codex
109
+ telepty allow --id codex-main codex
110
+
111
+ # Gemini CLI
112
+ telepty allow --id gemini-main gemini
71
113
  ```
72
114
 
73
- Keep the suite running while you work:
115
+ Then inject prompts, read output, or attach from anywhere:
74
116
 
75
117
  ```bash
76
- npm run test:watch
118
+ telepty inject claude-main "refactor the auth module"
119
+ telepty read-screen claude-main --lines 50
120
+ telepty attach claude-main
77
121
  ```
78
122
 
79
- The automated suite covers config generation, daemon HTTP APIs, WebSocket attach/output flow, bus events, session deletion regressions, and CLI smoke tests against a real daemon process.
123
+ ## Deliberation (Multi-Session Discussion)
80
124
 
81
- If the local daemon ever gets stuck or duplicated, open `telepty` and choose `Repair local daemon`.
125
+ Coordinate structured discussions across multiple AI sessions:
126
+
127
+ ```bash
128
+ telepty deliberate --topic "API design for v2" --sessions claude-1,claude-2,codex-1
129
+ telepty deliberate status
130
+ telepty deliberate end <thread_id>
131
+ ```
82
132
 
83
133
  ## Skill Installation
84
134
 
85
- The package installer opens the telepty skill TUI automatically when you run it in a terminal.
135
+ telepty ships with packaged skills for Claude Code, Codex, and Gemini CLI. Run the interactive installer:
136
+
137
+ ```bash
138
+ telepty
139
+ # Choose "Install telepty skills"
140
+ ```
141
+
142
+ ## Testing
143
+
144
+ ```bash
145
+ npm test # 70 tests (node:test)
146
+ npm run test:watch # Watch mode
147
+ ```
86
148
 
87
- To reopen it later, run `telepty` and choose `Install telepty skills`.
149
+ ## License
88
150
 
89
- The TUI lets you choose:
90
- - which packaged skills to install
91
- - which target clients to install into (`Claude Code`, `Codex`, `Gemini`)
92
- - whether each target uses a global path, the current project path, or a custom path
151
+ ISC
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); }
@@ -2711,43 +2744,66 @@ Discuss the following topic from your project's perspective. Engage with other s
2711
2744
  }
2712
2745
 
2713
2746
  console.log(`
2714
- \x1b[1maigentry-telepty\x1b[0m - Remote PTY Control
2715
-
2716
- Usage:
2717
- telepty daemon Start the background daemon
2718
- telepty spawn --id <id> <command> [args...] Spawn a new background CLI
2719
- telepty allow [--id <id>] [--auto-restart] <command> [args...] Allow inject on a CLI (auto-restart on crash)
2720
- telepty list [--json] List all active sessions across discovered hosts
2721
- telepty attach [id[@host]] Attach to a session (Interactive picker if no ID)
2722
- telepty inject [--ref [file]] [--from <id>] [--reply-to <id>] <id[@host]> "<prompt>" Inject text into a single session
2723
- telepty enter <id[@host]> Send only Enter/Return to a single session
2724
- telepty read-screen <id[@host]> [--lines N] [--raw] Read session screen buffer
2725
- telepty reply "<text>" Reply to the session that last injected into $TELEPTY_SESSION_ID
2726
- telepty status-report [--id <id>] --phase <phase> [--task <text>] [--blocker <text>] [--needs-input] [--thread-id <id>] [--seq N]
2727
- telepty multicast <id1[@host],id2[@host]> "<prompt>" Inject text into multiple specific sessions
2728
- telepty broadcast [--ref [file]] "<prompt>" Inject text into ALL active sessions
2729
- telepty rename <old_id[@host]> <new_id> Rename a session (updates terminal title too)
2730
- telepty session info <id[@host]> [--json] Show detailed session metadata
2731
- telepty connect <user@host> [--name N] [--port P] Connect to a remote machine via SSH tunnel
2732
- telepty disconnect <name> | --all Disconnect from a remote machine
2733
- telepty peers [--remove <name>] List connected and known peers
2734
- telepty listen Listen to the event bus and print JSON to stdout
2735
- telepty monitor Human-readable real-time billboard of bus events
2736
- telepty update Update telepty to the latest version
2737
- telepty layout [grid|tall|stack] Arrange kitty windows on screen (default: grid)
2738
-
2739
- Handoff Commands:
2740
- handoff list [--status=S] List handoffs (filter: pending/claimed/executing/completed)
2741
- handoff drop [options] Create handoff from synthesis (pipe JSON or use --summary/--tasks)
2742
- handoff claim <id> [--agent=S] Claim a pending handoff
2743
- handoff status <id> [status] Get or update handoff status
2744
- handoff get <id> Get full synthesis JSON (for piping)
2745
-
2746
- Deliberation Commands:
2747
- deliberate --topic "..." [--sessions s1,s2] [--context file]
2748
- Start multi-session deliberation
2749
- deliberate status [thread_id] List threads or show thread details
2750
- deliberate end <thread_id> Close a deliberation thread
2747
+ \x1b[1mtelepty\x1b[0m Connect any terminal to any terminal, any machine.
2748
+
2749
+ \x1b[1mSession Management:\x1b[0m
2750
+ telepty daemon Start the background daemon (port 3848)
2751
+ telepty spawn --id <id> <command> [args...] Spawn a new background session
2752
+ telepty allow [--id <id>] [--auto-restart] <command> [args...] Wrap a CLI for remote control
2753
+ telepty list [--json] List sessions (local + Tailnet)
2754
+ telepty attach [id[@host]] Attach interactively (picker if no ID)
2755
+ telepty rename <old_id[@host]> <new_id> Rename a session
2756
+ telepty session info <id[@host]> [--json] Show session metadata
2757
+
2758
+ \x1b[1mInject & Communicate:\x1b[0m
2759
+ telepty inject [--ref [file]] [--from <id>] <id[@host]> "<prompt>" Inject text
2760
+ telepty enter <id[@host]> Send Enter/Return
2761
+ telepty reply "<text>" Reply to last injector
2762
+ telepty multicast <id1,id2> "<prompt>" Inject into multiple sessions
2763
+ telepty broadcast [--ref [file]] "<prompt>" Inject into ALL sessions
2764
+ telepty read-screen <id[@host]> [--lines N] Read session screen buffer
2765
+
2766
+ \x1b[1mCross-Machine:\x1b[0m
2767
+ telepty connect <user@host> [--name N] [--port P] SSH tunnel to remote host
2768
+ telepty disconnect <name> | --all Disconnect remote host
2769
+ telepty peers [--remove <name>] List connected peers
2770
+
2771
+ \x1b[1mMonitoring:\x1b[0m
2772
+ telepty tui Full TUI dashboard
2773
+ telepty monitor Real-time event billboard
2774
+ telepty listen Stream event bus as JSON
2775
+
2776
+ \x1b[1mHandoff:\x1b[0m
2777
+ telepty handoff list [--status=S] List handoffs
2778
+ telepty handoff drop [options] Create handoff from synthesis
2779
+ telepty handoff claim <id> [--agent=S] Claim a pending handoff
2780
+ telepty handoff status <id> [status] Get/update handoff status
2781
+
2782
+ \x1b[1mDeliberation:\x1b[0m
2783
+ telepty deliberate --topic "..." [--sessions s1,s2] Start multi-session discussion
2784
+ telepty deliberate status [thread_id] Show thread details
2785
+ telepty deliberate end <thread_id> Close a thread
2786
+
2787
+ \x1b[1mOther:\x1b[0m
2788
+ telepty update Update to latest version
2789
+ telepty layout [grid|tall|stack] Arrange terminal windows
2790
+ telepty status-report --phase <p> [options] Emit structured status event
2791
+
2792
+ \x1b[1mExamples:\x1b[0m
2793
+ \x1b[2m# Wrap Claude Code for remote control\x1b[0m
2794
+ telepty allow --id my-claude claude
2795
+
2796
+ \x1b[2m# Send a prompt to a session\x1b[0m
2797
+ telepty inject my-claude "explain the auth module"
2798
+
2799
+ \x1b[2m# Read what a session is showing\x1b[0m
2800
+ telepty read-screen my-claude --lines 30
2801
+
2802
+ \x1b[2m# Broadcast to all sessions\x1b[0m
2803
+ telepty broadcast "status report please"
2804
+
2805
+ \x1b[2m# Inject into a session on another machine\x1b[0m
2806
+ telepty inject my-claude@server-01 "run the tests"
2751
2807
  `);
2752
2808
  }
2753
2809
 
package/daemon.js CHANGED
@@ -1478,18 +1478,20 @@ app.delete('/api/sessions/:id', (req, res) => {
1478
1478
  try {
1479
1479
  session.isClosing = true;
1480
1480
  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 {
1481
+ if (session.clients) session.clients.forEach(ws => ws.close(1000, 'Session destroyed'));
1482
+ } else if (session.ptyProcess) {
1486
1483
  session.ptyProcess.kill();
1487
- console.log(`[KILL] Session ${id} forcefully closed`);
1488
- persistSessions();
1489
1484
  }
1485
+ delete sessions[id];
1486
+ console.log(`[KILL] Session ${id} removed`);
1487
+ persistSessions();
1490
1488
  res.json({ success: true, status: 'closing' });
1491
1489
  } catch (err) {
1492
- res.status(500).json({ error: err.message });
1490
+ // Even if kill fails, remove from registry
1491
+ delete sessions[id];
1492
+ persistSessions();
1493
+ console.log(`[KILL] Session ${id} force-removed (process cleanup error: ${err.message})`);
1494
+ res.json({ success: true, status: 'force-removed' });
1493
1495
  }
1494
1496
  });
1495
1497
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dmsdc-ai/aigentry-telepty",
3
- "version": "0.1.80",
3
+ "version": "0.1.82",
4
4
  "main": "daemon.js",
5
5
  "bin": {
6
6
  "aigentry-telepty": "install.js",
@@ -12,10 +12,31 @@
12
12
  "test:watch": "node --test --watch test/auth.test.js test/daemon.test.js test/daemon-singleton.test.js test/cli.test.js test/skill-installer.test.js test/interactive-terminal.test.js test/runtime-info.test.js test/session-routing.test.js",
13
13
  "test:ci": "node --test --test-reporter=spec test/auth.test.js test/daemon.test.js test/daemon-singleton.test.js test/cli.test.js test/skill-installer.test.js test/interactive-terminal.test.js test/runtime-info.test.js test/session-routing.test.js"
14
14
  },
15
- "keywords": [],
16
- "author": "",
15
+ "keywords": [
16
+ "pty",
17
+ "terminal",
18
+ "session",
19
+ "multiplexer",
20
+ "remote",
21
+ "inject",
22
+ "ai-cli",
23
+ "claude",
24
+ "codex",
25
+ "gemini",
26
+ "cross-machine",
27
+ "tailscale"
28
+ ],
29
+ "author": "dmsdc-ai",
17
30
  "license": "ISC",
18
- "description": "",
31
+ "description": "Universal terminal session bridge — connect any terminal to any terminal, any machine",
32
+ "repository": {
33
+ "type": "git",
34
+ "url": "git+https://github.com/dmsdc-ai/aigentry-telepty.git"
35
+ },
36
+ "homepage": "https://github.com/dmsdc-ai/aigentry-telepty#readme",
37
+ "bugs": {
38
+ "url": "https://github.com/dmsdc-ai/aigentry-telepty/issues"
39
+ },
19
40
  "dependencies": {
20
41
  "blessed": "^0.1.81",
21
42
  "cors": "^2.8.6",