Skip to content

Commit 0c19cd7

Browse files
added environment on terminal header and fixed agent behavior to detect shell
1 parent 523996b commit 0c19cd7

File tree

3 files changed

+141
-0
lines changed

3 files changed

+141
-0
lines changed

codex-cli/src/components/chat/terminal-header.tsx

+35
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ export interface TerminalHeaderProps {
1515
agent?: AgentLoop;
1616
initialImagePaths?: Array<string>;
1717
flexModeEnabled?: boolean;
18+
environment?: string;
1819
}
1920

2021
const TerminalHeader: React.FC<TerminalHeaderProps> = ({
@@ -28,7 +29,36 @@ const TerminalHeader: React.FC<TerminalHeaderProps> = ({
2829
agent,
2930
initialImagePaths,
3031
flexModeEnabled = false,
32+
environment,
3133
}) => {
34+
const envName =
35+
environment ??
36+
(() => {
37+
// check for Windows
38+
if (process.platform === "win32") {
39+
const msystem = process.env["MSYSTEM"];
40+
// Check git bash
41+
if (msystem && msystem.toLowerCase().includes("mingw")) {
42+
return "Git Bash";
43+
}
44+
45+
const keys = Object.keys(process.env).map((k) => k.toLowerCase());
46+
// Check pwsh vs powershell
47+
if (keys.includes("psedition")) {
48+
return "PowerShell Core";
49+
}
50+
// Check for PowerShell
51+
if (keys.includes("psmodulepath")) {
52+
return "PowerShell";
53+
}
54+
55+
const comspec = process.env["ComSpec"];
56+
return comspec ? path.basename(comspec) : "cmd";
57+
}
58+
59+
const shell = process.env["SHELL"];
60+
return shell ? path.basename(shell) : "sh";
61+
})();
3262
return (
3363
<>
3464
{terminalRows < 10 ? (
@@ -37,6 +67,7 @@ const TerminalHeader: React.FC<TerminalHeaderProps> = ({
3767
● Codex v{version} - {PWD} - {model} ({provider}) -{" "}
3868
<Text color={colorsByPolicy[approvalPolicy]}>{approvalPolicy}</Text>
3969
{flexModeEnabled ? " - flex-mode" : ""}
70+
{` - environment: ${envName}`}
4071
</Text>
4172
) : (
4273
<>
@@ -71,6 +102,10 @@ const TerminalHeader: React.FC<TerminalHeaderProps> = ({
71102
<Text color="blueBright"></Text> provider:{" "}
72103
<Text bold>{provider}</Text>
73104
</Text>
105+
<Text dimColor>
106+
<Text color="blueBright"></Text> environment:{" "}
107+
<Text bold>{envName}</Text>
108+
</Text>
74109
<Text dimColor>
75110
<Text color="blueBright"></Text> approval:{" "}
76111
<Text bold color={colorsByPolicy[approvalPolicy]}>

codex-cli/src/utils/agent/agent-loop.ts

+26
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import {
1818
getApiKey,
1919
getBaseUrl,
2020
} from "../config.js";
21+
import { detectShell } from "../detect-shell.js";
2122
import { log } from "../logger/log.js";
2223
import { parseToolCallArguments } from "../parsers.js";
2324
import { responsesCreateViaChatCompletions } from "../responses.js";
@@ -1459,8 +1460,33 @@ export class AgentLoop {
14591460
}
14601461
}
14611462

1463+
// Determine shell environment for command formatting guidance
1464+
const shellEnv = detectShell().environment;
1465+
const shellInstruction = /PowerShell/i.test(shellEnv)
1466+
? `On Windows PowerShell, to correctly capture the working directory, please choose the one that is most appropriate:
1467+
- Drop into CMD: "cmd /C cd"
1468+
- Or stay in PowerShell but pipe through Out-String: "Get-Location | Out-String"
1469+
- Or use Write-Output (Get-Location).Path`
1470+
: /cmd/i.test(shellEnv)
1471+
? `To determine the current working directory, run "cmd /C cd".`
1472+
: `To determine the current working directory, run "pwd".`;
1473+
14621474
const prefix = `You are operating as and within the Codex CLI, a terminal-based agentic coding assistant built by OpenAI. It wraps OpenAI models to enable natural language interaction with a local codebase. You are expected to be precise, safe, and helpful.
14631475
1476+
All commands should be formatted for: ${shellEnv}.
1477+
${shellInstruction}
1478+
1479+
When inspecting the filesystem, you MUST adhere to the following procedure:
1480+
- Always begin by printing the current working directory (cwd) with the appropriate shell command:
1481+
- For PowerShell: Get-Location | Out-String, cmd /C cd, or (Get-Location).Path, whichever is most appropriate.
1482+
- For CMD: cmd /C cd
1483+
- For *nix shells: pwd
1484+
- Then, explicitly cd into the repo root if needed, or set the working directory (workdir) in your tool calls to ensure you are operating from the repo root.
1485+
- Normalize on a single listing command to view files:
1486+
- Use ls -a on *nix
1487+
- Use dir /a /b on Windows
1488+
- Only proceed with reading or editing files after you have confirmed you are at the correct root location.
1489+
14641490
You can:
14651491
- Receive user prompts, project context, and files.
14661492
- Stream responses and emit function calls (e.g., shell commands, code edits).

codex-cli/src/utils/detect-shell.ts

+80
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
import type { ParseEntry } from "shell-quote";
2+
3+
import { spawnSync } from "child_process";
4+
import os from "os";
5+
import path from "path";
6+
import { parse } from "shell-quote";
7+
8+
export interface ShellDetection {
9+
shellOption?: boolean | string;
10+
environment: string;
11+
}
12+
13+
function requiresShell(cmd: Array<string>): boolean {
14+
if (cmd.length === 1 && cmd[0]) {
15+
const tokens = parse(cmd[0]) as Array<ParseEntry>;
16+
return tokens.some((t) => typeof t === "object" && "op" in t);
17+
}
18+
return false;
19+
}
20+
21+
export function detectShell(cmd?: Array<string>): ShellDetection {
22+
const override = process.env["CODEX_SHELL"];
23+
if (override) {
24+
return { shellOption: override, environment: path.basename(override) };
25+
}
26+
27+
// Windows
28+
if (os.platform() === "win32") {
29+
// Check git bash
30+
const msystem = process.env["MSYSTEM"];
31+
if (msystem && /mingw/i.test(msystem)) {
32+
return { shellOption: "bash.exe", environment: "Git Bash" };
33+
}
34+
// Check pwsh vs powershell
35+
const keys = Object.keys(process.env).map((k) => k.toLowerCase());
36+
if (keys.includes("psedition")) {
37+
return { shellOption: "pwsh.exe", environment: "PowerShell Core" };
38+
}
39+
if (keys.includes("psmodulepath")) {
40+
return { shellOption: "powershell.exe", environment: "PowerShell" };
41+
}
42+
// Fallback to parent process
43+
try {
44+
const out =
45+
spawnSync("tasklist", ["/fi", `PID eq ${process.ppid}`, "/nh"], {
46+
encoding: "utf8",
47+
}).stdout?.trim() || "";
48+
const exe = out.split(/\s+/)[0]?.toLowerCase();
49+
if (exe === "bash.exe") {
50+
return { shellOption: "bash.exe", environment: "Git Bash" };
51+
}
52+
if (exe === "pwsh.exe") {
53+
return { shellOption: "pwsh.exe", environment: "PowerShell Core" };
54+
}
55+
if (exe === "powershell.exe") {
56+
return { shellOption: "powershell.exe", environment: "PowerShell" };
57+
}
58+
} catch {
59+
console.warn("Failed to detect parent process shell");
60+
}
61+
// 4) final fallback
62+
const com = process.env["ComSpec"];
63+
return {
64+
shellOption: com || true,
65+
environment: com ? path.basename(com) : "cmd",
66+
};
67+
}
68+
69+
// UNIX‑like
70+
let shellOption: boolean | string | undefined;
71+
// Check if the command requires a shell
72+
if (cmd && requiresShell(cmd)) {
73+
shellOption = process.env["SHELL"] || true;
74+
}
75+
const shellEnv = process.env["SHELL"] || "";
76+
const base = path.basename(shellEnv);
77+
const envName =
78+
base === "bash" ? "Bash" : base === "zsh" ? "Zsh" : base || "sh";
79+
return { shellOption, environment: envName };
80+
}

0 commit comments

Comments
 (0)