@@ -111,6 +111,36 @@ vi.mock("../process/supervisor/index.js", () => {
|
111 | 111 | env[readPathKey(env)] = value; |
112 | 112 | }; |
113 | 113 | const extractCommand = (input: SpawnInput) => input.ptyCommand ?? input.argv?.at(-1) ?? ""; |
| 114 | +const parseShellSingleQuoted = (input: string) => { |
| 115 | +if (!input.startsWith("'")) { |
| 116 | +return null; |
| 117 | +} |
| 118 | +let output = ""; |
| 119 | +for (let index = 1; index < input.length; index += 1) { |
| 120 | +const char = input[index]; |
| 121 | +if (char !== "'") { |
| 122 | +output += char; |
| 123 | +continue; |
| 124 | +} |
| 125 | +if (input.startsWith("'\\''", index)) { |
| 126 | +output += "'"; |
| 127 | +index += 3; |
| 128 | +continue; |
| 129 | +} |
| 130 | +return input.slice(index + 1).trim().length === 0 ? output : null; |
| 131 | +} |
| 132 | +return null; |
| 133 | +}; |
| 134 | +const unwrapSnapshotEvalCommand = (command: string) => { |
| 135 | +const evalIndex = command.lastIndexOf("\neval "); |
| 136 | +const evalCommand = |
| 137 | +evalIndex === -1 |
| 138 | + ? command.trimStart().startsWith("eval ") |
| 139 | + ? command.trimStart().slice("eval ".length) |
| 140 | + : null |
| 141 | + : command.slice(evalIndex + "\neval ".length); |
| 142 | +return evalCommand ? (parseShellSingleQuoted(evalCommand.trim()) ?? command) : command; |
| 143 | +}; |
114 | 144 | const splitCommands = (command: string) => { |
115 | 145 | const commands: string[] = []; |
116 | 146 | for (const part of command.split(";")) { |
@@ -147,7 +177,7 @@ vi.mock("../process/supervisor/index.js", () => {
|
147 | 177 | |
148 | 178 | const commandOutput = (command: string, env?: NodeJS.ProcessEnv) => { |
149 | 179 | const shellEnv = { ...env }; |
150 | | -return splitCommands(command) |
| 180 | +return splitCommands(unwrapSnapshotEvalCommand(command)) |
151 | 181 | .map((segment) => { |
152 | 182 | applySegmentShellEffects(segment, shellEnv); |
153 | 183 | return stdoutForSegment(segment, shellEnv); |
@@ -160,7 +190,9 @@ vi.mock("../process/supervisor/index.js", () => {
|
160 | 190 | spawn: async (input: SpawnInput) => { |
161 | 191 | const command = extractCommand(input); |
162 | 192 | const output = commandOutput(command, input.env); |
163 | | -const exitCode = splitCommands(command).includes("exit 1") ? 1 : 0; |
| 193 | +const exitCode = splitCommands(unwrapSnapshotEvalCommand(command)).includes("exit 1") |
| 194 | + ? 1 |
| 195 | + : 0; |
164 | 196 | const stagedOutput = command.includes("after") |
165 | 197 | ? output.replace(/after[^\n]*\n?/gu, "") |
166 | 198 | : output; |
|