59 lines
1.9 KiB
TypeScript
59 lines
1.9 KiB
TypeScript
/**
|
||
* tmux capture-pane snapshot.
|
||
*
|
||
* Returns a plain-text snapshot of a pane's visible content.
|
||
* Used by the snapshot route (T-1.5) and the /thumbnail endpoint (T-1.6).
|
||
*
|
||
* Owner: T-1.1
|
||
*/
|
||
|
||
import { execFile } from "node:child_process";
|
||
import { promisify } from "node:util";
|
||
|
||
const execFileAsync = promisify(execFile);
|
||
|
||
export interface SnapshotOptions {
|
||
/** tmux session name */
|
||
session: string;
|
||
/** pane index within session (default "0.0") */
|
||
pane?: string;
|
||
/** capture width (default: actual pane width) */
|
||
width?: number;
|
||
/** capture height (default: actual pane height) */
|
||
height?: number;
|
||
/** include escape sequences for colour/style (default: false = plain text) */
|
||
escapes?: boolean;
|
||
}
|
||
|
||
/**
|
||
* Capture a plain-text (or escape-annotated) snapshot of a tmux pane.
|
||
* Returns raw text as a string.
|
||
*/
|
||
export async function capturePane(opts: SnapshotOptions): Promise<string> {
|
||
const { session, pane, escapes = false } = opts;
|
||
// Target just the session when no pane specified — avoids base-index issues.
|
||
const target = pane ? `${session}:${pane}` : session;
|
||
|
||
const args = ["capture-pane", "-t", target, "-p"];
|
||
if (escapes) args.push("-e"); // include escape sequences
|
||
// Note: -S/-E (start/end line) omitted — captures current visible content
|
||
|
||
const { stdout } = await execFileAsync("tmux", args);
|
||
return stdout;
|
||
}
|
||
|
||
/**
|
||
* Capture a thumbnail-sized snapshot (40×12) for the REST thumbnail endpoint.
|
||
* Returns plain text, trimmed.
|
||
*/
|
||
export async function captureThumbnail(
|
||
session: string,
|
||
pane?: string,
|
||
): Promise<string> {
|
||
// tmux can't resize the capture directly via capture-pane flags, so we
|
||
// capture full content and truncate to 40-char wide × 12 lines.
|
||
const raw = await capturePane({ session, pane, escapes: false });
|
||
const lines = raw.split("\n").slice(0, 12);
|
||
return lines.map((l) => l.slice(0, 40)).join("\n");
|
||
}
|