@dmsdc-ai/aigentry-telepty 0.1.9 → 0.1.11
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/README.md +7 -5
- package/cli.js +41 -8
- package/interactive-terminal.js +18 -1
- package/package.json +5 -4
- package/runtime-info.js +41 -0
- package/skills/telepty/SKILL.md +48 -35
package/README.md
CHANGED
|
@@ -20,6 +20,12 @@ Open PowerShell as Administrator and run:
|
|
|
20
20
|
iwr -useb https://raw.githubusercontent.com/dmsdc-ai/aigentry-telepty/main/install.ps1 | iex
|
|
21
21
|
```
|
|
22
22
|
|
|
23
|
+
You can also launch the installer through npm without downloading the script first:
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
npx --yes @dmsdc-ai/aigentry-telepty@latest
|
|
27
|
+
```
|
|
28
|
+
|
|
23
29
|
*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).*
|
|
24
30
|
The installer now stops older local telepty daemons before starting the new one, so updates do not leave duplicate background processes behind.
|
|
25
31
|
|
|
@@ -57,11 +63,7 @@ npm run test:watch
|
|
|
57
63
|
|
|
58
64
|
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.
|
|
59
65
|
|
|
60
|
-
If
|
|
61
|
-
|
|
62
|
-
```bash
|
|
63
|
-
telepty cleanup-daemons
|
|
64
|
-
```
|
|
66
|
+
If the local daemon ever gets stuck or duplicated, open `telepty` and choose `Repair local daemon`.
|
|
65
67
|
|
|
66
68
|
## Skill Installation
|
|
67
69
|
|
package/cli.js
CHANGED
|
@@ -10,7 +10,8 @@ const updateNotifier = require('update-notifier');
|
|
|
10
10
|
const pkg = require('./package.json');
|
|
11
11
|
const { getConfig } = require('./auth');
|
|
12
12
|
const { cleanupDaemonProcesses } = require('./daemon-control');
|
|
13
|
-
const { attachInteractiveTerminal } = require('./interactive-terminal');
|
|
13
|
+
const { attachInteractiveTerminal, getTerminalSize } = require('./interactive-terminal');
|
|
14
|
+
const { getRuntimeInfo } = require('./runtime-info');
|
|
14
15
|
const { runInteractiveSkillInstaller } = require('./skill-installer');
|
|
15
16
|
const args = process.argv.slice(2);
|
|
16
17
|
|
|
@@ -55,6 +56,20 @@ function startDetachedDaemon() {
|
|
|
55
56
|
cp.unref();
|
|
56
57
|
}
|
|
57
58
|
|
|
59
|
+
async function repairLocalDaemon(options = {}) {
|
|
60
|
+
const restart = options.restart !== false;
|
|
61
|
+
const results = cleanupDaemonProcesses();
|
|
62
|
+
|
|
63
|
+
if (!restart) {
|
|
64
|
+
return { stopped: results.stopped.length, failed: results.failed.length, meta: null };
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
startDetachedDaemon();
|
|
68
|
+
await new Promise((resolve) => setTimeout(resolve, 1000));
|
|
69
|
+
const meta = await getDaemonMeta('127.0.0.1');
|
|
70
|
+
return { stopped: results.stopped.length, failed: results.failed.length, meta };
|
|
71
|
+
}
|
|
72
|
+
|
|
58
73
|
async function discoverSessions() {
|
|
59
74
|
await ensureDaemonRunning();
|
|
60
75
|
const hosts = ['127.0.0.1'];
|
|
@@ -129,7 +144,7 @@ async function ensureDaemonRunning(options = {}) {
|
|
|
129
144
|
|
|
130
145
|
const meta = await getDaemonMeta('127.0.0.1');
|
|
131
146
|
if (!meta || !requiredCapabilities.every((item) => meta.capabilities.includes(item))) {
|
|
132
|
-
console.error('❌ Failed to start a compatible local telepty daemon.
|
|
147
|
+
console.error('❌ Failed to start a compatible local telepty daemon. Open telepty and choose "Repair local daemon", or rerun the installer.');
|
|
133
148
|
}
|
|
134
149
|
}
|
|
135
150
|
|
|
@@ -144,7 +159,10 @@ async function manageInteractiveAttach(sessionId, targetHost) {
|
|
|
144
159
|
console.log(`\n\x1b[32mEntered room '${sessionId}'.\x1b[0m\n`);
|
|
145
160
|
cleanupTerminal = attachInteractiveTerminal(process.stdin, process.stdout, {
|
|
146
161
|
onData: (d) => ws.send(JSON.stringify({ type: 'input', data: d.toString() })),
|
|
147
|
-
onResize: () =>
|
|
162
|
+
onResize: () => {
|
|
163
|
+
const size = getTerminalSize(process.stdout, { cols: 80, rows: 30 });
|
|
164
|
+
ws.send(JSON.stringify({ type: 'resize', cols: size.cols, rows: size.rows }));
|
|
165
|
+
}
|
|
148
166
|
});
|
|
149
167
|
});
|
|
150
168
|
ws.on('message', m => {
|
|
@@ -178,8 +196,10 @@ async function manageInteractiveAttach(sessionId, targetHost) {
|
|
|
178
196
|
}
|
|
179
197
|
|
|
180
198
|
async function manageInteractive() {
|
|
199
|
+
const runtimeInfo = getRuntimeInfo(__dirname);
|
|
181
200
|
console.clear();
|
|
182
201
|
console.log('\x1b[36m\x1b[1m⚡ Telepty Agent Manager\x1b[0m\n');
|
|
202
|
+
console.log(`\x1b[90mVersion ${runtimeInfo.version} Updated ${runtimeInfo.updatedAtLabel}\x1b[0m\n`);
|
|
183
203
|
|
|
184
204
|
while (true) {
|
|
185
205
|
const response = await prompts({
|
|
@@ -192,6 +212,7 @@ async function manageInteractive() {
|
|
|
192
212
|
{ title: '🔌 Allow inject (Run CLI with inject)', value: 'allow' },
|
|
193
213
|
{ title: '💬 Send message to a room (Inject command)', value: 'inject' },
|
|
194
214
|
{ title: '📋 View all open rooms (List sessions)', value: 'list' },
|
|
215
|
+
{ title: '🧹 Repair local daemon', value: 'repair-daemon' },
|
|
195
216
|
{ title: '🧠 Install telepty skills', value: 'install-skills' },
|
|
196
217
|
{ title: '🔄 Update telepty to latest version', value: 'update' },
|
|
197
218
|
{ title: '❌ Exit', value: 'exit' }
|
|
@@ -203,7 +224,7 @@ async function manageInteractive() {
|
|
|
203
224
|
try {
|
|
204
225
|
execSync('npm install -g @dmsdc-ai/aigentry-telepty@latest', { stdio: 'inherit' });
|
|
205
226
|
console.log('\n\x1b[32m✅ Update complete! Restarting daemon...\x1b[0m');
|
|
206
|
-
|
|
227
|
+
await repairLocalDaemon({ restart: true });
|
|
207
228
|
} catch (e) {
|
|
208
229
|
console.error('\n❌ Update failed.\n');
|
|
209
230
|
}
|
|
@@ -223,6 +244,17 @@ async function manageInteractive() {
|
|
|
223
244
|
continue;
|
|
224
245
|
}
|
|
225
246
|
|
|
247
|
+
if (response.action === 'repair-daemon') {
|
|
248
|
+
console.log('\n\x1b[36m🧹 Repairing local telepty daemon...\x1b[0m');
|
|
249
|
+
const result = await repairLocalDaemon({ restart: true });
|
|
250
|
+
if (result.meta) {
|
|
251
|
+
console.log(`✅ Local daemon is healthy. Version ${result.meta.version}, pid ${result.meta.pid}, stopped ${result.stopped} old daemon(s).\n`);
|
|
252
|
+
} else {
|
|
253
|
+
console.log(`⚠️ Daemon cleanup ran, but a fresh local daemon did not respond. Stopped ${result.stopped} old daemon(s).\n`);
|
|
254
|
+
}
|
|
255
|
+
continue;
|
|
256
|
+
}
|
|
257
|
+
|
|
226
258
|
if (response.action === 'install-skills') {
|
|
227
259
|
try {
|
|
228
260
|
await runInteractiveSkillInstaller({ packageRoot: __dirname, cwd: process.cwd() });
|
|
@@ -518,7 +550,8 @@ async function main() {
|
|
|
518
550
|
child.write(data.toString());
|
|
519
551
|
},
|
|
520
552
|
onResize: () => {
|
|
521
|
-
|
|
553
|
+
const size = getTerminalSize(process.stdout, { cols: 120, rows: 40 });
|
|
554
|
+
child.resize(size.cols, size.rows);
|
|
522
555
|
}
|
|
523
556
|
});
|
|
524
557
|
|
|
@@ -594,10 +627,11 @@ async function main() {
|
|
|
594
627
|
ws.send(JSON.stringify({ type: 'input', data: data.toString() }));
|
|
595
628
|
},
|
|
596
629
|
onResize: () => {
|
|
630
|
+
const size = getTerminalSize(process.stdout, { cols: 80, rows: 30 });
|
|
597
631
|
ws.send(JSON.stringify({
|
|
598
632
|
type: 'resize',
|
|
599
|
-
cols:
|
|
600
|
-
rows:
|
|
633
|
+
cols: size.cols,
|
|
634
|
+
rows: size.rows
|
|
601
635
|
}));
|
|
602
636
|
}
|
|
603
637
|
});
|
|
@@ -776,7 +810,6 @@ Usage:
|
|
|
776
810
|
telepty multicast <id1,id2> "<prompt>" Inject text into multiple specific sessions
|
|
777
811
|
telepty broadcast "<prompt>" Inject text into ALL active sessions
|
|
778
812
|
telepty rename <old_id> <new_id> Rename a session (updates terminal title too)
|
|
779
|
-
telepty cleanup-daemons Stop old local telepty daemon processes
|
|
780
813
|
telepty listen Listen to the event bus and print JSON to stdout
|
|
781
814
|
telepty monitor Human-readable real-time billboard of bus events
|
|
782
815
|
telepty update Update telepty to the latest version
|
package/interactive-terminal.js
CHANGED
|
@@ -1,5 +1,21 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
+
function getTerminalSize(output, fallback = {}) {
|
|
4
|
+
const envCols = Number.parseInt(process.env.COLUMNS || '', 10);
|
|
5
|
+
const envRows = Number.parseInt(process.env.LINES || '', 10);
|
|
6
|
+
const fallbackCols = Number.isInteger(fallback.cols) && fallback.cols > 0 ? fallback.cols : 120;
|
|
7
|
+
const fallbackRows = Number.isInteger(fallback.rows) && fallback.rows > 0 ? fallback.rows : 40;
|
|
8
|
+
|
|
9
|
+
const cols = Number.isInteger(output && output.columns) && output.columns > 0
|
|
10
|
+
? output.columns
|
|
11
|
+
: (Number.isInteger(envCols) && envCols > 0 ? envCols : fallbackCols);
|
|
12
|
+
const rows = Number.isInteger(output && output.rows) && output.rows > 0
|
|
13
|
+
? output.rows
|
|
14
|
+
: (Number.isInteger(envRows) && envRows > 0 ? envRows : fallbackRows);
|
|
15
|
+
|
|
16
|
+
return { cols, rows };
|
|
17
|
+
}
|
|
18
|
+
|
|
3
19
|
function removeListener(stream, eventName, handler) {
|
|
4
20
|
if (!handler || !stream) {
|
|
5
21
|
return;
|
|
@@ -50,5 +66,6 @@ function attachInteractiveTerminal(input, output, handlers = {}) {
|
|
|
50
66
|
}
|
|
51
67
|
|
|
52
68
|
module.exports = {
|
|
53
|
-
attachInteractiveTerminal
|
|
69
|
+
attachInteractiveTerminal,
|
|
70
|
+
getTerminalSize
|
|
54
71
|
};
|
package/package.json
CHANGED
|
@@ -1,15 +1,16 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dmsdc-ai/aigentry-telepty",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.11",
|
|
4
4
|
"main": "daemon.js",
|
|
5
5
|
"bin": {
|
|
6
|
+
"aigentry-telepty": "install.js",
|
|
6
7
|
"telepty": "cli.js",
|
|
7
8
|
"telepty-install": "install.js"
|
|
8
9
|
},
|
|
9
10
|
"scripts": {
|
|
10
|
-
"test": "node --test 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",
|
|
11
|
-
"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",
|
|
12
|
-
"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"
|
|
11
|
+
"test": "node --test 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",
|
|
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",
|
|
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"
|
|
13
14
|
},
|
|
14
15
|
"keywords": [],
|
|
15
16
|
"author": "",
|
package/runtime-info.js
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const fs = require('fs');
|
|
4
|
+
const path = require('path');
|
|
5
|
+
|
|
6
|
+
function pad(value) {
|
|
7
|
+
return String(value).padStart(2, '0');
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
function formatTimestamp(date) {
|
|
11
|
+
const year = date.getFullYear();
|
|
12
|
+
const month = pad(date.getMonth() + 1);
|
|
13
|
+
const day = pad(date.getDate());
|
|
14
|
+
const hours = pad(date.getHours());
|
|
15
|
+
const minutes = pad(date.getMinutes());
|
|
16
|
+
const seconds = pad(date.getSeconds());
|
|
17
|
+
const offsetMinutes = -date.getTimezoneOffset();
|
|
18
|
+
const sign = offsetMinutes >= 0 ? '+' : '-';
|
|
19
|
+
const absoluteOffset = Math.abs(offsetMinutes);
|
|
20
|
+
const offsetHours = pad(Math.floor(absoluteOffset / 60));
|
|
21
|
+
const offsetRemainder = pad(absoluteOffset % 60);
|
|
22
|
+
return `${year}-${month}-${day} ${hours}:${minutes}:${seconds} ${sign}${offsetHours}:${offsetRemainder}`;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
function getRuntimeInfo(packageRoot = __dirname) {
|
|
26
|
+
const packageJsonPath = path.join(packageRoot, 'package.json');
|
|
27
|
+
const pkg = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8'));
|
|
28
|
+
const packageStat = fs.statSync(packageJsonPath);
|
|
29
|
+
const updatedAt = packageStat.mtime;
|
|
30
|
+
|
|
31
|
+
return {
|
|
32
|
+
version: pkg.version || 'unknown',
|
|
33
|
+
updatedAt,
|
|
34
|
+
updatedAtLabel: formatTimestamp(updatedAt)
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
module.exports = {
|
|
39
|
+
formatTimestamp,
|
|
40
|
+
getRuntimeInfo
|
|
41
|
+
};
|
package/skills/telepty/SKILL.md
CHANGED
|
@@ -1,86 +1,99 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: telepty
|
|
3
|
+
description: Use telepty to inspect sessions, attach or inject into rooms, repair local daemon issues, and guide users through the TUI-first workflow when telepty is installed.
|
|
4
|
+
---
|
|
5
|
+
|
|
1
6
|
# telepty
|
|
2
7
|
|
|
3
|
-
Use
|
|
8
|
+
Use this skill when the user wants help operating `telepty`, recovering a broken local daemon, or managing telepty sessions in natural language.
|
|
4
9
|
|
|
5
|
-
##
|
|
10
|
+
## Default approach
|
|
6
11
|
|
|
7
|
-
|
|
8
|
-
-
|
|
9
|
-
-
|
|
10
|
-
- Attach to a telepty session
|
|
11
|
-
- Inject a prompt or command into another telepty session
|
|
12
|
-
- Listen to telepty bus events or publish a JSON payload
|
|
13
|
-
- Rename a session
|
|
14
|
-
- Update telepty
|
|
12
|
+
- For interactive human guidance, prefer the `telepty` TUI and point the user to the relevant menu action.
|
|
13
|
+
- For agent execution inside a CLI session, run the underlying `telepty` command directly.
|
|
14
|
+
- When the request is about a broken or duplicated local daemon, repair the daemon before doing session work.
|
|
15
15
|
|
|
16
|
-
##
|
|
16
|
+
## Common actions
|
|
17
17
|
|
|
18
|
-
1. Check the current telepty session:
|
|
18
|
+
1. Check whether the current shell is already inside a telepty session:
|
|
19
19
|
|
|
20
20
|
```bash
|
|
21
21
|
echo "$TELEPTY_SESSION_ID"
|
|
22
22
|
```
|
|
23
23
|
|
|
24
|
-
2.
|
|
24
|
+
2. Inspect active sessions:
|
|
25
25
|
|
|
26
26
|
```bash
|
|
27
27
|
telepty list
|
|
28
28
|
```
|
|
29
29
|
|
|
30
|
-
3. Attach to a
|
|
30
|
+
3. Attach to a room:
|
|
31
31
|
|
|
32
32
|
```bash
|
|
33
33
|
telepty attach <session_id>
|
|
34
34
|
```
|
|
35
35
|
|
|
36
|
-
4. Inject a
|
|
36
|
+
4. Inject a command or prompt:
|
|
37
37
|
|
|
38
38
|
```bash
|
|
39
39
|
telepty inject <session_id> "<prompt text>"
|
|
40
40
|
```
|
|
41
41
|
|
|
42
|
-
5.
|
|
43
|
-
|
|
44
|
-
```bash
|
|
45
|
-
telepty multicast <id1,id2,...> "<prompt text>"
|
|
46
|
-
```
|
|
47
|
-
|
|
48
|
-
6. Broadcast to all sessions:
|
|
42
|
+
5. Allow inject on a local CLI:
|
|
49
43
|
|
|
50
44
|
```bash
|
|
51
|
-
telepty
|
|
45
|
+
telepty allow --id <session_id> <command> [args...]
|
|
52
46
|
```
|
|
53
47
|
|
|
54
|
-
|
|
48
|
+
6. Rename a room:
|
|
55
49
|
|
|
56
50
|
```bash
|
|
57
51
|
telepty rename <old_id> <new_id>
|
|
58
52
|
```
|
|
59
53
|
|
|
60
|
-
|
|
54
|
+
7. Listen to the event bus:
|
|
61
55
|
|
|
62
56
|
```bash
|
|
63
57
|
telepty listen
|
|
64
58
|
```
|
|
65
59
|
|
|
66
|
-
|
|
60
|
+
8. Update telepty:
|
|
67
61
|
|
|
68
62
|
```bash
|
|
69
|
-
|
|
70
|
-
curl -s -X POST http://127.0.0.1:3848/api/bus/publish \
|
|
71
|
-
-H "Content-Type: application/json" \
|
|
72
|
-
-H "x-telepty-token: $TOKEN" \
|
|
73
|
-
-d '{"type":"bg_message","payload":"..."}'
|
|
63
|
+
telepty update
|
|
74
64
|
```
|
|
75
65
|
|
|
76
|
-
|
|
66
|
+
## Local daemon recovery
|
|
67
|
+
|
|
68
|
+
When the user reports any of these symptoms, repair the local daemon first:
|
|
69
|
+
|
|
70
|
+
- `Failed to connect to local daemon`
|
|
71
|
+
- local sessions do not appear but remote sessions do
|
|
72
|
+
- duplicate or stale daemon processes
|
|
73
|
+
- install/update completed but `spawn` or `allow` still fails locally
|
|
74
|
+
|
|
75
|
+
### Human-facing path
|
|
76
|
+
|
|
77
|
+
Tell the user to run `telepty` and choose `Repair local daemon`.
|
|
78
|
+
|
|
79
|
+
### Agent execution path
|
|
80
|
+
|
|
81
|
+
Use the maintenance command directly:
|
|
77
82
|
|
|
78
83
|
```bash
|
|
79
|
-
telepty
|
|
84
|
+
telepty cleanup-daemons
|
|
85
|
+
telepty daemon
|
|
80
86
|
```
|
|
81
87
|
|
|
88
|
+
If the daemon still does not come up, rerun the installer.
|
|
89
|
+
|
|
82
90
|
## Notes
|
|
83
91
|
|
|
84
92
|
- `TELEPTY_SESSION_ID` is only set inside telepty-managed sessions.
|
|
85
|
-
-
|
|
86
|
-
|
|
93
|
+
- For non-interactive `telepty allow` use cases, set terminal dimensions if the environment does not provide them:
|
|
94
|
+
|
|
95
|
+
```bash
|
|
96
|
+
COLUMNS=120 LINES=40 telepty allow --id <session_id> <command>
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
- For interactive users, keep explanations centered on TUI actions instead of raw maintenance commands whenever possible.
|