pi-interactive-shell 0.4.6 → 0.4.8

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pi-interactive-shell",
3
- "version": "0.4.6",
3
+ "version": "0.4.8",
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": {
@@ -23,7 +23,7 @@
23
23
  ]
24
24
  },
25
25
  "dependencies": {
26
- "node-pty": "^1.0.0",
26
+ "node-pty": "^1.1.0",
27
27
  "@xterm/headless": "^5.5.0",
28
28
  "@xterm/addon-serialize": "^0.13.0"
29
29
  },
package/pty-session.ts CHANGED
@@ -501,47 +501,61 @@ export class PtyTerminalSession {
501
501
  return lines;
502
502
  }
503
503
 
504
- getTailLines(options: { lines: number; ansi?: boolean; maxChars?: number }): string[] {
504
+ getTailLines(options: { lines: number; ansi?: boolean; maxChars?: number }): {
505
+ lines: string[];
506
+ totalLinesInBuffer: number;
507
+ truncatedByChars: boolean;
508
+ } {
505
509
  const requested = Math.max(0, Math.trunc(options.lines));
506
510
  const maxChars = options.maxChars !== undefined ? Math.max(0, Math.trunc(options.maxChars)) : undefined;
507
- if (requested === 0) return [];
508
-
511
+
509
512
  const buffer = this.xterm.buffer.active;
510
- const totalLines = buffer.length;
511
- const start = Math.max(0, totalLines - requested);
513
+ const totalLinesInBuffer = buffer.length;
514
+
515
+ if (requested === 0) {
516
+ return { lines: [], totalLinesInBuffer, truncatedByChars: false };
517
+ }
512
518
 
519
+ const start = Math.max(0, totalLinesInBuffer - requested);
513
520
  const out: string[] = [];
514
521
  let remainingChars = maxChars;
522
+ let truncatedByChars = false;
515
523
 
516
524
  const useAnsi = options.ansi && this.serializer;
517
525
  if (useAnsi) {
518
526
  const serialized = this.serializer!.serialize();
519
527
  const serializedLines = serialized.split(/\r?\n/);
520
- if (serializedLines.length >= totalLines) {
521
- for (let i = start; i < totalLines; i++) {
528
+ if (serializedLines.length >= totalLinesInBuffer) {
529
+ for (let i = start; i < totalLinesInBuffer; i++) {
522
530
  const raw = serializedLines[i] ?? "";
523
531
  const line = sanitizeLine(raw) + "\u001b[0m";
524
532
  if (remainingChars !== undefined) {
525
- if (remainingChars <= 0) break;
533
+ if (remainingChars <= 0) {
534
+ truncatedByChars = true;
535
+ break;
536
+ }
526
537
  remainingChars -= line.length;
527
538
  }
528
539
  out.push(line);
529
540
  }
530
- return out;
541
+ return { lines: out, totalLinesInBuffer, truncatedByChars };
531
542
  }
532
543
  }
533
544
 
534
- for (let i = start; i < totalLines; i++) {
545
+ for (let i = start; i < totalLinesInBuffer; i++) {
535
546
  const lineObj = buffer.getLine(i);
536
547
  const line = sanitizeLine(lineObj?.translateToString(true) ?? "");
537
548
  if (remainingChars !== undefined) {
538
- if (remainingChars <= 0) break;
549
+ if (remainingChars <= 0) {
550
+ truncatedByChars = true;
551
+ break;
552
+ }
539
553
  remainingChars -= line.length;
540
554
  }
541
555
  out.push(line);
542
556
  }
543
557
 
544
- return out;
558
+ return { lines: out, totalLinesInBuffer, truncatedByChars };
545
559
  }
546
560
 
547
561
  /**
@@ -578,6 +592,7 @@ export class PtyTerminalSession {
578
592
  slice: string;
579
593
  totalLines: number;
580
594
  totalChars: number;
595
+ sliceLineCount: number;
581
596
  } {
582
597
  let text = this.rawOutput;
583
598
 
@@ -587,7 +602,7 @@ export class PtyTerminalSession {
587
602
  }
588
603
 
589
604
  if (!text) {
590
- return { slice: "", totalLines: 0, totalChars: 0 };
605
+ return { slice: "", totalLines: 0, totalChars: 0, sliceLineCount: 0 };
591
606
  }
592
607
 
593
608
  // Normalize line endings and split
@@ -618,10 +633,13 @@ export class PtyTerminalSession {
618
633
  ? start + Math.max(0, Math.floor(options.limit))
619
634
  : undefined;
620
635
 
636
+ const selectedLines = lines.slice(start, end);
637
+
621
638
  return {
622
- slice: lines.slice(start, end).join("\n"),
639
+ slice: selectedLines.join("\n"),
623
640
  totalLines,
624
641
  totalChars,
642
+ sliceLineCount: selectedLines.length,
625
643
  };
626
644
  }
627
645
 
@@ -24,6 +24,9 @@ export interface OutputResult {
24
24
  output: string;
25
25
  truncated: boolean;
26
26
  totalBytes: number;
27
+ // For incremental/offset modes
28
+ totalLines?: number;
29
+ hasMore?: boolean;
27
30
  // Rate limiting
28
31
  rateLimited?: boolean;
29
32
  waitSeconds?: number;
@@ -34,7 +37,8 @@ export interface OutputOptions {
34
37
  lines?: number; // Override default 20 lines
35
38
  maxChars?: number; // Override default 5KB
36
39
  offset?: number; // Line offset for pagination (0-indexed)
37
- drain?: boolean; // If true, return only NEW output since last query (incremental)
40
+ drain?: boolean; // If true, return only NEW output since last query (raw stream)
41
+ incremental?: boolean; // If true, return next N lines not yet seen (server tracks position)
38
42
  }
39
43
 
40
44
  export interface ActiveSession {
@@ -141,7 +145,7 @@ export class ShellSessionManager {
141
145
  reason?: string;
142
146
  write: (data: string) => void;
143
147
  kill: () => void;
144
- getOutput: (skipRateLimit?: boolean) => OutputResult;
148
+ getOutput: (options?: OutputOptions | boolean) => OutputResult;
145
149
  getStatus: () => ActiveSessionStatus;
146
150
  getRuntime: () => number;
147
151
  getResult: () => ActiveSessionResult | undefined;