Fix CLI resource cleanup and auth flow
This commit is contained in:
parent
54bc458b7d
commit
508a1c9837
2 changed files with 44 additions and 28 deletions
51
src/cli.ts
51
src/cli.ts
|
|
@ -60,7 +60,9 @@ async function main() {
|
||||||
let pty: IPty | null = null;
|
let pty: IPty | null = null;
|
||||||
let ws: WebSocket | null = null;
|
let ws: WebSocket | null = null;
|
||||||
let isExiting = false;
|
let isExiting = false;
|
||||||
|
let isAuthenticated = false;
|
||||||
let reconnectTimer: Timer | null = null;
|
let reconnectTimer: Timer | null = null;
|
||||||
|
const disposables: Array<{ dispose: () => void }> = [];
|
||||||
|
|
||||||
const cleanup = () => {
|
const cleanup = () => {
|
||||||
if (isExiting) return;
|
if (isExiting) return;
|
||||||
|
|
@ -69,6 +71,12 @@ async function main() {
|
||||||
if (reconnectTimer) {
|
if (reconnectTimer) {
|
||||||
clearTimeout(reconnectTimer);
|
clearTimeout(reconnectTimer);
|
||||||
}
|
}
|
||||||
|
for (const d of disposables) {
|
||||||
|
d.dispose();
|
||||||
|
}
|
||||||
|
if (process.stdin.isTTY) {
|
||||||
|
process.stdin.setRawMode(false);
|
||||||
|
}
|
||||||
if (pty) {
|
if (pty) {
|
||||||
pty.kill();
|
pty.kill();
|
||||||
}
|
}
|
||||||
|
|
@ -102,19 +110,28 @@ async function main() {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// Forward PTY output to stdout
|
// Forward PTY output to stdout AND WebSocket (if authenticated)
|
||||||
|
disposables.push(
|
||||||
pty.onData((data: string) => {
|
pty.onData((data: string) => {
|
||||||
process.stdout.write(data);
|
process.stdout.write(data);
|
||||||
});
|
|
||||||
|
if (ws && ws.readyState === WebSocket.OPEN && isAuthenticated) {
|
||||||
|
const msg: ClientMessage = { type: "output", data };
|
||||||
|
ws.send(JSON.stringify(msg));
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
|
||||||
// Handle PTY exit
|
// Handle PTY exit
|
||||||
|
disposables.push(
|
||||||
pty.onExit((event) => {
|
pty.onExit((event) => {
|
||||||
if (ws && !isExiting) {
|
if (ws && !isExiting) {
|
||||||
const msg: ClientMessage = { type: "exit", code: event.exitCode };
|
const msg: ClientMessage = { type: "exit", code: event.exitCode };
|
||||||
ws.send(JSON.stringify(msg));
|
ws.send(JSON.stringify(msg));
|
||||||
}
|
}
|
||||||
cleanup();
|
cleanup();
|
||||||
});
|
}),
|
||||||
|
);
|
||||||
|
|
||||||
// Handle terminal resize
|
// Handle terminal resize
|
||||||
process.stdout.on("resize", () => {
|
process.stdout.on("resize", () => {
|
||||||
|
|
@ -154,15 +171,20 @@ async function main() {
|
||||||
};
|
};
|
||||||
|
|
||||||
ws.onmessage = (event) => {
|
ws.onmessage = (event) => {
|
||||||
if (!pty) return;
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const msg: ServerMessage = JSON.parse(event.data);
|
const msg: ServerMessage = JSON.parse(event.data);
|
||||||
|
|
||||||
if (msg.type === "input") {
|
if (msg.type === "authenticated") {
|
||||||
|
isAuthenticated = true;
|
||||||
|
console.debug(`Authenticated with session ID: ${msg.session_id}`);
|
||||||
|
} else if (msg.type === "input") {
|
||||||
|
if (pty) {
|
||||||
pty.write(msg.data);
|
pty.write(msg.data);
|
||||||
|
}
|
||||||
} else if (msg.type === "resize") {
|
} else if (msg.type === "resize") {
|
||||||
|
if (pty) {
|
||||||
pty.resize(msg.cols, msg.rows);
|
pty.resize(msg.cols, msg.rows);
|
||||||
|
}
|
||||||
} else if (msg.type === "ping") {
|
} else if (msg.type === "ping") {
|
||||||
// Acknowledge ping (keep-alive)
|
// Acknowledge ping (keep-alive)
|
||||||
}
|
}
|
||||||
|
|
@ -171,13 +193,16 @@ async function main() {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
ws.onerror = () => {
|
ws.onerror = (event) => {
|
||||||
console.error("WebSocket error");
|
console.error("WebSocket error:", event);
|
||||||
};
|
};
|
||||||
|
|
||||||
ws.onclose = () => {
|
ws.onclose = () => {
|
||||||
if (isExiting) return;
|
if (isExiting) return;
|
||||||
|
|
||||||
|
// Reset auth flag on disconnect
|
||||||
|
isAuthenticated = false;
|
||||||
|
|
||||||
// Try to reconnect after 2 seconds
|
// Try to reconnect after 2 seconds
|
||||||
reconnectTimer = setTimeout(() => {
|
reconnectTimer = setTimeout(() => {
|
||||||
console.debug("Reconnecting to server...");
|
console.debug("Reconnecting to server...");
|
||||||
|
|
@ -186,16 +211,6 @@ async function main() {
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
// Forward PTY output to server
|
|
||||||
if (pty) {
|
|
||||||
pty.onData((data: string) => {
|
|
||||||
if (ws && ws.readyState === WebSocket.OPEN) {
|
|
||||||
const msg: ClientMessage = { type: "output", data };
|
|
||||||
ws.send(JSON.stringify(msg));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
connect();
|
connect();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -45,6 +45,7 @@ export type ClientMessage =
|
||||||
| { type: "prompt"; session_id: number; prompt_text: string };
|
| { type: "prompt"; session_id: number; prompt_text: string };
|
||||||
|
|
||||||
export type ServerMessage =
|
export type ServerMessage =
|
||||||
|
| { type: "authenticated"; session_id: number }
|
||||||
| { type: "input"; data: string }
|
| { type: "input"; data: string }
|
||||||
| { type: "resize"; cols: number; rows: number }
|
| { type: "resize"; cols: number; rows: number }
|
||||||
| { type: "ping" };
|
| { type: "ping" };
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue