Persist exit codes without tmux pane_dead_status
This commit is contained in:
@@ -6,6 +6,7 @@ import {
|
|||||||
listPanes,
|
listPanes,
|
||||||
findWindowByName,
|
findWindowByName,
|
||||||
capturePaneContent,
|
capturePaneContent,
|
||||||
|
extractExitCodeMarkerFromOutput,
|
||||||
sendText as tmuxSendText,
|
sendText as tmuxSendText,
|
||||||
sendKeys as tmuxSendKeys,
|
sendKeys as tmuxSendKeys,
|
||||||
renameWindow,
|
renameWindow,
|
||||||
@@ -382,7 +383,9 @@ export class TerminalManager {
|
|||||||
// Use stored values for dead panes, current values for live ones
|
// Use stored values for dead panes, current values for live ones
|
||||||
const workingDirectory = await getStoredWorkingDirectory(window.id, paneId);
|
const workingDirectory = await getStoredWorkingDirectory(window.id, paneId);
|
||||||
const currentCommand = await getStoredCommand(window.id, paneId);
|
const currentCommand = await getStoredCommand(window.id, paneId);
|
||||||
const lastLines = await capturePaneContent(paneId, 5, false);
|
const rawLastLines = await capturePaneContent(paneId, 5, false);
|
||||||
|
const lastLinesExtracted = extractExitCodeMarkerFromOutput(rawLastLines);
|
||||||
|
const lastLines = lastLinesExtracted.output;
|
||||||
|
|
||||||
let exitCode: number | null = null;
|
let exitCode: number | null = null;
|
||||||
if (isDead) {
|
if (isDead) {
|
||||||
@@ -394,7 +397,7 @@ export class TerminalManager {
|
|||||||
"#{pane_dead_status}",
|
"#{pane_dead_status}",
|
||||||
]);
|
]);
|
||||||
const parsed = parseInt(exitCodeStr, 10);
|
const parsed = parseInt(exitCodeStr, 10);
|
||||||
exitCode = Number.isFinite(parsed) ? parsed : null;
|
exitCode = Number.isFinite(parsed) ? parsed : lastLinesExtracted.exitCode;
|
||||||
}
|
}
|
||||||
|
|
||||||
commands.push({
|
commands.push({
|
||||||
@@ -427,9 +430,11 @@ export class TerminalManager {
|
|||||||
throw new Error(`Session '${this.sessionName}' not found.`);
|
throw new Error(`Session '${this.sessionName}' not found.`);
|
||||||
}
|
}
|
||||||
|
|
||||||
const paneId = `${commandId}.0`;
|
const paneId = `${commandId}.0`;
|
||||||
|
|
||||||
const output = await capturePaneContent(paneId, lines, false);
|
const rawOutput = await capturePaneContent(paneId, lines, false);
|
||||||
|
const extracted = extractExitCodeMarkerFromOutput(rawOutput);
|
||||||
|
const output = extracted.output;
|
||||||
|
|
||||||
const deadStatus = await executeTmux([
|
const deadStatus = await executeTmux([
|
||||||
"display-message",
|
"display-message",
|
||||||
@@ -450,7 +455,7 @@ export class TerminalManager {
|
|||||||
"#{pane_dead_status}",
|
"#{pane_dead_status}",
|
||||||
]);
|
]);
|
||||||
const parsed = parseInt(exitCodeStr, 10);
|
const parsed = parseInt(exitCodeStr, 10);
|
||||||
exitCode = Number.isFinite(parsed) ? parsed : null;
|
exitCode = Number.isFinite(parsed) ? parsed : extracted.exitCode;
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
|||||||
@@ -49,6 +49,8 @@ let shellConfig: { type: ShellType } = { type: "bash" };
|
|||||||
const ANSI_ESCAPE_REGEX =
|
const ANSI_ESCAPE_REGEX =
|
||||||
/\u001B[\[()#;?]*(?:[0-9]{1,4}(?:;[0-9]{0,4})*)?[0-9A-ORZcf-nqry=><]/g;
|
/\u001B[\[()#;?]*(?:[0-9]{1,4}(?:;[0-9]{0,4})*)?[0-9A-ORZcf-nqry=><]/g;
|
||||||
|
|
||||||
|
const EXIT_CODE_MARKER = "__PASEO_EXIT_CODE__:";
|
||||||
|
|
||||||
function stripAnsiSequences(value: string): string {
|
function stripAnsiSequences(value: string): string {
|
||||||
if (!value) {
|
if (!value) {
|
||||||
return "";
|
return "";
|
||||||
@@ -56,6 +58,33 @@ function stripAnsiSequences(value: string): string {
|
|||||||
return value.replace(ANSI_ESCAPE_REGEX, "");
|
return value.replace(ANSI_ESCAPE_REGEX, "");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function extractExitCodeMarkerFromOutput(output: string): {
|
||||||
|
exitCode: number | null;
|
||||||
|
output: string;
|
||||||
|
} {
|
||||||
|
if (!output) {
|
||||||
|
return { exitCode: null, output };
|
||||||
|
}
|
||||||
|
|
||||||
|
let exitCode: number | null = null;
|
||||||
|
const kept: string[] = [];
|
||||||
|
|
||||||
|
for (const line of output.split("\n")) {
|
||||||
|
const trimmed = line.trim();
|
||||||
|
if (trimmed.startsWith(EXIT_CODE_MARKER)) {
|
||||||
|
const codeStr = trimmed.slice(EXIT_CODE_MARKER.length).trim();
|
||||||
|
const parsed = parseInt(codeStr, 10);
|
||||||
|
if (Number.isFinite(parsed)) {
|
||||||
|
exitCode = parsed;
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
kept.push(line);
|
||||||
|
}
|
||||||
|
|
||||||
|
return { exitCode, output: kept.join("\n").trimEnd() };
|
||||||
|
}
|
||||||
|
|
||||||
export function setShellConfig(config: { type: string }): void {
|
export function setShellConfig(config: { type: string }): void {
|
||||||
// Validate shell type
|
// Validate shell type
|
||||||
const validShells: ShellType[] = ["bash", "zsh", "fish"];
|
const validShells: ShellType[] = ["bash", "zsh", "fish"];
|
||||||
@@ -559,7 +588,7 @@ export async function executeCommand({
|
|||||||
|
|
||||||
// Execute command via respawn-pane with bash -c wrapper
|
// Execute command via respawn-pane with bash -c wrapper
|
||||||
// This ensures all bash features work (pipes, operators, etc.)
|
// This ensures all bash features work (pipes, operators, etc.)
|
||||||
const wrappedCommand = `bash -c 'cd "${expandedPath}" && ${command.replace(/'/g, "'\\''")} 2>&1; exit $?'`;
|
const wrappedCommand = `bash -c 'cd "${expandedPath}" && ${command.replace(/'/g, "'\\''")} 2>&1; code=$?; echo ${EXIT_CODE_MARKER}$code; exit $code'`;
|
||||||
await executeTmux(["respawn-pane", "-t", pane.id, "-k", wrappedCommand]);
|
await executeTmux(["respawn-pane", "-t", pane.id, "-k", wrappedCommand]);
|
||||||
|
|
||||||
// Wait for command to finish or reach stability
|
// Wait for command to finish or reach stability
|
||||||
@@ -584,6 +613,8 @@ export async function executeCommand({
|
|||||||
if (isDead) {
|
if (isDead) {
|
||||||
// Command finished - capture output and exit code
|
// Command finished - capture output and exit code
|
||||||
output = await capturePaneContent(pane.id, 1000, false);
|
output = await capturePaneContent(pane.id, 1000, false);
|
||||||
|
const extracted = extractExitCodeMarkerFromOutput(output);
|
||||||
|
output = extracted.output;
|
||||||
const exitCodeStr = await executeTmux([
|
const exitCodeStr = await executeTmux([
|
||||||
"display-message",
|
"display-message",
|
||||||
"-p",
|
"-p",
|
||||||
@@ -592,7 +623,7 @@ export async function executeCommand({
|
|||||||
"#{pane_dead_status}",
|
"#{pane_dead_status}",
|
||||||
]);
|
]);
|
||||||
const parsed = parseInt(exitCodeStr, 10);
|
const parsed = parseInt(exitCodeStr, 10);
|
||||||
exitCode = Number.isFinite(parsed) ? parsed : null;
|
exitCode = Number.isFinite(parsed) ? parsed : extracted.exitCode;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user