Просмотр исходного кода

feat(herdr): clear agent-area tracking on close and layout change

Michael Henke 1 месяц назад
Родитель
Сommit
627694797f
2 измененных файлов с 62 добавлено и 3 удалено
  1. 55 0
      src/multiplexer/herdr/index.test.ts
  2. 7 3
      src/multiplexer/herdr/index.ts

+ 55 - 0
src/multiplexer/herdr/index.test.ts

@@ -474,6 +474,61 @@ describe('HerdrMultiplexer', () => {
     ]);
   });
 
+  test('main-vertical: fallback to parent when agent area closed', async () => {
+    const { HerdrMultiplexer } = await importFreshHerdr();
+    const herdr = new HerdrMultiplexer('main-vertical', 60);
+
+    const r1 = await herdr.spawnPane('s1', 'A1', 'http://localhost:4096', '/repo');
+    // Simulate agent area pane being closed externally
+    await herdr.closePane(r1.paneId!);
+
+    // Next spawn should split from parent (w1:p1) → right, not from stale w1:p2
+    await herdr.spawnPane('s2', 'A2', 'http://localhost:4096', '/repo');
+
+    const splitCommands = commands().filter((c) => c.includes('split'));
+    // 1st: parent → right (w1:p1)
+    expect(splitCommands[0]).toContain('w1:p1');
+    // 2nd (after close): parent → right again (w1:p1), not w1:p2
+    expect(splitCommands[1]).toEqual([
+      '/usr/bin/herdr', 'pane', 'split', 'w1:p1',
+      '--direction', 'right', '--cwd', '/repo', '--no-focus',
+    ]);
+  });
+
+  test('closePane clears agentAreaPaneId when agent area closed', async () => {
+    const { HerdrMultiplexer } = await importFreshHerdr();
+    const herdr = new HerdrMultiplexer('main-vertical', 60);
+
+    const r1 = await herdr.spawnPane('s1', 'A1', 'http://localhost:4096', '/repo');
+    await herdr.closePane(r1.paneId!);
+
+    // @ts-expect-error - accessing private for test
+    expect(herdr.agentAreaPaneId).toBeNull();
+  });
+
+  test('closePane does NOT clear agentAreaPaneId for non-agent pane', async () => {
+    const { HerdrMultiplexer } = await importFreshHerdr();
+    const herdr = new HerdrMultiplexer('main-vertical', 60);
+
+    await herdr.spawnPane('s1', 'A1', 'http://localhost:4096', '/repo');
+    // Close a different pane (simulated)
+    await herdr.closePane('w1:p99');
+
+    // @ts-expect-error
+    expect(herdr.agentAreaPaneId).not.toBeNull();
+  });
+
+  test('applyLayout clears agentAreaPaneId', async () => {
+    const { HerdrMultiplexer } = await importFreshHerdr();
+    const herdr = new HerdrMultiplexer('main-vertical', 60);
+
+    await herdr.spawnPane('s1', 'A1', 'http://localhost:4096', '/repo');
+    await herdr.applyLayout('tiled', 50);
+
+    // @ts-expect-error
+    expect(herdr.agentAreaPaneId).toBeNull();
+  });
+
   test('applyLayout is a no-op', async () => {
     const { HerdrMultiplexer } = await importFreshHerdr();
     const herdr = new HerdrMultiplexer('main-vertical', 60);

+ 7 - 3
src/multiplexer/herdr/index.ts

@@ -158,6 +158,10 @@ export class HerdrMultiplexer implements Multiplexer {
   async closePane(paneId: string): Promise<boolean> {
     if (!paneId || paneId === 'unknown') return true;
 
+    if (paneId === this.agentAreaPaneId) {
+      this.agentAreaPaneId = null;
+    }
+
     const herdr = await this.getBinary();
     if (!herdr) {
       log('[herdr] closePane: herdr binary not found');
@@ -206,9 +210,9 @@ export class HerdrMultiplexer implements Multiplexer {
     _layout: MultiplexerLayout,
     _mainPaneSize: number,
   ): Promise<void> {
-    // No-op for herdr. Herdr does not support tmux-like exact main pane
-    // sizing/rebalancing; layout is applied to future pane creation by
-    // mapping configured layouts to pane split directions.
+    // ponytail: herdr has no rebalancing API; clear agent area so a layout
+    // switch starts fresh from the parent pane.
+    this.agentAreaPaneId = null;
   }
 
   private async runSplit(