Skip to content

Commit ac86592

Browse files
authored
fix(mux): require configured herdr anchor (#12)
1 parent 5668ab7 commit ac86592

4 files changed

Lines changed: 22 additions & 11 deletions

File tree

docs/specs/SPEC-04-multiplexer-adapter-layer.md

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -86,8 +86,9 @@ export function getMultiplexer(
8686
- Keep it pure mechanism: no pino-session knowledge here.
8787

8888
## Acceptance criteria
89-
- [x] `HerdrAdapter.isAvailable()` returns true inside a herdr environment,
90-
false when `herdr` is missing.
89+
- [x] `HerdrAdapter.isAvailable()` returns true when herdr is reachable and the
90+
configured anchor pane exists, false when `herdr` is missing or the anchor
91+
is not usable.
9192
- [x] `spawnPane({cwd, command:'echo hi; sleep 30', label:'pino: test'})` creates
9293
a **new, unfocused** pane running the command; `paneExists` is true;
9394
`setLabel` shows the label; `closePane` removes it and is safe to call twice.
@@ -100,9 +101,11 @@ export function getMultiplexer(
100101
clean.
101102

102103
## Decisions (formerly open questions)
103-
- **Anchor pane / workspace:** `PINO_MUX_ANCHOR` env or `config.json` key
104-
`mux.anchor` (default `"pino"`). New panes split into that anchor so sessions
105-
don't fragment the user's active layout. Callers can override per-host.
104+
- **Anchor pane:** `PINO_MUX_ANCHOR` env or `config.json` key `mux.anchor`
105+
(default `"pino"` as a setup label). New panes split from that anchor pane id
106+
so sessions don't fragment the user's active layout. `HerdrAdapter.isAvailable()`
107+
returns false until the configured anchor appears in `herdr pane list`; callers
108+
can then fall back instead of failing on `pane_not_found`.
106109
- **Exec injection:** yes — `HerdrAdapter` accepts an optional `exec` fn in its
107110
constructor (defaults to `execFile`). Keeps the adapter testable without a real
108111
herdr binary.

server/src/mux/config.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import { log } from "../log.js";
1111
export interface MuxConfig {
1212
/** Active multiplexer name, e.g. "herdr". Env PINO_MUX wins. */
1313
mux: string;
14-
/** Anchor pane id or workspace for new splits. Env PINO_MUX_ANCHOR wins. */
14+
/** Anchor pane id for new splits. Env PINO_MUX_ANCHOR wins. */
1515
anchor: string;
1616
}
1717

@@ -39,7 +39,7 @@ function readConfigFile(file: string): ConfigFileShape {
3939
}
4040
}
4141

42-
/** Default anchor: dedicated "pino" workspace so sessions don't fragment the active layout. */
42+
/** Default anchor label; herdr is unavailable until this resolves to an actual pane id. */
4343
export const DEFAULT_MUX_ANCHOR = "pino";
4444

4545
/** Load mux config. Env vars override file values. */

server/src/mux/herdr.test.ts

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -68,12 +68,20 @@ test("parsePaneList returns [] on garbage", () => {
6868

6969
test("isAvailable true when pane list succeeds", async () => {
7070
const exec = recordingExec({
71-
"herdr pane list": paneListJson([]),
71+
"herdr pane list": paneListJson(["w1:p1"]),
7272
});
73-
const adapter = new HerdrAdapter({ exec, anchor: "pino" });
73+
const adapter = new HerdrAdapter({ exec, anchor: "w1:p1" });
7474
assert.equal(await adapter.isAvailable(), true);
7575
});
7676

77+
test("isAvailable false when configured anchor is missing", async () => {
78+
const exec = recordingExec({
79+
"herdr pane list": paneListJson(["w1:p1"]),
80+
});
81+
const adapter = new HerdrAdapter({ exec, anchor: "pino" });
82+
assert.equal(await adapter.isAvailable(), false);
83+
});
84+
7785
test("isAvailable false when herdr missing", async () => {
7886
const failing: ExecFn = async () => {
7987
throw Object.assign(new Error("ENOENT"), { code: "ENOENT" });

server/src/mux/herdr.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -70,8 +70,8 @@ export class HerdrAdapter implements MultiplexerAdapter {
7070

7171
async isAvailable(): Promise<boolean> {
7272
try {
73-
await this.exec(MUX, ["pane", "list"]);
74-
return true;
73+
const { stdout } = await this.exec(MUX, ["pane", "list"]);
74+
return parsePaneList(stdout).includes(this.anchor);
7575
} catch {
7676
return false;
7777
}

0 commit comments

Comments
 (0)