Archived
fix: close workspace terminals before deletion
This commit is contained in:
@@ -31,6 +31,14 @@ describe("terminal routes", () => {
|
||||
socket.close();
|
||||
});
|
||||
|
||||
it("closes all terminals for a cwd", async () => {
|
||||
const response = await app.inject({ method: "DELETE", url: `/terminals?cwd=${encodeURIComponent("/repo/worktree")}` });
|
||||
|
||||
expect(response.statusCode).toBe(200);
|
||||
expect(response.json()).toEqual({ closed: true });
|
||||
expect(terminals.events).toEqual(["close-cwd:/repo/worktree"]);
|
||||
});
|
||||
|
||||
it("creates and lists terminal command runs with filters", async () => {
|
||||
const createResponse = await app.inject({
|
||||
method: "POST",
|
||||
@@ -77,6 +85,10 @@ class FakeTerminals implements TerminalRouteService {
|
||||
};
|
||||
}
|
||||
|
||||
closeForCwd(cwd: string): void {
|
||||
this.events.push(`close-cwd:${cwd}`);
|
||||
}
|
||||
|
||||
close(id: string): void {
|
||||
this.events.push(`close:${id}`);
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@ import { parseTerminalSize } from "./terminalSize.js";
|
||||
export interface TerminalRouteService {
|
||||
list(cwd: string): TerminalInfo[];
|
||||
create(options: { cwd: string; name?: string; cols?: number; rows?: number }): TerminalInfo;
|
||||
closeForCwd(cwd: string): void;
|
||||
close(id: string): void;
|
||||
attach(id: string, handlers: { output: (data: string, replay: boolean) => void; exit: (exitCode: number | undefined) => void }): () => void;
|
||||
write(id: string, data: string): void;
|
||||
@@ -32,6 +33,16 @@ export function registerTerminalRoutes(app: FastifyInstance, terminals: Terminal
|
||||
}
|
||||
});
|
||||
|
||||
app.delete<{ Querystring: { cwd?: string } }>(`${prefix}/terminals`, (request, reply) => {
|
||||
if (request.query.cwd === undefined || request.query.cwd === "") return reply.code(400).send({ error: "cwd query parameter is required" });
|
||||
try {
|
||||
terminals.closeForCwd(request.query.cwd);
|
||||
return { closed: true };
|
||||
} catch (error) {
|
||||
return reply.code(400).send({ error: error instanceof Error ? error.message : String(error) });
|
||||
}
|
||||
});
|
||||
|
||||
app.post<{ Body: RunTerminalCommandOptions }>(`${prefix}/terminal-command-runs`, (request, reply) => {
|
||||
try {
|
||||
return terminals.runCommand(request.body);
|
||||
|
||||
@@ -2,6 +2,20 @@ import { describe, expect, it } from "vitest";
|
||||
import { TerminalService } from "./terminalService";
|
||||
|
||||
describe("TerminalService command runs", () => {
|
||||
it("closes all terminal records for a cwd", () => {
|
||||
const service = new TerminalService();
|
||||
try {
|
||||
const terminal = service.create({ cwd: process.cwd() });
|
||||
|
||||
service.closeForCwd(process.cwd());
|
||||
|
||||
expect(service.get(terminal.id)).toBeUndefined();
|
||||
expect(service.list(process.cwd())).toEqual([]);
|
||||
} finally {
|
||||
service.dispose();
|
||||
}
|
||||
});
|
||||
|
||||
it("tracks dedicated terminal command runs through completion", async () => {
|
||||
const service = new TerminalService();
|
||||
try {
|
||||
|
||||
@@ -48,6 +48,11 @@ export class TerminalService {
|
||||
.map(toInfo);
|
||||
}
|
||||
|
||||
closeForCwd(cwd: string): void {
|
||||
if (cwd === "") throw new Error("cwd is required");
|
||||
for (const terminal of [...this.terminals.values()].filter((candidate) => candidate.cwd === cwd)) this.close(terminal.id);
|
||||
}
|
||||
|
||||
create(options: { cwd: string; name?: string; cols?: number; rows?: number }): TerminalInfo {
|
||||
return this.createTerminal({ ...options, shellArgs: [] });
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user