feat: stream worktree setup progress and terminal subscriptions
This commit is contained in:
@@ -1236,4 +1236,89 @@ describe("DaemonClient", () => {
|
||||
expect(received).toHaveLength(0);
|
||||
expect(logger.warn).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
test("sends subscribe/unsubscribe terminals messages", async () => {
|
||||
const logger = createMockLogger();
|
||||
const mock = createMockTransport();
|
||||
|
||||
const client = new DaemonClient({
|
||||
url: "ws://test",
|
||||
logger,
|
||||
reconnect: { enabled: false },
|
||||
transportFactory: () => mock.transport,
|
||||
});
|
||||
clients.push(client);
|
||||
|
||||
const connectPromise = client.connect();
|
||||
mock.triggerOpen();
|
||||
await connectPromise;
|
||||
|
||||
client.subscribeTerminals({ cwd: "/tmp/project" });
|
||||
client.unsubscribeTerminals({ cwd: "/tmp/project" });
|
||||
|
||||
expect(mock.sent).toHaveLength(2);
|
||||
expect(JSON.parse(String(mock.sent[0]))).toEqual({
|
||||
type: "session",
|
||||
message: {
|
||||
type: "subscribe_terminals_request",
|
||||
cwd: "/tmp/project",
|
||||
},
|
||||
});
|
||||
expect(JSON.parse(String(mock.sent[1]))).toEqual({
|
||||
type: "session",
|
||||
message: {
|
||||
type: "unsubscribe_terminals_request",
|
||||
cwd: "/tmp/project",
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
test("dispatches terminals_changed events to typed listeners", async () => {
|
||||
const logger = createMockLogger();
|
||||
const mock = createMockTransport();
|
||||
|
||||
const client = new DaemonClient({
|
||||
url: "ws://test",
|
||||
logger,
|
||||
reconnect: { enabled: false },
|
||||
transportFactory: () => mock.transport,
|
||||
});
|
||||
clients.push(client);
|
||||
|
||||
const connectPromise = client.connect();
|
||||
mock.triggerOpen();
|
||||
await connectPromise;
|
||||
|
||||
const received: Array<{ cwd: string; names: string[] }> = [];
|
||||
const unsubscribe = client.on("terminals_changed", (message) => {
|
||||
received.push({
|
||||
cwd: message.payload.cwd,
|
||||
names: message.payload.terminals.map((terminal) => terminal.name),
|
||||
});
|
||||
});
|
||||
|
||||
mock.triggerMessage(
|
||||
wrapSessionMessage({
|
||||
type: "terminals_changed",
|
||||
payload: {
|
||||
cwd: "/tmp/project",
|
||||
terminals: [
|
||||
{
|
||||
id: "term-1",
|
||||
name: "Dev Server",
|
||||
},
|
||||
],
|
||||
},
|
||||
})
|
||||
);
|
||||
|
||||
unsubscribe();
|
||||
|
||||
expect(received).toEqual([
|
||||
{
|
||||
cwd: "/tmp/project",
|
||||
names: ["Dev Server"],
|
||||
},
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -356,6 +356,7 @@ export class DaemonClient {
|
||||
string,
|
||||
{ cwd: string; compare: { mode: "uncommitted" | "base"; baseRef?: string } }
|
||||
>();
|
||||
private terminalDirectorySubscriptions = new Set<string>();
|
||||
private logger: Logger;
|
||||
private pendingSendQueue: PendingSend[] = [];
|
||||
private relayClientId: string | null = null;
|
||||
@@ -474,6 +475,7 @@ export class DaemonClient {
|
||||
this.updateConnectionState({ status: "connected" });
|
||||
this.resubscribeAgentUpdates();
|
||||
this.resubscribeCheckoutDiffSubscriptions();
|
||||
this.resubscribeTerminalDirectorySubscriptions();
|
||||
this.flushPendingSendQueue();
|
||||
this.resolveConnect();
|
||||
}),
|
||||
@@ -1093,6 +1095,18 @@ export class DaemonClient {
|
||||
}
|
||||
}
|
||||
|
||||
private resubscribeTerminalDirectorySubscriptions(): void {
|
||||
if (this.terminalDirectorySubscriptions.size === 0) {
|
||||
return;
|
||||
}
|
||||
for (const cwd of this.terminalDirectorySubscriptions) {
|
||||
this.sendSessionMessage({
|
||||
type: "subscribe_terminals_request",
|
||||
cwd,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// Agent Lifecycle
|
||||
// ============================================================================
|
||||
@@ -2314,6 +2328,28 @@ export class DaemonClient {
|
||||
// Terminals
|
||||
// ============================================================================
|
||||
|
||||
subscribeTerminals(input: { cwd: string }): void {
|
||||
this.terminalDirectorySubscriptions.add(input.cwd);
|
||||
if (!this.transport || this.connectionState.status !== "connected") {
|
||||
return;
|
||||
}
|
||||
this.sendSessionMessage({
|
||||
type: "subscribe_terminals_request",
|
||||
cwd: input.cwd,
|
||||
});
|
||||
}
|
||||
|
||||
unsubscribeTerminals(input: { cwd: string }): void {
|
||||
this.terminalDirectorySubscriptions.delete(input.cwd);
|
||||
if (!this.transport || this.connectionState.status !== "connected") {
|
||||
return;
|
||||
}
|
||||
this.sendSessionMessage({
|
||||
type: "unsubscribe_terminals_request",
|
||||
cwd: input.cwd,
|
||||
});
|
||||
}
|
||||
|
||||
async listTerminals(
|
||||
cwd: string,
|
||||
requestId?: string
|
||||
|
||||
Reference in New Issue
Block a user