From 16c118769874069be2d5c20ad06bdada4ad144e4 Mon Sep 17 00:00:00 2001 From: can1357 Date: Sun, 16 Aug 2026 02:06:45 +0200 Subject: [PATCH] fix(coding-agent): filtered Claude plugin tool modules --- .../src/discovery/claude-plugins.ts | 3 +- .../test/discovery/claude-tools.test.ts | 44 +++++++++++++++++++ 2 files changed, 46 insertions(+), 1 deletion(-) diff --git a/packages/coding-agent/src/discovery/claude-plugins.ts b/packages/coding-agent/src/discovery/claude-plugins.ts index 86d7e2dd6..50d4dea38 100644 --- a/packages/coding-agent/src/discovery/claude-plugins.ts +++ b/packages/coding-agent/src/discovery/claude-plugins.ts @@ -379,8 +379,9 @@ async function loadTools(ctx: LoadContext): Promise> { roots.map(async root => { const toolsDir = path.join(root.path, "tools"); return loadFilesFromDir(ctx, toolsDir, PROVIDER_ID, root.scope, { + extensions: ["ts", "js"], transform: (name, _content, filePath, source) => { - const toolName = name.replace(/\.(ts|js|sh|bash|py)$/, ""); + const toolName = name.replace(/\.(ts|js)$/, ""); return { name: toolName, path: filePath, diff --git a/packages/coding-agent/test/discovery/claude-tools.test.ts b/packages/coding-agent/test/discovery/claude-tools.test.ts index 2124505bb..8138e821a 100644 --- a/packages/coding-agent/test/discovery/claude-tools.test.ts +++ b/packages/coding-agent/test/discovery/claude-tools.test.ts @@ -2,9 +2,11 @@ import { afterEach, beforeEach, describe, expect, test, vi } from "bun:test"; import * as fs from "node:fs/promises"; import * as os from "node:os"; import * as path from "node:path"; +import { clearCache as clearFsCache } from "@oh-my-pi/pi-coding-agent/capability/fs"; import { type CustomTool, toolCapability } from "@oh-my-pi/pi-coding-agent/capability/tool"; import { resetSettingsForTest, Settings } from "@oh-my-pi/pi-coding-agent/config/settings"; import { initializeWithSettings, loadCapability } from "@oh-my-pi/pi-coding-agent/discovery"; +import { clearClaudePluginRootsCache } from "@oh-my-pi/pi-coding-agent/discovery/helpers"; import { removeWithRetries } from "@oh-my-pi/pi-utils"; describe("Claude Code custom tool discovery", () => { @@ -16,6 +18,8 @@ describe("Claude Code custom tool discovery", () => { beforeEach(async () => { resetSettingsForTest(); + clearClaudePluginRootsCache(); + clearFsCache(); originalHome = process.env.HOME; originalClaudeConfigDir = process.env.CLAUDE_CONFIG_DIR; delete process.env.CLAUDE_CONFIG_DIR; @@ -31,6 +35,8 @@ describe("Claude Code custom tool discovery", () => { afterEach(async () => { resetSettingsForTest(); + clearClaudePluginRootsCache(); + clearFsCache(); vi.restoreAllMocks(); if (originalHome === undefined) delete process.env.HOME; else process.env.HOME = originalHome; @@ -67,4 +73,42 @@ describe("Claude Code custom tool discovery", () => { { name: "user-tool", level: "user" }, ]); }); + + test("filters non-module files from marketplace plugin tools", async () => { + const pluginsDir = path.join(home, ".claude", "plugins"); + const pluginPath = path.join(root, "fixture-plugin"); + const toolsDir = path.join(pluginPath, "tools"); + await fs.mkdir(pluginsDir, { recursive: true }); + await fs.mkdir(toolsDir, { recursive: true }); + await fs.writeFile( + path.join(pluginsDir, "installed_plugins.json"), + JSON.stringify({ + version: 2, + plugins: { + "fixture@market": [ + { + scope: "user", + installPath: pluginPath, + version: "1.0.0", + installedAt: "2026-01-01T00:00:00Z", + lastUpdated: "2026-01-01T00:00:00Z", + }, + ], + }, + }), + ); + await Promise.all([ + fs.writeFile(path.join(toolsDir, "plugin-tool.ts"), "export default () => ({});\n"), + fs.writeFile(path.join(toolsDir, "helper.sh"), "#!/bin/sh\n"), + fs.writeFile(path.join(toolsDir, "notes.md"), "# Notes\n"), + ]); + + const result = await loadCapability(toolCapability.id, { + cwd: project, + providers: ["claude-plugins"], + }); + + expect(result.warnings).toEqual([]); + expect(result.items.map(tool => tool.name)).toEqual(["plugin-tool"]); + }); });