@dmsdc-ai/aigentry-telepty 0.3.5 → 0.4.0
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/CHANGELOG.md +72 -0
- package/cli.js +36 -15
- package/daemon.js +355 -5
- package/package.json +25 -1
- package/session-state.js +23 -0
- package/src/prompt-symbol-registry.js +43 -1
- package/.claude/commands/telepty-allow.md +0 -58
- package/.claude/commands/telepty-attach.md +0 -22
- package/.claude/commands/telepty-inject.md +0 -72
- package/.claude/commands/telepty-list.md +0 -22
- package/.claude/commands/telepty-manual-test.md +0 -73
- package/.claude/commands/telepty-start.md +0 -25
- package/.claude/commands/telepty-test.md +0 -25
- package/.claude/commands/telepty.md +0 -82
- package/AGENTS.md +0 -97
- package/BOUNDARY.md +0 -31
- package/BUS_EVENT_SCHEMA.md +0 -206
- package/CLAUDE.md +0 -100
- package/GEMINI.md +0 -10
- package/URGENT_ISSUES.resolved.md +0 -1
- package/docs/reports/2026-05-05-issue-8-claude-review.md +0 -194
- package/docs/specs/2026-05-05-issue-8-telepty-init.md +0 -477
- package/docs/superpowers/specs/2026-04-26-inject-submit-enter-reliability.md +0 -447
- package/docs/superpowers/specs/2026-04-26-prompt-symbol-render-gate.md +0 -571
- package/docs/superpowers/specs/2026-04-26-submit-gate-fixes-v2.md +0 -608
- package/docs/superpowers/specs/2026-05-02-submit-force-and-retry.md +0 -139
- package/protocol/mailbox.md +0 -244
- package/scripts/regen-snippet-fixtures.js +0 -42
- package/specs/codex-inject-spec.md +0 -201
- package/specs/enforce-report-spec.md +0 -237
- package/templates/AGENTS.md +0 -71
- package/tests/snippet-protocol/v1/golden-agents.json +0 -1
- package/tests/snippet-protocol/v1/golden-agents.md +0 -17
- package/tests/snippet-protocol/v1/golden-all.json +0 -3
- package/tests/snippet-protocol/v1/golden-all.md +0 -53
- package/tests/snippet-protocol/v1/golden-claude.json +0 -1
- package/tests/snippet-protocol/v1/golden-claude.md +0 -17
- package/tests/snippet-protocol/v1/golden-gemini.json +0 -1
- package/tests/snippet-protocol/v1/golden-gemini.md +0 -17
package/session-state.js
CHANGED
|
@@ -203,6 +203,9 @@ class SessionStateMachine {
|
|
|
203
203
|
|
|
204
204
|
// Strip ANSI and split into lines for pattern analysis
|
|
205
205
|
const cleaned = stripAnsi(data);
|
|
206
|
+
if (cleaned.trim().length === 0) {
|
|
207
|
+
return;
|
|
208
|
+
}
|
|
206
209
|
const lines = cleaned.split(/\r?\n/).filter(l => l.trim().length > 0);
|
|
207
210
|
|
|
208
211
|
for (const line of lines) {
|
|
@@ -269,6 +272,16 @@ class SessionStateMachine {
|
|
|
269
272
|
this._transition(STATES.RESTARTING, 1.0, { trigger: 'lifecycle' });
|
|
270
273
|
}
|
|
271
274
|
|
|
275
|
+
markIdle(confidence = 1.0, detail = {}) {
|
|
276
|
+
if (this._state === STATES.DEAD || this._state === STATES.RESTARTING) {
|
|
277
|
+
return;
|
|
278
|
+
}
|
|
279
|
+
this._transition(STATES.IDLE, confidence, {
|
|
280
|
+
trigger: 'manual_idle',
|
|
281
|
+
...detail,
|
|
282
|
+
});
|
|
283
|
+
}
|
|
284
|
+
|
|
272
285
|
// --- Internal ---
|
|
273
286
|
|
|
274
287
|
_transition(newState, confidence, detail) {
|
|
@@ -538,6 +551,16 @@ class SessionStateManager {
|
|
|
538
551
|
if (sm) sm.markRestarting();
|
|
539
552
|
}
|
|
540
553
|
|
|
554
|
+
/**
|
|
555
|
+
* Mark a session as idle from a semantic daemon event.
|
|
556
|
+
*/
|
|
557
|
+
markIdle(sessionId, confidence = 1.0, detail = {}) {
|
|
558
|
+
const sm = this._machines.get(sessionId);
|
|
559
|
+
if (!sm) return false;
|
|
560
|
+
sm.markIdle(confidence, detail);
|
|
561
|
+
return true;
|
|
562
|
+
}
|
|
563
|
+
|
|
541
564
|
/**
|
|
542
565
|
* Unregister and cleanup a session's state machine.
|
|
543
566
|
*/
|
|
@@ -94,4 +94,46 @@ function lookup(command) {
|
|
|
94
94
|
return null;
|
|
95
95
|
}
|
|
96
96
|
|
|
97
|
-
|
|
97
|
+
function commandKey(command) {
|
|
98
|
+
const entry = lookup(command);
|
|
99
|
+
if (!entry) return null;
|
|
100
|
+
for (const [key, value] of Object.entries(ENTRIES)) {
|
|
101
|
+
if (value === entry) return key;
|
|
102
|
+
}
|
|
103
|
+
return null;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
function isKnownAiCli(command) {
|
|
107
|
+
return !!lookup(command);
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
const ANSI_RE = /\x1b\[[0-9;?]*[ -/]*[@-~]|\x1b\][^\x07]*(?:\x07|\x1b\\)|\x1b[()][AB012]|\x1b[>=<78DMEHcNOZ~}|]/g;
|
|
111
|
+
|
|
112
|
+
function stripAnsi(value) {
|
|
113
|
+
return String(value == null ? '' : value).replace(ANSI_RE, '');
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
function normalizeOutputForDetection(output) {
|
|
117
|
+
return stripAnsi(output)
|
|
118
|
+
.replace(/\r\n/g, '\n')
|
|
119
|
+
.replace(/\r/g, '\n')
|
|
120
|
+
.replace(/\n{2,}/g, '\n');
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
function detectOutput(command, output) {
|
|
124
|
+
const entry = lookup(command);
|
|
125
|
+
if (!entry) {
|
|
126
|
+
return { found: false, reason: 'unknown_cli' };
|
|
127
|
+
}
|
|
128
|
+
const screenLike = normalizeOutputForDetection(output);
|
|
129
|
+
return entry.detect(screenLike);
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
module.exports = {
|
|
133
|
+
lookup,
|
|
134
|
+
commandKey,
|
|
135
|
+
isKnownAiCli,
|
|
136
|
+
detectOutput,
|
|
137
|
+
normalizeOutputForDetection,
|
|
138
|
+
ENTRIES,
|
|
139
|
+
};
|
|
@@ -1,58 +0,0 @@
|
|
|
1
|
-
# telepty-allow
|
|
2
|
-
|
|
3
|
-
Allow inject on an LLM CLI (or any command) via telepty.
|
|
4
|
-
|
|
5
|
-
## Instructions
|
|
6
|
-
|
|
7
|
-
### Usage
|
|
8
|
-
```bash
|
|
9
|
-
telepty allow [--id <session_id>] -- <command> [args...]
|
|
10
|
-
```
|
|
11
|
-
|
|
12
|
-
### Examples
|
|
13
|
-
```bash
|
|
14
|
-
# Claude Code with custom session ID
|
|
15
|
-
telepty allow --id my-claude -- claude
|
|
16
|
-
|
|
17
|
-
# Codex with auto-generated ID
|
|
18
|
-
telepty allow -- codex
|
|
19
|
-
|
|
20
|
-
# Gemini with custom ID
|
|
21
|
-
telepty allow --id gemini-main -- gemini
|
|
22
|
-
|
|
23
|
-
# Any shell command
|
|
24
|
-
telepty allow --id dev-shell -- bash
|
|
25
|
-
```
|
|
26
|
-
|
|
27
|
-
### What it does
|
|
28
|
-
1. Registers the session with the telepty daemon
|
|
29
|
-
2. Spawns the command locally via `node-pty` (preserves isTTY, raw mode, colors)
|
|
30
|
-
3. Connects to daemon as WebSocket owner for inject reception
|
|
31
|
-
4. Sets `TELEPTY_SESSION_ID` env var inside the process
|
|
32
|
-
|
|
33
|
-
### Key behaviors
|
|
34
|
-
- **isTTY preserved**: TUI apps (claude, codex, gemini) work normally
|
|
35
|
-
- **Daemon fault-tolerant**: if daemon dies, the CLI keeps running (inject unavailable until reconnect)
|
|
36
|
-
- **Session auto-cleanup**: when the command exits, session is deregistered
|
|
37
|
-
|
|
38
|
-
### After allowing, from another terminal:
|
|
39
|
-
```bash
|
|
40
|
-
# List sessions
|
|
41
|
-
telepty list
|
|
42
|
-
|
|
43
|
-
# Inject into the session
|
|
44
|
-
telepty inject <session_id> "your prompt here"
|
|
45
|
-
|
|
46
|
-
# Attach to watch output
|
|
47
|
-
telepty attach <session_id>
|
|
48
|
-
```
|
|
49
|
-
|
|
50
|
-
## Execute
|
|
51
|
-
If the user provides arguments, run the allow command for them:
|
|
52
|
-
|
|
53
|
-
```bash
|
|
54
|
-
cd /Users/duckyoungkim/projects/aigentry-telepty
|
|
55
|
-
node cli.js allow $ARGUMENTS
|
|
56
|
-
```
|
|
57
|
-
|
|
58
|
-
If no arguments, show the usage guide above and ask what they want to run.
|
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
# telepty-attach
|
|
2
|
-
|
|
3
|
-
Attach to an active telepty session to observe its output in real-time.
|
|
4
|
-
|
|
5
|
-
## Instructions
|
|
6
|
-
|
|
7
|
-
### Execute
|
|
8
|
-
```bash
|
|
9
|
-
cd /Users/duckyoungkim/projects/aigentry-telepty && node cli.js attach $ARGUMENTS
|
|
10
|
-
```
|
|
11
|
-
|
|
12
|
-
### If no arguments
|
|
13
|
-
1. List available sessions: `node cli.js list`
|
|
14
|
-
2. Ask the user which session to attach to
|
|
15
|
-
|
|
16
|
-
### Notes
|
|
17
|
-
- For **spawned** sessions: you can both view output and send input
|
|
18
|
-
- For **wrapped** sessions: input from attached clients is forwarded to the owner as inject
|
|
19
|
-
- Press `Ctrl+C` to detach without killing the session
|
|
20
|
-
|
|
21
|
-
## Arguments
|
|
22
|
-
- `$ARGUMENTS`: session ID to attach to
|
|
@@ -1,72 +0,0 @@
|
|
|
1
|
-
# telepty-inject
|
|
2
|
-
|
|
3
|
-
Inject a prompt into a telepty session (spawned or wrapped).
|
|
4
|
-
|
|
5
|
-
## Instructions
|
|
6
|
-
|
|
7
|
-
Parse `$ARGUMENTS` to extract target session ID and prompt text.
|
|
8
|
-
|
|
9
|
-
### Format
|
|
10
|
-
```
|
|
11
|
-
<session_id> <prompt text>
|
|
12
|
-
```
|
|
13
|
-
|
|
14
|
-
### Step 1: Parse Arguments
|
|
15
|
-
|
|
16
|
-
If no arguments provided:
|
|
17
|
-
1. List available sessions: `telepty list`
|
|
18
|
-
2. Ask the user which session to target and what to inject
|
|
19
|
-
|
|
20
|
-
Extract `session_id` (first word) and `prompt` (rest of the arguments).
|
|
21
|
-
|
|
22
|
-
### Step 2: English-Only Enforcement
|
|
23
|
-
|
|
24
|
-
Check if the prompt body contains non-English text (Korean, Japanese, Chinese, etc.).
|
|
25
|
-
|
|
26
|
-
- If non-English text detected: Warn the user and auto-translate the prompt to English before proceeding.
|
|
27
|
-
- Exception: Technical terms (e.g., 'hangul', 'jamo', session IDs like 'aigentry-*') used alongside English are OK.
|
|
28
|
-
- The `--from` header and `[reply-to:]` metadata are exempt from this check.
|
|
29
|
-
|
|
30
|
-
### Step 3: Auto --ref for Long Content
|
|
31
|
-
|
|
32
|
-
Detect if the prompt is long (>500 characters OR >3 lines):
|
|
33
|
-
|
|
34
|
-
- **Long content**: Use `--ref` flag automatically. This writes the prompt to a shared file and sends a SHA reference instead of inline text. Tell the user: "Using --ref (content is X chars / Y lines)."
|
|
35
|
-
- **Short content**: Send inline as-is.
|
|
36
|
-
|
|
37
|
-
### Step 4: Pre-Send Confirmation
|
|
38
|
-
|
|
39
|
-
Before executing, show the user:
|
|
40
|
-
```
|
|
41
|
-
Target: <session_id>
|
|
42
|
-
Prompt: <first 100 chars of prompt>... (X chars total)
|
|
43
|
-
Flags: --ref (if applicable), --from (if set)
|
|
44
|
-
```
|
|
45
|
-
|
|
46
|
-
Then ask: "Send? (y/n)"
|
|
47
|
-
|
|
48
|
-
**Skip confirmation when:**
|
|
49
|
-
- User explicitly said "send it", "just send", "바로 보내", or similar
|
|
50
|
-
- The command was invoked with `--yes` or `-y` flag
|
|
51
|
-
- Context clearly implies immediate send (e.g., replying to an orchestrator request)
|
|
52
|
-
|
|
53
|
-
### Step 5: Execute
|
|
54
|
-
|
|
55
|
-
```bash
|
|
56
|
-
telepty inject [--ref] [--from <from_id>] <session_id> "<prompt>"
|
|
57
|
-
```
|
|
58
|
-
|
|
59
|
-
If `TELEPTY_SESSION_ID` env var is set, automatically add `--from $TELEPTY_SESSION_ID`.
|
|
60
|
-
|
|
61
|
-
### Multicast (multiple targets)
|
|
62
|
-
```bash
|
|
63
|
-
telepty multicast <id1>,<id2> "<prompt>"
|
|
64
|
-
```
|
|
65
|
-
|
|
66
|
-
### Broadcast (all sessions)
|
|
67
|
-
```bash
|
|
68
|
-
telepty broadcast "<prompt>"
|
|
69
|
-
```
|
|
70
|
-
|
|
71
|
-
## Arguments
|
|
72
|
-
- `$ARGUMENTS`: `<session_id> "<prompt>"` or empty for interactive mode
|
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
# telepty-list
|
|
2
|
-
|
|
3
|
-
List all active telepty sessions with their types and status.
|
|
4
|
-
|
|
5
|
-
## Instructions
|
|
6
|
-
|
|
7
|
-
1. Run:
|
|
8
|
-
```bash
|
|
9
|
-
cd /Users/duckyoungkim/projects/aigentry-telepty && node cli.js list
|
|
10
|
-
```
|
|
11
|
-
|
|
12
|
-
2. If the daemon is not running, tell the user and suggest `/project:telepty-start`.
|
|
13
|
-
|
|
14
|
-
3. Format the output as a clear table showing:
|
|
15
|
-
- Session ID
|
|
16
|
-
- Type (spawned / wrapped)
|
|
17
|
-
- Command
|
|
18
|
-
- Active clients
|
|
19
|
-
- Created time
|
|
20
|
-
|
|
21
|
-
## Arguments
|
|
22
|
-
- `$ARGUMENTS`: ignored
|
|
@@ -1,73 +0,0 @@
|
|
|
1
|
-
# telepty-manual-test
|
|
2
|
-
|
|
3
|
-
Guided manual test of the telepty enable (inject) feature. Runs step-by-step verification.
|
|
4
|
-
|
|
5
|
-
## Instructions
|
|
6
|
-
|
|
7
|
-
Execute each step sequentially, verifying results before proceeding.
|
|
8
|
-
|
|
9
|
-
### Step 1: Ensure daemon is running
|
|
10
|
-
```bash
|
|
11
|
-
cd /Users/duckyoungkim/projects/aigentry-telepty
|
|
12
|
-
curl -s http://127.0.0.1:3848/api/sessions 2>/dev/null || node daemon.js &
|
|
13
|
-
sleep 1
|
|
14
|
-
```
|
|
15
|
-
|
|
16
|
-
### Step 2: Register a wrapped session via API
|
|
17
|
-
```bash
|
|
18
|
-
TOKEN=$(cat ~/.telepty/config.json 2>/dev/null | grep authToken | cut -d '"' -f 4)
|
|
19
|
-
curl -s -X POST http://127.0.0.1:3848/api/sessions/register \
|
|
20
|
-
-H "Content-Type: application/json" \
|
|
21
|
-
-H "x-telepty-token: $TOKEN" \
|
|
22
|
-
-d '{"session_id": "manual-test-1", "command": "test", "cwd": "'"$(pwd)"'"}'
|
|
23
|
-
```
|
|
24
|
-
**Verify**: response has `type: "wrapped"` and status 201.
|
|
25
|
-
|
|
26
|
-
### Step 3: Check session listing
|
|
27
|
-
```bash
|
|
28
|
-
curl -s http://127.0.0.1:3848/api/sessions -H "x-telepty-token: $TOKEN" | python3 -m json.tool
|
|
29
|
-
```
|
|
30
|
-
**Verify**: `manual-test-1` appears with `type: "wrapped"`.
|
|
31
|
-
|
|
32
|
-
### Step 4: Test inject without owner (should fail)
|
|
33
|
-
```bash
|
|
34
|
-
curl -s -X POST http://127.0.0.1:3848/api/sessions/manual-test-1/inject \
|
|
35
|
-
-H "Content-Type: application/json" \
|
|
36
|
-
-H "x-telepty-token: $TOKEN" \
|
|
37
|
-
-d '{"prompt": "hello"}'
|
|
38
|
-
```
|
|
39
|
-
**Verify**: returns 503 with "not connected" error.
|
|
40
|
-
|
|
41
|
-
### Step 5: Clean up test session
|
|
42
|
-
```bash
|
|
43
|
-
curl -s -X DELETE http://127.0.0.1:3848/api/sessions/manual-test-1 \
|
|
44
|
-
-H "x-telepty-token: $TOKEN"
|
|
45
|
-
```
|
|
46
|
-
**Verify**: returns status "closing".
|
|
47
|
-
|
|
48
|
-
### Step 6: Verify session removed
|
|
49
|
-
```bash
|
|
50
|
-
curl -s http://127.0.0.1:3848/api/sessions -H "x-telepty-token: $TOKEN"
|
|
51
|
-
```
|
|
52
|
-
**Verify**: `manual-test-1` no longer in the list.
|
|
53
|
-
|
|
54
|
-
### Step 7: Run automated tests
|
|
55
|
-
```bash
|
|
56
|
-
npm test
|
|
57
|
-
```
|
|
58
|
-
**Verify**: all 25 tests pass.
|
|
59
|
-
|
|
60
|
-
### Report
|
|
61
|
-
Summarize all verification results in a table:
|
|
62
|
-
|
|
63
|
-
| Step | Check | Result |
|
|
64
|
-
|------|-------|--------|
|
|
65
|
-
| 2 | Register returns 201 + wrapped | ? |
|
|
66
|
-
| 3 | Session in list with type | ? |
|
|
67
|
-
| 4 | Inject without owner = 503 | ? |
|
|
68
|
-
| 5 | DELETE returns closing | ? |
|
|
69
|
-
| 6 | Session removed | ? |
|
|
70
|
-
| 7 | All tests pass | ? |
|
|
71
|
-
|
|
72
|
-
## Arguments
|
|
73
|
-
- `$ARGUMENTS`: ignored
|
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
# telepty-start
|
|
2
|
-
|
|
3
|
-
Start the telepty daemon process.
|
|
4
|
-
|
|
5
|
-
## Instructions
|
|
6
|
-
|
|
7
|
-
1. Check if daemon is already running:
|
|
8
|
-
```bash
|
|
9
|
-
curl -s http://127.0.0.1:3848/api/sessions 2>/dev/null && echo "RUNNING" || echo "NOT RUNNING"
|
|
10
|
-
```
|
|
11
|
-
|
|
12
|
-
2. If not running, start it:
|
|
13
|
-
```bash
|
|
14
|
-
cd /Users/duckyoungkim/projects/aigentry-telepty && node daemon.js &
|
|
15
|
-
```
|
|
16
|
-
|
|
17
|
-
3. Verify it started:
|
|
18
|
-
```bash
|
|
19
|
-
sleep 1 && curl -s http://127.0.0.1:3848/api/sessions
|
|
20
|
-
```
|
|
21
|
-
|
|
22
|
-
4. Report status.
|
|
23
|
-
|
|
24
|
-
## Arguments
|
|
25
|
-
- `$ARGUMENTS`: optional port override (e.g., "3849")
|
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
# telepty-test
|
|
2
|
-
|
|
3
|
-
Run the telepty automated test suite and report results.
|
|
4
|
-
|
|
5
|
-
## Instructions
|
|
6
|
-
|
|
7
|
-
1. Run the full test suite:
|
|
8
|
-
```bash
|
|
9
|
-
cd /Users/duckyoungkim/projects/aigentry-telepty && npm test
|
|
10
|
-
```
|
|
11
|
-
|
|
12
|
-
2. Parse the output and report:
|
|
13
|
-
- Total tests, passed, failed
|
|
14
|
-
- If any failures: show the failing test name and error message
|
|
15
|
-
- If all pass: confirm with count
|
|
16
|
-
|
|
17
|
-
3. If tests fail, investigate:
|
|
18
|
-
- Read the failing test in `test/daemon.test.js`
|
|
19
|
-
- Check if daemon.js has related issues
|
|
20
|
-
- Suggest or apply fixes
|
|
21
|
-
- Re-run tests to confirm
|
|
22
|
-
|
|
23
|
-
## Arguments
|
|
24
|
-
- No arguments: run all tests
|
|
25
|
-
- `$ARGUMENTS`: if provided, use as a grep filter to run specific tests (e.g., "wrap", "register", "inject")
|
|
@@ -1,82 +0,0 @@
|
|
|
1
|
-
# telepty
|
|
2
|
-
|
|
3
|
-
Help the user interact with the `telepty` daemon — check session IDs, list active sessions, inject commands, send bus events, and manage terminal windows.
|
|
4
|
-
|
|
5
|
-
## Trigger
|
|
6
|
-
|
|
7
|
-
When the user asks about their current session ID, wants to check/list active sessions, inject a prompt into a session, send a JSON event via the bus, subscribe to the bus, rename a session, or update telepty.
|
|
8
|
-
|
|
9
|
-
## Instructions
|
|
10
|
-
|
|
11
|
-
### 1. Check Current Session ID
|
|
12
|
-
- Run: `echo $TELEPTY_SESSION_ID`
|
|
13
|
-
- If empty: this shell is NOT inside a telepty session.
|
|
14
|
-
- If set: display it. This is the ID other agents use to target this session.
|
|
15
|
-
|
|
16
|
-
### 2. List All Sessions
|
|
17
|
-
- Run: `telepty list`
|
|
18
|
-
|
|
19
|
-
### 3. Send a Message to Another Agent
|
|
20
|
-
Choose ONE of three methods based on intent:
|
|
21
|
-
|
|
22
|
-
**Method A: Prompt Injection (Active Interruption)**
|
|
23
|
-
The receiving AI will IMMEDIATELY read and execute the message as a prompt.
|
|
24
|
-
```bash
|
|
25
|
-
telepty inject <target_session_id> "<prompt text>"
|
|
26
|
-
```
|
|
27
|
-
For multiple targets: `telepty multicast <id1>,<id2> "<prompt>"`
|
|
28
|
-
|
|
29
|
-
**Method B: Log Injection (Visual Notification)**
|
|
30
|
-
The message appears on the receiving terminal screen for the user to see, but the AI does NOT execute it as a prompt.
|
|
31
|
-
```bash
|
|
32
|
-
telepty inject <target_session_id> "echo '\x1b[33m[Message from $TELEPTY_SESSION_ID]\x1b[0m <message text>'"
|
|
33
|
-
```
|
|
34
|
-
|
|
35
|
-
**Method C: Background JSON Bus (Passive/Silent)**
|
|
36
|
-
Structured data transfer that won't disturb the receiving terminal screen.
|
|
37
|
-
```bash
|
|
38
|
-
TOKEN=$(cat ~/.telepty/config.json | grep authToken | cut -d '"' -f 4)
|
|
39
|
-
curl -s -X POST http://127.0.0.1:3848/api/bus/publish \
|
|
40
|
-
-H "Content-Type: application/json" \
|
|
41
|
-
-H "x-telepty-token: $TOKEN" \
|
|
42
|
-
-d '{"type": "bg_message", "payload": "..."}'
|
|
43
|
-
```
|
|
44
|
-
|
|
45
|
-
### 4. Subscribe to the Event Bus
|
|
46
|
-
```bash
|
|
47
|
-
nohup telepty listen > .telepty_bus_events.log 2>&1 &
|
|
48
|
-
```
|
|
49
|
-
|
|
50
|
-
### 5. Open a New Ghostty Terminal Window
|
|
51
|
-
Physically spawn a new terminal window already attached to a telepty session:
|
|
52
|
-
```bash
|
|
53
|
-
cat << 'EOF' > /tmp/telepty-auto.command
|
|
54
|
-
#!/bin/bash
|
|
55
|
-
telepty spawn --id <ID> <CMD>
|
|
56
|
-
EOF
|
|
57
|
-
chmod +x /tmp/telepty-auto.command
|
|
58
|
-
open -a Ghostty /tmp/telepty-auto.command || open /tmp/telepty-auto.command
|
|
59
|
-
```
|
|
60
|
-
|
|
61
|
-
### 6. Terminal Title Convention
|
|
62
|
-
Each telepty session displays its ID in the Ghostty tab title:
|
|
63
|
-
- Local: `⚡ telepty :: {session_id}`
|
|
64
|
-
- Remote: `⚡ telepty :: {session_id} @ {host}`
|
|
65
|
-
|
|
66
|
-
### 7. Allow Inject on a CLI
|
|
67
|
-
Run any command with inject allowed:
|
|
68
|
-
```bash
|
|
69
|
-
# With custom session ID
|
|
70
|
-
telepty allow --id my-claude -- claude
|
|
71
|
-
telepty allow --id codex-main -- codex
|
|
72
|
-
telepty allow --id gemini-1 -- gemini
|
|
73
|
-
|
|
74
|
-
# Auto-generated session ID
|
|
75
|
-
telepty allow -- bash
|
|
76
|
-
```
|
|
77
|
-
The process runs locally (isTTY preserved), but registers with the daemon so inject works.
|
|
78
|
-
|
|
79
|
-
### 8. Update
|
|
80
|
-
```bash
|
|
81
|
-
telepty update
|
|
82
|
-
```
|
package/AGENTS.md
DELETED
|
@@ -1,97 +0,0 @@
|
|
|
1
|
-
# AGENTS.md — aigentry-telepty
|
|
2
|
-
|
|
3
|
-
## Overview
|
|
4
|
-
|
|
5
|
-
PTY Multiplexer & Session Orchestrator — aigentry 에코시스템의 **통신 인프라**.
|
|
6
|
-
npm: `@dmsdc-ai/aigentry-telepty` | 멀티 AI 세션을 생성·연결·제어하는 PTY 멀티플렉서.
|
|
7
|
-
|
|
8
|
-
## Architecture
|
|
9
|
-
|
|
10
|
-
```
|
|
11
|
-
CLI (cli.js) ──→ HTTP/WS ──→ Daemon (daemon.js:3848)
|
|
12
|
-
├── Session WS (/api/sessions/:id)
|
|
13
|
-
├── Event Bus WS (/api/bus)
|
|
14
|
-
└── REST API (/api/sessions/*)
|
|
15
|
-
```
|
|
16
|
-
|
|
17
|
-
| 파일 | 역할 |
|
|
18
|
-
|------|------|
|
|
19
|
-
| `cli.js` | CLI 명령 + allow-bridge (PTY 래핑) |
|
|
20
|
-
| `daemon.js` | HTTP/WS 서버, 세션 상태, inject 전달 |
|
|
21
|
-
| `tui.js` | blessed 기반 TUI 대시보드 |
|
|
22
|
-
| `session-routing.js` | 세션 ID 해석, alias 매칭, 호스트 그룹핑 |
|
|
23
|
-
| `daemon-control.js` | 싱글톤 daemon PID 관리 |
|
|
24
|
-
| `auth.js` | UUID 토큰 기반 인증 |
|
|
25
|
-
| `interactive-terminal.js` | raw mode stdin/stdout 관리 |
|
|
26
|
-
| `skill-installer.js` | CLI별 스킬 설치 (Claude/Codex/Gemini) |
|
|
27
|
-
|
|
28
|
-
## Inject 전달 경로 (wrapped session)
|
|
29
|
-
|
|
30
|
-
1. **Primary**: `kitty @ send-text` (터미널 직접 전달, allow-bridge 우회)
|
|
31
|
-
2. **Fallback**: WS → allow-bridge → `child.write()` (PTY)
|
|
32
|
-
3. **Submit**: `osascript` Return 키 → kitty fallback → WS `\r`
|
|
33
|
-
|
|
34
|
-
busy 세션: CR은 큐에 대기 중인 텍스트와 함께 큐잉 후 올바른 순서로 flush.
|
|
35
|
-
|
|
36
|
-
## Commands
|
|
37
|
-
|
|
38
|
-
```bash
|
|
39
|
-
npm test # 43 tests (node:test)
|
|
40
|
-
telepty daemon # daemon 시작 (포트 3848)
|
|
41
|
-
telepty allow --id <name> claude # 세션 래핑
|
|
42
|
-
telepty tui # TUI 대시보드
|
|
43
|
-
telepty list # 세션 목록
|
|
44
|
-
telepty inject <id> "msg" # 메시지 주입
|
|
45
|
-
telepty broadcast "msg" # 전체 브로드캐스트
|
|
46
|
-
telepty session start --launch # kitty 탭으로 다중 세션 시작
|
|
47
|
-
```
|
|
48
|
-
|
|
49
|
-
## Key Rules
|
|
50
|
-
|
|
51
|
-
- inject 후 submit은 항상 `osascript`로 통일 (`--no-enter` + osascript keystroke)
|
|
52
|
-
- inject 시 발신자 session ID (`--from`)를 항상 포함
|
|
53
|
-
- PTY `\r` 직접 의존 금지
|
|
54
|
-
|
|
55
|
-
## Session Communication
|
|
56
|
-
|
|
57
|
-
```bash
|
|
58
|
-
# List active sessions
|
|
59
|
-
telepty list
|
|
60
|
-
|
|
61
|
-
# Send message to another session
|
|
62
|
-
telepty inject --from aigentry-telepty-{cli} <target-session> "message"
|
|
63
|
-
|
|
64
|
-
# Report to orchestrator
|
|
65
|
-
telepty inject --ref --from aigentry-telepty-{cli} aigentry-orchestrator-claude "report"
|
|
66
|
-
```
|
|
67
|
-
|
|
68
|
-
## Work Principles
|
|
69
|
-
|
|
70
|
-
- **Best-First**: 항상 최선의 해결책 선택. 차선책/우회 금지.
|
|
71
|
-
- **Configurable**: 설정으로 제어 가능한 구조. 하드코딩 금지.
|
|
72
|
-
- **Evidence-Based**: 추측 금지. 데이터/로그/테스트 결과 기반 판단.
|
|
73
|
-
- **Fail Fast**: 에러 즉시 보고. 숨기지 않음.
|
|
74
|
-
- **Constitution**: ~/projects/aigentry/docs/CONSTITUTION.md 준수.
|
|
75
|
-
|
|
76
|
-
## Legacy exception — `skill-installer.js`
|
|
77
|
-
|
|
78
|
-
`skill-installer.js` is a **named legacy exception** grandfathered by
|
|
79
|
-
**ADR 2026-05-05-telepty-devkit-boundary §6.2.1**. It is the single
|
|
80
|
-
exception to the telepty/devkit boundary rule and is NOT precedent for
|
|
81
|
-
new placements.
|
|
82
|
-
|
|
83
|
-
- **Scope**: bugfixes, security patches, dependency upgrades only.
|
|
84
|
-
- **No new feature expansion**: net-new functionality (new CLI detection,
|
|
85
|
-
new skill types, new install paths, new flags) MUST land in
|
|
86
|
-
`@dmsdc-ai/aigentry-devkit`. At migration time devkit will introduce
|
|
87
|
-
`aigentry scaffold install-skills`.
|
|
88
|
-
- **Reviewer enforcement**: PR reviewers cite ADR 2026-05-05 §6.2.1 when
|
|
89
|
-
rejecting feature-expansion PRs against `skill-installer.js`.
|
|
90
|
-
- **Migration triggers** (per ADR §6.2.1): ≥2 PRs in 60 days attempting
|
|
91
|
-
net-new features; devkit feature requires functionality only in
|
|
92
|
-
`skill-installer.js`; breaking change to its interface.
|
|
93
|
-
|
|
94
|
-
Per-CLI hook installation, `CLAUDE.md`/`AGENTS.md`/`GEMINI.md` scaffolding,
|
|
95
|
-
project-file generation, and cross-cutting installable skills are
|
|
96
|
-
**devkit-owned** per ADR 2026-05-05 §3.3 — not telepty's responsibility.
|
|
97
|
-
See `@dmsdc-ai/aigentry-devkit` (`aigentry scaffold …`).
|
package/BOUNDARY.md
DELETED
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
# telepty Responsibility Boundary
|
|
2
|
-
|
|
3
|
-
## What telepty owns
|
|
4
|
-
|
|
5
|
-
- **PTY lifecycle**: spawn, resize, kill PTY processes; emit session_spawn / session_register / session_rename events
|
|
6
|
-
- **Raw stdin write**: accept inject requests and write bytes to the PTY fd (best-effort, fire-and-forget)
|
|
7
|
-
- **stdout streaming**: pipe PTY output to connected WebSocket clients in real time
|
|
8
|
-
- **Bus event broadcast**: publish structured events to all `/api/bus` subscribers
|
|
9
|
-
- **Session lifecycle**: track active sessions, clean up on exit or owner disconnect
|
|
10
|
-
- **Liveness heartbeat**: emit `session_health` every 10 seconds per active session
|
|
11
|
-
|
|
12
|
-
## What telepty does NOT own
|
|
13
|
-
|
|
14
|
-
- **CLI state management**: the caller owns its own state machine; telepty does not know what state an agent is in
|
|
15
|
-
- **Inject processing confirmation**: telepty emits `inject_written` when bytes are handed to the OS; it cannot confirm the process consumed or acted on them
|
|
16
|
-
- **Output parsing / interpretation**: telepty streams raw bytes; callers parse meaning
|
|
17
|
-
- **Message guarantee / retry / ordering**: no retry logic, no queue, no ordering guarantees across multiple injects
|
|
18
|
-
- **Session recovery / persistence**: sessions are in-memory; a daemon restart loses all sessions
|
|
19
|
-
- **Cross-session routing**: routing logic (which session gets which message) belongs to the caller or an orchestration layer above telepty
|
|
20
|
-
|
|
21
|
-
## PTY limitations
|
|
22
|
-
|
|
23
|
-
- `inject_written` is **best-effort**: it confirms the write syscall to the OS PTY fd succeeded, not that the running process read or processed the input
|
|
24
|
-
- The OS buffers stdin asynchronously; a process blocked, sleeping, or not reading stdin will silently queue the bytes
|
|
25
|
-
- There is no read-back or echo confirmation; callers must observe stdout via the WebSocket stream to infer processing
|
|
26
|
-
|
|
27
|
-
## Design principle
|
|
28
|
-
|
|
29
|
-
> **telepty = stateless dumb pipe**
|
|
30
|
-
|
|
31
|
-
telepty moves bytes. It does not interpret, retry, sequence, or guarantee delivery beyond the OS write call. All higher-level semantics (acknowledgement, ordering, state machines, recovery) are the responsibility of the layer above.
|