fix(bash): honor explicit working directories
This commit is contained in:
@@ -0,0 +1,112 @@
|
||||
import assert from "node:assert/strict";
|
||||
import { execFileSync } from "node:child_process";
|
||||
import { access, mkdir, mkdtemp, rm, writeFile } from "node:fs/promises";
|
||||
import { tmpdir } from "node:os";
|
||||
import { join } from "node:path";
|
||||
import test from "node:test";
|
||||
|
||||
import type { ExtensionContext } from "@earendil-works/pi-coding-agent";
|
||||
|
||||
import { createContextualBashTool } from "./index.ts";
|
||||
|
||||
function git(cwd: string, ...args: string[]): void {
|
||||
execFileSync("git", args, { cwd, stdio: "pipe" });
|
||||
}
|
||||
|
||||
function getOutput(
|
||||
result: Awaited<ReturnType<ReturnType<typeof createContextualBashTool>["execute"]>>,
|
||||
): string {
|
||||
return result.content
|
||||
.filter((item) => item.type === "text")
|
||||
.map((item) => item.text)
|
||||
.join("")
|
||||
.trim();
|
||||
}
|
||||
|
||||
async function executeIn(
|
||||
sessionCwd: string,
|
||||
command: string,
|
||||
cwd?: string,
|
||||
) {
|
||||
const params = cwd === undefined ? { command } : { command, cwd };
|
||||
return createContextualBashTool().execute(
|
||||
"bash-cwd-test",
|
||||
params,
|
||||
undefined,
|
||||
undefined,
|
||||
{
|
||||
cwd: sessionCwd,
|
||||
sessionManager: {
|
||||
getSessionId: () => "bash-cwd-test-session",
|
||||
getSessionFile: () => undefined,
|
||||
},
|
||||
} as ExtensionContext,
|
||||
);
|
||||
}
|
||||
|
||||
test("bash honors hidden-worktree and nested-package cwd arguments", async (t) => {
|
||||
const repository = await mkdtemp(join(tmpdir(), "pi-bash-cwd-"));
|
||||
t.after(() => rm(repository, { recursive: true, force: true }));
|
||||
|
||||
await writeFile(join(repository, ".gitignore"), ".worktrees/\n");
|
||||
await mkdir(join(repository, "extensions", "fixture"), { recursive: true });
|
||||
await writeFile(
|
||||
join(repository, "extensions", "fixture", "package.json"),
|
||||
'{"private":true}\n',
|
||||
);
|
||||
|
||||
git(repository, "init", "--initial-branch=main");
|
||||
git(repository, "config", "user.name", "Bash cwd test");
|
||||
git(repository, "config", "user.email", "bash-cwd@example.invalid");
|
||||
git(repository, "add", ".");
|
||||
git(repository, "commit", "-m", "fixture");
|
||||
|
||||
const worktree = join(repository, ".worktrees", "feature");
|
||||
git(repository, "worktree", "add", "-b", "feature", worktree, "main");
|
||||
const packageDirectory = join(worktree, "extensions", "fixture");
|
||||
|
||||
assert.equal(getOutput(await executeIn(repository, "pwd")), repository);
|
||||
assert.equal(
|
||||
getOutput(await executeIn(repository, 'printf %s "$PI_SESSION_ID"')),
|
||||
"bash-cwd-test-session",
|
||||
);
|
||||
assert.equal(getOutput(await executeIn(repository, "pwd", worktree)), worktree);
|
||||
assert.equal(
|
||||
getOutput(
|
||||
await executeIn(
|
||||
repository,
|
||||
"pwd",
|
||||
".worktrees/feature/extensions/fixture",
|
||||
),
|
||||
),
|
||||
packageDirectory,
|
||||
);
|
||||
|
||||
const missingDirectory = join(worktree, "missing");
|
||||
const sentinel = join(repository, "should-not-run");
|
||||
await assert.rejects(
|
||||
executeIn(repository, "touch should-not-run", missingDirectory),
|
||||
/Working directory does not exist/,
|
||||
);
|
||||
await assert.rejects(access(sentinel));
|
||||
});
|
||||
|
||||
test("bash exposes cwd without changing existing arguments", () => {
|
||||
const schema = createContextualBashTool().parameters;
|
||||
assert.deepEqual(Object.keys(schema.properties), ["command", "cwd", "timeout"]);
|
||||
assert.deepEqual(schema.required, ["command"]);
|
||||
});
|
||||
|
||||
test("bash fails before execution when Pi omits the tool context", async () => {
|
||||
const tool = createContextualBashTool();
|
||||
await assert.rejects(
|
||||
tool.execute(
|
||||
"bash-cwd-test",
|
||||
{ command: "pwd" },
|
||||
undefined,
|
||||
undefined,
|
||||
undefined as unknown as ExtensionContext,
|
||||
),
|
||||
/Bash execution context is unavailable/,
|
||||
);
|
||||
});
|
||||
Reference in New Issue
Block a user