Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
8 changes: 8 additions & 0 deletions index.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1089,6 +1089,14 @@ describe("ToolContext path resolution", () => {
rmSync(tempRoot, { recursive: true, force: true });
}
});

test("morph_edit file IO avoids Bun runtime globals", () => {
const source = readFileSync(join(import.meta.dir, "index.ts"), "utf-8");

expect(source).toContain('from "node:fs/promises"');
expect(source).not.toContain("Bun.file");
expect(source).not.toContain("Bun.write");
});
});

describe("formatWarpGrepResult edge cases", () => {
Expand Down
35 changes: 25 additions & 10 deletions index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import { type Plugin, tool } from "@opencode-ai/plugin";
import { MorphClient, WarpGrepClient, CompactClient } from "@morphllm/morphsdk";
import type { WarpGrepResult, CompactResult } from "@morphllm/morphsdk";
import type { Part, TextPart, ToolPart, Message } from "@opencode-ai/sdk";
import { readFile, writeFile } from "node:fs/promises";
import { isAbsolute, resolve as resolvePath } from "node:path";

// API key from MORPH_API_KEY env var, or the `morph.apiKey` field in
Expand Down Expand Up @@ -369,6 +370,14 @@ function resolveSessionFilepath(
: resolvePath(sessionDirectory, targetFilepath);
}

function isFileNotFoundError(error: unknown): boolean {
return (
error instanceof Error &&
"code" in error &&
(error as { code?: string }).code === "ENOENT"
);
}

function resolveSessionRepoRoot(
sessionDirectory: string,
sessionWorktree: string,
Expand Down Expand Up @@ -952,19 +961,25 @@ Alternatively, use the native 'edit' tool for this change.`;
// Read the original file
let originalCode: string;
try {
const file = Bun.file(filepath);
if (!(await file.exists())) {
if (!normalizedCodeEdit.includes(EXISTING_CODE_MARKER)) {
await Bun.write(filepath, normalizedCodeEdit);
return `Created new file: ${target_filepath}\n\nLines: ${normalizedCodeEdit.split("\n").length}`;
}
return `Error: File not found: ${target_filepath}
originalCode = await readFile(filepath, "utf8");
} catch (err) {
if (isFileNotFoundError(err)) {
if (normalizedCodeEdit.includes(EXISTING_CODE_MARKER)) {
return `Error: File not found: ${target_filepath}

The file doesn't exist and the code_edit contains lazy markers.
For new files, provide the complete content without "${EXISTING_CODE_MARKER}" markers.`;
}

try {
await writeFile(filepath, normalizedCodeEdit, "utf8");
} catch (writeErr) {
const error = writeErr as Error;
return `Error writing file ${target_filepath}: ${error.message}`;
}
return `Created new file: ${target_filepath}\n\nLines: ${normalizedCodeEdit.split("\n").length}`;
}
originalCode = await file.text();
} catch (err) {

const error = err as Error;
return `Error reading file ${target_filepath}: ${error.message}`;
}
Expand Down Expand Up @@ -1072,7 +1087,7 @@ Options:

// Write the merged result
try {
await Bun.write(filepath, mergedCode);
await writeFile(filepath, mergedCode, "utf8");
} catch (err) {
const error = err as Error;
return `Error writing file ${target_filepath}: ${error.message}`;
Expand Down