pi-interactive-shell 0.6.2 → 0.6.3
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 +6 -0
- package/overlay-component.ts +17 -53
- package/package.json +1 -1
- package/reattach-overlay.ts +17 -44
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,12 @@ All notable changes to the `pi-interactive-shell` extension will be documented i
|
|
|
4
4
|
|
|
5
5
|
## [Unreleased]
|
|
6
6
|
|
|
7
|
+
## [0.6.3] - 2026-01-30
|
|
8
|
+
|
|
9
|
+
### Fixed
|
|
10
|
+
- **Garbled output on Ctrl+T transfer** - Transfer and handoff preview captured raw PTY output via `getRawStream()`, which includes every intermediate frame of TUI spinners (e.g., Codex's "Working" spinner produced `WorkingWorking•orking•rking•king•ing...`). Switched both `captureTransferOutput()` and `maybeBuildHandoffPreview()` to use `getTailLines()` which reads from the xterm terminal emulator buffer. The emulator correctly processes carriage returns and cursor movements, so only the final rendered state of each line is captured. Fixed in both `overlay-component.ts` and `reattach-overlay.ts`.
|
|
11
|
+
- **Removed dead code** - Cleaned up unused private fields (`timedOut`, `lastDataTime`) and unreachable method (`getSessionId()`) from `InteractiveShellOverlay`.
|
|
12
|
+
|
|
7
13
|
## [0.6.2] - 2026-01-28
|
|
8
14
|
|
|
9
15
|
### Fixed
|
package/overlay-component.ts
CHANGED
|
@@ -43,7 +43,6 @@ export class InteractiveShellOverlay implements Component, Focusable {
|
|
|
43
43
|
private sessionUnregistered = false;
|
|
44
44
|
// Timeout
|
|
45
45
|
private timeoutTimer: ReturnType<typeof setTimeout> | null = null;
|
|
46
|
-
private timedOut = false;
|
|
47
46
|
// Prevent double done() calls
|
|
48
47
|
private finished = false;
|
|
49
48
|
// Budget tracking for hands-free updates
|
|
@@ -52,7 +51,6 @@ export class InteractiveShellOverlay implements Component, Focusable {
|
|
|
52
51
|
private currentUpdateInterval: number;
|
|
53
52
|
private currentQuietThreshold: number;
|
|
54
53
|
private updateMode: "on-quiet" | "interval";
|
|
55
|
-
private lastDataTime = 0;
|
|
56
54
|
private quietTimer: ReturnType<typeof setTimeout> | null = null;
|
|
57
55
|
private hasUnsentData = false;
|
|
58
56
|
// Non-blocking mode: track status for agent queries
|
|
@@ -101,7 +99,6 @@ export class InteractiveShellOverlay implements Component, Focusable {
|
|
|
101
99
|
|
|
102
100
|
// Track activity for on-quiet mode
|
|
103
101
|
if (this.state === "hands-free" && this.updateMode === "on-quiet") {
|
|
104
|
-
this.lastDataTime = Date.now();
|
|
105
102
|
this.hasUnsentData = true;
|
|
106
103
|
this.resetQuietTimer();
|
|
107
104
|
}
|
|
@@ -367,11 +364,6 @@ export class InteractiveShellOverlay implements Component, Focusable {
|
|
|
367
364
|
}, 16);
|
|
368
365
|
}
|
|
369
366
|
|
|
370
|
-
/** Get the session ID */
|
|
371
|
-
getSessionId(): string | null {
|
|
372
|
-
return this.sessionId;
|
|
373
|
-
}
|
|
374
|
-
|
|
375
367
|
/** Kill the session programmatically */
|
|
376
368
|
killSession(): void {
|
|
377
369
|
if (!this.finished) {
|
|
@@ -626,35 +618,19 @@ export class InteractiveShellOverlay implements Component, Focusable {
|
|
|
626
618
|
const maxLines = this.config.transferLines;
|
|
627
619
|
const maxChars = this.config.transferMaxChars;
|
|
628
620
|
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
}
|
|
634
|
-
|
|
635
|
-
const allLines = rawOutput.split("\n");
|
|
636
|
-
const totalLines = allLines.length;
|
|
637
|
-
|
|
638
|
-
// Get last N lines, respecting maxChars
|
|
639
|
-
let capturedLines: string[] = [];
|
|
640
|
-
let charCount = 0;
|
|
641
|
-
let truncated = false;
|
|
642
|
-
|
|
643
|
-
for (let i = allLines.length - 1; i >= 0 && capturedLines.length < maxLines; i--) {
|
|
644
|
-
const line = allLines[i]!;
|
|
645
|
-
if (charCount + line.length > maxChars && capturedLines.length > 0) {
|
|
646
|
-
truncated = true;
|
|
647
|
-
break;
|
|
648
|
-
}
|
|
649
|
-
capturedLines.unshift(line);
|
|
650
|
-
charCount += line.length + 1; // +1 for newline
|
|
651
|
-
}
|
|
621
|
+
const result = this.session.getTailLines({
|
|
622
|
+
lines: maxLines,
|
|
623
|
+
ansi: false,
|
|
624
|
+
maxChars,
|
|
625
|
+
});
|
|
652
626
|
|
|
653
|
-
|
|
654
|
-
truncated = true;
|
|
655
|
-
}
|
|
627
|
+
const truncated = result.lines.length < result.totalLinesInBuffer || result.truncatedByChars;
|
|
656
628
|
|
|
657
|
-
return {
|
|
629
|
+
return {
|
|
630
|
+
lines: result.lines,
|
|
631
|
+
totalLines: result.totalLinesInBuffer,
|
|
632
|
+
truncated,
|
|
633
|
+
};
|
|
658
634
|
}
|
|
659
635
|
|
|
660
636
|
private maybeBuildHandoffPreview(when: "exit" | "detach" | "kill" | "timeout" | "transfer"): InteractiveShellResult["handoffPreview"] | undefined {
|
|
@@ -665,24 +641,13 @@ export class InteractiveShellOverlay implements Component, Focusable {
|
|
|
665
641
|
const maxChars = this.options.handoffPreviewMaxChars ?? this.config.handoffPreviewMaxChars;
|
|
666
642
|
if (lines <= 0 || maxChars <= 0) return undefined;
|
|
667
643
|
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
const outputLines = rawOutput.split("\n");
|
|
674
|
-
|
|
675
|
-
// Get last N lines, respecting maxChars
|
|
676
|
-
let tail: string[] = [];
|
|
677
|
-
let charCount = 0;
|
|
678
|
-
for (let i = outputLines.length - 1; i >= 0 && tail.length < lines; i--) {
|
|
679
|
-
const line = outputLines[i];
|
|
680
|
-
if (charCount + line.length > maxChars && tail.length > 0) break;
|
|
681
|
-
tail.unshift(line);
|
|
682
|
-
charCount += line.length + 1; // +1 for newline
|
|
683
|
-
}
|
|
644
|
+
const result = this.session.getTailLines({
|
|
645
|
+
lines,
|
|
646
|
+
ansi: false,
|
|
647
|
+
maxChars,
|
|
648
|
+
});
|
|
684
649
|
|
|
685
|
-
return { type: "tail", when, lines:
|
|
650
|
+
return { type: "tail", when, lines: result.lines };
|
|
686
651
|
}
|
|
687
652
|
|
|
688
653
|
private maybeWriteHandoffSnapshot(when: "exit" | "detach" | "kill" | "timeout" | "transfer"): InteractiveShellResult["handoff"] | undefined {
|
|
@@ -884,7 +849,6 @@ export class InteractiveShellOverlay implements Component, Focusable {
|
|
|
884
849
|
}
|
|
885
850
|
|
|
886
851
|
this.stopHandsFreeUpdates();
|
|
887
|
-
this.timedOut = true;
|
|
888
852
|
const handoffPreview = this.maybeBuildHandoffPreview("timeout");
|
|
889
853
|
const handoff = this.maybeWriteHandoffSnapshot("timeout");
|
|
890
854
|
this.session.kill();
|
package/package.json
CHANGED
package/reattach-overlay.ts
CHANGED
|
@@ -106,35 +106,19 @@ export class ReattachOverlay implements Component, Focusable {
|
|
|
106
106
|
const maxLines = this.config.transferLines;
|
|
107
107
|
const maxChars = this.config.transferMaxChars;
|
|
108
108
|
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
const allLines = rawOutput.split("\n");
|
|
116
|
-
const totalLines = allLines.length;
|
|
117
|
-
|
|
118
|
-
// Get last N lines, respecting maxChars
|
|
119
|
-
let capturedLines: string[] = [];
|
|
120
|
-
let charCount = 0;
|
|
121
|
-
let truncated = false;
|
|
122
|
-
|
|
123
|
-
for (let i = allLines.length - 1; i >= 0 && capturedLines.length < maxLines; i--) {
|
|
124
|
-
const line = allLines[i]!;
|
|
125
|
-
if (charCount + line.length > maxChars && capturedLines.length > 0) {
|
|
126
|
-
truncated = true;
|
|
127
|
-
break;
|
|
128
|
-
}
|
|
129
|
-
capturedLines.unshift(line);
|
|
130
|
-
charCount += line.length + 1; // +1 for newline
|
|
131
|
-
}
|
|
109
|
+
const result = this.session.getTailLines({
|
|
110
|
+
lines: maxLines,
|
|
111
|
+
ansi: false,
|
|
112
|
+
maxChars,
|
|
113
|
+
});
|
|
132
114
|
|
|
133
|
-
|
|
134
|
-
truncated = true;
|
|
135
|
-
}
|
|
115
|
+
const truncated = result.lines.length < result.totalLinesInBuffer || result.truncatedByChars;
|
|
136
116
|
|
|
137
|
-
return {
|
|
117
|
+
return {
|
|
118
|
+
lines: result.lines,
|
|
119
|
+
totalLines: result.totalLinesInBuffer,
|
|
120
|
+
truncated,
|
|
121
|
+
};
|
|
138
122
|
}
|
|
139
123
|
|
|
140
124
|
private maybeBuildHandoffPreview(when: "exit" | "detach" | "kill" | "transfer"): InteractiveShellResult["handoffPreview"] | undefined {
|
|
@@ -143,24 +127,13 @@ export class ReattachOverlay implements Component, Focusable {
|
|
|
143
127
|
const maxChars = this.config.handoffPreviewMaxChars;
|
|
144
128
|
if (lines <= 0 || maxChars <= 0) return undefined;
|
|
145
129
|
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
const outputLines = rawOutput.split("\n");
|
|
152
|
-
|
|
153
|
-
// Get last N lines, respecting maxChars
|
|
154
|
-
let tail: string[] = [];
|
|
155
|
-
let charCount = 0;
|
|
156
|
-
for (let i = outputLines.length - 1; i >= 0 && tail.length < lines; i--) {
|
|
157
|
-
const line = outputLines[i];
|
|
158
|
-
if (charCount + line.length > maxChars && tail.length > 0) break;
|
|
159
|
-
tail.unshift(line);
|
|
160
|
-
charCount += line.length + 1; // +1 for newline
|
|
161
|
-
}
|
|
130
|
+
const result = this.session.getTailLines({
|
|
131
|
+
lines,
|
|
132
|
+
ansi: false,
|
|
133
|
+
maxChars,
|
|
134
|
+
});
|
|
162
135
|
|
|
163
|
-
return { type: "tail", when, lines:
|
|
136
|
+
return { type: "tail", when, lines: result.lines };
|
|
164
137
|
}
|
|
165
138
|
|
|
166
139
|
private maybeWriteHandoffSnapshot(when: "exit" | "detach" | "kill" | "transfer"): InteractiveShellResult["handoff"] | undefined {
|