mirror of
https://github.com/QwenLM/qwen-code.git
synced 2026-08-20 06:04:55 +00:00
fix(acp-bridge): abort direct shell waiting on a hung cwd change (#8068)
This commit is contained in:
parent
3fb32df434
commit
1b4aefc819
2 changed files with 69 additions and 1 deletions
|
|
@ -11715,6 +11715,65 @@ describe('createAcpSessionBridge', () => {
|
|||
await bridge.shutdown();
|
||||
shellSpy.mockRestore();
|
||||
});
|
||||
|
||||
it('returns an aborted direct shell without waiting for a hung cwd change', async () => {
|
||||
const shellSpy = mockShellExecute();
|
||||
const cdResult = deferred<{
|
||||
previousCwd: string;
|
||||
newCwd: string;
|
||||
warnings: string[];
|
||||
}>();
|
||||
const handle = makeChannel({
|
||||
extMethodImpl: async (method) => {
|
||||
if (method === SERVE_CONTROL_EXT_METHODS.sessionCd) {
|
||||
return cdResult.promise;
|
||||
}
|
||||
return {};
|
||||
},
|
||||
});
|
||||
const bridge = makeBridge({
|
||||
sessionShellCommandEnabled: true,
|
||||
channelFactory: async () => handle.channel,
|
||||
});
|
||||
const session = await bridge.spawnOrAttach({ workspaceCwd: WS_A });
|
||||
|
||||
const cd = bridge.changeSessionCwd(session.sessionId, { path: WS_B });
|
||||
await vi.waitFor(() =>
|
||||
expect(handle.agent.extMethodCalls).toContainEqual({
|
||||
method: SERVE_CONTROL_EXT_METHODS.sessionCd,
|
||||
params: {
|
||||
sessionId: session.sessionId,
|
||||
path: WS_B,
|
||||
},
|
||||
}),
|
||||
);
|
||||
|
||||
const abort = new AbortController();
|
||||
const shell = bridge.executeShellCommand(
|
||||
session.sessionId,
|
||||
'echo aborted-cd',
|
||||
abort.signal,
|
||||
{ clientId: session.clientId },
|
||||
);
|
||||
|
||||
await Promise.resolve();
|
||||
expect(shellSpy).not.toHaveBeenCalled();
|
||||
abort.abort();
|
||||
|
||||
// The cd extMethod never settles, yet the aborted command must return
|
||||
// promptly instead of parking on the cwd queue forever.
|
||||
await expect(shell).resolves.toEqual({
|
||||
exitCode: null,
|
||||
output: '',
|
||||
aborted: true,
|
||||
});
|
||||
expect(shellSpy).not.toHaveBeenCalled();
|
||||
|
||||
cdResult.resolve({ previousCwd: WS_A, newCwd: WS_B, warnings: [] });
|
||||
await cd;
|
||||
await bridge.shutdown();
|
||||
shellSpy.mockRestore();
|
||||
});
|
||||
});
|
||||
|
||||
describe('setSessionApprovalMode (#4175 Wave 4 PR 17)', () => {
|
||||
|
|
|
|||
|
|
@ -7791,7 +7791,16 @@ export function createAcpSessionBridge(opts: BridgeOptions): AcpSessionBridge {
|
|||
return { exitCode: null, output: '', aborted: true };
|
||||
}
|
||||
|
||||
await entry.cwdChangeQueue;
|
||||
// Race the cwd queue against the caller's abort signal so a shell
|
||||
// command cannot park forever on a changeSessionCwd extMethod that
|
||||
// never settles (agent crash / deadlock / partitioned ACP channel).
|
||||
await Promise.race([
|
||||
entry.cwdChangeQueue,
|
||||
new Promise<void>((resolve) => {
|
||||
if (signal?.aborted) return resolve();
|
||||
signal?.addEventListener('abort', () => resolve(), { once: true });
|
||||
}),
|
||||
]);
|
||||
if (signal?.aborted) {
|
||||
return { exitCode: null, output: '', aborted: true };
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue