diff --git a/CHANGELOG.md b/CHANGELOG.md index 4c59086..3b35363 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,18 @@ # Changelog +## 1.0.1 — Direct tool access + +### Fixes + +- Restores `lightpanda` as a directly callable tool in OpenCode V2 by explicitly setting `codemode: false`. Previously, the V2 migration left it behind `execute`, unlike the built-in WebFetch tool. +- Keeps the existing tool name, inputs, permission action, and fetch behavior unchanged. + +### Tests + +- Adds a regression test requiring direct tool exposure. +- Tightens the OpenCode V2 smoke test to require a direct `lightpanda` call rather than accepting a nested Code Mode invocation. +- Gives the smoke test a distinct plugin ID so a globally installed copy cannot shadow the checkout under test. + ## 1.0.0 — OpenCode V2 migration This is the first published release for **OpenCode V2**. The major version marks a breaking plugin API migration, not a change to the Lightpanda tool's name or inputs. diff --git a/README.md b/README.md index b2f5b39..1cdda64 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,7 @@ A Lightpanda browser plugin/tool for OpenCode V2. It is like WebFetch tool on st | `1.x` | OpenCode V2, 2.0.18 or newer | | `0.2.2` | OpenCode V1 | -See [Migrating from 0.x](#migrating-from-0x) and the [1.0.0 release notes](CHANGELOG.md). +See [Migrating from 0.x](#migrating-from-0x) and the [release notes](CHANGELOG.md). ## Features @@ -29,7 +29,7 @@ See [Migrating from 0.x](#migrating-from-0x) and the [1.0.0 release notes](CHANG Install Lightpanda, then add the plugin globally: ```sh -opencode plugin add opencode-lightpanda@1.0.0 +opencode plugin add opencode-lightpanda@1.0.1 ``` To update an existing installation: @@ -45,7 +45,7 @@ If OpenCode cannot find Lightpanda, start it with `LIGHTPANDA_BIN` set to the ex ## Migrating from 0.x 1. Upgrade to [OpenCode V2](https://opencode.ai/v2/docs/migrate-v1) (2.0.18 or newer) before upgrading this plugin. The 1.x plugin uses the new `@opencode/plugin` API; it cannot run in OpenCode V1. -2. Install `opencode-lightpanda@1.0.0` with the command above. For a configuration-managed installation, replace any pinned 0.x package entry with the V2 package: +2. Install `opencode-lightpanda@1.0.1` with the command above. For a configuration-managed installation, replace any pinned 0.x package entry with the V2 package: ```json { @@ -100,7 +100,7 @@ Load the checkout directly by adding it to `~/.config/opencode/opencode.json`: ## Behavior -- Adds a distinct `lightpanda` tool with its own permission action. +- Adds a directly callable `lightpanda` tool with its own permission action; no Code Mode `execute` wrapper is required. - Returns an error for non-2xx responses and responses over 5 MB. - Reports concise TLS/DNS fetch failures from Lightpanda's JSON diagnostics, with a bounded stderr fallback. - Blocks private-network requests, including subresources initiated by page JavaScript. diff --git a/lightpanda.test.ts b/lightpanda.test.ts index c7f3fb5..31fc5b4 100644 --- a/lightpanda.test.ts +++ b/lightpanda.test.ts @@ -21,6 +21,7 @@ test("registers the V2 lightpanda tool and permission action", () => { expect(tools).toHaveLength(1) expect(lightpanda.name).toBe("lightpanda") expect(lightpanda.options?.permission).toBe("lightpanda") + expect(lightpanda.options?.codemode).toBe(false) expect(lightpanda.input).toMatchObject({ type: "object", required: ["url"], diff --git a/lightpanda.ts b/lightpanda.ts index 7261d22..5a352a3 100644 --- a/lightpanda.ts +++ b/lightpanda.ts @@ -53,7 +53,7 @@ For web searches, use html.duckduckgo.com instead of Google because Google block required: ["url"], additionalProperties: false, }, - options: { permission: "lightpanda" }, + options: { permission: "lightpanda", codemode: false }, execute: fetchPage, }) }) diff --git a/package.json b/package.json index 85f3fb1..b7512bc 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "opencode-lightpanda", - "version": "1.0.0", + "version": "1.0.1", "description": "Lightpanda-powered web fetching for OpenCode V2", "type": "module", "main": "lightpanda.ts", diff --git a/test/fixtures/smoke-plugin/index.ts b/test/fixtures/smoke-plugin/index.ts new file mode 100644 index 0000000..751364f --- /dev/null +++ b/test/fixtures/smoke-plugin/index.ts @@ -0,0 +1,4 @@ +import plugin from "../../../index" + +// Keep a globally installed copy from shadowing the checkout under test. +export default { ...plugin, id: "opencode-lightpanda-smoke" } diff --git a/test/smoke.ts b/test/smoke.ts index ed751d8..e8e140e 100644 --- a/test/smoke.ts +++ b/test/smoke.ts @@ -13,7 +13,7 @@ try { join(project, "opencode.json"), JSON.stringify({ $schema: "https://opencode.ai/config.json", - plugins: [resolve(import.meta.dir, "..")], + plugins: [resolve(import.meta.dir, "fixtures/smoke-plugin")], permissions: [{ action: "lightpanda", resource: "*", effect: "allow" }], }), ) @@ -48,12 +48,9 @@ try { throw new Error(`OpenCode exited with ${exitCode}: ${error ?? stderr.trim()}`) } - const call = events.find((event) => { - if (event.type !== "tool_use" || event.part?.state?.status !== "completed") return false - return event.part.tool === "lightpanda" || event.part.state.metadata?.metadata?.toolCalls?.some( - (tool) => tool.tool === "lightpanda" && tool.status === "completed", - ) - }) + const call = events.find((event) => + event.type === "tool_use" && event.part?.tool === "lightpanda" && event.part.state?.status === "completed", + ) if (!call) { const tools = events.filter((event) => event.type === "tool_use").map((event) => ({ tool: event.part?.tool, @@ -61,7 +58,7 @@ try { nested: event.part?.state?.metadata?.metadata?.toolCalls, })) const logs = stderr.split("\n").filter((line) => line.includes("loading plugin") || line.includes("failed to load plugin")) - throw new Error(`OpenCode did not call lightpanda (session ${events[0]?.sessionID}; tools: ${JSON.stringify(tools)}; logs: ${logs.join("\n")})`) + throw new Error(`OpenCode did not call lightpanda directly (session ${events[0]?.sessionID}; tools: ${JSON.stringify(tools)}; logs: ${logs.join("\n")})`) } const args = JSON.parse(call.part!.state!.output ?? "null") as unknown @@ -72,7 +69,7 @@ try { throw new Error("Lightpanda did not receive the requested format and timeout") } - console.log("OpenCode V2 loaded and executed lightpanda") + console.log("OpenCode V2 loaded and directly executed lightpanda") } finally { try { if (sessionID) {