diff --git a/packages/coding-agent/CHANGELOG.md b/packages/coding-agent/CHANGELOG.md index 0174fce36..8e1b632be 100644 --- a/packages/coding-agent/CHANGELOG.md +++ b/packages/coding-agent/CHANGELOG.md @@ -5,6 +5,7 @@ ### Fixed - Fixed remote or LAN local-engine endpoints being ignored during model discovery: the llama.cpp and Ollama probes used timeouts tuned for loopback, so a host reached over the network could exceed them and return no models, while changing `OLLAMA_BASE_URL`/`OLLAMA_HOST` could keep reusing a fresh cache from the previous endpoint. Non-loopback hosts now get a generous discovery timeout, and Ollama cache rows are scoped to the normalized endpoint ([#7087](https://github.com/can1357/oh-my-pi/issues/7087)). +- Fixed `omp install` failing extension validation for pi extensions that import `createEditTool` or `createWriteTool` (e.g. gentle-pi) — the legacy `@oh-my-pi/pi-coding-agent` shim exported the read/bash/grep/find/ls tool factories but omitted the edit and write ones, so a named import threw Bun's static "Export named X not found" error. Added `createEditTool`/`createEditToolDefinition` and `createWriteTool`/`createWriteToolDefinition` to match the upstream pi surface ([#7094](https://github.com/can1357/oh-my-pi/issues/7094)). ## [17.2.0] - 2026-07-30 diff --git a/packages/coding-agent/src/extensibility/legacy-pi-coding-agent-shim.ts b/packages/coding-agent/src/extensibility/legacy-pi-coding-agent-shim.ts index 36e755eab..6c7857963 100644 --- a/packages/coding-agent/src/extensibility/legacy-pi-coding-agent-shim.ts +++ b/packages/coding-agent/src/extensibility/legacy-pi-coding-agent-shim.ts @@ -140,6 +140,25 @@ export interface LsToolOptions { operations?: LsOperations; } +export interface EditOperations { + readFile: (absolutePath: string) => Promise; + writeFile: (absolutePath: string, content: string) => Promise; + access: (absolutePath: string) => Promise; +} + +export interface EditToolOptions { + operations?: EditOperations; +} + +export interface WriteOperations { + writeFile: (absolutePath: string, content: string) => Promise; + mkdir: (dir: string) => Promise; +} + +export interface WriteToolOptions { + operations?: WriteOperations; +} + const legacyBashSchema = Type.Object({ command: Type.String({ description: "Bash command to execute" }), timeout: Type.Optional(Type.Number({ description: "Timeout in seconds" })), @@ -636,6 +655,40 @@ export function createLsTool(cwd: string, options?: LsToolOptions): ToolDefiniti return createLsToolDefinition(cwd, options); } +/** Create the legacy edit tool definition. */ +export function createEditToolDefinition(cwd: string, options?: EditToolOptions): ToolDefinition { + if (options?.operations) { + throw new Error( + "Legacy EditToolOptions.operations is not supported: OMP's built-in edit tool writes the local " + + "filesystem natively and exposes no pluggable operations seam. Register a custom edit tool via " + + "defineTool() instead of passing operations to createEditTool()/createEditToolDefinition().", + ); + } + return legacyBuiltinTool(cwd, "edit"); +} + +/** Create the legacy edit tool. */ +export function createEditTool(cwd: string, options?: EditToolOptions): ToolDefinition { + return createEditToolDefinition(cwd, options); +} + +/** Create the legacy write tool definition. */ +export function createWriteToolDefinition(cwd: string, options?: WriteToolOptions): ToolDefinition { + if (options?.operations) { + throw new Error( + "Legacy WriteToolOptions.operations is not supported: OMP's built-in write tool writes the local " + + "filesystem natively and exposes no pluggable operations seam. Register a custom write tool via " + + "defineTool() instead of passing operations to createWriteTool()/createWriteToolDefinition().", + ); + } + return legacyBuiltinTool(cwd, "write"); +} + +/** Create the legacy write tool. */ +export function createWriteTool(cwd: string, options?: WriteToolOptions): ToolDefinition { + return createWriteToolDefinition(cwd, options); +} + /** Create legacy read, bash, edit, and write tools. */ export function createCodingTools(cwd: string): ToolDefinition[] { return LEGACY_CODING_TOOL_NAMES.map(name => legacyBuiltinTool(cwd, name)); diff --git a/packages/coding-agent/test/extensibility/legacy-pi-edit-write-tools.test.ts b/packages/coding-agent/test/extensibility/legacy-pi-edit-write-tools.test.ts new file mode 100644 index 000000000..5f06cd15c --- /dev/null +++ b/packages/coding-agent/test/extensibility/legacy-pi-edit-write-tools.test.ts @@ -0,0 +1,38 @@ +import { describe, expect, it } from "bun:test"; +import * as shim from "@oh-my-pi/pi-coding-agent/extensibility/legacy-pi-coding-agent-shim"; + +// Issue #7094: pi extensions import the edit/write tool factories +// (`createEditTool`, `createEditToolDefinition`, `createWriteTool`, +// `createWriteToolDefinition`) from `@earendil-works/pi-coding-agent`, which +// aliases to this shim. The shim exported the other five tool factories +// (read/bash/grep/find/ls) but omitted edit and write, so a named import of +// either threw Bun's static "Export named X not found" error and any importing +// extension (e.g. gentle-pi) failed validation. These pin the factory surface +// and the tool definitions they build. +describe("legacy shim edit/write tool factories", () => { + it("exports the edit/write factories as callable functions", () => { + expect(typeof shim.createEditTool).toBe("function"); + expect(typeof shim.createEditToolDefinition).toBe("function"); + expect(typeof shim.createWriteTool).toBe("function"); + expect(typeof shim.createWriteToolDefinition).toBe("function"); + }); + + it("builds edit and write tool definitions bound to the built-in tools", () => { + const edit = shim.createEditTool(process.cwd()); + expect(edit.name).toBe("edit"); + expect(typeof edit.execute).toBe("function"); + + const write = shim.createWriteTool(process.cwd()); + expect(write.name).toBe("write"); + expect(typeof write.execute).toBe("function"); + }); + + it("rejects the unsupported operations seam", () => { + expect(() => shim.createEditTool(process.cwd(), { operations: {} as never })).toThrow( + /operations is not supported/, + ); + expect(() => shim.createWriteTool(process.cwd(), { operations: {} as never })).toThrow( + /operations is not supported/, + ); + }); +});