fix(coding-agent): speed up external editor launch (#6903)
* fix(coding-agent): speed up external editor launch Fixes #6774 * refactor(coding-agent): clarify external editor handling * refactor(coding-agent): simplify external editor result * refactor(coding-agent): model external editor lifecycle * fix(coding-agent): rename external editor test fake * fix(coding-agent): secure external editor temp files * fix(coding-agent): simplify external editor temp path * fix(coding-agent): restore system temp editor files
This commit is contained in:
@@ -0,0 +1,63 @@
|
||||
import { existsSync, mkdtempSync, readFileSync, rmSync } from "node:fs";
|
||||
import { tmpdir } from "node:os";
|
||||
import { basename, dirname, join } from "node:path";
|
||||
import { fileURLToPath } from "node:url";
|
||||
import { describe, expect, it } from "vitest";
|
||||
import { type ExternalEditorResult, editInExternalEditor } from "../src/modes/interactive/external-editor.ts";
|
||||
|
||||
const editorFixturePath = fileURLToPath(new URL("./fixtures/fake-external-editor.mjs", import.meta.url));
|
||||
|
||||
interface EditorCapture {
|
||||
filePath: string;
|
||||
content: string;
|
||||
entries: string[];
|
||||
directoryMode: number;
|
||||
}
|
||||
|
||||
async function runExternalEditor(fixtureFlag?: "--fail" | "--empty"): Promise<{
|
||||
result: ExternalEditorResult;
|
||||
capture: EditorCapture;
|
||||
}> {
|
||||
const testDirectory = mkdtempSync(join(tmpdir(), "pi-external-editor-test-"));
|
||||
const capturePath = join(testDirectory, "capture.json");
|
||||
try {
|
||||
const result = await editInExternalEditor({
|
||||
command: `${process.execPath} ${editorFixturePath} ${capturePath}${fixtureFlag ? ` ${fixtureFlag}` : ""}`,
|
||||
content: "original",
|
||||
});
|
||||
const capture = JSON.parse(readFileSync(capturePath, "utf-8")) as EditorCapture;
|
||||
return { result, capture };
|
||||
} finally {
|
||||
rmSync(testDirectory, { recursive: true, force: true });
|
||||
}
|
||||
}
|
||||
|
||||
describe("editInExternalEditor", () => {
|
||||
it("edits a prompt inside a private temporary directory", async () => {
|
||||
const { result, capture } = await runExternalEditor();
|
||||
const directory = dirname(capture.filePath);
|
||||
|
||||
expect(result).toEqual({ status: "complete", content: "edited" });
|
||||
expect(dirname(directory)).toBe(tmpdir());
|
||||
expect(basename(directory)).toMatch(/^pi-editor-.+$/);
|
||||
expect(basename(capture.filePath)).toBe("prompt.md");
|
||||
expect(capture.entries).toEqual(["prompt.md"]);
|
||||
expect(capture.content).toBe("original");
|
||||
if (process.platform !== "win32") {
|
||||
expect(capture.directoryMode & 0o077).toBe(0);
|
||||
}
|
||||
expect(existsSync(directory)).toBe(false);
|
||||
});
|
||||
|
||||
it("keeps the original content when the editor exits unsuccessfully", async () => {
|
||||
const { result, capture } = await runExternalEditor("--fail");
|
||||
|
||||
expect(result).toEqual({ status: "failed" });
|
||||
expect(existsSync(dirname(capture.filePath))).toBe(false);
|
||||
});
|
||||
it("returns empty content when the editor clears the prompt", async () => {
|
||||
const { result } = await runExternalEditor("--empty");
|
||||
|
||||
expect(result).toEqual({ status: "complete", content: "" });
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user