Merge PR #3354: fix: migrate coding-agent tests to removeWithRetries (@oldschoola)
This commit is contained in:
@@ -7,6 +7,7 @@ import { ToolExecutionComponent } from "@oh-my-pi/pi-coding-agent/modes/componen
|
||||
import * as themeModule from "@oh-my-pi/pi-coding-agent/modes/theme/theme";
|
||||
import { toolRenderers } from "@oh-my-pi/pi-coding-agent/tools/renderers";
|
||||
import type { TUI } from "@oh-my-pi/pi-tui";
|
||||
import { removeWithRetries } from "@oh-my-pi/pi-utils";
|
||||
|
||||
async function getUiTheme() {
|
||||
await themeModule.initTheme(false, undefined, undefined, "dark", "light");
|
||||
@@ -148,7 +149,7 @@ describe("apply_patch rendering", () => {
|
||||
expect(after).toContain("(preview)");
|
||||
expect(after).toContain("const value = 2;");
|
||||
} finally {
|
||||
await fs.rm(tmpDir, { recursive: true, force: true });
|
||||
await removeWithRetries(tmpDir);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -176,7 +177,7 @@ describe("apply_patch rendering", () => {
|
||||
expect(setTimeoutSpy).not.toHaveBeenCalled();
|
||||
} finally {
|
||||
setTimeoutSpy.mockRestore();
|
||||
await fs.rm(tmpDir, { recursive: true, force: true });
|
||||
await removeWithRetries(tmpDir);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@ import { Settings } from "@oh-my-pi/pi-coding-agent/config/settings";
|
||||
import { createAgentSession } from "@oh-my-pi/pi-coding-agent/sdk";
|
||||
import type { AgentSession } from "@oh-my-pi/pi-coding-agent/session/agent-session";
|
||||
import { SessionManager } from "@oh-my-pi/pi-coding-agent/session/session-manager";
|
||||
import { Snowflake } from "@oh-my-pi/pi-utils";
|
||||
import { removeSyncWithRetries, Snowflake } from "@oh-my-pi/pi-utils";
|
||||
|
||||
const BASE_SETTINGS = {
|
||||
"async.enabled": false,
|
||||
@@ -66,7 +66,7 @@ describe("tools.approvalMode setting", () => {
|
||||
// Windows can briefly hold tempdir handles after session.dispose(); retry a few times.
|
||||
for (let attempt = 0; attempt < 5; attempt++) {
|
||||
try {
|
||||
fs.rmSync(tempDir, { recursive: true, force: true });
|
||||
removeSyncWithRetries(tempDir);
|
||||
break;
|
||||
} catch (err) {
|
||||
const code = (err as NodeJS.ErrnoException).code;
|
||||
|
||||
@@ -6,6 +6,7 @@ import { adaptSchemaForStrict, toolWireSchema } from "@oh-my-pi/pi-ai/utils/sche
|
||||
import { Settings } from "@oh-my-pi/pi-coding-agent/config/settings";
|
||||
import { ToolChoiceQueue } from "@oh-my-pi/pi-coding-agent/session/tool-choice-queue";
|
||||
import { createTools, type ToolSession } from "@oh-my-pi/pi-coding-agent/tools";
|
||||
import { removeWithRetries } from "@oh-my-pi/pi-utils";
|
||||
|
||||
type InvokedToolResult = {
|
||||
content: Array<{ type: string; text?: string }>;
|
||||
@@ -85,7 +86,7 @@ describe("ast_edit tool schema", () => {
|
||||
expect(addedLine).toMatch(/^\+\d+:/);
|
||||
expect(removedLine?.split(":", 1)[0].length).toBe(addedLine?.split(":", 1)[0].length);
|
||||
} finally {
|
||||
await fs.rm(tempDir, { recursive: true, force: true });
|
||||
await removeWithRetries(tempDir);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -129,7 +130,7 @@ describe("ast_edit tool schema", () => {
|
||||
const updated = await Bun.file(filePath).text();
|
||||
expect(updated).toContain("modernWrap(x, value)");
|
||||
} finally {
|
||||
await fs.rm(tempDir, { recursive: true, force: true });
|
||||
await removeWithRetries(tempDir);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -172,7 +173,7 @@ describe("ast_edit tool schema", () => {
|
||||
).toBe(0);
|
||||
expect(await Bun.file(filePath).text()).toBe(mutatedContent);
|
||||
} finally {
|
||||
await fs.rm(tempDir, { recursive: true, force: true });
|
||||
await removeWithRetries(tempDir);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -235,7 +236,7 @@ describe("ast_edit tool schema", () => {
|
||||
"legacyWrap(outsideValue, outsideArg)",
|
||||
);
|
||||
} finally {
|
||||
await fs.rm(tempDir, { recursive: true, force: true });
|
||||
await removeWithRetries(tempDir);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -271,7 +272,7 @@ describe("ast_edit tool schema", () => {
|
||||
await invoker({ action: "apply", reason: "apply tlaplus AST edit" });
|
||||
expect(await Bun.file(filePath).text()).toContain("Start == x = 0");
|
||||
} finally {
|
||||
await fs.rm(tempDir, { recursive: true, force: true });
|
||||
await removeWithRetries(tempDir);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
@@ -4,6 +4,7 @@ import * as os from "node:os";
|
||||
import * as path from "node:path";
|
||||
import { Settings } from "@oh-my-pi/pi-coding-agent/config/settings";
|
||||
import { createTools, type ToolSession } from "@oh-my-pi/pi-coding-agent/tools";
|
||||
import { removeWithRetries } from "@oh-my-pi/pi-utils";
|
||||
|
||||
function createTestSession(cwd = "/tmp/test", overrides: Partial<ToolSession> = {}): ToolSession {
|
||||
return {
|
||||
@@ -43,7 +44,7 @@ describe("ast_grep parse errors", () => {
|
||||
expect(details?.parseErrors?.[0]).not.toContain("someUnlikelyCall($A):");
|
||||
expect(text.match(/parse error \(syntax tree contains error nodes\)/g)?.length ?? 0).toBe(1);
|
||||
} finally {
|
||||
await fs.rm(tempDir, { recursive: true, force: true });
|
||||
await removeWithRetries(tempDir);
|
||||
}
|
||||
});
|
||||
it("caps parseErrors at PARSE_ERRORS_LIMIT and records the original total", async () => {
|
||||
@@ -73,7 +74,7 @@ describe("ast_grep parse errors", () => {
|
||||
expect(details?.parseErrorsTotal).toBe(fileCount);
|
||||
expect(text).toContain(`Parse issues (20 / ${fileCount}):`);
|
||||
} finally {
|
||||
await fs.rm(tempDir, { recursive: true, force: true });
|
||||
await removeWithRetries(tempDir);
|
||||
}
|
||||
});
|
||||
it("combines globbing from path and glob parameters", async () => {
|
||||
@@ -109,7 +110,7 @@ describe("ast_grep parse errors", () => {
|
||||
expect(details?.matchCount).toBe(2);
|
||||
expect(details?.fileCount).toBe(2);
|
||||
} finally {
|
||||
await fs.rm(tempDir, { recursive: true, force: true });
|
||||
await removeWithRetries(tempDir);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -138,7 +139,7 @@ describe("ast_grep parse errors", () => {
|
||||
expect(details?.matchCount).toBe(1);
|
||||
expect(details?.parseErrors).toBeUndefined();
|
||||
} finally {
|
||||
await fs.rm(tempDir, { recursive: true, force: true });
|
||||
await removeWithRetries(tempDir);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
@@ -5,6 +5,7 @@ import * as path from "node:path";
|
||||
import { resetSettingsForTest, Settings } from "@oh-my-pi/pi-coding-agent/config/settings";
|
||||
import { createTools, type ToolSession } from "@oh-my-pi/pi-coding-agent/tools";
|
||||
import { ConflictHistory } from "@oh-my-pi/pi-coding-agent/tools/conflict-detect";
|
||||
import { removeWithRetries } from "@oh-my-pi/pi-utils";
|
||||
|
||||
function createTestSession(cwd: string, overrides: Partial<ToolSession> = {}): ToolSession {
|
||||
return {
|
||||
@@ -82,7 +83,7 @@ describe("read surfaces conflicts as a warning footer", () => {
|
||||
});
|
||||
|
||||
afterEach(async () => {
|
||||
await fs.rm(tempDir, { recursive: true, force: true });
|
||||
await removeWithRetries(tempDir);
|
||||
});
|
||||
|
||||
it("returns file content and appends a conflict warning with id 1", async () => {
|
||||
@@ -308,7 +309,7 @@ describe("write resolves conflicts via conflict://N", () => {
|
||||
});
|
||||
|
||||
afterEach(async () => {
|
||||
await fs.rm(tempDir, { recursive: true, force: true });
|
||||
await removeWithRetries(tempDir);
|
||||
});
|
||||
|
||||
it("splices the registered region with the supplied content", async () => {
|
||||
|
||||
@@ -9,6 +9,7 @@ import { editToolRenderer } from "@oh-my-pi/pi-coding-agent/edit/renderer";
|
||||
import { ToolExecutionComponent } from "@oh-my-pi/pi-coding-agent/modes/components/tool-execution";
|
||||
import * as themeModule from "@oh-my-pi/pi-coding-agent/modes/theme/theme";
|
||||
import { Text, type TUI, visibleWidth } from "@oh-my-pi/pi-tui";
|
||||
import { removeWithRetries } from "@oh-my-pi/pi-utils";
|
||||
|
||||
beforeAll(async () => {
|
||||
resetSettingsForTest();
|
||||
@@ -288,7 +289,7 @@ describe("editToolRenderer", () => {
|
||||
expect(rendered).toContain("export const b = 22;");
|
||||
expect(rendered).not.toContain("No changes would be made");
|
||||
} finally {
|
||||
await fs.rm(tmpDir, { recursive: true, force: true });
|
||||
await removeWithRetries(tmpDir);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -319,7 +320,7 @@ describe("editToolRenderer", () => {
|
||||
expect(rendered).toContain("export const b = 22;");
|
||||
expect(rendered).not.toContain(" …");
|
||||
} finally {
|
||||
await fs.rm(tmpDir, { recursive: true, force: true });
|
||||
await removeWithRetries(tmpDir);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@ import { ReadTool } from "@oh-my-pi/pi-coding-agent/tools/read";
|
||||
import { zip } from "@oh-my-pi/pi-coding-agent/utils/zip";
|
||||
import * as scrapers from "@oh-my-pi/pi-coding-agent/web/scrapers/types";
|
||||
import * as scraperUtils from "@oh-my-pi/pi-coding-agent/web/scrapers/utils";
|
||||
import { Snowflake } from "@oh-my-pi/pi-utils";
|
||||
import { removeSyncWithRetries, Snowflake } from "@oh-my-pi/pi-utils";
|
||||
|
||||
function makeSession(testDir: string): ToolSession {
|
||||
const sessionFile = path.join(testDir, "session.jsonl");
|
||||
@@ -108,7 +108,7 @@ describe("read URL binary dispatch", () => {
|
||||
|
||||
afterEach(() => {
|
||||
vi.restoreAllMocks();
|
||||
fs.rmSync(testDir, { recursive: true, force: true });
|
||||
removeSyncWithRetries(testDir);
|
||||
});
|
||||
|
||||
it("lists a remote zip instead of dumping decoded bytes", async () => {
|
||||
|
||||
@@ -10,7 +10,7 @@ import * as toolsManager from "@oh-my-pi/pi-coding-agent/utils/tools-manager";
|
||||
import * as scrapers from "@oh-my-pi/pi-coding-agent/web/scrapers/types";
|
||||
import * as scraperUtils from "@oh-my-pi/pi-coding-agent/web/scrapers/utils";
|
||||
import * as natives from "@oh-my-pi/pi-natives";
|
||||
import { ptree, Snowflake } from "@oh-my-pi/pi-utils";
|
||||
import { ptree, removeSyncWithRetries, Snowflake } from "@oh-my-pi/pi-utils";
|
||||
import { asGlobalFetch } from "../helpers/fetch-mock";
|
||||
|
||||
const withMissingSystemPython = () => {
|
||||
@@ -32,7 +32,7 @@ describe("read tool URL selector shorthands", () => {
|
||||
|
||||
afterEach(() => {
|
||||
vi.restoreAllMocks();
|
||||
fs.rmSync(testDir, { recursive: true, force: true });
|
||||
removeSyncWithRetries(testDir);
|
||||
});
|
||||
|
||||
const createSession = (settingsOverrides: Partial<Record<SettingPath, unknown>> = {}): ToolSession => {
|
||||
@@ -125,7 +125,7 @@ describe("read tool URL handling", () => {
|
||||
afterEach(() => {
|
||||
vi.restoreAllMocks();
|
||||
delete process.env.PARALLEL_API_KEY;
|
||||
fs.rmSync(testDir, { recursive: true, force: true });
|
||||
removeSyncWithRetries(testDir);
|
||||
});
|
||||
|
||||
const createSession = (overrides: Partial<Record<SettingPath, unknown>> = {}): ToolSession => {
|
||||
|
||||
@@ -6,7 +6,7 @@ import { Settings } from "@oh-my-pi/pi-coding-agent/config/settings";
|
||||
import type { ToolSession } from "@oh-my-pi/pi-coding-agent/tools";
|
||||
import { ReadTool } from "@oh-my-pi/pi-coding-agent/tools/read";
|
||||
import * as scrapers from "@oh-my-pi/pi-coding-agent/web/scrapers/types";
|
||||
import { Snowflake } from "@oh-my-pi/pi-utils";
|
||||
import { removeSyncWithRetries, Snowflake } from "@oh-my-pi/pi-utils";
|
||||
|
||||
const ATOM = `<?xml version="1.0"?>\n<feed xmlns="http://www.w3.org/2005/Atom"><title>Sample</title><entry><title>One</title><id>1</id><updated>2024-01-01T00:00:00Z</updated><content>body</content></entry></feed>`;
|
||||
const JSON_BODY = `{"alpha":1,"beta":[2,3]}`;
|
||||
@@ -47,7 +47,7 @@ describe("read URL with :raw selector (regression: JSON/feed parsers ignored raw
|
||||
});
|
||||
afterEach(() => {
|
||||
vi.restoreAllMocks();
|
||||
fs.rmSync(testDir, { recursive: true, force: true });
|
||||
removeSyncWithRetries(testDir);
|
||||
});
|
||||
|
||||
it("returns the raw atom feed body when :raw is set", async () => {
|
||||
@@ -130,7 +130,7 @@ describe("read URL with multi-range selector (regression: was stuck on URL → 4
|
||||
});
|
||||
afterEach(() => {
|
||||
vi.restoreAllMocks();
|
||||
fs.rmSync(testDir, { recursive: true, force: true });
|
||||
removeSyncWithRetries(testDir);
|
||||
});
|
||||
|
||||
it("routes :A-B,C-D to the multi-range builder against the cached body", async () => {
|
||||
|
||||
@@ -13,6 +13,7 @@ import {
|
||||
putCached,
|
||||
resetForTests as resetCacheForTests,
|
||||
} from "@oh-my-pi/pi-coding-agent/tools/github-cache";
|
||||
import { removeWithRetries } from "@oh-my-pi/pi-utils";
|
||||
|
||||
const REPO = "owner/example";
|
||||
|
||||
@@ -92,7 +93,7 @@ afterEach(async () => {
|
||||
} else {
|
||||
process.env.OMP_GITHUB_CACHE_DB = originalEnv;
|
||||
}
|
||||
await fs.rm(tempDir, { recursive: true, force: true });
|
||||
await removeWithRetries(tempDir);
|
||||
});
|
||||
|
||||
describe("invalidateGithubCacheForBashCommand", () => {
|
||||
|
||||
@@ -13,7 +13,7 @@ import {
|
||||
resolveDefaultRepoMemoized,
|
||||
} from "@oh-my-pi/pi-coding-agent/tools/gh";
|
||||
import * as git from "@oh-my-pi/pi-coding-agent/utils/git";
|
||||
import { getAgentDir, hashPath, setAgentDir } from "@oh-my-pi/pi-utils";
|
||||
import { getAgentDir, hashPath, removeWithRetries, setAgentDir } from "@oh-my-pi/pi-utils";
|
||||
|
||||
// Isolate every `git` invocation in this file from the developer's host
|
||||
// configuration. The fixture spawns dozens of git subprocesses against tiny
|
||||
@@ -197,7 +197,7 @@ async function setupTempHome(): Promise<{ home: string; cleanup: () => Promise<v
|
||||
home,
|
||||
cleanup: async () => {
|
||||
setAgentDir(originalAgentDir);
|
||||
await fs.rm(home, { recursive: true, force: true });
|
||||
await removeWithRetries(home);
|
||||
},
|
||||
};
|
||||
}
|
||||
@@ -267,7 +267,7 @@ describe("github tool", () => {
|
||||
|
||||
afterAll(async () => {
|
||||
if (prFixtureTemplate) {
|
||||
await fs.rm(prFixtureTemplate.baseDir, { recursive: true, force: true });
|
||||
await removeWithRetries(prFixtureTemplate.baseDir);
|
||||
prFixtureTemplate = null;
|
||||
}
|
||||
});
|
||||
@@ -777,7 +777,7 @@ describe("github tool", () => {
|
||||
});
|
||||
afterAll(async () => {
|
||||
await tempHome.cleanup();
|
||||
await fs.rm(fixture.baseDir, { recursive: true, force: true });
|
||||
await removeWithRetries(fixture.baseDir);
|
||||
});
|
||||
|
||||
it("checks out a pull request into a worktree and configures contributor push metadata", async () => {
|
||||
@@ -826,7 +826,7 @@ describe("github tool", () => {
|
||||
remoteFixture = await createPrFixture();
|
||||
});
|
||||
afterAll(async () => {
|
||||
await fs.rm(remoteFixture.baseDir, { recursive: true, force: true });
|
||||
await removeWithRetries(remoteFixture.baseDir);
|
||||
});
|
||||
|
||||
it("treats git.remote.add as a no-op when the remote already exists with the same URL", async () => {
|
||||
@@ -865,7 +865,7 @@ describe("github tool", () => {
|
||||
expect(dump).toContain(`branch.race-test.key${idx} value-${idx}`);
|
||||
}
|
||||
} finally {
|
||||
await fs.rm(repoRoot, { recursive: true, force: true });
|
||||
await removeWithRetries(repoRoot);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -879,7 +879,7 @@ describe("github tool", () => {
|
||||
});
|
||||
afterAll(async () => {
|
||||
await tempHome.cleanup();
|
||||
await fs.rm(fixture.baseDir, { recursive: true, force: true });
|
||||
await removeWithRetries(fixture.baseDir);
|
||||
});
|
||||
|
||||
it("checks out multiple pull requests in a single call when pr is an array", async () => {
|
||||
@@ -946,7 +946,7 @@ describe("github tool", () => {
|
||||
runGit(fixture.repoRoot, ["commit", "-m", "manual branch commit"]);
|
||||
});
|
||||
afterAll(async () => {
|
||||
await fs.rm(fixture.baseDir, { recursive: true, force: true });
|
||||
await removeWithRetries(fixture.baseDir);
|
||||
});
|
||||
|
||||
it("rejects PR pushes from branches without checkout metadata", async () => {
|
||||
@@ -1049,7 +1049,7 @@ describe("github tool", () => {
|
||||
expect(artifactText).toContain("epsilon");
|
||||
expect(artifactText).toContain("zeta");
|
||||
} finally {
|
||||
await fs.rm(artifactsDir, { recursive: true, force: true });
|
||||
await removeWithRetries(artifactsDir);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@@ -21,6 +21,7 @@ import {
|
||||
} from "@oh-my-pi/pi-coding-agent/tools/github-cache";
|
||||
import { ToolAbortError, throwIfAborted } from "@oh-my-pi/pi-coding-agent/tools/tool-errors";
|
||||
import * as git from "@oh-my-pi/pi-coding-agent/utils/git";
|
||||
import { removeWithRetries } from "@oh-my-pi/pi-utils";
|
||||
|
||||
const TEST_REPO = "owner/example";
|
||||
const TEST_AUTH_KEY = "test-auth";
|
||||
@@ -43,7 +44,7 @@ afterEach(async () => {
|
||||
process.env.OMP_GITHUB_CACHE_DB = originalEnv;
|
||||
}
|
||||
vi.restoreAllMocks();
|
||||
await fs.rm(tempDir, { recursive: true, force: true });
|
||||
await removeWithRetries(tempDir);
|
||||
});
|
||||
|
||||
function issuePayload(number: number, body: string) {
|
||||
|
||||
@@ -11,6 +11,7 @@ import {
|
||||
splitDelimitedPathEntry,
|
||||
} from "@oh-my-pi/pi-coding-agent/tools/path-utils";
|
||||
import type { Component } from "@oh-my-pi/pi-tui";
|
||||
import { removeWithRetries } from "@oh-my-pi/pi-utils";
|
||||
import { globToolRenderer } from "../../src/tools/glob";
|
||||
|
||||
let uiTheme: Theme;
|
||||
@@ -45,7 +46,7 @@ describe("delimited path expansion", () => {
|
||||
});
|
||||
|
||||
afterEach(async () => {
|
||||
await fs.rm(tempDir, { recursive: true, force: true });
|
||||
await removeWithRetries(tempDir);
|
||||
});
|
||||
|
||||
it("splits comma, semicolon, and space delimited entries when parts resolve", async () => {
|
||||
|
||||
@@ -17,6 +17,7 @@ import { AgentRegistry } from "@oh-my-pi/pi-coding-agent/registry/agent-registry
|
||||
import * as sshFileTransfer from "@oh-my-pi/pi-coding-agent/ssh/file-transfer";
|
||||
import type { ToolSession } from "@oh-my-pi/pi-coding-agent/tools";
|
||||
import { ReadTool } from "@oh-my-pi/pi-coding-agent/tools/read";
|
||||
import { removeWithRetries } from "@oh-my-pi/pi-utils";
|
||||
import { GlobTool } from "../../src/tools/glob";
|
||||
import { GrepTool } from "../../src/tools/grep";
|
||||
|
||||
@@ -90,7 +91,7 @@ describe("GrepTool internal URL resolution", () => {
|
||||
});
|
||||
|
||||
afterEach(async () => {
|
||||
await fs.rm(tmpDir, { recursive: true, force: true });
|
||||
await removeWithRetries(tmpDir);
|
||||
AgentRegistry.resetGlobalForTests();
|
||||
LocalProtocolHandler.resetOverrideForTests();
|
||||
InternalUrlRouter.resetForTests();
|
||||
|
||||
@@ -5,6 +5,7 @@ import * as path from "node:path";
|
||||
import { Settings } from "@oh-my-pi/pi-coding-agent/config/settings";
|
||||
import { GrepTool, type ToolSession } from "@oh-my-pi/pi-coding-agent/tools";
|
||||
import { ToolError } from "@oh-my-pi/pi-coding-agent/tools/tool-errors";
|
||||
import { removeWithRetries } from "@oh-my-pi/pi-utils";
|
||||
|
||||
function createTestSession(cwd: string, overrides: Partial<ToolSession> = {}): ToolSession {
|
||||
return {
|
||||
@@ -26,7 +27,7 @@ describe("search tool invalid regex handling", () => {
|
||||
});
|
||||
|
||||
afterEach(async () => {
|
||||
await fs.rm(cwd, { recursive: true, force: true });
|
||||
await removeWithRetries(cwd);
|
||||
});
|
||||
|
||||
it("wraps invalid regex pattern errors in a ToolError", async () => {
|
||||
|
||||
@@ -20,6 +20,7 @@ import type { SessionEntry, SessionTreeNode } from "@oh-my-pi/pi-coding-agent/se
|
||||
import { ToolChoiceQueue } from "@oh-my-pi/pi-coding-agent/session/tool-choice-queue";
|
||||
import { createTools, type ToolSession } from "@oh-my-pi/pi-coding-agent/tools";
|
||||
import { Text } from "@oh-my-pi/pi-tui";
|
||||
import { removeWithRetries } from "@oh-my-pi/pi-utils";
|
||||
import { grepToolRenderer } from "../../src/tools/grep";
|
||||
|
||||
function createTestSession(cwd: string, overrides: Partial<ToolSession> = {}): ToolSession {
|
||||
@@ -137,7 +138,7 @@ describe("tool path arrays", () => {
|
||||
});
|
||||
|
||||
afterAll(async () => {
|
||||
await fs.rm(tempDir, { recursive: true, force: true });
|
||||
await removeWithRetries(tempDir);
|
||||
resetSettingsForTest();
|
||||
});
|
||||
|
||||
@@ -279,7 +280,7 @@ describe("tool path arrays", () => {
|
||||
paths: ["apps/[id]"],
|
||||
});
|
||||
expect(getText(dir)).toContain("bracket-needle");
|
||||
await fs.rm(tmp, { recursive: true, force: true });
|
||||
await removeWithRetries(tmp);
|
||||
});
|
||||
|
||||
it("grep pending renderer accepts a single string path", () => {
|
||||
@@ -373,7 +374,7 @@ describe("tool path arrays", () => {
|
||||
// single-string `paths` arg shows up as the "in <paths>" scope meta on the
|
||||
// pending call line (a completed result merges the call line away).
|
||||
expect(rendered).toContain("in folder with spaces/");
|
||||
await fs.rm(tmp, { recursive: true, force: true });
|
||||
await removeWithRetries(tmp);
|
||||
});
|
||||
|
||||
it("tree selector renders a single-string grep path summary", () => {
|
||||
@@ -500,7 +501,7 @@ describe("tool path arrays", () => {
|
||||
expect(text).toContain("Successfully wrote 8 bytes to written.txt");
|
||||
expect(text).not.toContain(tmp);
|
||||
expect(await Bun.file(absoluteTarget).text()).toBe("written\n");
|
||||
await fs.rm(tmp, { recursive: true, force: true });
|
||||
await removeWithRetries(tmp);
|
||||
});
|
||||
|
||||
it("read expands comma-delimited paths", async () => {
|
||||
@@ -648,7 +649,7 @@ describe("tool path arrays", () => {
|
||||
);
|
||||
expect(await Bun.file(path.join(tmp, "phases", "ast.ts")).text()).toContain("modernWrap(phasesValue, phasesArg)");
|
||||
expect(await Bun.file(path.join(tmp, "other", "ast.ts")).text()).toContain("legacyWrap(otherValue, otherArg)");
|
||||
await fs.rm(tmp, { recursive: true, force: true });
|
||||
await removeWithRetries(tmp);
|
||||
});
|
||||
|
||||
it("find accepts explicit path arrays", async () => {
|
||||
@@ -787,7 +788,7 @@ describe("tool path arrays", () => {
|
||||
expect(details?.files).toEqual([expectedPath]);
|
||||
expect(details?.scopePath).toBe(outsideDir.replace(/\\/g, "/"));
|
||||
} finally {
|
||||
await fs.rm(outsideDir, { recursive: true, force: true });
|
||||
await removeWithRetries(outsideDir);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -839,7 +840,7 @@ describe("tool path arrays", () => {
|
||||
expect(text).not.toContain("nested");
|
||||
expect(details?.fileCount).toBe(2);
|
||||
expect(details?.scopePath).toBe("alpha.txt, beta.txt");
|
||||
await fs.rm(tmp, { recursive: true, force: true });
|
||||
await removeWithRetries(tmp);
|
||||
});
|
||||
|
||||
it("grep renders only file headings that have child lines", async () => {
|
||||
@@ -888,6 +889,6 @@ describe("tool path arrays", () => {
|
||||
expect(text).toMatch(/ 1:#if FLAG/);
|
||||
expect(text).toMatch(/\*2:needle/);
|
||||
expect(text).toMatch(/ 3:#endif/);
|
||||
await fs.rm(tmp, { recursive: true, force: true });
|
||||
await removeWithRetries(tmp);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import { afterEach, describe, expect, it } from "bun:test";
|
||||
import * as fs from "node:fs/promises";
|
||||
import type { Model } from "@oh-my-pi/pi-ai";
|
||||
import type { ModelRegistry } from "@oh-my-pi/pi-coding-agent/config/model-registry";
|
||||
import type { CustomToolContext } from "@oh-my-pi/pi-coding-agent/extensibility/custom-tools";
|
||||
@@ -10,12 +9,13 @@ import {
|
||||
imageGenTool,
|
||||
setPreferredImageProvider,
|
||||
} from "@oh-my-pi/pi-coding-agent/tools/image-gen";
|
||||
import { removeWithRetries } from "@oh-my-pi/pi-utils";
|
||||
|
||||
const originalOpenRouterKey = Bun.env.OPENROUTER_API_KEY;
|
||||
const generatedImagePaths: string[] = [];
|
||||
|
||||
afterEach(async () => {
|
||||
await Promise.all(generatedImagePaths.splice(0).map(imagePath => fs.rm(imagePath, { force: true })));
|
||||
await Promise.all(generatedImagePaths.splice(0).map(imagePath => removeWithRetries(imagePath)));
|
||||
if (originalOpenRouterKey === undefined) {
|
||||
delete Bun.env.OPENROUTER_API_KEY;
|
||||
} else {
|
||||
|
||||
@@ -13,7 +13,7 @@ import type { ToolSession } from "@oh-my-pi/pi-coding-agent/tools";
|
||||
import { InspectImageTool } from "@oh-my-pi/pi-coding-agent/tools/inspect-image";
|
||||
import { inspectImageToolRenderer } from "@oh-my-pi/pi-coding-agent/tools/inspect-image-renderer";
|
||||
import { toolRenderers } from "@oh-my-pi/pi-coding-agent/tools/renderers";
|
||||
import { sanitizeText } from "@oh-my-pi/pi-utils";
|
||||
import { removeSyncWithRetries, sanitizeText } from "@oh-my-pi/pi-utils";
|
||||
import { type } from "arktype";
|
||||
|
||||
const TINY_PNG_BASE64 =
|
||||
@@ -129,7 +129,7 @@ describe("InspectImageTool", () => {
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
fs.rmSync(testDir, { recursive: true, force: true });
|
||||
removeSyncWithRetries(testDir);
|
||||
});
|
||||
|
||||
it("sends image and question to completeSimple and returns text-only result", async () => {
|
||||
|
||||
@@ -5,6 +5,7 @@ import * as path from "node:path";
|
||||
import { Settings } from "@oh-my-pi/pi-coding-agent/config/settings";
|
||||
import { createTools, type ToolSession } from "@oh-my-pi/pi-coding-agent/tools";
|
||||
import { resolveExplicitSearchPaths } from "@oh-my-pi/pi-coding-agent/tools/path-utils";
|
||||
import { removeWithRetries } from "@oh-my-pi/pi-utils";
|
||||
|
||||
const isWindows = process.platform === "win32";
|
||||
|
||||
@@ -53,7 +54,7 @@ describe.skipIf(isWindows)("search with omitted paths", () => {
|
||||
});
|
||||
|
||||
afterEach(async () => {
|
||||
await fs.rm(cwd, { recursive: true, force: true });
|
||||
await removeWithRetries(cwd);
|
||||
});
|
||||
|
||||
it("defaults to the workspace root when paths is omitted", async () => {
|
||||
@@ -103,11 +104,7 @@ describe.skipIf(isWindows)("search across unrelated filesystem trees", () => {
|
||||
});
|
||||
|
||||
afterEach(async () => {
|
||||
await Promise.all([
|
||||
fs.rm(dirA, { recursive: true, force: true }),
|
||||
fs.rm(dirB, { recursive: true, force: true }),
|
||||
fs.rm(cwd, { recursive: true, force: true }),
|
||||
]);
|
||||
await Promise.all([removeWithRetries(dirA), removeWithRetries(dirB), removeWithRetries(cwd)]);
|
||||
});
|
||||
|
||||
it("returns matches from both trees without rooting the scan at /", async () => {
|
||||
@@ -151,7 +148,7 @@ describe.skipIf(isWindows)("resolveExplicitSearchPaths shared non-root ancestor"
|
||||
});
|
||||
|
||||
afterEach(async () => {
|
||||
await fs.rm(parent, { recursive: true, force: true });
|
||||
await removeWithRetries(parent);
|
||||
});
|
||||
|
||||
it("fans out per-path targets instead of walking the unrequested ancestor", async () => {
|
||||
@@ -198,7 +195,7 @@ describe.skipIf(isWindows)("search with explicit walker-pruned file targets", ()
|
||||
});
|
||||
|
||||
afterEach(async () => {
|
||||
await fs.rm(repo, { recursive: true, force: true });
|
||||
await removeWithRetries(repo);
|
||||
});
|
||||
|
||||
it("matches inside an explicit .git/config target alongside a directory scope", async () => {
|
||||
|
||||
@@ -4,6 +4,7 @@ import * as os from "node:os";
|
||||
import * as path from "node:path";
|
||||
import { Settings } from "@oh-my-pi/pi-coding-agent/config/settings";
|
||||
import { createTools, type ToolSession } from "@oh-my-pi/pi-coding-agent/tools";
|
||||
import { removeWithRetries } from "@oh-my-pi/pi-utils";
|
||||
|
||||
// Regression for grievances #208 (find) and #209 (search): a multi-path call
|
||||
// that includes an entry which does not exist on disk must not abort the whole
|
||||
@@ -39,7 +40,7 @@ describe("multi-path tools tolerate missing entries", () => {
|
||||
});
|
||||
|
||||
afterEach(async () => {
|
||||
await fs.rm(tempDir, { recursive: true, force: true });
|
||||
await removeWithRetries(tempDir);
|
||||
});
|
||||
|
||||
it("search returns matches from existing paths and reports the missing one", async () => {
|
||||
|
||||
@@ -5,6 +5,7 @@ import * as path from "node:path";
|
||||
import type { PlanModeState } from "@oh-my-pi/pi-coding-agent/plan-mode/state";
|
||||
import type { ToolSession } from "@oh-my-pi/pi-coding-agent/tools";
|
||||
import { enforcePlanModeWrite, resolvePlanPath } from "@oh-my-pi/pi-coding-agent/tools/plan-mode-guard";
|
||||
import { removeWithRetries } from "@oh-my-pi/pi-utils";
|
||||
|
||||
const ARTIFACTS_DIR = path.join(os.tmpdir(), "agent-artifacts");
|
||||
const REPO_ROOT = path.join(os.tmpdir(), "repo");
|
||||
@@ -126,7 +127,7 @@ describe("enforcePlanModeWrite accepts absolute local-sandbox paths", () => {
|
||||
const absolute = resolvePlanPath(session, "local://my-plan.md");
|
||||
expect(() => enforcePlanModeWrite(session, absolute, { op: "update" })).not.toThrow();
|
||||
} finally {
|
||||
await fs.rm(artifactsDir, { recursive: true, force: true });
|
||||
await removeWithRetries(artifactsDir);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -142,7 +143,7 @@ describe("enforcePlanModeWrite accepts absolute local-sandbox paths", () => {
|
||||
expect(() => enforcePlanModeWrite(session, `[${absolute}]`, { op: "update" })).not.toThrow();
|
||||
expect(() => enforcePlanModeWrite(session, `[local://my-plan.md#ABCD]`, { op: "update" })).not.toThrow();
|
||||
} finally {
|
||||
await fs.rm(artifactsDir, { recursive: true, force: true });
|
||||
await removeWithRetries(artifactsDir);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@ import * as path from "node:path";
|
||||
import { Settings } from "@oh-my-pi/pi-coding-agent/config/settings";
|
||||
import type { ToolSession } from "@oh-my-pi/pi-coding-agent/tools";
|
||||
import { ReadTool } from "@oh-my-pi/pi-coding-agent/tools/read";
|
||||
import { Snowflake } from "@oh-my-pi/pi-utils";
|
||||
import { removeSyncWithRetries, Snowflake } from "@oh-my-pi/pi-utils";
|
||||
|
||||
function getTextOutput(result: { content: Array<{ type: string; text?: string }> }): string {
|
||||
return result.content
|
||||
@@ -43,7 +43,7 @@ describe("read tool directory listings honor line selectors (regression: was sil
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
fs.rmSync(testDir, { recursive: true, force: true });
|
||||
removeSyncWithRetries(testDir);
|
||||
});
|
||||
|
||||
it("returns the full listing when no selector is given", async () => {
|
||||
|
||||
@@ -6,7 +6,7 @@ import { Settings } from "@oh-my-pi/pi-coding-agent/config/settings";
|
||||
import type { ToolSession } from "@oh-my-pi/pi-coding-agent/tools";
|
||||
import { ReadTool } from "@oh-my-pi/pi-coding-agent/tools/read";
|
||||
import { ToolAbortError } from "@oh-my-pi/pi-coding-agent/tools/tool-errors";
|
||||
import { Snowflake } from "@oh-my-pi/pi-utils";
|
||||
import { removeSyncWithRetries, Snowflake } from "@oh-my-pi/pi-utils";
|
||||
|
||||
function getTextOutput(result: { content: Array<{ type: string; text?: string }> }): string {
|
||||
return result.content
|
||||
@@ -52,7 +52,7 @@ describe("plain-file and directory reads ignore an already-aborted signal", () =
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
fs.rmSync(testDir, { recursive: true, force: true });
|
||||
removeSyncWithRetries(testDir);
|
||||
});
|
||||
|
||||
it("returns a plain-file line range with an aborted signal", async () => {
|
||||
|
||||
@@ -15,6 +15,7 @@ import { Settings } from "@oh-my-pi/pi-coding-agent/config/settings";
|
||||
import { InternalUrlRouter, LocalProtocolHandler, parseInternalUrl } from "@oh-my-pi/pi-coding-agent/internal-urls";
|
||||
import type { ToolSession } from "@oh-my-pi/pi-coding-agent/tools";
|
||||
import { ReadTool } from "@oh-my-pi/pi-coding-agent/tools/read";
|
||||
import { removeWithRetries } from "@oh-my-pi/pi-utils";
|
||||
|
||||
// 1x1 transparent PNG — small enough to pass through image loading untouched.
|
||||
const TINY_PNG = Buffer.from(
|
||||
@@ -62,7 +63,7 @@ describe("read local:// images", () => {
|
||||
afterEach(async () => {
|
||||
LocalProtocolHandler.resetOverrideForTests();
|
||||
InternalUrlRouter.resetForTests();
|
||||
await fs.rm(testDir, { recursive: true, force: true });
|
||||
await removeWithRetries(testDir);
|
||||
});
|
||||
|
||||
it("decodes a local:// PNG into an inline image block", async () => {
|
||||
|
||||
@@ -14,7 +14,7 @@ import { Settings } from "@oh-my-pi/pi-coding-agent/config/settings";
|
||||
import type { ToolSession } from "@oh-my-pi/pi-coding-agent/tools";
|
||||
import { ReadTool } from "@oh-my-pi/pi-coding-agent/tools/read";
|
||||
import * as markit from "@oh-my-pi/pi-coding-agent/utils/markit";
|
||||
import { Snowflake } from "@oh-my-pi/pi-utils";
|
||||
import { removeSyncWithRetries, Snowflake } from "@oh-my-pi/pi-utils";
|
||||
|
||||
// 1x1 transparent PNG — small enough to pass through image loading untouched.
|
||||
const TINY_PNG = Buffer.from(
|
||||
@@ -59,7 +59,7 @@ describe("read PDF image extraction", () => {
|
||||
});
|
||||
afterEach(() => {
|
||||
vi.restoreAllMocks();
|
||||
fs.rmSync(testDir, { recursive: true, force: true });
|
||||
removeSyncWithRetries(testDir);
|
||||
});
|
||||
|
||||
it("rewrites image placeholders into browse handles on a full read", async () => {
|
||||
|
||||
@@ -13,7 +13,7 @@ import { Markit } from "@oh-my-pi/pi-coding-agent/markit";
|
||||
import type { ToolSession } from "@oh-my-pi/pi-coding-agent/tools";
|
||||
import { ReadTool } from "@oh-my-pi/pi-coding-agent/tools/read";
|
||||
import * as markit from "@oh-my-pi/pi-coding-agent/utils/markit";
|
||||
import { __resetDirsFromEnvForTests, Snowflake, setAgentDir } from "@oh-my-pi/pi-utils";
|
||||
import { __resetDirsFromEnvForTests, removeSyncWithRetries, setAgentDir, Snowflake } from "@oh-my-pi/pi-utils";
|
||||
|
||||
function restoreEnv(key: string, value: string | undefined): void {
|
||||
if (value === undefined) {
|
||||
@@ -52,7 +52,7 @@ describe("read PDF with a line-range selector", () => {
|
||||
});
|
||||
afterEach(() => {
|
||||
vi.restoreAllMocks();
|
||||
fs.rmSync(testDir, { recursive: true, force: true });
|
||||
removeSyncWithRetries(testDir);
|
||||
});
|
||||
|
||||
it("honours `:N-M` against the converted markdown body", async () => {
|
||||
|
||||
@@ -6,6 +6,7 @@ import { Settings } from "@oh-my-pi/pi-coding-agent/config/settings";
|
||||
import { ToolChoiceQueue } from "@oh-my-pi/pi-coding-agent/session/tool-choice-queue";
|
||||
import { createTools, type ToolSession } from "@oh-my-pi/pi-coding-agent/tools";
|
||||
import { resolveToCwd } from "@oh-my-pi/pi-coding-agent/tools/path-utils";
|
||||
import { removeWithRetries } from "@oh-my-pi/pi-utils";
|
||||
|
||||
function createTestSession(cwd: string, overrides: Partial<ToolSession> = {}): ToolSession {
|
||||
return {
|
||||
@@ -38,7 +39,7 @@ describe("tool path root alias", () => {
|
||||
});
|
||||
|
||||
afterEach(async () => {
|
||||
await fs.rm(tempDir, { recursive: true, force: true });
|
||||
await removeWithRetries(tempDir);
|
||||
});
|
||||
|
||||
it("resolves a bare slash to the session cwd", () => {
|
||||
|
||||
@@ -3,6 +3,7 @@ import { afterAll, beforeAll, describe, expect, it } from "bun:test";
|
||||
import * as fs from "node:fs/promises";
|
||||
import * as os from "node:os";
|
||||
import * as path from "node:path";
|
||||
import { removeWithRetries } from "@oh-my-pi/pi-utils";
|
||||
import "@oh-my-pi/pi-coding-agent/tools/renderers";
|
||||
import { Settings } from "@oh-my-pi/pi-coding-agent/config/settings";
|
||||
import { ReadTool } from "@oh-my-pi/pi-coding-agent/tools/read";
|
||||
@@ -178,7 +179,7 @@ describe("SQLite tool support", () => {
|
||||
} else {
|
||||
Bun.env.PI_EDIT_VARIANT = originalEditVariant;
|
||||
}
|
||||
await fs.rm(tmpDir, { recursive: true, force: true });
|
||||
await removeWithRetries(tmpDir);
|
||||
});
|
||||
|
||||
it("parses SQLite path candidates at the extension boundary", () => {
|
||||
|
||||
@@ -10,6 +10,7 @@ import type { ToolSession } from "@oh-my-pi/pi-coding-agent/tools";
|
||||
import { astGrepToolRenderer } from "@oh-my-pi/pi-coding-agent/tools/ast-grep";
|
||||
import { ReadTool, readToolRenderer } from "@oh-my-pi/pi-coding-agent/tools/read";
|
||||
import { WriteTool, writeToolRenderer } from "@oh-my-pi/pi-coding-agent/tools/write";
|
||||
import { removeSyncWithRetries } from "@oh-my-pi/pi-utils";
|
||||
import { grepToolRenderer } from "../../src/tools/grep";
|
||||
|
||||
// 1x1 PNG so the read tool takes its image branch.
|
||||
@@ -81,7 +82,7 @@ describe("tool output OSC 8 file:// hyperlinks", () => {
|
||||
expect(extractLinkUris(textRender)).toContain(url.pathToFileURL(path.resolve(textPath)).href);
|
||||
expect(extractLinkUris(imgRender)).toContain(url.pathToFileURL(path.resolve(imgPath)).href);
|
||||
} finally {
|
||||
fs.rmSync(dir, { recursive: true, force: true });
|
||||
removeSyncWithRetries(dir);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -104,7 +105,7 @@ describe("tool output OSC 8 file:// hyperlinks", () => {
|
||||
.join("\n");
|
||||
expect(extractLinkUris(rendered)).toContain(url.pathToFileURL(path.resolve(filePath)).href);
|
||||
} finally {
|
||||
fs.rmSync(dir, { recursive: true, force: true });
|
||||
removeSyncWithRetries(dir);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@@ -13,6 +13,7 @@ import {
|
||||
searchExa,
|
||||
synthesizeAnswer,
|
||||
} from "@oh-my-pi/pi-coding-agent/web/search/providers/exa";
|
||||
import { removeWithRetries } from "@oh-my-pi/pi-utils";
|
||||
|
||||
async function withLocalAuthStorage<T>(run: (authStorage: AuthStorage) => Promise<T>): Promise<T> {
|
||||
const dir = await fs.mkdtemp(path.join(os.tmpdir(), "web-search-exa-auth-"));
|
||||
@@ -21,7 +22,7 @@ async function withLocalAuthStorage<T>(run: (authStorage: AuthStorage) => Promis
|
||||
return await run(authStorage);
|
||||
} finally {
|
||||
authStorage.close();
|
||||
await fs.rm(dir, { recursive: true, force: true });
|
||||
await removeWithRetries(dir);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@ import type { FetchImpl } from "@oh-my-pi/pi-ai/types";
|
||||
import { resetSettingsForTest, Settings } from "@oh-my-pi/pi-coding-agent/config/settings";
|
||||
import { searchSearXNG } from "@oh-my-pi/pi-coding-agent/web/search/providers/searxng";
|
||||
import { SearchProviderError } from "@oh-my-pi/pi-coding-agent/web/search/types";
|
||||
import { removeWithRetries } from "@oh-my-pi/pi-utils";
|
||||
|
||||
describe("SearXNG web search provider", () => {
|
||||
afterEach(() => {
|
||||
@@ -90,7 +91,7 @@ describe("SearXNG web search provider", () => {
|
||||
`Basic ${Buffer.from("alice:s3cret", "utf-8").toString("base64")}`,
|
||||
);
|
||||
} finally {
|
||||
await fs.rm(agentDir, { recursive: true, force: true });
|
||||
await removeWithRetries(agentDir);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
Reference in New Issue
Block a user