Repository navigation
[Feat] Tell the model which shell syntax execute_command uses (cmd.exe / PowerShell) #2115
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
cc9bb5c
61cf615
4f0b824
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,42 @@ | ||
| import { describeShellDialect } from "../shellDialect" | ||
|
|
||
| describe("describeShellDialect", () => { | ||
| const cmdSyntax = ["`&`", "`&&`", "`%VAR%`", "`set X=Y`", "`%ERRORLEVEL%`", "`!ERRORLEVEL!`"] | ||
| const powershellSyntax = ["`;`", "`$env:VAR`", "`$?`", "`$LASTEXITCODE`"] | ||
|
|
||
| it.each([ | ||
| { shell: "C:\\Windows\\System32\\cmd.exe", expected: "cmd.exe", syntax: cmdSyntax }, | ||
| { shell: "C:\\Windows\\System32\\CMD.EXE", expected: "cmd.exe", syntax: cmdSyntax }, | ||
| { shell: "cmd", expected: "cmd.exe", syntax: cmdSyntax }, | ||
| { shell: "C:\\Program Files\\PowerShell\\7\\pwsh.exe", expected: "PowerShell", syntax: powershellSyntax }, | ||
| { | ||
| shell: "C:\\Windows\\System32\\WindowsPowerShell\\v1.0\\powershell.exe", | ||
| expected: "PowerShell", | ||
| syntax: powershellSyntax, | ||
| }, | ||
| { shell: "powershell", expected: "PowerShell", syntax: powershellSyntax }, | ||
| { shell: "pwsh", expected: "PowerShell", syntax: powershellSyntax }, | ||
| ])("names the dialect and its syntax for $shell", ({ shell, expected, syntax }) => { | ||
|
coderabbitai[bot] marked this conversation as resolved.
|
||
| const description = describeShellDialect(shell) | ||
|
|
||
| expect(description).toContain(expected) | ||
| for (const token of syntax) { | ||
| expect(description).toContain(token) | ||
| } | ||
| }) | ||
|
|
||
| it("tells PowerShell users that a failed cmdlet does not change $LASTEXITCODE", () => { | ||
| expect(describeShellDialect("pwsh.exe")).toContain("does not change when a cmdlet fails") | ||
| }) | ||
|
|
||
| it("warns that ';' does not chain commands in cmd.exe", () => { | ||
| expect(describeShellDialect("C:\\Windows\\System32\\cmd.exe")).toContain("`;` is not a separator") | ||
| }) | ||
|
|
||
| it.each(["/bin/bash", "/bin/zsh", "C:\\Program Files\\Git\\bin\\bash.exe", "C:\\Windows\\System32\\wsl.exe"])( | ||
| "adds nothing for POSIX shell %s", | ||
| (shell) => { | ||
| expect(describeShellDialect(shell)).toBeUndefined() | ||
| }, | ||
| ) | ||
| }) | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,33 @@ | ||
| /** | ||
| * Describes the command syntax of Windows-native shells for the system prompt. | ||
| * | ||
| * Rules and habits written for bash silently do the wrong thing under these shells | ||
| * (e.g. `;` is not a command separator in cmd.exe), so the model is told which | ||
| * dialect it is writing for. Returns undefined for POSIX shells, where the shell | ||
| * path already names the dialect. | ||
| */ | ||
| export function describeShellDialect(shellPath: string): string | undefined { | ||
| // path.basename follows the host platform; split on both separators so Windows paths work anywhere. | ||
| const name = (shellPath.split(/[\\/]/).pop() ?? "").toLowerCase() | ||
|
Check warning on line 11 in src/utils/shellDialect.ts
|
||
|
|
||
| if (name === "cmd.exe" || name === "cmd") { | ||
| return ( | ||
| "Commands run through Windows cmd.exe, not bash. Use cmd syntax: `&` or `&&` to chain commands " + | ||
| "(`;` is not a separator), `%VAR%` for variables, `set X=Y`, and `%ERRORLEVEL%` for exit codes " + | ||
| "(`%ERRORLEVEL%` expands before a chained line runs, so use `&&` or `||` for same-line success checks; " + | ||
|
Check warning on line 17 in src/utils/shellDialect.ts
|
||
| "enable delayed expansion and use `!ERRORLEVEL!` when the numeric result is needed after a command), " + | ||
| "and `dir`, `type`, `findstr`. POSIX tools may be missing or shadowed by other binaries on PATH." | ||
|
Check warning on line 19 in src/utils/shellDialect.ts
|
||
| ) | ||
| } | ||
|
|
||
| if (name === "powershell.exe" || name === "pwsh.exe" || name === "powershell" || name === "pwsh") { | ||
| return ( | ||
| "Commands run through PowerShell, not bash. Use PowerShell syntax: `;` to chain commands, " + | ||
| "`$env:VAR` for environment variables, `$?` for whether the last command succeeded " + | ||
| "(`$LASTEXITCODE` only holds the exit code of native programs and does not change when a cmdlet fails), " + | ||
| "and cmdlets such as `Get-ChildItem` and `Select-String`." | ||
|
Check warning on line 28 in src/utils/shellDialect.ts
|
||
| ) | ||
| } | ||
|
|
||
| return undefined | ||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Script executed:
Repository: Zoo-Code-Org/Zoo-Code
Length of output: 3624
Script executed:
Repository: Zoo-Code-Org/Zoo-Code
Length of output: 14201
Assert the cmd.exe behavior guidance.
The cmd.exe description includes expansion timing and same-line success guidance, but the test checks only syntax tokens. Add behavior-focused assertions for both statements.
Suggested test assertions
it("warns that ';' does not chain commands in cmd.exe", () => { expect(describeShellDialect("C:\\Windows\\System32\\cmd.exe")).toContain("`;` is not a separator") }) + it("explains cmd.exe expansion timing for same-line success checks", () => { + const description = describeShellDialect("cmd.exe") + + expect(description).toContain("`%ERRORLEVEL%` expands before a chained line runs") + expect(description).toContain("use `&&` or `||` for same-line success checks") + }) +