|
|
@@ -15,7 +15,11 @@
|
|
|
import type { MultiplexerLayout } from '../../config/schema';
|
|
|
import { crossSpawn } from '../../utils/compat';
|
|
|
import { log } from '../../utils/logger';
|
|
|
-import { buildOpencodeAttachCommand, findBinary } from '../shared';
|
|
|
+import {
|
|
|
+ buildOpencodeAttachCommand,
|
|
|
+ findBinary,
|
|
|
+ gracefulClosePane,
|
|
|
+} from '../shared';
|
|
|
import type { Multiplexer, PaneResult } from '../types';
|
|
|
|
|
|
type HerdrPaneDirection = 'right' | 'down';
|
|
|
@@ -153,50 +157,13 @@ export class HerdrMultiplexer implements Multiplexer {
|
|
|
}
|
|
|
|
|
|
async closePane(paneId: string): Promise<boolean> {
|
|
|
- if (!paneId || paneId === 'unknown') return true;
|
|
|
-
|
|
|
const herdr = await this.getBinary();
|
|
|
- if (!herdr) {
|
|
|
- log('[herdr] closePane: herdr binary not found');
|
|
|
- return false;
|
|
|
- }
|
|
|
-
|
|
|
- try {
|
|
|
- // Send Ctrl+C for graceful shutdown
|
|
|
- log('[herdr] closePane: sending Ctrl+C', { paneId });
|
|
|
- await crossSpawn([herdr, 'pane', 'send-keys', paneId, 'ctrl+c'], {
|
|
|
- stdout: 'ignore',
|
|
|
- stderr: 'ignore',
|
|
|
- }).exited;
|
|
|
-
|
|
|
- // Wait for graceful shutdown
|
|
|
- await new Promise((r) => setTimeout(r, 250));
|
|
|
-
|
|
|
- // Close the pane
|
|
|
- log('[herdr] closePane: closing pane', { paneId });
|
|
|
- const proc = crossSpawn([herdr, 'pane', 'close', paneId], {
|
|
|
- stdout: 'pipe',
|
|
|
- stderr: 'pipe',
|
|
|
- });
|
|
|
-
|
|
|
- const exitCode = await proc.exited;
|
|
|
- const stderr = await proc.stderr();
|
|
|
-
|
|
|
- log('[herdr] closePane: result', { exitCode, stderr: stderr.trim() });
|
|
|
-
|
|
|
- if (exitCode === 0 || exitCode === 1) {
|
|
|
- return true;
|
|
|
- }
|
|
|
-
|
|
|
- // Pane might already be closed
|
|
|
- log('[herdr] closePane: failed (pane may already be closed)', {
|
|
|
- paneId,
|
|
|
- });
|
|
|
- return false;
|
|
|
- } catch (err) {
|
|
|
- log('[herdr] closePane: exception', { error: String(err) });
|
|
|
- return false;
|
|
|
- }
|
|
|
+ return gracefulClosePane(herdr, paneId, {
|
|
|
+ ctrlC: ['pane', 'send-keys', paneId, 'ctrl+c'],
|
|
|
+ close: ['pane', 'close', paneId],
|
|
|
+ acceptExitCode1: true,
|
|
|
+ emptyPaneReturnsTrue: true,
|
|
|
+ });
|
|
|
}
|
|
|
|
|
|
async applyLayout(
|