pi-interactive-shell 0.3.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 +63 -0
- package/README.md +173 -0
- package/SKILL.md +368 -0
- package/config.ts +132 -0
- package/index.ts +795 -0
- package/overlay-component.ts +1211 -0
- package/package.json +56 -0
- package/pty-session.ts +561 -0
- package/scripts/fix-spawn-helper.cjs +37 -0
- package/scripts/install.js +95 -0
- package/session-manager.ts +226 -0
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to the `pi-interactive-shell` extension will be documented in this file.
|
|
4
|
+
|
|
5
|
+
## [0.3.0] - 2026-01-17
|
|
6
|
+
|
|
7
|
+
### Added
|
|
8
|
+
- Hands-free mode (`mode: "hands-free"`) for agent-driven monitoring with periodic tail updates.
|
|
9
|
+
- User can take over hands-free sessions by typing anything (except scroll keys).
|
|
10
|
+
- Configurable update settings for hands-free mode (defaults: on-quiet mode, 5s quiet threshold, 60s max interval, 1500 chars/update, 100KB total budget).
|
|
11
|
+
- **Input injection**: Send input to active hands-free sessions via `sessionId` + `input` parameters.
|
|
12
|
+
- Named key support: `up`, `down`, `enter`, `escape`, `ctrl+c`, etc.
|
|
13
|
+
- "Foreground subagents" terminology to distinguish from background subagents (the `subagent` tool).
|
|
14
|
+
- `sessionId` now available in the first update (before overlay opens) for immediate input injection.
|
|
15
|
+
- **Timeout**: Auto-kill process after N milliseconds via `timeout` parameter. Useful for TUI commands that don't exit cleanly (e.g., `pi --help`).
|
|
16
|
+
- **DSR handling**: Automatically responds to cursor position queries (`ESC[6n` / `ESC[?6n`) with actual xterm cursor position. Prevents TUI apps from hanging when querying cursor.
|
|
17
|
+
- **Enhanced key encoding**: Full modifier support (`ctrl+alt+x`, `shift+tab`, `c-m-delete`), hex bytes (`hex: ["0x1b"]`), bracketed paste mode (`paste: "text"`), and all F1-F12 keys.
|
|
18
|
+
- **Human-readable session IDs**: Sessions now get memorable names like `calm-reef`, `swift-cove` instead of `shell-1`, `shell-2`.
|
|
19
|
+
- **Process tree killing**: Kill entire process tree on termination, preventing orphan child processes.
|
|
20
|
+
- **Session name derivation**: Better display names in `/attach` list showing command summary.
|
|
21
|
+
- **Write queue**: Ordered writes to terminal emulator prevent race conditions.
|
|
22
|
+
- **Raw output streaming**: `getRawStream()` method for incremental output reading with `sinceLast` option.
|
|
23
|
+
- **Exit message in terminal**: Process exit status appended to terminal buffer when process exits.
|
|
24
|
+
- **EOL conversion**: Added `convertEol: true` to xterm for consistent line ending handling.
|
|
25
|
+
- **Incremental updates**: Hands-free updates now send only NEW output since last update, not full tail. Dramatically reduces context bloat.
|
|
26
|
+
- **Activity-driven updates (on-quiet mode)**: Default behavior now waits for 5s of output silence before emitting update. Perfect for agent-to-agent delegation where you want complete "thoughts" not fragments.
|
|
27
|
+
- **Update modes**: `handsFree.updateMode` can be `"on-quiet"` (default) or `"interval"`. On-quiet emits when output stops; interval emits on fixed schedule.
|
|
28
|
+
- **Context budget**: Total character budget (default: 100KB, configurable via `handsFree.maxTotalChars`). Updates stop including content when exhausted.
|
|
29
|
+
- **Dynamic settings**: Change update interval and quiet threshold mid-session via `settings: { updateInterval, quietThreshold }`.
|
|
30
|
+
- **Keypad keys**: Added `kp0`-`kp9`, `kp/`, `kp*`, `kp-`, `kp+`, `kp.`, `kpenter` for numpad input.
|
|
31
|
+
- **tmux-style key aliases**: Added `ppage`/`npage` (PageUp/PageDown), `ic`/`dc` (Insert/Delete), `bspace` (Backspace) for compatibility.
|
|
32
|
+
|
|
33
|
+
### Changed
|
|
34
|
+
- ANSI stripping now uses Node.js built-in `stripVTControlCharacters` for cleaner, more robust output processing.
|
|
35
|
+
|
|
36
|
+
### Fixed
|
|
37
|
+
- Double unregistration in hands-free session cleanup (now idempotent via `sessionUnregistered` flag).
|
|
38
|
+
- Potential double `done()` call when timeout fires and process exits simultaneously (added `finished` guard).
|
|
39
|
+
- ReattachOverlay: untracked setTimeout for initial countdown could fire after dispose (now tracked).
|
|
40
|
+
- Input type annotation missing `hex` and `paste` fields.
|
|
41
|
+
- Background session auto-cleanup could dispose session while user is viewing it via `/attach` (now cancels timer on reattach).
|
|
42
|
+
- On-quiet mode now flushes pending output before sending "exited" or "user-takeover" notifications (prevents data loss).
|
|
43
|
+
- Interval mode now also flushes pending output on user takeover (was missing the `|| updateMode === "interval"` check).
|
|
44
|
+
- Timeout in hands-free mode now flushes pending output and sends "exited" notification before returning.
|
|
45
|
+
- Exit handler now waits for writeQueue to drain, ensuring exit message is in rawOutput before notification is sent.
|
|
46
|
+
|
|
47
|
+
### Removed
|
|
48
|
+
- `handsFree.updateLines` option (was defined but unused after switch to incremental char-based updates).
|
|
49
|
+
|
|
50
|
+
## [0.2.0] - 2026-01-17
|
|
51
|
+
|
|
52
|
+
### Added
|
|
53
|
+
- Interactive shell overlay tool `interactive_shell` for supervising interactive CLI agent sessions.
|
|
54
|
+
- Detach dialog (double `Esc`) with kill/background/cancel.
|
|
55
|
+
- Background session reattach command: `/attach`.
|
|
56
|
+
- Scroll support: `Shift+Up` / `Shift+Down`.
|
|
57
|
+
- Tail handoff preview included in tool result (bounded).
|
|
58
|
+
- Optional snapshot-to-file transcript handoff (disabled by default).
|
|
59
|
+
|
|
60
|
+
### Fixed
|
|
61
|
+
- Prevented TUI width crashes by avoiding unbounded terminal escape rendering.
|
|
62
|
+
- Reduced flicker by sanitizing/redrawing in a controlled overlay viewport.
|
|
63
|
+
|
package/README.md
ADDED
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
# Interactive Shell Extension
|
|
2
|
+
|
|
3
|
+
Run AI coding agents (Claude Code, Gemini CLI, Codex, Aider, etc.) as **foreground subagents** inside a pi TUI overlay. The user sees the agent working in real-time and can take over control at any time.
|
|
4
|
+
|
|
5
|
+
This is distinct from **background subagents** (the `subagent` tool) which run pi instances invisibly.
|
|
6
|
+
|
|
7
|
+
## Foreground vs Background Subagents
|
|
8
|
+
|
|
9
|
+
| | Foreground (`interactive_shell`) | Background (`subagent`) |
|
|
10
|
+
|---|---|---|
|
|
11
|
+
| **Visibility** | User sees overlay | Hidden |
|
|
12
|
+
| **Agents** | Any CLI agent | Pi only |
|
|
13
|
+
| **Output** | Incremental updates | Full capture |
|
|
14
|
+
| **User control** | Can intervene | None |
|
|
15
|
+
|
|
16
|
+
## Install
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
npx pi-interactive-shell-install
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
This installs the extension to `~/.pi/agent/extensions/interactive-shell/`, runs `npm install` for dependencies, and creates the skill symlink.
|
|
23
|
+
|
|
24
|
+
**Requirements:** `node-pty` requires build tools (Xcode Command Line Tools on macOS).
|
|
25
|
+
|
|
26
|
+
**Manual install:** If you prefer, clone/copy the files manually and run `npm install` in the extension directory.
|
|
27
|
+
|
|
28
|
+
## Usage
|
|
29
|
+
|
|
30
|
+
### Tool: `interactive_shell`
|
|
31
|
+
|
|
32
|
+
**Start a new session:**
|
|
33
|
+
- `command` (string, required): CLI agent command
|
|
34
|
+
- `cwd` (string): working directory
|
|
35
|
+
- `name` (string): session name (used in sessionId)
|
|
36
|
+
- `reason` (string): shown in overlay header (UI-only, not passed to subprocess)
|
|
37
|
+
- `mode` (string): `"interactive"` (default) or `"hands-free"`
|
|
38
|
+
- `timeout` (number): auto-kill after N milliseconds (for TUI commands that don't exit)
|
|
39
|
+
- `handsFree` (object): options for hands-free mode
|
|
40
|
+
- `updateMode` (string): `"on-quiet"` (default) or `"interval"`
|
|
41
|
+
- `updateInterval` (number): max ms between updates, fallback for on-quiet (default: 60000)
|
|
42
|
+
- `quietThreshold` (number): ms of silence before emitting update in on-quiet mode (default: 5000)
|
|
43
|
+
- `updateMaxChars` (number): max chars per update (default: 1500)
|
|
44
|
+
- `maxTotalChars` (number): total char budget for all updates (default: 100000)
|
|
45
|
+
- `handoffPreview` (object): tail preview in tool result
|
|
46
|
+
- `handoffSnapshot` (object): write transcript to file
|
|
47
|
+
|
|
48
|
+
**Send input to active session:**
|
|
49
|
+
- `sessionId` (string, required): session ID from hands-free updates
|
|
50
|
+
- `input` (string | object): input to send
|
|
51
|
+
- As string: raw text/keystrokes (e.g., `"/model\n"`)
|
|
52
|
+
- As object: `{ text?, keys?, hex?, paste? }`
|
|
53
|
+
|
|
54
|
+
**Change settings mid-session:**
|
|
55
|
+
- `sessionId` (string, required): session ID
|
|
56
|
+
- `settings` (object): `{ updateInterval?, quietThreshold? }`
|
|
57
|
+
|
|
58
|
+
### Command: `/attach`
|
|
59
|
+
|
|
60
|
+
Reattach to background sessions:
|
|
61
|
+
```
|
|
62
|
+
/attach
|
|
63
|
+
/attach <id>
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
## Modes
|
|
67
|
+
|
|
68
|
+
### Interactive (default)
|
|
69
|
+
|
|
70
|
+
User supervises and controls the session directly.
|
|
71
|
+
|
|
72
|
+
```typescript
|
|
73
|
+
interactive_shell({ command: 'pi "Review this code"' })
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
### Hands-Free (Foreground Subagent)
|
|
77
|
+
|
|
78
|
+
Agent monitors with periodic updates. User sees the overlay and can take over by typing. **Default to `pi`** unless user requests a different agent.
|
|
79
|
+
|
|
80
|
+
```typescript
|
|
81
|
+
interactive_shell({
|
|
82
|
+
command: 'pi "Fix all lint errors in src/"',
|
|
83
|
+
mode: "hands-free",
|
|
84
|
+
reason: "Fixing lint errors"
|
|
85
|
+
})
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
**Update modes:**
|
|
89
|
+
- `on-quiet` (default): Emit update after 5s of output silence. Perfect for agent-to-agent delegation.
|
|
90
|
+
- `interval`: Emit on fixed schedule (every 60s). Use when continuous output is expected.
|
|
91
|
+
|
|
92
|
+
**Context budget:**
|
|
93
|
+
- Updates include only NEW output since last update (incremental)
|
|
94
|
+
- Default: 1500 chars per update, 100KB total budget
|
|
95
|
+
- When budget exhausted, updates continue but without content
|
|
96
|
+
|
|
97
|
+
**Status updates (all include `sessionId`):**
|
|
98
|
+
- Initial update - sent immediately when session starts
|
|
99
|
+
- `status: "running"` - incremental output
|
|
100
|
+
- `status: "user-takeover"` - user typed something
|
|
101
|
+
- `status: "exited"` - process finished
|
|
102
|
+
|
|
103
|
+
### Sending Input to Active Sessions
|
|
104
|
+
|
|
105
|
+
Use `sessionId` from updates to send input:
|
|
106
|
+
|
|
107
|
+
```typescript
|
|
108
|
+
// Text input
|
|
109
|
+
interactive_shell({ sessionId: "calm-reef", input: "/help\n" })
|
|
110
|
+
|
|
111
|
+
// Named keys
|
|
112
|
+
interactive_shell({ sessionId: "calm-reef", input: { text: "/model", keys: ["enter"] } })
|
|
113
|
+
|
|
114
|
+
// Navigate menus
|
|
115
|
+
interactive_shell({ sessionId: "calm-reef", input: { keys: ["down", "down", "enter"] } })
|
|
116
|
+
|
|
117
|
+
// Hex bytes for raw escape sequences
|
|
118
|
+
interactive_shell({ sessionId: "calm-reef", input: { hex: ["0x1b", "0x5b", "0x41"] } })
|
|
119
|
+
|
|
120
|
+
// Bracketed paste (prevents auto-execution)
|
|
121
|
+
interactive_shell({ sessionId: "calm-reef", input: { paste: "multi\nline\ntext" } })
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
**Named keys:** `up`, `down`, `left`, `right`, `enter`, `escape`, `tab`, `backspace`, `delete`, `home`, `end`, `pageup`, `pagedown`, `f1`-`f12`, `ctrl+c`, `ctrl+d`, etc.
|
|
125
|
+
|
|
126
|
+
**Keypad keys:** `kp0`-`kp9`, `kp/`, `kp*`, `kp-`, `kp+`, `kp.`, `kpenter`
|
|
127
|
+
|
|
128
|
+
**tmux-style aliases:** `ppage`/`npage` (PageUp/PageDown), `ic`/`dc` (Insert/Delete), `bspace` (Backspace), `btab` (Shift+Tab)
|
|
129
|
+
|
|
130
|
+
**Modifiers:** `ctrl+x`, `alt+x`, `shift+tab`, `ctrl+alt+delete` (or shorthand: `c-x`, `m-x`, `s-tab`)
|
|
131
|
+
|
|
132
|
+
### Change Settings Mid-Session
|
|
133
|
+
|
|
134
|
+
```typescript
|
|
135
|
+
interactive_shell({ sessionId: "calm-reef", settings: { updateInterval: 30000 } })
|
|
136
|
+
interactive_shell({ sessionId: "calm-reef", settings: { quietThreshold: 3000 } })
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
## Config
|
|
140
|
+
|
|
141
|
+
Global: `~/.pi/agent/interactive-shell.json`
|
|
142
|
+
Project: `<cwd>/.pi/interactive-shell.json`
|
|
143
|
+
|
|
144
|
+
```json
|
|
145
|
+
{
|
|
146
|
+
"doubleEscapeThreshold": 300,
|
|
147
|
+
"exitAutoCloseDelay": 10,
|
|
148
|
+
"overlayWidthPercent": 95,
|
|
149
|
+
"overlayHeightPercent": 90,
|
|
150
|
+
"scrollbackLines": 5000,
|
|
151
|
+
"ansiReemit": true,
|
|
152
|
+
"handoffPreviewEnabled": true,
|
|
153
|
+
"handoffPreviewLines": 30,
|
|
154
|
+
"handoffPreviewMaxChars": 2000,
|
|
155
|
+
"handoffSnapshotEnabled": false,
|
|
156
|
+
"handoffSnapshotLines": 200,
|
|
157
|
+
"handoffSnapshotMaxChars": 12000,
|
|
158
|
+
"handsFreeUpdateMode": "on-quiet",
|
|
159
|
+
"handsFreeUpdateInterval": 60000,
|
|
160
|
+
"handsFreeQuietThreshold": 5000,
|
|
161
|
+
"handsFreeUpdateMaxChars": 1500,
|
|
162
|
+
"handsFreeMaxTotalChars": 100000
|
|
163
|
+
}
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
## Keys
|
|
167
|
+
|
|
168
|
+
| Key | Action |
|
|
169
|
+
|-----|--------|
|
|
170
|
+
| `Esc` twice | Detach dialog (kill/background/cancel) |
|
|
171
|
+
| `Shift+Up/Down` | Scroll (no takeover in hands-free) |
|
|
172
|
+
| `Ctrl+C` | Forwarded to subprocess |
|
|
173
|
+
| Any other key (hands-free) | Triggers user takeover |
|
package/SKILL.md
ADDED
|
@@ -0,0 +1,368 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: interactive-shell
|
|
3
|
+
description: Cheat sheet + workflow for launching interactive coding-agent CLIs (Claude Code, Gemini CLI, Codex CLI, Cursor CLI, and pi itself) via the interactive_shell overlay. The overlay is for interactive supervision only - headless commands should use the bash tool instead.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Interactive Shell (Skill)
|
|
7
|
+
|
|
8
|
+
Last verified: 2026-01-17
|
|
9
|
+
|
|
10
|
+
## Foreground vs Background Subagents
|
|
11
|
+
|
|
12
|
+
Pi has two ways to delegate work to other AI coding agents:
|
|
13
|
+
|
|
14
|
+
| | Foreground Subagents | Background Subagents |
|
|
15
|
+
|---|---|---|
|
|
16
|
+
| **Tool** | `interactive_shell` | `subagent` |
|
|
17
|
+
| **Visibility** | User sees overlay in real-time | Hidden from user |
|
|
18
|
+
| **Default agent** | `pi` (others if user requests) | Pi only |
|
|
19
|
+
| **Output** | Minimal (tail preview) | Full output captured |
|
|
20
|
+
| **User control** | Can take over anytime | No intervention |
|
|
21
|
+
| **Best for** | Long tasks needing supervision | Parallel tasks, structured delegation |
|
|
22
|
+
|
|
23
|
+
**Foreground subagents** run in an overlay where the user watches (and can intervene). Use `interactive_shell` with `mode: "hands-free"` to monitor while receiving periodic updates.
|
|
24
|
+
|
|
25
|
+
**Background subagents** run invisibly via the `subagent` tool. Pi-only, but captures full output and supports parallel execution.
|
|
26
|
+
|
|
27
|
+
## When to Use Foreground Subagents
|
|
28
|
+
|
|
29
|
+
Use `interactive_shell` (foreground) when:
|
|
30
|
+
- The task is **long-running** and the user should see progress
|
|
31
|
+
- The user might want to **intervene or guide** the agent
|
|
32
|
+
- You want **hands-free monitoring** with periodic status updates
|
|
33
|
+
- You need a **different agent's capabilities** (only if user specifies)
|
|
34
|
+
|
|
35
|
+
Use `subagent` (background) when:
|
|
36
|
+
- You need **parallel execution** of multiple tasks
|
|
37
|
+
- You want **full output capture** for processing
|
|
38
|
+
- The task is **quick and deterministic**
|
|
39
|
+
- User doesn't need to see the work happening
|
|
40
|
+
|
|
41
|
+
### Default Agent Choice
|
|
42
|
+
|
|
43
|
+
**Default to `pi`** for foreground subagents unless the user explicitly requests a different agent:
|
|
44
|
+
|
|
45
|
+
| User says | Agent to use |
|
|
46
|
+
|-----------|--------------|
|
|
47
|
+
| "Run this in hands-free" | `pi` |
|
|
48
|
+
| "Delegate this task" | `pi` |
|
|
49
|
+
| "Use Claude to review this" | `claude` |
|
|
50
|
+
| "Have Gemini analyze this" | `gemini` |
|
|
51
|
+
| "Run aider to fix this" | `aider` |
|
|
52
|
+
|
|
53
|
+
Pi is the default because it's already available, has the same capabilities, and maintains consistency. Only use Claude, Gemini, Codex, or other agents when the user specifically asks for them.
|
|
54
|
+
|
|
55
|
+
## Foreground Subagent Modes
|
|
56
|
+
|
|
57
|
+
### Interactive (default)
|
|
58
|
+
User has full control, types directly into the agent.
|
|
59
|
+
```typescript
|
|
60
|
+
interactive_shell({ command: 'pi' })
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
### Interactive with Initial Prompt
|
|
64
|
+
Agent starts working immediately, user supervises.
|
|
65
|
+
```typescript
|
|
66
|
+
interactive_shell({ command: 'pi "Review this codebase for security issues"' })
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
### Hands-Free (Foreground Subagent)
|
|
70
|
+
Agent works autonomously, you receive periodic updates, user can take over anytime.
|
|
71
|
+
```typescript
|
|
72
|
+
interactive_shell({
|
|
73
|
+
command: 'pi "Fix all TypeScript errors in src/"',
|
|
74
|
+
mode: "hands-free",
|
|
75
|
+
reason: "Fixing TS errors"
|
|
76
|
+
})
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
This is the primary pattern for **foreground subagents** - you delegate to pi (or another agent if user specifies) while monitoring progress.
|
|
80
|
+
|
|
81
|
+
## Hands-Free Status Updates
|
|
82
|
+
|
|
83
|
+
When running in hands-free mode, `sessionId` is available immediately in the first update (before the overlay opens). Subsequent updates include:
|
|
84
|
+
- `status: "running"` - update with **incremental output** (only new content since last update)
|
|
85
|
+
- `status: "user-takeover"` - user typed something and took control
|
|
86
|
+
- `status: "exited"` - process exited (final update before tool returns)
|
|
87
|
+
|
|
88
|
+
Updates include budget tracking: `totalCharsSent` and `budgetExhausted` fields.
|
|
89
|
+
|
|
90
|
+
After takeover or exit, the tool continues blocking until the session closes.
|
|
91
|
+
|
|
92
|
+
### Update Modes
|
|
93
|
+
|
|
94
|
+
**on-quiet (default)**: Updates emit after 5 seconds of output silence. Perfect for agent-to-agent delegation - you receive complete "thoughts" rather than fragments mid-stream.
|
|
95
|
+
|
|
96
|
+
**interval**: Updates emit on a fixed schedule (every 60s). Use when continuous output is expected.
|
|
97
|
+
|
|
98
|
+
```typescript
|
|
99
|
+
// Default: on-quiet mode (recommended for agent delegation)
|
|
100
|
+
interactive_shell({
|
|
101
|
+
command: 'pi "Fix all TypeScript errors"',
|
|
102
|
+
mode: "hands-free"
|
|
103
|
+
})
|
|
104
|
+
|
|
105
|
+
// Force interval mode for continuous output
|
|
106
|
+
interactive_shell({
|
|
107
|
+
command: 'tail -f /var/log/app.log',
|
|
108
|
+
mode: "hands-free",
|
|
109
|
+
handsFree: { updateMode: "interval", updateInterval: 10000 }
|
|
110
|
+
})
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
### Context Budget
|
|
114
|
+
|
|
115
|
+
Updates have a **total character budget** (default: 100KB) to prevent overwhelming your context window:
|
|
116
|
+
- Each update includes only NEW output since the last update (not full tail)
|
|
117
|
+
- Default: 1500 chars max per update, 100KB total budget
|
|
118
|
+
- When budget is exhausted, updates continue but without content (status-only)
|
|
119
|
+
- Configure via `handsFree.maxTotalChars`
|
|
120
|
+
|
|
121
|
+
```typescript
|
|
122
|
+
// Custom budget for a long task
|
|
123
|
+
interactive_shell({
|
|
124
|
+
command: 'pi "Refactor entire codebase"',
|
|
125
|
+
mode: "hands-free",
|
|
126
|
+
handsFree: { maxTotalChars: 200000 } // 200KB budget
|
|
127
|
+
})
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
## Sending Input to Active Sessions
|
|
131
|
+
|
|
132
|
+
Use the `sessionId` from updates to send input to a running hands-free session:
|
|
133
|
+
|
|
134
|
+
### Basic Input
|
|
135
|
+
```typescript
|
|
136
|
+
// Send text
|
|
137
|
+
interactive_shell({ sessionId: "shell-1", input: "/help\n" })
|
|
138
|
+
|
|
139
|
+
// Send with named keys
|
|
140
|
+
interactive_shell({ sessionId: "shell-1", input: { text: "/model", keys: ["enter"] } })
|
|
141
|
+
|
|
142
|
+
// Navigate menus
|
|
143
|
+
interactive_shell({ sessionId: "shell-1", input: { keys: ["down", "down", "enter"] } })
|
|
144
|
+
|
|
145
|
+
// Interrupt
|
|
146
|
+
interactive_shell({ sessionId: "shell-1", input: { keys: ["ctrl+c"] } })
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
### Named Keys
|
|
150
|
+
| Key | Description |
|
|
151
|
+
|-----|-------------|
|
|
152
|
+
| `up`, `down`, `left`, `right` | Arrow keys |
|
|
153
|
+
| `enter`, `return` | Enter/Return |
|
|
154
|
+
| `escape`, `esc` | Escape |
|
|
155
|
+
| `tab`, `shift+tab` (or `btab`) | Tab / Back-tab |
|
|
156
|
+
| `backspace`, `bspace` | Backspace |
|
|
157
|
+
| `delete`, `del`, `dc` | Delete |
|
|
158
|
+
| `insert`, `ic` | Insert |
|
|
159
|
+
| `home`, `end` | Home/End |
|
|
160
|
+
| `pageup`, `pgup`, `ppage` | Page Up |
|
|
161
|
+
| `pagedown`, `pgdn`, `npage` | Page Down |
|
|
162
|
+
| `f1`-`f12` | Function keys |
|
|
163
|
+
| `kp0`-`kp9`, `kp/`, `kp*`, `kp-`, `kp+`, `kp.`, `kpenter` | Keypad keys |
|
|
164
|
+
| `ctrl+c`, `ctrl+d`, `ctrl+z` | Control sequences |
|
|
165
|
+
| `ctrl+a` through `ctrl+z` | All control keys |
|
|
166
|
+
|
|
167
|
+
Note: `ic`/`dc`, `ppage`/`npage`, `bspace` are tmux-style aliases for compatibility.
|
|
168
|
+
|
|
169
|
+
### Modifier Combinations
|
|
170
|
+
Supports `ctrl+`, `alt+`, `shift+` prefixes (or shorthand `c-`, `m-`, `s-`):
|
|
171
|
+
```typescript
|
|
172
|
+
// Cancel
|
|
173
|
+
{ keys: ["ctrl+c"] }
|
|
174
|
+
|
|
175
|
+
// Alt+Tab
|
|
176
|
+
{ keys: ["alt+tab"] }
|
|
177
|
+
|
|
178
|
+
// Ctrl+Alt+Delete
|
|
179
|
+
{ keys: ["ctrl+alt+delete"] }
|
|
180
|
+
|
|
181
|
+
// Shorthand syntax
|
|
182
|
+
{ keys: ["c-c", "m-x", "s-tab"] }
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
### Hex Bytes (Advanced)
|
|
186
|
+
Send raw escape sequences:
|
|
187
|
+
```typescript
|
|
188
|
+
{ hex: ["0x1b", "0x5b", "0x41"] } // ESC[A (up arrow)
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
### Bracketed Paste
|
|
192
|
+
Paste multiline text without triggering autocompletion/execution:
|
|
193
|
+
```typescript
|
|
194
|
+
{ paste: "function foo() {\n return 42;\n}" }
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
### Model Selection Example
|
|
198
|
+
```typescript
|
|
199
|
+
// Step 1: Open model selector
|
|
200
|
+
interactive_shell({ sessionId: "shell-1", input: { text: "/model", keys: ["enter"] } })
|
|
201
|
+
|
|
202
|
+
// Step 2: Filter and select (after ~500ms delay)
|
|
203
|
+
interactive_shell({ sessionId: "shell-1", input: { text: "sonnet", keys: ["enter"] } })
|
|
204
|
+
|
|
205
|
+
// Or navigate with arrows:
|
|
206
|
+
interactive_shell({ sessionId: "shell-1", input: { keys: ["down", "down", "down", "enter"] } })
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
### Context Compaction
|
|
210
|
+
```typescript
|
|
211
|
+
interactive_shell({ sessionId: "shell-1", input: { text: "/compact", keys: ["enter"] } })
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
### Changing Update Settings
|
|
215
|
+
Adjust timing during a session:
|
|
216
|
+
```typescript
|
|
217
|
+
// Change max interval (fallback for on-quiet mode)
|
|
218
|
+
interactive_shell({ sessionId: "calm-reef", settings: { updateInterval: 120000 } })
|
|
219
|
+
|
|
220
|
+
// Change quiet threshold (how long to wait after output stops)
|
|
221
|
+
interactive_shell({ sessionId: "calm-reef", settings: { quietThreshold: 3000 } })
|
|
222
|
+
|
|
223
|
+
// Both at once
|
|
224
|
+
interactive_shell({ sessionId: "calm-reef", settings: { updateInterval: 30000, quietThreshold: 2000 } })
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
## CLI Cheat Sheet
|
|
228
|
+
|
|
229
|
+
### Claude Code (`claude`)
|
|
230
|
+
|
|
231
|
+
| Mode | Command |
|
|
232
|
+
|------|---------|
|
|
233
|
+
| Interactive (idle) | `claude` |
|
|
234
|
+
| Interactive (prompted) | `claude "Explain this project"` |
|
|
235
|
+
| Headless (use bash, not overlay) | `claude -p "Explain this function"` |
|
|
236
|
+
|
|
237
|
+
### Gemini CLI (`gemini`)
|
|
238
|
+
|
|
239
|
+
| Mode | Command |
|
|
240
|
+
|------|---------|
|
|
241
|
+
| Interactive (idle) | `gemini` |
|
|
242
|
+
| Interactive (prompted) | `gemini -i "Explain this codebase"` |
|
|
243
|
+
| Headless (use bash, not overlay) | `gemini -p "What is fine tuning?"` |
|
|
244
|
+
|
|
245
|
+
### Codex CLI (`codex`)
|
|
246
|
+
|
|
247
|
+
| Mode | Command |
|
|
248
|
+
|------|---------|
|
|
249
|
+
| Interactive (idle) | `codex` |
|
|
250
|
+
| Interactive (prompted) | `codex "Explain this codebase"` |
|
|
251
|
+
| Headless (use bash, not overlay) | `codex exec "summarize the repo"` |
|
|
252
|
+
|
|
253
|
+
### Cursor CLI (`cursor-agent`)
|
|
254
|
+
|
|
255
|
+
| Mode | Command |
|
|
256
|
+
|------|---------|
|
|
257
|
+
| Interactive (idle) | `cursor-agent` |
|
|
258
|
+
| Interactive (prompted) | `cursor-agent "review this repo"` |
|
|
259
|
+
| Headless (use bash, not overlay) | `cursor-agent -p "find issues" --output-format text` |
|
|
260
|
+
|
|
261
|
+
### Pi (`pi`)
|
|
262
|
+
|
|
263
|
+
| Mode | Command |
|
|
264
|
+
|------|---------|
|
|
265
|
+
| Interactive (idle) | `pi` |
|
|
266
|
+
| Interactive (prompted) | `pi "List all .ts files"` |
|
|
267
|
+
| Headless (use bash, not overlay) | `pi -p "List all .ts files"` |
|
|
268
|
+
|
|
269
|
+
Note: Delegating pi to pi is recursive - usually prefer `subagent` for pi-to-pi delegation.
|
|
270
|
+
|
|
271
|
+
## Prompt Packaging Rules
|
|
272
|
+
|
|
273
|
+
The `reason` parameter is **UI-only** - it's shown in the overlay header but NOT passed to the subprocess.
|
|
274
|
+
|
|
275
|
+
To give the agent an initial prompt, embed it in the `command`:
|
|
276
|
+
```typescript
|
|
277
|
+
// WRONG - agent starts idle, reason is just UI text
|
|
278
|
+
interactive_shell({ command: 'claude', reason: 'Review the codebase' })
|
|
279
|
+
|
|
280
|
+
// RIGHT - agent receives the prompt
|
|
281
|
+
interactive_shell({ command: 'claude "Review the codebase"', reason: 'Code review' })
|
|
282
|
+
```
|
|
283
|
+
|
|
284
|
+
## Handoff Options
|
|
285
|
+
|
|
286
|
+
### Tail Preview (default)
|
|
287
|
+
Last 30 lines included in tool result. Good for seeing errors/final status.
|
|
288
|
+
|
|
289
|
+
### Snapshot to File
|
|
290
|
+
Write full transcript to `~/.pi/agent/cache/interactive-shell/snapshot-*.log`:
|
|
291
|
+
```typescript
|
|
292
|
+
interactive_shell({
|
|
293
|
+
command: 'claude "Fix bugs"',
|
|
294
|
+
handoffSnapshot: { enabled: true, lines: 200 }
|
|
295
|
+
})
|
|
296
|
+
```
|
|
297
|
+
|
|
298
|
+
### Artifact Handoff (recommended for complex tasks)
|
|
299
|
+
Instruct the delegated agent to write a handoff file:
|
|
300
|
+
```
|
|
301
|
+
Write your findings to .pi/delegation/claude-handoff.md including:
|
|
302
|
+
- What you did
|
|
303
|
+
- Files changed
|
|
304
|
+
- Any errors
|
|
305
|
+
- Next steps for the main agent
|
|
306
|
+
```
|
|
307
|
+
|
|
308
|
+
## Safe TUI Capture
|
|
309
|
+
|
|
310
|
+
**Never run TUI agents via bash** - they hang even with `--help`. Use `interactive_shell` with `timeout` instead:
|
|
311
|
+
|
|
312
|
+
```typescript
|
|
313
|
+
interactive_shell({
|
|
314
|
+
command: "pi --help",
|
|
315
|
+
mode: "hands-free",
|
|
316
|
+
timeout: 5000 // Auto-kill after 5 seconds
|
|
317
|
+
})
|
|
318
|
+
```
|
|
319
|
+
|
|
320
|
+
The process is killed after timeout and captured output is returned in the handoff preview. This is useful for:
|
|
321
|
+
- Getting CLI help from TUI applications
|
|
322
|
+
- Capturing output from commands that don't exit cleanly
|
|
323
|
+
- Any TUI command where you need quick output without user interaction
|
|
324
|
+
|
|
325
|
+
For pi CLI documentation, you can also read directly: `/opt/homebrew/lib/node_modules/@mariozechner/pi-coding-agent/README.md`
|
|
326
|
+
|
|
327
|
+
## Quick Reference
|
|
328
|
+
|
|
329
|
+
**Start foreground subagent (hands-free, default to pi):**
|
|
330
|
+
```typescript
|
|
331
|
+
interactive_shell({
|
|
332
|
+
command: 'pi "Implement the feature described in SPEC.md"',
|
|
333
|
+
mode: "hands-free",
|
|
334
|
+
reason: "Implementing feature"
|
|
335
|
+
})
|
|
336
|
+
// Returns sessionId in updates, e.g., "shell-1"
|
|
337
|
+
```
|
|
338
|
+
|
|
339
|
+
**Send input to active session:**
|
|
340
|
+
```typescript
|
|
341
|
+
// Text with enter
|
|
342
|
+
interactive_shell({ sessionId: "calm-reef", input: "/compact\n" })
|
|
343
|
+
|
|
344
|
+
// Named keys
|
|
345
|
+
interactive_shell({ sessionId: "calm-reef", input: { text: "/model", keys: ["enter"] } })
|
|
346
|
+
|
|
347
|
+
// Menu navigation
|
|
348
|
+
interactive_shell({ sessionId: "calm-reef", input: { keys: ["down", "down", "enter"] } })
|
|
349
|
+
```
|
|
350
|
+
|
|
351
|
+
**Change update frequency:**
|
|
352
|
+
```typescript
|
|
353
|
+
interactive_shell({ sessionId: "calm-reef", settings: { updateInterval: 60000 } })
|
|
354
|
+
```
|
|
355
|
+
|
|
356
|
+
**Foreground subagent (user requested different agent):**
|
|
357
|
+
```typescript
|
|
358
|
+
interactive_shell({
|
|
359
|
+
command: 'claude "Review this code for security issues"',
|
|
360
|
+
mode: "hands-free",
|
|
361
|
+
reason: "Security review with Claude"
|
|
362
|
+
})
|
|
363
|
+
```
|
|
364
|
+
|
|
365
|
+
**Background subagent:**
|
|
366
|
+
```typescript
|
|
367
|
+
subagent({ agent: "scout", task: "Find all TODO comments" })
|
|
368
|
+
```
|