import { describe, expect, it } from "bun:test"; import { sanitizeSnapshotForBrush } from "@oh-my-pi/pi-coding-agent/utils/shell-snapshot"; // `sanitizeSnapshotForBrush` is the snapshot-side mitigation for brush's // whitespace-only alias expander (`crates/brush-core-vendored/src/interp.rs:1500`, // brush issue reubeno/brush#57). Aliases whose body needs real shell parsing // must be dropped or brush turns the first whitespace piece into the command // name and the user sees `error: command not found: (alias;` (issue #3234). describe("sanitizeSnapshotForBrush", () => { it("drops the Fedora `which` alias and reports the dropped name", () => { const snapshot = [ "unalias -a 2>/dev/null || true", "alias -- which='(alias; declare -f) | /usr/bin/which --tty-only --read-alias --show-dot --show-tilde'", "alias -- ll='ls -l'", "", ].join("\n"); const result = sanitizeSnapshotForBrush(snapshot); expect(result.dropped).toEqual(["which"]); expect(result.content).not.toContain("alias -- which="); // Simple aliases must still pass through untouched. expect(result.content).toContain("alias -- ll='ls -l'"); }); it.each([ ["subshell", "alias -- a='(echo hi)'"], ["pipe", "alias -- a='cat /etc/hostname | head -n1'"], ["semicolon", "alias -- a='echo a; echo b'"], ["redirect-out", "alias -- a='tee >foo'"], ["redirect-in", "alias -- a='cat { const result = sanitizeSnapshotForBrush(`${line}\n`); expect(result.dropped).toEqual(["a"]); expect(result.content).not.toContain("alias -- a="); }); it.each([ ["simple", "alias -- ll='ls -l'"], ["flag-with-equals", "alias -- gc='git --color=auto commit'"], ["multi-flag", "alias -- la='ls -lAh --group-directories-first'"], // A plain single quote escape that decodes to a metachar-free body // must survive — we only ban truly unparseable bodies. ["embedded-quote", "alias -- say='echo '\\''hello'\\'''"], ])("preserves aliases brush can handle by whitespace split (%s)", (_label, line) => { const result = sanitizeSnapshotForBrush(`${line}\n`); expect(result.dropped).toEqual([]); expect(result.content).toContain(line); }); it("leaves non-alias lines (functions, exports, unalias) untouched", () => { const snapshot = [ "# Shell snapshot - generated by omp agent", "unalias -a 2>/dev/null || true", "my_fn () { echo hi; }", "export PATH='/usr/bin:/bin'", "shopt -s expand_aliases", "alias -- which='(alias; declare -f) | /usr/bin/which'", // poisoned ].join("\n"); const result = sanitizeSnapshotForBrush(snapshot); expect(result.dropped).toEqual(["which"]); for (const keep of [ "# Shell snapshot - generated by omp agent", "unalias -a 2>/dev/null || true", "my_fn () { echo hi; }", // function body contains `;` but is not an alias line "export PATH='/usr/bin:/bin'", "shopt -s expand_aliases", ]) { expect(result.content).toContain(keep); } }); });