@dmsdc-ai/aigentry-telepty 0.1.1 → 0.1.3
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/.gemini/skills/telepty/SKILL.md +22 -4
- package/cli.js +27 -6
- package/clipboard_image.png +0 -0
- package/package.json +2 -4
- package/mcp.js +0 -118
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
# telepty
|
|
2
2
|
|
|
3
3
|
**Description:**
|
|
4
|
-
Help the user interact with the `telepty` daemon, check their current session ID, list active sessions, and inject commands into remote or local PTY sessions.
|
|
4
|
+
Help the user interact with the `telepty` daemon, check their current session ID, list active sessions, and inject commands or JSON events into remote or local PTY sessions. All operations are performed using standard CLI commands or `curl`.
|
|
5
5
|
|
|
6
6
|
**Trigger:**
|
|
7
|
-
When the user asks about their current session ID
|
|
7
|
+
When the user asks about their current session ID, wants to check active sessions, wants to inject a prompt/command into a specific session, wants to send a JSON event via the bus, wants to subscribe/listen to the bus, or wants to update telepty.
|
|
8
8
|
|
|
9
9
|
**Instructions:**
|
|
10
10
|
1. **To check the current session ID:**
|
|
11
11
|
- Execute `run_shell_command` with `echo $TELEPTY_SESSION_ID`.
|
|
12
|
-
- If the value is empty, inform the user that the current shell is *not* running inside a telepty spawned session
|
|
13
|
-
- If it has a value, output it clearly
|
|
12
|
+
- If the value is empty, inform the user that the current shell is *not* running inside a telepty spawned session.
|
|
13
|
+
- If it has a value, output it clearly.
|
|
14
14
|
2. **To list all sessions:**
|
|
15
15
|
- Run `telepty list`.
|
|
16
16
|
3. **To inject a command into another session:**
|
|
@@ -19,3 +19,21 @@ When the user asks about their current session ID (e.g. "내 세션 ID가 뭐야
|
|
|
19
19
|
- For multicasting to multiple specific sessions: Run `telepty multicast <id1>,<id2> "<message or command>"`.
|
|
20
20
|
4. **To update telepty:**
|
|
21
21
|
- Run `telepty update`.
|
|
22
|
+
5. **To publish a JSON event to the Event Bus (/api/bus):**
|
|
23
|
+
- Use `curl` to post directly to the local daemon (it will relay to all active clients).
|
|
24
|
+
- First, get the token: `TOKEN=$(cat ~/.telepty/config.json | grep authToken | cut -d '"' -f 4)`
|
|
25
|
+
- Then run:
|
|
26
|
+
```bash
|
|
27
|
+
curl -X POST http://127.0.0.1:3848/api/bus/publish \
|
|
28
|
+
-H "Content-Type: application/json" \
|
|
29
|
+
-H "x-telepty-token: $TOKEN" \
|
|
30
|
+
-d '{"type": "my_event", "payload": "data"}'
|
|
31
|
+
```
|
|
32
|
+
- (Modify the JSON payload structure according to the user's specific request.)
|
|
33
|
+
6. **To subscribe to the Event Bus (Listen for JSON events):**
|
|
34
|
+
- If the user wants to wait for and listen to messages from other agents, simply run `telepty listen`.
|
|
35
|
+
- Run it in the background and redirect output to a log file so you can periodically check it:
|
|
36
|
+
```bash
|
|
37
|
+
nohup telepty listen > .telepty_bus_events.log 2>&1 &
|
|
38
|
+
```
|
|
39
|
+
- Inform the user that the agent is now listening, and any received JSON messages will be saved to `.telepty_bus_events.log` in the current directory. (You can read this file using `read_file` to see what messages arrived).
|
package/cli.js
CHANGED
|
@@ -305,11 +305,6 @@ async function main() {
|
|
|
305
305
|
return;
|
|
306
306
|
}
|
|
307
307
|
|
|
308
|
-
if (cmd === 'mcp') {
|
|
309
|
-
require('./mcp.js');
|
|
310
|
-
return;
|
|
311
|
-
}
|
|
312
|
-
|
|
313
308
|
if (cmd === 'daemon') {
|
|
314
309
|
console.log('Starting telepty daemon...');
|
|
315
310
|
require('./daemon.js');
|
|
@@ -490,6 +485,32 @@ async function main() {
|
|
|
490
485
|
return;
|
|
491
486
|
}
|
|
492
487
|
|
|
488
|
+
if (cmd === 'listen') {
|
|
489
|
+
await ensureDaemonRunning();
|
|
490
|
+
console.log('\x1b[36m👂 Listening to the telepty event bus...\x1b[0m');
|
|
491
|
+
const wsUrl = `ws://${REMOTE_HOST}:${PORT}/api/bus?token=${encodeURIComponent(TOKEN)}`;
|
|
492
|
+
const ws = new WebSocket(wsUrl);
|
|
493
|
+
|
|
494
|
+
ws.on('open', () => {
|
|
495
|
+
// connected
|
|
496
|
+
});
|
|
497
|
+
|
|
498
|
+
ws.on('message', (message) => {
|
|
499
|
+
// Print raw JSON to stdout so agents can parse it
|
|
500
|
+
console.log(message.toString());
|
|
501
|
+
});
|
|
502
|
+
|
|
503
|
+
ws.on('close', () => {
|
|
504
|
+
console.error('\x1b[31m❌ Disconnected from event bus.\x1b[0m');
|
|
505
|
+
process.exit(1);
|
|
506
|
+
});
|
|
507
|
+
|
|
508
|
+
ws.on('error', (err) => {
|
|
509
|
+
console.error('\x1b[31m❌ WebSocket error:\x1b[0m', err.message);
|
|
510
|
+
});
|
|
511
|
+
return;
|
|
512
|
+
}
|
|
513
|
+
|
|
493
514
|
console.log(`
|
|
494
515
|
\x1b[1maigentry-telepty\x1b[0m - Remote PTY Control
|
|
495
516
|
|
|
@@ -501,8 +522,8 @@ Usage:
|
|
|
501
522
|
telepty inject <id> "<prompt>" Inject text into a single session
|
|
502
523
|
telepty multicast <id1,id2> "<prompt>" Inject text into multiple specific sessions
|
|
503
524
|
telepty broadcast "<prompt>" Inject text into ALL active sessions
|
|
525
|
+
telepty listen Listen to the event bus and print JSON to stdout
|
|
504
526
|
telepty update Update telepty to the latest version
|
|
505
|
-
telepty mcp Start the MCP stdio server
|
|
506
527
|
`);
|
|
507
528
|
}
|
|
508
529
|
|
|
Binary file
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dmsdc-ai/aigentry-telepty",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.3",
|
|
4
4
|
"main": "daemon.js",
|
|
5
5
|
"bin": {
|
|
6
6
|
"telepty": "cli.js",
|
|
@@ -14,14 +14,12 @@
|
|
|
14
14
|
"license": "ISC",
|
|
15
15
|
"description": "",
|
|
16
16
|
"dependencies": {
|
|
17
|
-
"@modelcontextprotocol/sdk": "^1.27.1",
|
|
18
17
|
"cors": "^2.8.6",
|
|
19
18
|
"express": "^5.2.1",
|
|
20
19
|
"node-pty": "^1.2.0-beta.11",
|
|
21
20
|
"prompts": "^2.4.2",
|
|
22
21
|
"update-notifier": "^5.1.0",
|
|
23
22
|
"uuid": "^13.0.0",
|
|
24
|
-
"ws": "^8.19.0"
|
|
25
|
-
"zod": "^4.3.6"
|
|
23
|
+
"ws": "^8.19.0"
|
|
26
24
|
}
|
|
27
25
|
}
|
package/mcp.js
DELETED
|
@@ -1,118 +0,0 @@
|
|
|
1
|
-
const { Server } = require('@modelcontextprotocol/sdk/server/index.js');
|
|
2
|
-
const { StdioServerTransport } = require('@modelcontextprotocol/sdk/server/stdio.js');
|
|
3
|
-
const { CallToolRequestSchema, ListToolsRequestSchema } = require('@modelcontextprotocol/sdk/types.js');
|
|
4
|
-
const { z } = require('zod');
|
|
5
|
-
const { zodToJsonSchema } = require('zod-to-json-schema');
|
|
6
|
-
const { getConfig } = require('./auth');
|
|
7
|
-
|
|
8
|
-
const config = getConfig();
|
|
9
|
-
const TOKEN = config.authToken;
|
|
10
|
-
|
|
11
|
-
const server = new Server({ name: 'telepty-mcp-server', version: '0.0.1' }, { capabilities: { tools: {} } });
|
|
12
|
-
|
|
13
|
-
const tools = [
|
|
14
|
-
{
|
|
15
|
-
name: 'telepty_list_remote_sessions',
|
|
16
|
-
description: 'List all active AI CLI sessions (PTYs) running on a remote telepty daemon. Used to discover available target session IDs.',
|
|
17
|
-
schema: z.object({ remote_url: z.string().describe('Tailscale IP/Host and port (e.g., 100.100.100.5:3848) of the remote daemon.') })
|
|
18
|
-
},
|
|
19
|
-
{
|
|
20
|
-
name: 'telepty_inject_context',
|
|
21
|
-
description: 'Inject a prompt or context into specific active AI CLI sessions on a remote machine. You can specify a single session ID, multiple session IDs, or broadcast to all.',
|
|
22
|
-
schema: z.object({
|
|
23
|
-
remote_url: z.string(),
|
|
24
|
-
session_ids: z.array(z.string()).optional().describe('An array of exact session IDs to inject into. If not provided, it will inject into session_id.'),
|
|
25
|
-
session_id: z.string().optional().describe('Legacy fallback for a single session ID.'),
|
|
26
|
-
broadcast: z.boolean().optional().describe('If true, injects the prompt into ALL active sessions on the remote daemon. Overrides session_ids.'),
|
|
27
|
-
prompt: z.string().describe('Text to inject into stdin.')
|
|
28
|
-
})
|
|
29
|
-
},
|
|
30
|
-
{
|
|
31
|
-
name: 'telepty_publish_bus_event',
|
|
32
|
-
description: 'Publish a structured JSON event to the telepty in-memory event bus. This is a fire-and-forget broadcast to any AI agents currently listening. If no agents are listening, the message is dropped.',
|
|
33
|
-
schema: z.object({
|
|
34
|
-
remote_url: z.string().describe('Tailscale IP/Host and port (e.g., 100.100.100.5:3848) of the remote daemon.'),
|
|
35
|
-
payload: z.record(z.any()).describe('The structured JSON payload to broadcast to the event bus. Must be an object.')
|
|
36
|
-
})
|
|
37
|
-
}
|
|
38
|
-
];
|
|
39
|
-
|
|
40
|
-
server.setRequestHandler(ListToolsRequestSchema, async () => ({
|
|
41
|
-
tools: tools.map(t => {
|
|
42
|
-
const schema = zodToJsonSchema(t.schema);
|
|
43
|
-
delete schema.$schema;
|
|
44
|
-
if (!schema.type) schema.type = 'object';
|
|
45
|
-
return { name: t.name, description: t.description, inputSchema: schema };
|
|
46
|
-
})
|
|
47
|
-
}));
|
|
48
|
-
|
|
49
|
-
server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
50
|
-
try {
|
|
51
|
-
const { name, arguments: args } = request.params;
|
|
52
|
-
if (name === 'telepty_list_remote_sessions') {
|
|
53
|
-
const baseUrl = args.remote_url.startsWith('http') ? args.remote_url : `http://${args.remote_url}`;
|
|
54
|
-
const res = await fetch(`${baseUrl}/api/sessions`, { headers: { 'x-telepty-token': TOKEN } });
|
|
55
|
-
if (!res.ok) throw new Error(`HTTP ${res.status}`);
|
|
56
|
-
const sessions = await res.json();
|
|
57
|
-
if (!sessions || sessions.length === 0) return { content: [{ type: 'text', text: `No active sessions found on ${args.remote_url}` }] };
|
|
58
|
-
let text = `Active sessions on ${args.remote_url}:\n\n`;
|
|
59
|
-
sessions.forEach(s => { text += `- ID: ${s.id}\n Command: ${s.command}\n Workspace: ${s.cwd}\n\n`; });
|
|
60
|
-
return { content: [{ type: 'text', text }] };
|
|
61
|
-
}
|
|
62
|
-
if (name === 'telepty_inject_context') {
|
|
63
|
-
const baseUrl = args.remote_url.startsWith('http') ? args.remote_url : `http://${args.remote_url}`;
|
|
64
|
-
|
|
65
|
-
let endpoint = '';
|
|
66
|
-
let body = {};
|
|
67
|
-
|
|
68
|
-
if (args.broadcast) {
|
|
69
|
-
endpoint = `${baseUrl}/api/sessions/broadcast/inject`;
|
|
70
|
-
body = { prompt: args.prompt };
|
|
71
|
-
} else if (args.session_ids && args.session_ids.length > 0) {
|
|
72
|
-
endpoint = `${baseUrl}/api/sessions/multicast/inject`;
|
|
73
|
-
body = { session_ids: args.session_ids, prompt: args.prompt };
|
|
74
|
-
} else if (args.session_id) {
|
|
75
|
-
endpoint = `${baseUrl}/api/sessions/${encodeURIComponent(args.session_id)}/inject`;
|
|
76
|
-
body = { prompt: args.prompt };
|
|
77
|
-
} else {
|
|
78
|
-
throw new Error('You must provide either broadcast: true, session_ids: [...], or session_id: "..."');
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
const res = await fetch(endpoint, {
|
|
82
|
-
method: 'POST', headers: { 'Content-Type': 'application/json', 'x-telepty-token': TOKEN }, body: JSON.stringify(body)
|
|
83
|
-
});
|
|
84
|
-
const data = await res.json();
|
|
85
|
-
if (!res.ok) throw new Error(data.error || `HTTP ${res.status}`);
|
|
86
|
-
|
|
87
|
-
let msg = `✅ Successfully injected context.`;
|
|
88
|
-
if (args.broadcast) msg += ` (Broadcasted to ${data.results.successful.length} sessions)`;
|
|
89
|
-
else if (args.session_ids) msg += ` (Multicasted to ${data.results.successful.length} sessions)`;
|
|
90
|
-
else msg += ` (Targeted session '${args.session_id}')`;
|
|
91
|
-
|
|
92
|
-
return { content: [{ type: 'text', text: msg }] };
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
if (name === 'telepty_publish_bus_event') {
|
|
96
|
-
const baseUrl = args.remote_url.startsWith('http') ? args.remote_url : `http://${args.remote_url}`;
|
|
97
|
-
|
|
98
|
-
const res = await fetch(`${baseUrl}/api/bus/publish`, {
|
|
99
|
-
method: 'POST', headers: { 'Content-Type': 'application/json', 'x-telepty-token': TOKEN }, body: JSON.stringify(args.payload)
|
|
100
|
-
});
|
|
101
|
-
const data = await res.json();
|
|
102
|
-
if (!res.ok) throw new Error(data.error || `HTTP ${res.status}`);
|
|
103
|
-
|
|
104
|
-
return { content: [{ type: 'text', text: `✅ Successfully published event to the bus. Delivered to ${data.delivered} active listeners.` }] };
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
throw new Error(`Unknown tool: ${name}`);
|
|
108
|
-
} catch (err) {
|
|
109
|
-
return { content: [{ type: 'text', text: `❌ Error: ${err.message}` }], isError: true };
|
|
110
|
-
}
|
|
111
|
-
});
|
|
112
|
-
|
|
113
|
-
async function main() {
|
|
114
|
-
const transport = new StdioServerTransport();
|
|
115
|
-
await server.connect(transport);
|
|
116
|
-
console.error('Telepty MCP Server running on stdio');
|
|
117
|
-
}
|
|
118
|
-
main().catch(console.error);
|