Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
157 commits
Select commit Hold shift + click to select a range
84a4102
feat: attemp to inject shell advice in bash tool description, needs t…
ariane-emory Nov 28, 2025
cac1c5e
fix: safer windows corner case
ariane-emory Nov 28, 2025
e444456
Merge remote-tracking branch 'upstream/dev' into feat/shell-advice-ta…
ariane-emory Nov 29, 2025
2d2adce
Merge remote-tracking branch 'upstream/dev' into feat/shell-advice-ta…
ariane-emory Nov 29, 2025
daa6d17
Merge remote-tracking branch 'upstream/dev' into feat/shell-advice-ta…
ariane-emory Nov 29, 2025
21a3816
...
ariane-emory Nov 30, 2025
a7f6cc9
fix: revise Bash tool test to account for the changes.
ariane-emory Nov 30, 2025
083a2ce
Merge remote-tracking branch 'upstream/dev' into feat/shell-advice
ariane-emory Nov 30, 2025
7511cf2
Merge remote-tracking branch 'upstream/dev' into feat/shell-advice
ariane-emory Nov 30, 2025
ac56976
Merge remote-tracking branch 'upstream/dev' into feat/shell-advice
ariane-emory Nov 30, 2025
ebcedac
Merge remote-tracking branch 'upstream/dev' into feat/shell-advice
ariane-emory Dec 1, 2025
92c5e69
chore: format code
actions-user Dec 1, 2025
4c93e68
Update Nix flake.lock and hashes
actions-user Dec 1, 2025
f1de95e
Merge remote-tracking branch 'upstream/dev' into feat/shell-advice
ariane-emory Dec 1, 2025
5630a29
Merge upstream/dev into feat/shell-advice
ariane-emory Dec 1, 2025
880db56
Merge remote-tracking branch 'upstream/dev' into feat/shell-advice
ariane-emory Dec 2, 2025
281fa16
Merge remote-tracking branch 'upstream/dev' into feat/shell-advice
ariane-emory Dec 2, 2025
23a96fb
Merge remote-tracking branch 'upstream/dev' into feat/shell-advice
ariane-emory Dec 2, 2025
6e56b0d
Merge remote-tracking branch 'upstream/dev' into feat/shell-advice
ariane-emory Dec 2, 2025
33645e9
Merge remote-tracking branch 'upstream/dev' into feat/shell-advice
ariane-emory Dec 3, 2025
9920506
Merge remote-tracking branch 'upstream/dev' into feat/shell-advice
ariane-emory Dec 3, 2025
053ae51
Merge remote-tracking branch 'upstream/dev' into feat/shell-advice
ariane-emory Dec 3, 2025
04948f8
Merge remote-tracking branch 'upstream/dev' into feat/shell-advice
ariane-emory Dec 3, 2025
e1112ce
Merge remote-tracking branch 'upstream/dev' into feat/shell-advice
ariane-emory Dec 4, 2025
fa3132a
Merge dev branch preserving shell-specific Bash tool description feature
ariane-emory Dec 12, 2025
69b28ac
Merge branch 'dev' into wip/feat/shell-advice
ariane-emory Dec 12, 2025
91fc9cd
Merge dev branch into repair/feat/shell-advice
ariane-emory Dec 13, 2025
6753987
feat: enable fish and nu shell support in Bash tool
ariane-emory Dec 13, 2025
0ece1f7
tidy: remove TODO.
ariane-emory Dec 13, 2025
586ea9d
Merge branch 'dev' into feat/shell-advice
ariane-emory Dec 21, 2025
ddb8e84
Merge branch 'dev' into feat/shell-advice
ariane-emory Dec 22, 2025
cfd3b58
Merge branch 'dev' into feat/shell-advice
ariane-emory Dec 23, 2025
c3f0fbe
Merge branch 'dev' into feat/shell-advice
ariane-emory Dec 23, 2025
83ffc95
Merge branch 'feat/shell-advice' of github.com:ariane-emory/opencode …
ariane-emory Dec 23, 2025
2980f51
Merge branch 'dev' into feat/shell-advice
ariane-emory Dec 23, 2025
97fbf36
Merge branch 'dev' into feat/shell-advice
ariane-emory Dec 23, 2025
21dac83
Merge branch 'dev' into feat/shell-advice
ariane-emory Dec 23, 2025
3425ccf
Merge remote-tracking branch 'origin/dev' into feat/shell-advice
ariane-emory Dec 23, 2025
58ea13f
Merge branch 'dev' into feat/shell-advice
ariane-emory Dec 24, 2025
e982979
Merge branch 'dev' into feat/shell-advice
ariane-emory Dec 24, 2025
0ebb0d2
Merge branch 'dev' into feat/shell-advice
ariane-emory Dec 24, 2025
7f4f801
Merge branch 'dev' into feat/shell-advice
ariane-emory Dec 24, 2025
3e17386
Merge branch 'dev' into feat/shell-advice
ariane-emory Dec 25, 2025
0926809
Merge branch 'dev' into feat/shell-advice
ariane-emory Dec 25, 2025
c94d8dd
Merge branch 'dev' into feat/shell-advice
ariane-emory Dec 25, 2025
ffb5758
Merge dev into feat/shell-advice, resolving conflicts
ariane-emory Dec 26, 2025
d1060f8
Merge branch 'dev' into feat/shell-advice
ariane-emory Dec 27, 2025
a801149
Merge dev into feat/shell-advice
ariane-emory Dec 27, 2025
b5a72ad
Merge branch 'dev' into feat/shell-advice
ariane-emory Dec 27, 2025
6587035
fix: minimize bash.txt changes to only essential shell name substitut…
ariane-emory Dec 28, 2025
08ab0e6
Merge branch 'dev' into feat/shell-advice
ariane-emory Dec 28, 2025
206a22b
Merge branch 'dev' into feat/shell-advice
ariane-emory Dec 28, 2025
b9b21ce
Merge branch 'dev' into feat/shell-advice
ariane-emory Dec 28, 2025
9cd56a9
Merge branch 'dev' into feat/shell-advice
ariane-emory Dec 29, 2025
f9e5af6
Merge branch 'dev' into feat/shell-advice
ariane-emory Dec 29, 2025
4f8935f
Merge branch 'dev' into feat/shell-advice
ariane-emory Dec 29, 2025
db1f61f
Merge branch 'dev' into feat/shell-advice
ariane-emory Dec 29, 2025
f4ce6f3
Merge branch 'dev' into feat/shell-advice
ariane-emory Dec 30, 2025
cecb983
Merge branch 'dev' into feat/shell-advice
ariane-emory Dec 30, 2025
46db975
Merge branch 'dev' into feat/shell-advice
ariane-emory Dec 30, 2025
93fae5b
Merge branch 'dev' into feat/shell-advice
ariane-emory Dec 30, 2025
8ce0254
Merge branch 'dev' into feat/shell-advice
ariane-emory Dec 30, 2025
1bb5b29
Merge branch 'dev' into feat/shell-advice
ariane-emory Dec 31, 2025
12609cc
Merge branch 'dev' into feat/shell-advice
ariane-emory Jan 1, 2026
f7a2e18
Merge branch 'dev' into feat/shell-advice
ariane-emory Jan 1, 2026
d310d56
Merge branch 'dev' into feat/shell-advice
ariane-emory Jan 1, 2026
d993548
Merge branch 'dev' into feat/shell-advice
ariane-emory Jan 2, 2026
57970db
Fix missing path import in bash.ts after merge
ariane-emory Jan 2, 2026
6cae64a
Merge branch 'dev' into feat/shell-advice
ariane-emory Jan 3, 2026
efe7716
Merge branch 'dev' into feat/shell-advice
ariane-emory Jan 3, 2026
82fd0ea
Merge branch 'dev' into feat/shell-advice
ariane-emory Jan 4, 2026
294a9f4
Merge branch 'dev' into feat/shell-advice
ariane-emory Jan 4, 2026
0fe47a4
Merge branch 'dev' into feat/shell-advice
ariane-emory Jan 4, 2026
0994f64
Merge branch 'dev' into feat/shell-advice
ariane-emory Jan 5, 2026
e8eac39
Merge branch 'dev' into feat/shell-advice
ariane-emory Jan 5, 2026
fb39a83
Merge branch 'dev' into feat/shell-advice
ariane-emory Jan 5, 2026
1a7efbf
Merge branch 'dev' into feat/shell-advice
ariane-emory Jan 6, 2026
0558cf9
Merge branch 'dev' into feat/shell-advice
ariane-emory Jan 6, 2026
5e1a6b1
Merge branch 'dev' into feat/shell-advice
ariane-emory Jan 6, 2026
2bb295f
Merge branch 'dev' into feat/shell-advice
ariane-emory Jan 6, 2026
50f4dec
Merge branch 'dev' into feat/shell-advice
ariane-emory Jan 6, 2026
d2650a9
Merge remote-tracking branch 'origin/dev' into feat/shell-advice
ariane-emory Jan 7, 2026
560ff18
Merge branch 'dev' into feat/shell-advice
ariane-emory Jan 7, 2026
77df498
Merge remote-tracking branch 'origin/dev' into feat/shell-advice
ariane-emory Jan 7, 2026
c3f2a20
Merge dev into feat/shell-advice
ariane-emory Jan 7, 2026
3087042
Merge branch 'dev' into feat/shell-advice
ariane-emory Jan 11, 2026
0f02dd5
Merge branch 'dev' into feat/shell-advice
ariane-emory Jan 13, 2026
454b905
Merge branch 'dev' into feat/shell-advice
ariane-emory Jan 13, 2026
2336a01
Merge branch 'dev' into feat/shell-advice
ariane-emory Jan 13, 2026
0687bb3
Merge branch 'dev' into feat/shell-advice
ariane-emory Jan 15, 2026
1fabf3b
Merge branch 'dev' into feat/shell-advice
ariane-emory Jan 16, 2026
3a7669c
Merge branch 'dev' into feat/shell-advice
ariane-emory Jan 17, 2026
2edbc88
Merge branch 'dev' into feat/shell-advice
ariane-emory Jan 17, 2026
4776888
Merge branch 'dev' into feat/shell-advice
ariane-emory Jan 19, 2026
54831b2
Merge branch 'dev' into feat/shell-advice
ariane-emory Jan 20, 2026
207f32d
Merge branch 'dev' into feat/shell-advice
ariane-emory Jan 22, 2026
fd132de
Merge branch 'dev' into feat/shell-advice
ariane-emory Jan 23, 2026
9cab2a8
Merge branch 'dev' into feat/shell-advice
ariane-emory Jan 25, 2026
cafafac
Merge branch 'dev' into feat/shell-advice
ariane-emory Jan 25, 2026
fbf9b75
Merge branch 'dev' into feat/shell-advice
ariane-emory Jan 26, 2026
73c27db
Merge branch 'dev' into feat/shell-advice
ariane-emory Jan 27, 2026
d3d665e
Merge branch 'dev' into feat/shell-advice
ariane-emory Jan 29, 2026
37264be
Merge branch 'dev' into feat/shell-advice
ariane-emory Jan 29, 2026
bcfc914
Merge dev into feat/shell-advice
ariane-emory Jan 30, 2026
8ad85f2
Merge branch 'dev' into feat/shell-advice
ariane-emory Feb 1, 2026
692a770
Merge branch 'dev' into feat/shell-advice
ariane-emory Feb 2, 2026
2571fad
Merge branch 'dev' into feat/shell-advice
ariane-emory Feb 3, 2026
67434e1
Merge dev into feat/shell-advice
ariane-emory Feb 4, 2026
7683ff0
Merge branch 'dev' into feat/shell-advice
ariane-emory Feb 5, 2026
0374dc6
Merge branch 'dev' into feat/shell-advice
ariane-emory Feb 5, 2026
ea0518b
Merge branch 'dev' into feat/shell-advice
ariane-emory Feb 5, 2026
7965dfb
Merge branch 'feat/shell-advice' of github.com:ariane-emory/opencode …
ariane-emory Feb 5, 2026
27f9487
Merge dev into feat/shell-advice
ariane-emory Feb 6, 2026
15106f6
Merge dev into feat/shell-advice
ariane-emory Feb 7, 2026
4e197a5
Merge branch 'dev' into feat/shell-advice
ariane-emory Feb 10, 2026
81d9bf4
Merge branch 'dev' into feat/shell-advice
ariane-emory Feb 11, 2026
3eb82d1
Merge branch 'dev' into feat/shell-advice
ariane-emory Feb 12, 2026
325f6c9
Merge dev into feat/shell-advice
ariane-emory Feb 13, 2026
35a1106
Merge branch 'dev' into feat/shell-advice
ariane-emory Feb 14, 2026
b808eba
Merge branch 'dev' into feat/shell-advice
ariane-emory Feb 15, 2026
5dde87d
Merge branch 'dev' into feat/shell-advice
ariane-emory Feb 15, 2026
1b9ae1a
Merge branch 'dev' into feat/shell-advice
ariane-emory Feb 17, 2026
8d589ce
Merge branch 'dev' into feat/shell-advice
ariane-emory Feb 18, 2026
41fec36
Merge branch 'dev' into feat/shell-advice
ariane-emory Feb 20, 2026
8c08be4
Merge branch 'dev' into feat/shell-advice
ariane-emory Feb 20, 2026
5b81e26
Merge branch 'dev' into feat/shell-advice
ariane-emory Feb 20, 2026
4e0f40f
Merge branch 'dev' into feat/shell-advice
ariane-emory Feb 21, 2026
e415323
Merge branch 'dev' into feat/shell-advice
ariane-emory Feb 26, 2026
1363e38
Merge branch 'dev' into feat/shell-advice
ariane-emory Feb 26, 2026
c17f234
Merge branch 'dev' into feat/shell-advice
ariane-emory Mar 5, 2026
404a510
Merge branch 'dev' into feat/shell-advice
ariane-emory Mar 8, 2026
8382385
Merge branch 'dev' into feat/shell-advice
ariane-emory Mar 8, 2026
415922d
Merge branch 'dev' into feat/shell-advice
ariane-emory Mar 13, 2026
7352af3
Merge branch 'dev' into feat/shell-advice
ariane-emory Mar 20, 2026
7094f86
Merge branch 'dev' into feat/shell-advice
ariane-emory Mar 20, 2026
6294871
Merge branch 'dev' into feat/shell-advice
ariane-emory Mar 24, 2026
ceef063
Merge branch 'dev' into feat/shell-advice
ariane-emory Mar 24, 2026
b1f82fb
Merge branch 'dev' into feat/shell-advice
ariane-emory Mar 24, 2026
dfbe74c
Merge branch 'dev' into feat/shell-advice
ariane-emory Apr 4, 2026
b49a869
Merge branch 'dev' into feat/shell-advice
ariane-emory Apr 12, 2026
7f9a41e
Merge branch 'dev' into feat/shell-advice
ariane-emory Apr 17, 2026
78a5ebe
fix: restore fish and nu bash shell support
ariane-emory Apr 17, 2026
436201d
chore: consolidate shell placeholder in bash description
ariane-emory Apr 17, 2026
e08f6b3
fix: replace remaining ${shellName} with ${shell} in bash description
ariane-emory Apr 17, 2026
adc04ec
style: undo needless whitespace change.
ariane-emory Apr 17, 2026
a40cfe7
Merge dev into feat/shell-advice
ariane-emory Apr 24, 2026
df084e5
Merge dev into feat/shell-advice
ariane-emory May 4, 2026
1ffefb5
fix: update shell tests to use WithInstance.provide and correct fallb…
ariane-emory May 4, 2026
c2961fd
fix: allow fish and nu shells in shell tool
ariane-emory May 6, 2026
c423fd5
revert: restore shell.txt to dev version
ariane-emory May 6, 2026
baf7e18
style: defensive comments
ariane-emory May 7, 2026
cee85e4
tweak: verbiage
ariane-emory May 7, 2026
8b9aa7f
Merge branch 'dev' into feat/shell-advice
ariane-emory May 11, 2026
8be3d0c
Merge branch 'dev' into feat/shell-advice
ariane-emory May 11, 2026
58e904b
Merge branch 'dev' into feat/shell-advice
ariane-emory May 11, 2026
c6e7e0b
Merge branch 'dev' into feat/shell-advice
ariane-emory May 11, 2026
0a66348
Merge branch 'dev' into feat/shell-tool-unblacklist-fish-and-extend-d…
ariane-emory May 18, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 5 additions & 9 deletions packages/opencode/src/shell/shell.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,12 @@ import { spawn, type ChildProcess } from "child_process"
import { setTimeout as sleep } from "node:timers/promises"

