Skip to content

Commit 420c330

Browse files
committed
fix(terminal): avoid replaying commands after shell integration failure
1 parent 5236445 commit 420c330

4 files changed

Lines changed: 16 additions & 24 deletions

File tree

src/core/webview/__tests__/webviewMessageHandler.spec.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -876,6 +876,10 @@ describe("webviewMessageHandler - terminalProfile", () => {
876876
vi.clearAllMocks()
877877
})
878878

879+
afterEach(() => {
880+
vi.restoreAllMocks()
881+
})
882+
879883
it("bridges a saved terminalProfile from updateSettings into the process-wide terminal state", async () => {
880884
const setTerminalProfileSpy = vi.spyOn(Terminal, "setTerminalProfile").mockImplementation(() => {})
881885

@@ -885,8 +889,6 @@ describe("webviewMessageHandler - terminalProfile", () => {
885889
})
886890

887891
expect(setTerminalProfileSpy).toHaveBeenCalledWith("Git Bash")
888-
889-
setTerminalProfileSpy.mockRestore()
890892
})
891893

892894
it("clears the terminal profile when updateSettings sends undefined", async () => {
@@ -898,8 +900,6 @@ describe("webviewMessageHandler - terminalProfile", () => {
898900
})
899901

900902
expect(setTerminalProfileSpy).toHaveBeenCalledWith(undefined)
901-
902-
setTerminalProfileSpy.mockRestore()
903903
})
904904
})
905905

src/integrations/terminal/TerminalProcess.ts

Lines changed: 9 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -229,30 +229,21 @@ export class TerminalProcess extends BaseTerminalProcess {
229229
} else {
230230
const inspectPreOutput = inspect(preOutput, { colors: false, breakLength: Infinity })
231231

232-
// Empty stream (preOutput === '') is a first-run race: VS Code fires
233-
// onDidStartTerminalShellExecution before the shell is fully initialized on
234-
// a freshly-created terminal. The command was never submitted, so this is
235-
// retryable (commandSubmitted: false triggers the execa fallback).
236-
//
237-
// Non-empty preOutput means the stream had data but ]633;C never arrived —
238-
// a genuine shell integration failure after submission (not retryable).
239-
const commandSubmitted = preOutput !== ""
240-
241-
const errorMsg = commandSubmitted
242-
? "VSCE output start escape sequence (]633;C or ]133;C) not received, but the stream has started. Upstream VSCE Bug?"
243-
: "VSCE shell integration stream completed with no output on first command (shell startup race). Command was not submitted."
232+
// executeCommand() has already been called, so an empty stream cannot prove
233+
// the command was never submitted. Treat the status as submitted/unknown to
234+
// avoid replaying a potentially side-effecting command through Execa.
235+
const errorMsg =
236+
"VSCE output start escape sequence (]633;C or ]133;C) not received after command submission. Command execution status is unknown."
244237

245238
console.error(`[Terminal Process] ${errorMsg} preOutput: ${inspectPreOutput}`)
246239

247-
this.emit("no_shell_integration", { message: errorMsg, commandSubmitted })
240+
this.emit("no_shell_integration", { message: errorMsg, commandSubmitted: true })
248241

249242
this.emit(
250243
"completed",
251-
commandSubmitted
252-
? "<VSCE shell integration markers not found: terminal output and command execution status is unknown>\n" +
253-
`<preOutput>${inspectPreOutput}</preOutput>\n` +
254-
"AI MODEL: You MUST notify the user with the information above so they can open a bug report."
255-
: "<shell integration stream was empty on first execution: command was not submitted>",
244+
"<VSCE shell integration markers not found: terminal output and command execution status is unknown>\n" +
245+
`<preOutput>${inspectPreOutput}</preOutput>\n` +
246+
"AI MODEL: You MUST notify the user with the information above so they can open a bug report.",
256247
)
257248

258249
this.continue()

src/integrations/terminal/__tests__/TerminalProcess.spec.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -140,7 +140,7 @@ describe("TerminalProcess", () => {
140140
consoleWarnSpy.mockRestore()
141141
})
142142

143-
it("emits no_shell_integration with commandSubmitted=false when stream is empty (first-run startup race)", async () => {
143+
it("emits no_shell_integration with commandSubmitted=true when stream is empty after submission", async () => {
144144
const consoleErrorSpy = vi.spyOn(console, "error").mockImplementation(() => {})
145145

146146
let details: { message: string; commandSubmitted: boolean } | undefined
@@ -173,7 +173,7 @@ describe("TerminalProcess", () => {
173173
await runPromise
174174
await eventPromises
175175

176-
expect(details?.commandSubmitted).toBe(false)
176+
expect(details?.commandSubmitted).toBe(true)
177177
consoleErrorSpy.mockRestore()
178178
})
179179

src/integrations/terminal/__tests__/TerminalProfile.spec.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,7 @@ describe("Terminal VS Code terminal profile (#277)", () => {
120120
linux: {
121121
zsh: { path: "/bin/zsh" },
122122
PowerShell: { source: "PowerShell" },
123+
disabled: null,
123124
bash: { path: "/bin/bash" },
124125
missing: { path: "/missing/bash" },
125126
},

0 commit comments

Comments
 (0)