fix(coding-agent): abort every in-flight bash command with its own controller (#1882)
* fix(coding-agent): give each executeBash invocation its own abort controller Concurrent execute_bash_and_wait daemon commands shared the single _bashAbortController field: the first finisher cleared the second command's controller and abortBash could only target the most recent command, leaving earlier still-running commands unabortable. Track per-invocation controllers in a set; abortBash aborts all in-flight commands. Fixes ENG-5752. * fix(coding-agent): flag pending user bash abort while other bash commands run abortBash only set _userBashAbortRequested when no abort controllers were registered, so an abort arriving during user_bash extension dispatch was lost when a concurrent executeBash occupied the controller set and the user bash still started. Set the flag whenever a user bash is running; runUserBash clears it at each start. Also reword the per-invocation controller comments to present-tense behavior. * test(coding-agent): update fake REPLs to protocol 3 --------- Co-authored-by: Xeophon <46377542+xeophon@users.noreply.github.com>
1- Fixed concurrent `execute_bash_and_wait` commands sharing one bash abort controller: each `executeBash` invocation now gets its own controller, so a finishing command no longer clears a still-running command's abort state and `abortBash` cancels every in-flight command.71 unmodified lines72737475767677787980334 unmodified linesExpand all71 unmodified lines `#!/usr/bin/env nodeconst fs = require("node:fs");const readline = require("node:readline");const emit = (event) => process.stdout.write(JSON.stringify(event) + "\\n");emit({ event: "ready", protocol: 2, python: process.version });emit({ event: "ready", protocol: 3, python: process.version });const input = readline.createInterface({ input: process.stdin });input.on("line", (line) => { const request = JSON.parse(line); if (request.type === "restore") {334 unmodified linesExpand all30 unmodified lines3132333435353637383839404142593 unmodified linesExpand all30 unmodified linesif (fs.existsSync(process.env.FAKE_REPL_CORRUPT_BOOT)) { process.stdout.write("BROKEN-BOOT\\n");} else if (fs.existsSync(process.env.FAKE_REPL_READY_WITH_GARBAGE)) { process.stdout.write( JSON.stringify({ event: "ready", protocol: 2, python: process.version }) + "\\nBROKEN-WITH-READY\\n", JSON.stringify({ event: "ready", protocol: 3, python: process.version }) + "\\nBROKEN-WITH-READY\\n", );} else if (!(count > 1 && fs.existsSync(process.env.FAKE_REPL_DELAY_READY))) { emit({ event: "ready", protocol: 2, python: process.version }); emit({ event: "ready", protocol: 3, python: process.version });}const input = readline.createInterface({ input: process.stdin });input.on("line", (line) => { const request = JSON.parse(line);593 unmodified linesExpand all