const SIGKILL_TIMEOUT_MS = 200
const META: Record<string, { deny?: boolean; login?: boolean; posix?: boolean; ps?: boolean }> = {
const META: Record<string, { login?: boolean; posix?: boolean; ps?: boolean }> = {
bash: { login: true, posix: true },
dash: { login: true, posix: true },
fish: { deny: true, login: true },
// AGENTS: The change below permitting the fish shell is crucial to the purpose of this branch, and this change and this comment MUST NOT be clobbered during merges!
fish: { login: true },
ksh: { login: true, posix: true },
nu: { deny: true },
powershell: { ps: true },
pwsh: { ps: true },
sh: { login: true, posix: true },
Expand Down Expand Up @@ -71,10 +71,6 @@ function meta(file: string) {
return META[name(file)]
}

function ok(file: string) {
return meta(file)?.deny !== true
}

function rooted(file: string) {
return path.isAbsolute(Filesystem.windowsPath(file))
}
Expand Down Expand Up @@ -105,7 +101,7 @@ async function unix() {
}

function select(file: string | undefined, opts?: { acceptable?: boolean }) {
if (file && (!opts?.acceptable || ok(file))) {
if (file) {
const shell = resolve(file)
if (shell) return shell
}
Expand Down Expand Up @@ -152,7 +148,7 @@ function info(file: string): Item {
return {
path: item,
name: resolve(n) ? n : item,
acceptable: ok(item),
acceptable: true, // AGENTS: You must not allow this chain to be compromised during merges!
}
}

Expand Down
6 changes: 3 additions & 3 deletions packages/opencode/src/tool/shell/prompt.ts
Original file line number Diff line number Diff line change
Expand Up @@ -257,12 +257,12 @@ function profile(name: string, platform: NodeJS.Platform, limits: Limits) {
}
return {
intro:
"Executes a given bash command in a persistent shell session with optional timeout, ensuring proper handling and security measures.",
`Executes a given ${name} command in a persistent shell session with optional timeout, ensuring proper handling and security measures.`,
workdirSection:
"All commands run in the current working directory by default. Use the `workdir` parameter if you need to run a command in a different directory. AVOID using `cd <directory> && <command>` patterns - use `workdir` instead.",
commandSection: bashCommandSection(chain, limits),
gitCommands: "bash commands",
gitCommandRestriction: "git bash commands",
gitCommands: `${name} commands`,
gitCommandRestriction: `git ${name} commands`,
createPrInstruction:
"Create PR using gh pr create with the format below. Use a HEREDOC to pass the body to ensure correct formatting.",
createPrExample: `gh pr create --title "the pr title" --body "$(cat <<'EOF'
Expand Down
10 changes: 5 additions & 5 deletions packages/opencode/test/shell/shell.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,15 +49,15 @@ describe("shell", () => {
})
})

test("falls back for terminal-only acceptable shells", () => {
expect(Shell.name(Shell.acceptable("fish"))).not.toBe("fish")
expect(Shell.name(Shell.acceptable("nu"))).not.toBe("nu")
test("accepts fish and nu shells", () => {
expect(Shell.name(Shell.acceptable("fish"))).toBe("fish")
expect(Shell.name(Shell.acceptable("nu"))).toBe("nu")
})

if (process.platform === "win32") {
test("rejects blacklisted shells case-insensitively", async () => {
test("accepts nu shell case-insensitively", async () => {
await withShell("NU.EXE", async () => {
expect(Shell.name(Shell.acceptable())).not.toBe("nu")
expect(Shell.name(Shell.acceptable())).toBe("nu")
})
})

Expand Down
95 changes: 88 additions & 7 deletions packages/opencode/test/tool/shell.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -186,26 +186,107 @@ describe("tool.shell", () => {
),
)

it.live("falls back from terminal-only configured shell", () =>
it.live("description includes shell information", () =>
runIn(
projectRoot,
Effect.gen(function* () {
const bash = yield* initBash()
expect(bash.description).toContain("Be aware: OS:")
expect(bash.description).toContain("Shell:")
const shellMatch = bash.description.match(/Shell: ([^\n]+)/)
expect(shellMatch).toBeTruthy()
expect(shellMatch?.[1]).toBeTruthy()
}),
),
)

it.live("shell name detection is platform-aware", () =>
runIn(
projectRoot,
Effect.gen(function* () {
const bash = yield* initBash()
const detectedShell = bash.description.match(/Shell: ([^\n]+)/)?.[1]?.trim()

expect(detectedShell).toBeTruthy()

if (process.platform === "win32") {
expect(["cmd", "powershell"]).toContain(detectedShell!)
} else {
expect(["bash", "zsh", "fish", "ksh", "csh", "tcsh", "dash"]).toContain(detectedShell!)
}
}),
),
)

it.live("description uses dynamic shell-specific language", () =>
runIn(
projectRoot,
Effect.gen(function* () {
const bash = yield* initBash()
const detectedShell = bash.description.match(/Shell: ([^\n]+)/)?.[1]?.trim()

expect(detectedShell).toBeTruthy()

if (detectedShell) {
expect(bash.description).toContain(`${detectedShell} command`)
}

expect(bash.description).toContain("persistent shell session")
}),
),
)

it.live("shell-specific language works for different shell types", () =>
runIn(
projectRoot,
Effect.gen(function* () {
yield* withShell({ label: "zsh", shell: "/bin/zsh" }, Effect.gen(function* () {
const bash = yield* initBash()
expect(bash.description).toContain("zsh command")
}))

yield* withShell({ label: "bash", shell: "/bin/bash" }, Effect.gen(function* () {
const bash = yield* initBash()
expect(bash.description).toContain("bash command")
}))

yield* withShell({ label: "ksh", shell: "/bin/ksh" }, Effect.gen(function* () {
const bash = yield* initBash()
expect(bash.description).toContain("ksh command")
}))

yield* withShell({ label: "fish", shell: "fish" }, Effect.gen(function* () {
const bash = yield* initBash()
expect(bash.description).toContain("fish command")
}))

yield* withShell({ label: "nu", shell: "nu" }, Effect.gen(function* () {
const bash = yield* initBash()
expect(bash.description).toContain("nu command")
}))
}),
),
)

it.live("uses configured fish shell", () =>
Effect.gen(function* () {
const tmp = yield* tmpdirScoped({ config: { shell: "fish" } })
yield* runIn(
tmp,
Effect.gen(function* () {
const bash = yield* initBash()
const fallback = Shell.name(Shell.acceptable("fish"))
expect(fallback).not.toBe("fish")
expect(bash.description).toContain(fallback)
expect(Shell.name(Shell.acceptable("fish"))).toBe("fish")
expect(bash.description).toContain("fish")

const result = yield* bash.execute(
{
command: "echo fallback",
description: "Echo fallback text",
command: "echo fish",
description: "Echo fish text",
},
ctx,
)
expect(result.metadata.exit).toBe(0)
expect(result.output).toContain("fallback")
expect(result.output).toContain("fish")
}),
)
}),
Expand Down