pi-interactive-shell 0.4.9 → 0.5.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 CHANGED
@@ -2,6 +2,31 @@
2
2
 
3
3
  All notable changes to the `pi-interactive-shell` extension will be documented in this file.
4
4
 
5
+ ## [0.5.0] - 2026-01-22
6
+
7
+ ### Changed
8
+ - **BREAKING: Split `input` into separate fields for Vertex AI compatibility** - The `input` parameter which previously accepted either a string or an object with `text/keys/hex/paste` fields has been split into separate parameters:
9
+ - `input` - Raw text/keystrokes (string only)
10
+ - `inputKeys` - Named keys array (e.g., `["ctrl+c", "enter"]`)
11
+ - `inputHex` - Hex bytes array for raw escape sequences
12
+ - `inputPaste` - Text for bracketed paste mode
13
+
14
+ This change was required because Claude's Vertex AI API (`google-antigravity` provider) rejects `anyOf` JSON schemas with mixed primitive/object types.
15
+
16
+ ### Migration
17
+ ```typescript
18
+ // Before (0.4.x)
19
+ interactive_shell({ sessionId: "abc", input: { keys: ["ctrl+c"] } })
20
+ interactive_shell({ sessionId: "abc", input: { paste: "code" } })
21
+
22
+ // After (0.5.0)
23
+ interactive_shell({ sessionId: "abc", inputKeys: ["ctrl+c"] })
24
+ interactive_shell({ sessionId: "abc", inputPaste: "code" })
25
+
26
+ // Combining text with keys (still works)
27
+ interactive_shell({ sessionId: "abc", input: "y", inputKeys: ["enter"] })
28
+ ```
29
+
5
30
  ## [0.4.9] - 2026-01-21
6
31
 
7
32
  ### Fixed
package/README.md CHANGED
@@ -60,7 +60,7 @@ interactive_shell({ sessionId: "calm-reef" })
60
60
  // → { status: "running", output: "...", runtime: 45000 }
61
61
 
62
62
  // Send input if needed
63
- interactive_shell({ sessionId: "calm-reef", input: { keys: ["ctrl+c"] } })
63
+ interactive_shell({ sessionId: "calm-reef", inputKeys: ["ctrl+c"] })
64
64
 
65
65
  // Kill when done
66
66
  interactive_shell({ sessionId: "calm-reef", kill: true })
@@ -103,11 +103,17 @@ For multi-turn sessions where you need back-and-forth interaction, leave it disa
103
103
  interactive_shell({ sessionId: "calm-reef", input: "SELECT * FROM users;\n" })
104
104
 
105
105
  // Named keys
106
- interactive_shell({ sessionId: "calm-reef", input: { keys: ["ctrl+c"] } })
107
- interactive_shell({ sessionId: "calm-reef", input: { keys: ["down", "down", "enter"] } })
106
+ interactive_shell({ sessionId: "calm-reef", inputKeys: ["ctrl+c"] })
107
+ interactive_shell({ sessionId: "calm-reef", inputKeys: ["down", "down", "enter"] })
108
108
 
109
109
  // Bracketed paste (multiline without execution)
110
- interactive_shell({ sessionId: "calm-reef", input: { paste: "line1\nline2\nline3" } })
110
+ interactive_shell({ sessionId: "calm-reef", inputPaste: "line1\nline2\nline3" })
111
+
112
+ // Hex bytes (raw escape sequences)
113
+ interactive_shell({ sessionId: "calm-reef", inputHex: ["0x1b", "0x5b", "0x41"] })
114
+
115
+ // Combine text with keys
116
+ interactive_shell({ sessionId: "calm-reef", input: "y", inputKeys: ["enter"] })
111
117
  ```
112
118
 
113
119
  ### Configurable Output
package/SKILL.md CHANGED
@@ -161,7 +161,9 @@ interactive_shell({ sessionId: "calm-reef", kill: true })
161
161
  ### Sending Input
162
162
  ```typescript
163
163
  interactive_shell({ sessionId: "calm-reef", input: "/help\n" })
