fix(maestro): draft-pane regressions from the integration review

Six findings from reviewing the accumulated blitz/spawn-v2 diff:

- loadRecents restored the seeded cwd but never emitted it, so the leaf's
  draft kept cwd:"" and the next render reseeded the form blank.
- stripDrafts did not recurse, so every half-filled draft in a split tab
  was written to localStorage; the old test passed only because hydrate
  discards draft on the way back in.
- showRawCwd and selectPreset grabbed focus from async init paths, so a
  draft pane stole the caret seconds after mounting.
- .mv-draft inherited no layout once the form left .modal-body.
- onSuccess mounted the new session onto a leaf that may have been closed
  while the POST was in flight, stranding it in no pane.
This commit is contained in:
Miguel Palhas
2026-08-23 20:12:28 +01:00
parent 35bc5bfb40
commit 6f8de8de7c
5 changed files with 60 additions and 11 deletions
+26
View File
@@ -99,4 +99,30 @@ describe("serializeLayout", () => {
}
expect(leaves(restored!.tabs[0].root).map((l) => l.sessionId)).toEqual(["s1", null]);
});
it("keeps the draft out of the stored blob itself, not just out of hydrate", () => {
// A draft pane only exists once a tab has split, so the strip has to walk
// into split branches; asserting on the restored layout alone passes even
// when the draft was written to localStorage, because hydrate drops it.
const layout = hydrate({
tabs: [
{
id: "t",
root: {
kind: "split",
dir: "row",
a: { kind: "leaf", id: "l1", sessionId: "s1" },
b: { kind: "leaf", id: "l2", sessionId: null },
},
},
],
activeTabId: "t",
}) as Layout;
const draftLeaf = leaves(layout.tabs[0].root).find((l) => !l.sessionId)!;
draftLeaf.draft = { command: "claude", cwd: "/home/user/secret-project", name: "amber-fox" };
const raw = serializeLayout(layout);
expect(raw).not.toContain("secret-project");
expect(raw).not.toContain("amber-fox");
});
});