2bd7946001
Closes #3607. ## Root cause On Windows, `detectCommandShellType()` fell through to `detectShellType()` for two common environments and incorrectly returned `"unix"`: 1. **SHELL points at a Unix-shaped path** (e.g. Git Bash sets `SHELL=/usr/bin/bash` on a fresh Windows install). The `detectWindowsShellType(process.env.SHELL)` probe didn't recognize `bash` as a Windows shell, so the function fell through and `detectShellType()` returned `"unix"`. 2. **MSYSTEM is set but SHELL is not** (Git Bash leaves MSYSTEM permanently set system-wide even when the active shell is PowerShell). The fall-through path returned `"unix"` via the MSYSTEM check. In both cases, the hook then prepended `export KEY=val;` to git commands, which PowerShell rejects with: `export : 无法将"export"项识别为 cmdlet...` OpenCode on Windows runs the bash tool through a Windows shell (PowerShell by default, cmd as the user-overridable fallback), regardless of MSYSTEM or a Unix-shaped SHELL set by Git Bash — so the env prefix must use Windows-compatible syntax. ## Fix `detectCommandShellType()` now short-circuits on `process.platform === "win32"`: - If `SHELL` points at a recognized Windows shell (`cmd.exe`, `powershell.exe`, `pwsh.exe`), return that. - If `SHELL` and `MSYSTEM` are both unset, fall back to `ComSpec` then to cmd. - Otherwise, default to PowerShell — matching what OpenCode actually spawns. `detectShellType()` is unchanged; other callers (including non-Windows platforms) are unaffected. ## Test changes Three pre-existing tests encoded the buggy behavior as expected behavior and have been updated to assert the new PowerShell syntax with a `(#3607)` marker and a comment explaining why a Unix-shaped SHELL on win32 must still resolve to PowerShell. WSL is not affected because in WSL `process.platform === "linux"`, not `"win32"`. - `src/hooks/non-interactive-env/`: 24 tests pass / 0 fail - `bunx tsc --noEmit`: clean ## Note on issue thread The sisyphus-bot triage comment on #3607 framed this as a policy choice between (A) forcing Windows env-prefix syntax and (B) resolving against the OpenCode-configured shell. This PR implements option (A) as the minimal surgical fix; option (B) remains a follow-up. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
546 lines
20 KiB
TypeScript
546 lines
20 KiB
TypeScript
import { describe, test, expect, beforeEach, afterEach } from "bun:test"
|
|
import { createNonInteractiveEnvHook, NON_INTERACTIVE_ENV } from "./index"
|
|
|
|
describe("non-interactive-env hook", () => {
|
|
const mockCtx = {} as Parameters<typeof createNonInteractiveEnvHook>[0]
|
|
|
|
let originalPlatform: NodeJS.Platform
|
|
let originalEnv: Record<string, string | undefined>
|
|
|
|
beforeEach(() => {
|
|
originalPlatform = process.platform
|
|
originalEnv = {
|
|
SHELL: process.env.SHELL,
|
|
PSModulePath: process.env.PSModulePath,
|
|
MSYSTEM: process.env.MSYSTEM,
|
|
ComSpec: process.env.ComSpec,
|
|
CI: process.env.CI,
|
|
OPENCODE_NON_INTERACTIVE: process.env.OPENCODE_NON_INTERACTIVE,
|
|
}
|
|
// given clean Unix-like environment for all tests
|
|
// This prevents CI environments (which may have PSModulePath set) from
|
|
// triggering PowerShell detection in tests that expect Unix behavior
|
|
delete process.env.PSModulePath
|
|
process.env.SHELL = "/bin/bash"
|
|
process.env.OPENCODE_NON_INTERACTIVE = "true"
|
|
})
|
|
|
|
afterEach(() => {
|
|
Object.defineProperty(process, "platform", { value: originalPlatform })
|
|
for (const [key, value] of Object.entries(originalEnv)) {
|
|
if (value !== undefined) {
|
|
process.env[key] = value
|
|
} else {
|
|
delete process.env[key]
|
|
}
|
|
}
|
|
})
|
|
|
|
describe("git command modification", () => {
|
|
test("#given git command #when hook executes #then prepends export statement", async () => {
|
|
const hook = createNonInteractiveEnvHook(mockCtx)
|
|
const output: { args: Record<string, unknown>; message?: string } = {
|
|
args: { command: "git commit -m 'test'" },
|
|
}
|
|
|
|
await hook["tool.execute.before"](
|
|
{ tool: "bash", sessionID: "test", callID: "1" },
|
|
output
|
|
)
|
|
|
|
const cmd = output.args.command as string
|
|
expect(cmd).toStartWith("export ")
|
|
expect(cmd).toContain("GIT_EDITOR=:")
|
|
expect(cmd).toContain("EDITOR=:")
|
|
expect(cmd).toContain("PAGER=cat")
|
|
expect(cmd).toContain("; git commit -m 'test'")
|
|
})
|
|
|
|
test("#given chained git commands #when hook executes #then export applies to all", async () => {
|
|
const hook = createNonInteractiveEnvHook(mockCtx)
|
|
const output: { args: Record<string, unknown>; message?: string } = {
|
|
args: { command: "git add file && git rebase --continue" },
|
|
}
|
|
|
|
await hook["tool.execute.before"](
|
|
{ tool: "bash", sessionID: "test", callID: "1" },
|
|
output
|
|
)
|
|
|
|
const cmd = output.args.command as string
|
|
expect(cmd).toStartWith("export ")
|
|
expect(cmd).toContain("; git add file && git rebase --continue")
|
|
})
|
|
|
|
test("#given non-git bash command #when hook executes #then command unchanged", async () => {
|
|
const hook = createNonInteractiveEnvHook(mockCtx)
|
|
const output: { args: Record<string, unknown>; message?: string } = {
|
|
args: { command: "ls -la" },
|
|
}
|
|
|
|
await hook["tool.execute.before"](
|
|
{ tool: "bash", sessionID: "test", callID: "1" },
|
|
output
|
|
)
|
|
|
|
expect(output.args.command).toBe("ls -la")
|
|
})
|
|
|
|
test("#given non-bash tool #when hook executes #then command unchanged", async () => {
|
|
const hook = createNonInteractiveEnvHook(mockCtx)
|
|
const output: { args: Record<string, unknown>; message?: string } = {
|
|
args: { command: "git status" },
|
|
}
|
|
|
|
await hook["tool.execute.before"](
|
|
{ tool: "Read", sessionID: "test", callID: "1" },
|
|
output
|
|
)
|
|
|
|
expect(output.args.command).toBe("git status")
|
|
})
|
|
|
|
test("#given empty command #when hook executes #then no error", async () => {
|
|
const hook = createNonInteractiveEnvHook(mockCtx)
|
|
const output: { args: Record<string, unknown>; message?: string } = {
|
|
args: {},
|
|
}
|
|
|
|
await hook["tool.execute.before"](
|
|
{ tool: "bash", sessionID: "test", callID: "1" },
|
|
output
|
|
)
|
|
|
|
expect(output.args.command).toBeUndefined()
|
|
})
|
|
|
|
test("#given git command already has prefix #when hook executes again #then does not duplicate prefix", async () => {
|
|
const hook = createNonInteractiveEnvHook(mockCtx)
|
|
|
|
// First call: transforms the command
|
|
const output1: { args: Record<string, unknown>; message?: string } = {
|
|
args: { command: "git commit -m 'test'" },
|
|
}
|
|
await hook["tool.execute.before"](
|
|
{ tool: "bash", sessionID: "test", callID: "1" },
|
|
output1
|
|
)
|
|
|
|
const firstResult = output1.args.command as string
|
|
expect(firstResult).toStartWith("export ")
|
|
|
|
// Second call: takes the already-prefixed command
|
|
const output2: { args: Record<string, unknown>; message?: string } = {
|
|
args: { command: firstResult },
|
|
}
|
|
await hook["tool.execute.before"](
|
|
{ tool: "bash", sessionID: "test", callID: "2" },
|
|
output2
|
|
)
|
|
|
|
// Should be exactly the same (no double prefix)
|
|
expect(output2.args.command).toBe(firstResult)
|
|
})
|
|
})
|
|
|
|
describe("shell escaping", () => {
|
|
test("#given git command #when building prefix #then VISUAL properly escaped", async () => {
|
|
const hook = createNonInteractiveEnvHook(mockCtx)
|
|
const output: { args: Record<string, unknown>; message?: string } = {
|
|
args: { command: "git status" },
|
|
}
|
|
|
|
await hook["tool.execute.before"](
|
|
{ tool: "bash", sessionID: "test", callID: "1" },
|
|
output
|
|
)
|
|
|
|
const cmd = output.args.command as string
|
|
expect(cmd).toContain("VISUAL=''")
|
|
})
|
|
|
|
test("#given git command #when building prefix #then all NON_INTERACTIVE_ENV vars included", async () => {
|
|
const hook = createNonInteractiveEnvHook(mockCtx)
|
|
const output: { args: Record<string, unknown>; message?: string } = {
|
|
args: { command: "git log" },
|
|
}
|
|
|
|
await hook["tool.execute.before"](
|
|
{ tool: "bash", sessionID: "test", callID: "1" },
|
|
output
|
|
)
|
|
|
|
const cmd = output.args.command as string
|
|
for (const key of Object.keys(NON_INTERACTIVE_ENV)) {
|
|
expect(cmd).toContain(`${key}=`)
|
|
}
|
|
})
|
|
})
|
|
|
|
describe("banned command detection", () => {
|
|
test("#given vim command #when hook executes #then warning message set", async () => {
|
|
const hook = createNonInteractiveEnvHook(mockCtx)
|
|
const output: { args: Record<string, unknown>; message?: string } = {
|
|
args: { command: "vim file.txt" },
|
|
}
|
|
|
|
await hook["tool.execute.before"](
|
|
{ tool: "bash", sessionID: "test", callID: "1" },
|
|
output
|
|
)
|
|
|
|
expect(output.message).toContain("vim")
|
|
expect(output.message).toContain("interactive")
|
|
})
|
|
|
|
test("#given safe command #when hook executes #then no warning", async () => {
|
|
const hook = createNonInteractiveEnvHook(mockCtx)
|
|
const output: { args: Record<string, unknown>; message?: string } = {
|
|
args: { command: "ls -la" },
|
|
}
|
|
|
|
await hook["tool.execute.before"](
|
|
{ tool: "bash", sessionID: "test", callID: "1" },
|
|
output
|
|
)
|
|
|
|
expect(output.message).toBeUndefined()
|
|
})
|
|
})
|
|
|
|
describe("platform-aware shell syntax", () => {
|
|
|
|
test("#given macOS platform #when git command executes #then uses unix export syntax", async () => {
|
|
delete process.env.PSModulePath
|
|
process.env.SHELL = "/bin/zsh"
|
|
Object.defineProperty(process, "platform", { value: "darwin" })
|
|
|
|
const hook = createNonInteractiveEnvHook(mockCtx)
|
|
const output: { args: Record<string, unknown>; message?: string } = {
|
|
args: { command: "git status" },
|
|
}
|
|
|
|
await hook["tool.execute.before"](
|
|
{ tool: "bash", sessionID: "test", callID: "1" },
|
|
output
|
|
)
|
|
|
|
const cmd = output.args.command as string
|
|
expect(cmd).toStartWith("export ")
|
|
expect(cmd).toContain(";")
|
|
expect(cmd).not.toContain("$env:")
|
|
expect(cmd).not.toContain("set ")
|
|
})
|
|
|
|
test("#given Linux platform #when git command executes #then uses unix export syntax", async () => {
|
|
delete process.env.PSModulePath
|
|
process.env.SHELL = "/bin/bash"
|
|
Object.defineProperty(process, "platform", { value: "linux" })
|
|
|
|
const hook = createNonInteractiveEnvHook(mockCtx)
|
|
const output: { args: Record<string, unknown>; message?: string } = {
|
|
args: { command: "git commit -m 'test'" },
|
|
}
|
|
|
|
await hook["tool.execute.before"](
|
|
{ tool: "bash", sessionID: "test", callID: "1" },
|
|
output
|
|
)
|
|
|
|
const cmd = output.args.command as string
|
|
expect(cmd).toStartWith("export ")
|
|
expect(cmd).toContain("; git commit")
|
|
})
|
|
|
|
test("#given Windows cmd environment with PSModulePath #when bash tool git command executes #then uses cmd syntax", async () => {
|
|
delete process.env.SHELL
|
|
delete process.env.MSYSTEM
|
|
process.env.PSModulePath = "C:\\Program Files\\PowerShell\\Modules"
|
|
Object.defineProperty(process, "platform", { value: "win32" })
|
|
|
|
const hook = createNonInteractiveEnvHook(mockCtx)
|
|
const output: { args: Record<string, unknown>; message?: string } = {
|
|
args: { command: "git status" },
|
|
}
|
|
|
|
await hook["tool.execute.before"](
|
|
{ tool: "bash", sessionID: "test", callID: "1" },
|
|
output
|
|
)
|
|
|
|
const cmd = output.args.command as string
|
|
expect(cmd).toStartWith("set ")
|
|
expect(cmd).toContain(" && git status")
|
|
expect(cmd).toContain('GIT_EDITOR=":"')
|
|
expect(cmd).not.toContain("$env:")
|
|
expect(cmd).not.toContain("export ")
|
|
})
|
|
|
|
test("#given Windows SHELL=cmd.exe #when bash tool git command executes #then uses cmd syntax", async () => {
|
|
process.env.SHELL = "C:\\Windows\\System32\\cmd.exe"
|
|
delete process.env.MSYSTEM
|
|
process.env.PSModulePath = "C:\\Program Files\\PowerShell\\Modules"
|
|
Object.defineProperty(process, "platform", { value: "win32" })
|
|
|
|
const hook = createNonInteractiveEnvHook(mockCtx)
|
|
const output: { args: Record<string, unknown>; message?: string } = {
|
|
args: { command: "git status" },
|
|
}
|
|
|
|
await hook["tool.execute.before"](
|
|
{ tool: "bash", sessionID: "test", callID: "1" },
|
|
output
|
|
)
|
|
|
|
const cmd = output.args.command as string
|
|
expect(cmd).toStartWith("set ")
|
|
expect(cmd).toContain(" && git status")
|
|
expect(cmd).not.toContain("$env:")
|
|
expect(cmd).not.toContain("export ")
|
|
})
|
|
|
|
test("#given Windows ComSpec=pwsh.exe without SHELL #when bash tool git command executes #then uses powershell syntax", async () => {
|
|
delete process.env.SHELL
|
|
delete process.env.MSYSTEM
|
|
process.env.ComSpec = "C:\\Program Files\\PowerShell\\7\\pwsh.exe"
|
|
process.env.PSModulePath = "C:\\Program Files\\PowerShell\\Modules"
|
|
Object.defineProperty(process, "platform", { value: "win32" })
|
|
|
|
const hook = createNonInteractiveEnvHook(mockCtx)
|
|
const output: { args: Record<string, unknown>; message?: string } = {
|
|
args: { command: "git status" },
|
|
}
|
|
|
|
await hook["tool.execute.before"](
|
|
{ tool: "bash", sessionID: "test", callID: "1" },
|
|
output
|
|
)
|
|
|
|
const cmd = output.args.command as string
|
|
expect(cmd).toStartWith("$env:")
|
|
expect(cmd).toContain("; git status")
|
|
expect(cmd).not.toContain("set ")
|
|
expect(cmd).not.toContain("export ")
|
|
})
|
|
|
|
test("#given Windows SHELL=pwsh.exe #when bash tool git command executes #then uses powershell syntax", async () => {
|
|
process.env.SHELL = "C:\\Program Files\\PowerShell\\7\\pwsh.exe"
|
|
delete process.env.MSYSTEM
|
|
process.env.PSModulePath = "C:\\Program Files\\PowerShell\\Modules"
|
|
Object.defineProperty(process, "platform", { value: "win32" })
|
|
|
|
const hook = createNonInteractiveEnvHook(mockCtx)
|
|
const output: { args: Record<string, unknown>; message?: string } = {
|
|
args: { command: "git status" },
|
|
}
|
|
|
|
await hook["tool.execute.before"](
|
|
{ tool: "bash", sessionID: "test", callID: "1" },
|
|
output
|
|
)
|
|
|
|
const cmd = output.args.command as string
|
|
expect(cmd).toStartWith("$env:")
|
|
expect(cmd).toContain("; git status")
|
|
expect(cmd).not.toContain("set ")
|
|
expect(cmd).not.toContain("export ")
|
|
})
|
|
|
|
test("#given Windows without SHELL env #when bash tool git command executes #then uses cmd syntax", async () => {
|
|
delete process.env.PSModulePath
|
|
delete process.env.SHELL
|
|
delete process.env.MSYSTEM
|
|
Object.defineProperty(process, "platform", { value: "win32" })
|
|
|
|
const hook = createNonInteractiveEnvHook(mockCtx)
|
|
const output: { args: Record<string, unknown>; message?: string } = {
|
|
args: { command: "git log" },
|
|
}
|
|
|
|
await hook["tool.execute.before"](
|
|
{ tool: "bash", sessionID: "test", callID: "1" },
|
|
output
|
|
)
|
|
|
|
const cmd = output.args.command as string
|
|
expect(cmd).toStartWith("set ")
|
|
expect(cmd).toContain(" && git log")
|
|
expect(cmd).toContain('GIT_EDITOR=":"')
|
|
expect(cmd).not.toContain("$env:")
|
|
expect(cmd).not.toContain("export ")
|
|
})
|
|
|
|
test("#given Windows Git Bash SHELL=/usr/bin/bash #when git command executes #then uses powershell syntax (#3607)", async () => {
|
|
// Regression for #3607: OpenCode on Windows runs the bash tool through
|
|
// PowerShell by default, regardless of a Unix-shaped SHELL set by Git
|
|
// Bash. The export prefix is invalid PowerShell, so we must use
|
|
// PowerShell syntax even when SHELL points at /usr/bin/bash.
|
|
delete process.env.PSModulePath
|
|
process.env.SHELL = "/usr/bin/bash"
|
|
Object.defineProperty(process, "platform", { value: "win32" })
|
|
|
|
const hook = createNonInteractiveEnvHook(mockCtx)
|
|
const output: { args: Record<string, unknown>; message?: string } = {
|
|
args: { command: "git status" },
|
|
}
|
|
|
|
await hook["tool.execute.before"](
|
|
{ tool: "bash", sessionID: "test", callID: "1" },
|
|
output
|
|
)
|
|
|
|
const cmd = output.args.command as string
|
|
expect(cmd).toStartWith("$env:")
|
|
expect(cmd).toContain("; git status")
|
|
expect(cmd).not.toContain("export ")
|
|
})
|
|
|
|
test("#given Windows MSYSTEM=MINGW64 without SHELL #when git command executes #then uses powershell syntax (#3607)", async () => {
|
|
// Regression for #3607: MSYSTEM is permanently set on systems with Git
|
|
// Bash installed, but OpenCode on Windows still spawns PowerShell.
|
|
// MSYSTEM alone must not select Unix env-prefix syntax.
|
|
delete process.env.SHELL
|
|
process.env.MSYSTEM = "MINGW64"
|
|
process.env.PSModulePath = "C:\\Program Files\\PowerShell\\Modules"
|
|
Object.defineProperty(process, "platform", { value: "win32" })
|
|
|
|
const hook = createNonInteractiveEnvHook(mockCtx)
|
|
const output: { args: Record<string, unknown>; message?: string } = {
|
|
args: { command: "git status" },
|
|
}
|
|
|
|
await hook["tool.execute.before"](
|
|
{ tool: "bash", sessionID: "test", callID: "1" },
|
|
output
|
|
)
|
|
|
|
const cmd = output.args.command as string
|
|
expect(cmd).toStartWith("$env:")
|
|
expect(cmd).toContain("; git status")
|
|
expect(cmd).not.toContain("export ")
|
|
})
|
|
|
|
test("#given Windows platform #when chained git commands via bash tool #then uses cmd syntax", async () => {
|
|
delete process.env.PSModulePath
|
|
delete process.env.SHELL
|
|
delete process.env.MSYSTEM
|
|
Object.defineProperty(process, "platform", { value: "win32" })
|
|
|
|
const hook = createNonInteractiveEnvHook(mockCtx)
|
|
const output: { args: Record<string, unknown>; message?: string } = {
|
|
args: { command: "git add file && git commit -m 'test'" },
|
|
}
|
|
|
|
await hook["tool.execute.before"](
|
|
{ tool: "bash", sessionID: "test", callID: "1" },
|
|
output
|
|
)
|
|
|
|
const cmd = output.args.command as string
|
|
expect(cmd).toStartWith("set ")
|
|
expect(cmd).toContain(" && git add file && git commit")
|
|
expect(cmd).toContain('GIT_EDITOR=":"')
|
|
expect(cmd).not.toContain("export ")
|
|
expect(cmd).not.toContain("$env:")
|
|
})
|
|
|
|
test("#given SHELL=/bin/bash on win32 #when git command executes #then uses powershell syntax (#3607)", async () => {
|
|
// Regression for #3607: a Unix-shaped SHELL value (Git Bash sets
|
|
// SHELL=/bin/bash or /usr/bin/bash) does NOT mean OpenCode will run
|
|
// the bash tool in a Unix shell on Windows — OpenCode spawns
|
|
// PowerShell, so the env prefix must use PowerShell syntax.
|
|
// WSL is not affected by this assertion because in WSL,
|
|
// process.platform === "linux", not "win32".
|
|
delete process.env.PSModulePath
|
|
process.env.SHELL = "/bin/bash"
|
|
Object.defineProperty(process, "platform", { value: "win32" })
|
|
|
|
const hook = createNonInteractiveEnvHook(mockCtx)
|
|
const output: { args: Record<string, unknown>; message?: string } = {
|
|
args: { command: "git status" },
|
|
}
|
|
|
|
await hook["tool.execute.before"](
|
|
{ tool: "bash", sessionID: "test", callID: "1" },
|
|
output
|
|
)
|
|
|
|
const cmd = output.args.command as string
|
|
expect(cmd).toStartWith("$env:")
|
|
expect(cmd).toContain("; git status")
|
|
expect(cmd).not.toContain("export ")
|
|
})
|
|
|
|
test("#given PSModulePath set on non-Windows #when git command executes #then uses powershell syntax", async () => {
|
|
// PowerShell detection via PSModulePath should work regardless of platform
|
|
delete process.env.SHELL
|
|
delete process.env.MSYSTEM
|
|
process.env.PSModulePath = "C:\\Program Files\\PowerShell\\Modules"
|
|
Object.defineProperty(process, "platform", { value: "linux" })
|
|
|
|
const hook = createNonInteractiveEnvHook(mockCtx)
|
|
const output: { args: Record<string, unknown>; message?: string } = {
|
|
args: { command: "git log" },
|
|
}
|
|
|
|
await hook["tool.execute.before"](
|
|
{ tool: "bash", sessionID: "test", callID: "1" },
|
|
output
|
|
)
|
|
|
|
const cmd = output.args.command as string
|
|
expect(cmd).toStartWith("$env:")
|
|
expect(cmd).toContain("; git log")
|
|
expect(cmd).not.toContain("export ")
|
|
})
|
|
|
|
test("#given no SHELL and no PSModulePath on win32 #when git command executes #then uses cmd syntax", async () => {
|
|
// Platform fallback: win32 without env hints should use cmd
|
|
delete process.env.SHELL
|
|
delete process.env.PSModulePath
|
|
delete process.env.MSYSTEM
|
|
Object.defineProperty(process, "platform", { value: "win32" })
|
|
|
|
const hook = createNonInteractiveEnvHook(mockCtx)
|
|
const output: { args: Record<string, unknown>; message?: string } = {
|
|
args: { command: "git status" },
|
|
}
|
|
|
|
await hook["tool.execute.before"](
|
|
{ tool: "bash", sessionID: "test", callID: "1" },
|
|
output
|
|
)
|
|
|
|
const cmd = output.args.command as string
|
|
expect(cmd).toStartWith("set ")
|
|
expect(cmd).toContain(" && git status")
|
|
expect(cmd).toContain('GIT_EDITOR=":"')
|
|
expect(cmd).not.toContain("export ")
|
|
expect(cmd).not.toContain("$env:")
|
|
})
|
|
|
|
test("#given no SHELL and no PSModulePath on linux #when git command executes #then uses unix syntax", async () => {
|
|
// Platform fallback: non-win32 without env hints should use unix
|
|
delete process.env.SHELL
|
|
delete process.env.PSModulePath
|
|
Object.defineProperty(process, "platform", { value: "linux" })
|
|
|
|
const hook = createNonInteractiveEnvHook(mockCtx)
|
|
const output: { args: Record<string, unknown>; message?: string } = {
|
|
args: { command: "git status" },
|
|
}
|
|
|
|
await hook["tool.execute.before"](
|
|
{ tool: "bash", sessionID: "test", callID: "1" },
|
|
output
|
|
)
|
|
|
|
const cmd = output.args.command as string
|
|
expect(cmd).toStartWith("export ")
|
|
expect(cmd).toContain("; git status")
|
|
expect(cmd).not.toContain("$env:")
|
|
expect(cmd).not.toContain("set ")
|
|
})
|
|
})
|
|
})
|