164
- interactive_shell({ sessionId: "calm-reef", input: { keys: ["ctrl+c"] } })
164
+ interactive_shell({ sessionId: "calm-reef", inputKeys: ["ctrl+c"] })
165
+ interactive_shell({ sessionId: "calm-reef", inputPaste: "multi\nline\ncode" })
166
+ interactive_shell({ sessionId: "calm-reef", input: "y", inputKeys: ["enter"] }) // combine text + keys
165
167
  ```
166
168
 
167
169
  ### Query Output
@@ -223,14 +225,14 @@ Use the `sessionId` from updates to send input to a running hands-free session:
223
225
  // Send text
224
226
  interactive_shell({ sessionId: "shell-1", input: "/help\n" })
225
227
 
226
- // Send with named keys
227
- interactive_shell({ sessionId: "shell-1", input: { text: "/model", keys: ["enter"] } })
228
+ // Send text with keys
229
+ interactive_shell({ sessionId: "shell-1", input: "/model", inputKeys: ["enter"] })
228
230
 
229
231
  // Navigate menus
230
- interactive_shell({ sessionId: "shell-1", input: { keys: ["down", "down", "enter"] } })
232
+ interactive_shell({ sessionId: "shell-1", inputKeys: ["down", "down", "enter"] })
231
233
 
232
234
  // Interrupt
233
- interactive_shell({ sessionId: "shell-1", input: { keys: ["ctrl+c"] } })
235
+ interactive_shell({ sessionId: "shell-1", inputKeys: ["ctrl+c"] })
234
236
  ```
235
237
 
236
238
  ### Named Keys
@@ -257,45 +259,45 @@ Note: `ic`/`dc`, `ppage`/`npage`, `bspace` are tmux-style aliases for compatibil
257
259
  Supports `ctrl+`, `alt+`, `shift+` prefixes (or shorthand `c-`, `m-`, `s-`):
258
260
  ```typescript
259
261
  // Cancel
260
- { keys: ["ctrl+c"] }
262
+ inputKeys: ["ctrl+c"]
261
263
 
262
264
  // Alt+Tab
263
- { keys: ["alt+tab"] }
265
+ inputKeys: ["alt+tab"]
264
266
 
265
267
  // Ctrl+Alt+Delete
266
- { keys: ["ctrl+alt+delete"] }
268
+ inputKeys: ["ctrl+alt+delete"]
267
269
 
268
270
  // Shorthand syntax
269
- { keys: ["c-c", "m-x", "s-tab"] }
271
+ inputKeys: ["c-c", "m-x", "s-tab"]
270
272
  ```
271
273
 
272
274
  ### Hex Bytes (Advanced)
273
275
  Send raw escape sequences:
274
276
  ```typescript
275
- { hex: ["0x1b", "0x5b", "0x41"] } // ESC[A (up arrow)
277
+ inputHex: ["0x1b", "0x5b", "0x41"] // ESC[A (up arrow)
276
278
  ```
277
279
 
278
280
  ### Bracketed Paste
279
281
  Paste multiline text without triggering autocompletion/execution:
280
282
  ```typescript
281
- { paste: "function foo() {\n return 42;\n}" }
283
+ inputPaste: "function foo() {\n return 42;\n}"
282
284
  ```
283
285
 
284
286
  ### Model Selection Example
285
287
  ```typescript
286
288
  // Step 1: Open model selector
287
- interactive_shell({ sessionId: "shell-1", input: { text: "/model", keys: ["enter"] } })
289
+ interactive_shell({ sessionId: "shell-1", input: "/model", inputKeys: ["enter"] })
288
290
 
289
291
  // Step 2: Filter and select (after ~500ms delay)
290
- interactive_shell({ sessionId: "shell-1", input: { text: "sonnet", keys: ["enter"] } })
292
+ interactive_shell({ sessionId: "shell-1", input: "sonnet", inputKeys: ["enter"] })
291
293
 
292
294
  // Or navigate with arrows:
293
- interactive_shell({ sessionId: "shell-1", input: { keys: ["down", "down", "down", "enter"] } })
295
+ interactive_shell({ sessionId: "shell-1", inputKeys: ["down", "down", "down", "enter"] })
294
296
  ```
295
297
 
296
298
  ### Context Compaction
297
299
  ```typescript
298
- interactive_shell({ sessionId: "shell-1", input: { text: "/compact", keys: ["enter"] } })
300
+ interactive_shell({ sessionId: "shell-1", input: "/compact", inputKeys: ["enter"] })
299
301
  ```
300
302
 
301
303
  ### Changing Update Settings
