pi-interactive-shell 0.6.1 → 0.6.2

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
@@ -4,6 +4,15 @@ All notable changes to the `pi-interactive-shell` extension will be documented i
4
4
 
5
5
  ## [Unreleased]
6
6
 
7
+ ## [0.6.2] - 2026-01-28
8
+
9
+ ### Fixed
10
+ - **Ctrl+T transfer now works in hands-free mode** - When using Ctrl+T to transfer output in non-blocking hands-free mode, the captured output is now properly sent back to the main agent using `pi.sendMessage()` with `triggerTurn: true`. Previously, the transfer data was captured but never delivered to the agent because the tool had already returned. The fix uses the event bus pattern to wake the agent with the transferred content.
11
+ - **Race condition when Ctrl+T during polling** - Added guard in `getOutputSinceLastCheck()` to return empty output if the session is finished. This prevents errors when a query races with Ctrl+T transfer (PTY disposed before query completes).
12
+
13
+ ### Added
14
+ - **New event: `interactive-shell:transfer`** - Emitted via `pi.events` when Ctrl+T transfer occurs, allowing other extensions to hook into transfer events.
15
+
7
16
  ## [0.6.1] - 2026-01-27
8
17
 
9
18
  ### Added
package/README.md CHANGED
@@ -25,11 +25,9 @@ Works with any CLI: `vim`, `htop`, `psql`, `ssh`, `docker logs -f`, `npm run dev
25
25
  ## Install
26
26
 
27
27
  ```bash
28
- npx pi-interactive-shell
28
+ pi install npm:pi-interactive-shell
29
29
  ```
30
30
 
31
- Installs to `~/.pi/agent/extensions/interactive-shell/`.
32
-
33
31
  The `interactive-shell` skill is automatically symlinked to `~/.pi/agent/skills/interactive-shell/`.
34
32
 
35
33
  **Requires:** Node.js, build tools for `node-pty` (Xcode CLI tools on macOS).
package/index.ts CHANGED
@@ -437,10 +437,37 @@ export default function interactiveShellExtension(pi: ExtensionAPI) {
437
437
  // Handle overlay completion in background (cleanup when user closes)
438
438
  overlayPromise.then((result) => {
439
439
  overlayOpen = false;
440
- // Session already handles cleanup via finishWith* methods
441
- // This just ensures the promise doesn't cause unhandled rejection
442
- if (result.userTookOver) {
443
- // User took over - session continues interactively
440
+
441
+ // Handle Ctrl+T transfer: send output back to main agent
442
+ if (result.transferred) {
443
+ const truncatedNote = result.transferred.truncated
444
+ ? ` (truncated from ${result.transferred.totalLines} total lines)`
445
+ : "";
446
+ const content = `Session ${generatedSessionId} output transferred (${result.transferred.lines.length} lines${truncatedNote}):\n\n${result.transferred.lines.join("\n")}`;
447
+
448
+ // Send message with triggerTurn to wake the agent
449
+ pi.sendMessage({
450
+ customType: "interactive-shell-transfer",
451
+ content,
452
+ display: true,
453
+ details: {
454
+ sessionId: generatedSessionId,
455
+ transferred: result.transferred,
456
+ exitCode: result.exitCode,
457
+ signal: result.signal,
458
+ },
459
+ }, { triggerTurn: true });
460
+
461
+ // Emit event for extensions that want to handle transfers
462
+ pi.events.emit("interactive-shell:transfer", {
463
+ sessionId: generatedSessionId,
464
+ transferred: result.transferred,
465
+ exitCode: result.exitCode,
466
+ signal: result.signal,
467
+ });
468
+
469
+ // Unregister session - PTY is disposed, agent has the output via sendMessage
470
+ sessionManager.unregisterActive(generatedSessionId, true);
444
471
  }
445
472
  }).catch(() => {
446
473
  overlayOpen = false;
@@ -190,6 +190,16 @@ export class InteractiveShellOverlay implements Component, Focusable {
190
190
 
191
191
  /** Get rendered terminal output (last N lines, truncated if too large) */
192
192
  getOutputSinceLastCheck(options: { skipRateLimit?: boolean; lines?: number; maxChars?: number; offset?: number; drain?: boolean; incremental?: boolean } | boolean = false): { output: string; truncated: boolean; totalBytes: number; totalLines?: number; hasMore?: boolean; rateLimited?: boolean; waitSeconds?: number } {
193
+ // Guard: if session is finished (PTY disposed), return empty output
194
+ // This handles race conditions where query arrives after Ctrl+T transfer
195
+ if (this.finished) {
196
+ return {
197
+ output: "",
198
+ truncated: false,
199
+ totalBytes: 0,
200
+ };
201
+ }
202
+
193
203
  // Handle legacy boolean parameter
194
204
  const opts = typeof options === "boolean" ? { skipRateLimit: options } : options;
195
205
  const skipRateLimit = opts.skipRateLimit ?? false;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pi-interactive-shell",
3
- "version": "0.6.1",
3
+ "version": "0.6.2",
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": {