feat: pet chat window replaces the Sagi panel; Windows pane attach no longer crashes the server
- Sagi: clicking the pet opens its chat window directly (PetChat + SagiInfo status strip, Needs you, Mute / Clear alerts); SagiPanel removed. - Chat view answers Claude's unnumbered folder-trust prompt (parseBareMenu). - pty-attach: resize/write after a Windows attach exited, and node-pty's pipe errors, no longer throw out of the WebSocket handler. - restart-helper: the server started by an update logs to data/agenthub-server.log instead of discarding its output.
This commit is contained in:
@@ -204,6 +204,45 @@ describe("pty-attach", () => {
|
||||
assert.deepEqual(JSON.parse(a.__sent.at(-1).data), { type: "lead" });
|
||||
});
|
||||
|
||||
it("survives a stopped pane: pipe errors, typing and resizes after the attach exited", () => {
|
||||
// Windows node-pty re-throws a read-pipe error nobody listens for, and its
|
||||
// write pipe has no listener at all: Stop (kill-session) ended the attach
|
||||
// with EPIPE and the uncaught error killed the whole dashboard.
|
||||
const ptys = [];
|
||||
ptyAttach.__setSpawnImpl(() => {
|
||||
const p = makeFakePty();
|
||||
p.on = (evt, fn) => p.__emitter.on(evt, fn);
|
||||
p._agent = { inSocket: new EventEmitter() };
|
||||
p.resize = () => {
|
||||
if (p.__gone) throw new Error("Cannot resize a pty that has already exited");
|
||||
};
|
||||
p.write = () => {
|
||||
if (p.__gone) throw new Error("write EPIPE");
|
||||
};
|
||||
ptys.push(p);
|
||||
return p;
|
||||
});
|
||||
const a = makeFakeWs();
|
||||
const b = makeFakeWs();
|
||||
a.close = b.close = () => {};
|
||||
ptyAttach.attach(a, "agenthub-lane-1", { cols: 80, rows: 24 });
|
||||
ptyAttach.attach(b, "agenthub-lane-1", { cols: 80, rows: 24 });
|
||||
|
||||
const epipe = Object.assign(new Error("read EPIPE"), { code: "EPIPE" });
|
||||
assert.doesNotThrow(() => ptys[0].__emitter.emit("error", epipe));
|
||||
assert.doesNotThrow(() => ptys[0]._agent.inSocket.emit("error", epipe));
|
||||
|
||||
ptys[0].__gone = true;
|
||||
ptys[0].__emitter.emit("exit", { exitCode: 1 }); // a's close event not yet in
|
||||
const msg = (ws, data, binary) => ws.__emitter.emit("message", Buffer.from(data), { binary });
|
||||
assert.doesNotThrow(() =>
|
||||
msg(b, JSON.stringify({ type: "resize", cols: 90, rows: 30, drive: true }), false)
|
||||
);
|
||||
assert.doesNotThrow(() => msg(a, "x", true));
|
||||
ptys[1].__gone = true; // exited, onExit still queued
|
||||
assert.doesNotThrow(() => msg(b, "y", true));
|
||||
});
|
||||
|
||||
it("kills the PTY attach process when the WS connection closes", () => {
|
||||
const ws = makeFakeWs();
|
||||
ptyAttach.attach(ws, "agenthub-lane-1", { cols: 80, rows: 24 });
|
||||
|
||||
Reference in New Issue
Block a user