@@ -396,11 +398,11 @@ interactive_shell({
396
398
  // Text with enter
397
399
  interactive_shell({ sessionId: "calm-reef", input: "/compact\n" })
398
400
 
399
- // Named keys
400
- interactive_shell({ sessionId: "calm-reef", input: { text: "/model", keys: ["enter"] } })
401
+ // Text + named keys
402
+ interactive_shell({ sessionId: "calm-reef", input: "/model", inputKeys: ["enter"] })
401
403
 
402
404
  // Menu navigation
403
- interactive_shell({ sessionId: "calm-reef", input: { keys: ["down", "down", "enter"] } })
405
+ interactive_shell({ sessionId: "calm-reef", inputKeys: ["down", "down", "enter"] })
404
406
  ```
405
407
 
406
408
  **Change update frequency:**
package/index.ts CHANGED
@@ -31,6 +31,9 @@ export default function interactiveShellExtension(pi: ExtensionAPI) {
31
31
  incremental,
32
32
  settings,
33
33
  input,
34
+ inputKeys,
35
+ inputHex,
36
+ inputPaste,
34
37
  cwd,
35
38
  name,
36
39
  reason,
@@ -41,6 +44,12 @@ export default function interactiveShellExtension(pi: ExtensionAPI) {
41
44
  timeout,
42
45
  } = params as ToolParams;
43
46
 
47
+ // Build structured input from separate fields if any are provided
48
+ const hasStructuredInput = inputKeys?.length || inputHex?.length || inputPaste;
49
+ const effectiveInput = hasStructuredInput
50
+ ? { text: input, keys: inputKeys, hex: inputHex, paste: inputPaste }
51
+ : input;
52
+
44
53
  // Mode 1: Interact with existing session (query status, send input, kill, or change settings)
45
54
  if (sessionId) {
46
55
  const session = sessionManager.getActive(sessionId);
@@ -100,8 +109,8 @@ export default function interactiveShellExtension(pi: ExtensionAPI) {
100
109
  }
101
110
 
102
111
  // Send input if provided
103
- if (input !== undefined) {
104
- const translatedInput = translateInput(input);
112
+ if (effectiveInput !== undefined) {
113
+ const translatedInput = translateInput(effectiveInput);
105
114
  const success = sessionManager.writeToActive(sessionId, translatedInput);
106
115
 
107
116
  if (!success) {
@@ -113,17 +122,17 @@ export default function interactiveShellExtension(pi: ExtensionAPI) {
113
122
  }
114
123
 
115
124
  const inputDesc =
116
- typeof input === "string"
117
- ? input.length === 0
125
+ typeof effectiveInput === "string"
126
+ ? effectiveInput.length === 0
118
127
  ? "(empty)"
119
- : input.length > 50
120
- ? `${input.slice(0, 50)}...`
121
- : input
128
+ : effectiveInput.length > 50
129
+ ? `${effectiveInput.slice(0, 50)}...`
130
+ : effectiveInput
122
131
  : [
123
- input.text ?? "",
124
- input.keys ? `keys:[${input.keys.join(",")}]` : "",
125
- input.hex ? `hex:[${input.hex.length} bytes]` : "",
126
- input.paste ? `paste:[${input.paste.length} chars]` : "",
132
+ effectiveInput.text ?? "",
133
+ effectiveInput.keys ? `keys:[${effectiveInput.keys.join(",")}]` : "",
134
+ effectiveInput.hex ? `hex:[${effectiveInput.hex.length} bytes]` : "",
135
+ effectiveInput.paste ? `paste:[${effectiveInput.paste.length} chars]` : "",
127
136
  ]
128
137
  .filter(Boolean)
129
138
  .join(" + ") || "(empty)";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pi-interactive-shell",
3
- "version": "0.4.9",
3
+ "version": "0.5.0",
4
4
  "description": "Run AI coding agents as foreground subagents in pi TUI overlays with hands-free monitoring",
5
5
  "type": "module",
6
6
  "bin": {
package/tool-schema.ts CHANGED
@@ -54,13 +54,14 @@ Queries are limited to once every 60 seconds (configurable). If you query too so
54
54
  the tool will automatically wait until the limit expires before returning.
55
55
 
56
56
  SENDING INPUT:
57
- - interactive_shell({ sessionId: "calm-reef", input: "/help\\n" })
58
- - interactive_shell({ sessionId: "calm-reef", input: { keys: ["ctrl+c"] } })
57
+ - interactive_shell({ sessionId: "calm-reef", input: "/help\\n" }) - raw text/keystrokes
58
+ - interactive_shell({ sessionId: "calm-reef", inputKeys: ["ctrl+c"] }) - named keys
59
+ - interactive_shell({ sessionId: "calm-reef", inputKeys: ["up", "up", "enter"] }) - multiple keys
60
+ - interactive_shell({ sessionId: "calm-reef", inputHex: ["0x1b", "0x5b", "0x41"] }) - raw escape sequences
61
+ - interactive_shell({ sessionId: "calm-reef", inputPaste: "multiline\\ntext" }) - bracketed paste (prevents auto-execution)
59
62
 
60
- Named keys: up, down, left, right, enter, escape, tab, backspace, ctrl+c, ctrl+d, etc.
63
+ Named keys for inputKeys: up, down, left, right, enter, escape, tab, backspace, ctrl+c, ctrl+d, etc.
61
64
  Modifiers: ctrl+x, alt+x, shift+tab, ctrl+alt+delete (or c-x, m-x, s-tab syntax)
62
- Hex bytes: input: { hex: ["0x1b", "0x5b", "0x41"] } for raw escape sequences
63
- Bracketed paste: input: { paste: "multiline\\ntext" } prevents auto-execution
64
65
 
65
66
  TIMEOUT (for TUI commands that don't exit cleanly):
66
67
  Use timeout to auto-kill after N milliseconds. Useful for capturing output from commands like "pi --help":
@@ -128,31 +129,22 @@ export const toolParameters = Type.Object({
128
129
  }),
129
130
  ),
130
131
  input: Type.Optional(
131
- Type.Union(
132
- [
133
- Type.String({ description: "Raw text/keystrokes to send" }),
134
- Type.Object({
135
- text: Type.Optional(Type.String({ description: "Text to type" })),
136
- keys: Type.Optional(
137
- Type.Array(Type.String(), {
138
- description:
139
- "Named keys with modifier support: up, down, enter, ctrl+c, alt+x, shift+tab, ctrl+alt+delete, etc.",
140
- }),
141
- ),
142
- hex: Type.Optional(
143
- Type.Array(Type.String(), {
144
- description: "Hex bytes to send (e.g., ['0x1b', '0x5b', '0x41'] for ESC[A)",
145
- }),
146
- ),
147
- paste: Type.Optional(
148
- Type.String({
149
- description: "Text to paste with bracketed paste mode (prevents auto-execution)",
150
- }),
151
- ),
152
- }),
153
- ],
154
- { description: "Input to send to an existing session (requires sessionId)" },
155
- ),
132
+ Type.String({ description: "Raw text/keystrokes to send to the session (requires sessionId). For special keys, use inputKeys instead." }),
133
+ ),
134
+ inputKeys: Type.Optional(
135
+ Type.Array(Type.String(), {
136
+ description: "Named keys with modifier support: up, down, enter, ctrl+c, alt+x, shift+tab, ctrl+alt+delete, etc. (requires sessionId)",
137
+ }),
138
+ ),
139
+ inputHex: Type.Optional(
140
+ Type.Array(Type.String(), {
141
+ description: "Hex bytes to send as raw escape sequences (e.g., ['0x1b', '0x5b', '0x41'] for ESC[A). (requires sessionId)",
142
+ }),
143
+ ),
144
+ inputPaste: Type.Optional(
145
+ Type.String({
146
+ description: "Text to paste with bracketed paste mode - prevents shells from auto-executing multiline input. (requires sessionId)",
147
+ }),
156
148
  ),
157
149
  cwd: Type.Optional(
158
150
  Type.String({
@@ -171,15 +163,15 @@ export const toolParameters = Type.Object({
171
163
  }),
172
164
  ),
173
165
  mode: Type.Optional(
174
- Type.Union([Type.Literal("interactive"), Type.Literal("hands-free")], {
175
- description: "interactive (default): user controls. hands-free: agent monitors, user can take over",
166
+ Type.String({
167
+ description: "Mode: 'interactive' (default, user controls) or 'hands-free' (agent monitors, user can take over)",
176
168
  }),
177
169
  ),
178
170
  handsFree: Type.Optional(
179
171
  Type.Object({
180
172
  updateMode: Type.Optional(
181
- Type.Union([Type.Literal("on-quiet"), Type.Literal("interval")], {
182
- description: "on-quiet (default): emit when output stops. interval: emit on fixed schedule.",
173
+ Type.String({
174
+ description: "Update mode: 'on-quiet' (default, emit when output stops) or 'interval' (emit on fixed schedule)",
183
175
  }),
184
176
  ),
185
177
  updateInterval: Type.Optional(
@@ -235,7 +227,10 @@ export interface ToolParams {
235
227
  drain?: boolean;
236
228
  incremental?: boolean;
237
229
  settings?: { updateInterval?: number; quietThreshold?: number };
238
- input?: string | { text?: string; keys?: string[]; hex?: string[]; paste?: string };
230
+ input?: string;
231
+ inputKeys?: string[];
232
+ inputHex?: string[];
233
+ inputPaste?: string;
239
234
  cwd?: string;
240
235
  name?: string;
241
236
  reason?: string;