mirror of
https://github.com/anomalyco/opencode.git
synced 2026-05-11 21:41:36 +00:00
fix(shell): preserve powershell exit codes
Use a multiline PowerShell trailer so native Windows commands keep their actual exit status without masking cmdlet failures, and add focused regression coverage. Remove the accidentally committed .opencode package-lock to keep generated state out of the branch.
This commit is contained in:
parent
6ad6358eb1
commit
23e77fd9bc
2 changed files with 49 additions and 4 deletions
|
|
@ -11,9 +11,11 @@ export function preview(text: string) {
|
|||
}
|
||||
|
||||
export namespace ShellRunner {
|
||||
function wrap(name: string, command: string) {
|
||||
if (name !== "powershell" && name !== "pwsh") return command
|
||||
return `${command}; if ($null -ne $LASTEXITCODE) { exit $LASTEXITCODE }; if ($?) { exit 0 }; exit 1`
|
||||
function preserveExitCode(command: string) {
|
||||
return `${command}
|
||||
if ($null -ne $LASTEXITCODE) { exit $LASTEXITCODE }
|
||||
if ($?) { exit 0 }
|
||||
exit 1`
|
||||
}
|
||||
|
||||
export async function shellEnv(ctx: Tool.Context, cwd: string) {
|
||||
|
|
@ -26,7 +28,7 @@ export namespace ShellRunner {
|
|||
|
||||
export function launch(shell: string, name: string, command: string, cwd: string, env: NodeJS.ProcessEnv) {
|
||||
if (process.platform === "win32" && (name === "powershell" || name === "pwsh")) {
|
||||
return spawn(shell, ["-NoLogo", "-NoProfile", "-NonInteractive", "-Command", wrap(name, command)], {
|
||||
return spawn(shell, ["-NoLogo", "-NoProfile", "-NonInteractive", "-Command", preserveExitCode(command)], {
|
||||
cwd,
|
||||
env,
|
||||
stdio: ["ignore", "pipe", "pipe"],
|
||||
|
|
|
|||
|
|
@ -115,6 +115,15 @@ const each = (name: string, fn: (item: { label: string; shell: string }) => Prom
|
|||
}
|
||||
}
|
||||
|
||||
const eachps = (name: string, fn: (item: { label: string; shell: string }) => Promise<void>) => {
|
||||
for (const item of ps) {
|
||||
test(
|
||||
`${name} [${item.label}]`,
|
||||
withShell(item, () => fn(item)),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
const capture = (requests: Array<Omit<Permission.Request, "id" | "sessionID" | "tool">>, stop?: Error) => ({
|
||||
...ctx,
|
||||
ask: async (req: Omit<Permission.Request, "id" | "sessionID" | "tool">) => {
|
||||
|
|
@ -1018,6 +1027,40 @@ describe("tool.shell runtime", () => {
|
|||
})
|
||||
})
|
||||
|
||||
eachps("preserves native exit code with trailing comment", async () => {
|
||||
await Instance.provide({
|
||||
directory: projectRoot,
|
||||
fn: async () => {
|
||||
const bash = await getTool()
|
||||
const result = await bash.execute(
|
||||
{
|
||||
command: `${js("process.exit(42)")} # keep wrapper separate`,
|
||||
description: "Trailing comment exit",
|
||||
},
|
||||
ctx,
|
||||
)
|
||||
expect(result.metadata.exit).toBe(42)
|
||||
},
|
||||
})
|
||||
})
|
||||
|
||||
eachps("returns non-zero exit for powershell cmdlet errors", async () => {
|
||||
await Instance.provide({
|
||||
directory: projectRoot,
|
||||
fn: async () => {
|
||||
const bash = await getTool()
|
||||
const result = await bash.execute(
|
||||
{
|
||||
command: "Write-Error x",
|
||||
description: "Cmdlet error exit",
|
||||
},
|
||||
ctx,
|
||||
)
|
||||
expect(result.metadata.exit).toBe(1)
|
||||
},
|
||||
})
|
||||
})
|
||||
|
||||
each("streams metadata updates progressively", async () => {
|
||||
await Instance.provide({
|
||||
directory: projectRoot,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue