Merge pull request #1081 from can1357/farm/dc9cae94/disabledproviders-claude-plugins-does-no
fix(discovery): respect disabledProviders in discoverAgents for claude-plugins
This commit is contained in:
@@ -29,6 +29,7 @@
|
||||
- Fixed hashline payload parsing to silently treat truly-blank lines as empty `~`-prefixed payload lines when more payload follows in the same run. The previous behavior broke at the blank ("payload line has no preceding +, <, or = operation.") even though the intent is obvious — the only ambiguity is between in-payload blanks and end-of-section blanks, and a one-line lookahead resolves it: blanks that precede a non-payload op still end the run cleanly as section separators. Recovers the common case of forgetting the leading separator on a blank inserted line without changing how trailing blanks between ops behave.
|
||||
- Rewrote the hashline edit prompt examples to use an ASCII-only `TITLE = "Mr"` → `"Mrs"` / `"Dr"` motif instead of the previous `" • "` and `"·"` separators. Some agents had been copying the middle-dot literal characters into real edits as if they were format scaffolding (e.g. emitting payload lines like `~ ·`), since the demo inserts were near-twins of the existing string. The new example keeps every original op shape (single-line replace, multiline replace, insert AFTER/BEFORE, append, delete, blank, plus both anti-patterns) but uses content that is obviously domain-specific and clearly distinct from any payload separator. Pure prompt change; no parser, schema, or runtime behavior is affected.
|
||||
|
||||
- Fixed `discoverAgents()` ignoring `disabledProviders` for the `claude-plugins` provider. Plugin roots from `~/.claude/plugins/` were scanned unconditionally, so agents from Claude Code marketplace plugins continued to appear in `/agents` and the Agent Control Center even when `disabledProviders: [claude-plugins]` was set. The discovery path now checks `isProviderEnabled("claude-plugins")` before calling `listClaudePluginRoots()`, matching how every other capability respects the disabled-providers set. ([#1075](https://github.com/can1357/oh-my-pi/issues/1075))
|
||||
## [15.0.1] - 2026-05-14
|
||||
### Breaking Changes
|
||||
|
||||
|
||||
@@ -15,6 +15,7 @@ import * as fs from "node:fs/promises";
|
||||
import * as os from "node:os";
|
||||
import * as path from "node:path";
|
||||
import { logger } from "@oh-my-pi/pi-utils";
|
||||
import { isProviderEnabled } from "../capability";
|
||||
import { findAllNearestProjectConfigDirs, getConfigDirs } from "../config";
|
||||
import { listClaudePluginRoots } from "../discovery/helpers";
|
||||
import { loadBundledAgents, parseAgent } from "./agents";
|
||||
@@ -87,8 +88,10 @@ export async function discoverAgents(cwd: string, home: string = os.homedir()):
|
||||
if (user) orderedDirs.push({ dir: user.path, source: "user" });
|
||||
}
|
||||
|
||||
// Load agents from Claude Code marketplace plugins
|
||||
const { roots: pluginRoots } = await listClaudePluginRoots(home, resolvedCwd);
|
||||
// Load agents from Claude Code marketplace plugins (respects disabledProviders)
|
||||
const { roots: pluginRoots } = isProviderEnabled("claude-plugins")
|
||||
? await listClaudePluginRoots(home, resolvedCwd)
|
||||
: { roots: [] };
|
||||
const sortedPluginRoots = [...pluginRoots].sort((a, b) => {
|
||||
if (a.scope === b.scope) return 0;
|
||||
return a.scope === "project" ? -1 : 1;
|
||||
|
||||
@@ -0,0 +1,80 @@
|
||||
/**
|
||||
* Regression test for #1075:
|
||||
* discoverAgents() must skip Claude plugin roots when claude-plugins is disabled.
|
||||
*/
|
||||
import { afterEach, beforeEach, describe, expect, test } from "bun:test";
|
||||
import * as fs from "node:fs";
|
||||
import * as os from "node:os";
|
||||
import * as path from "node:path";
|
||||
import { disableProvider, enableProvider } from "../../src/capability";
|
||||
import { clearCache as clearFsCache } from "../../src/capability/fs";
|
||||
import { clearClaudePluginRootsCache } from "../../src/discovery/helpers";
|
||||
import { discoverAgents } from "../../src/task/discovery";
|
||||
|
||||
const PLUGIN_AGENT_MD = [
|
||||
"---",
|
||||
"name: simplifier",
|
||||
"description: A code simplifier agent from a Claude plugin",
|
||||
"---",
|
||||
"Simplify code.",
|
||||
].join("\n");
|
||||
|
||||
describe("discoverAgents — claude-plugins disabled provider", () => {
|
||||
let tempHome: string;
|
||||
|
||||
beforeEach(() => {
|
||||
tempHome = fs.mkdtempSync(path.join(os.tmpdir(), "pi-agent-disco-home-"));
|
||||
|
||||
// Build a fake Claude plugin install with an agents/ subdirectory.
|
||||
const pluginInstallPath = path.join(tempHome, "plugin-cache", "code-simplifier");
|
||||
const agentsDir = path.join(pluginInstallPath, "agents");
|
||||
fs.mkdirSync(agentsDir, { recursive: true });
|
||||
fs.writeFileSync(path.join(agentsDir, "simplifier.md"), PLUGIN_AGENT_MD);
|
||||
|
||||
// Register the plugin in the Claude registry so listClaudePluginRoots picks it up.
|
||||
const claudePluginsDir = path.join(tempHome, ".claude", "plugins");
|
||||
fs.mkdirSync(claudePluginsDir, { recursive: true });
|
||||
fs.writeFileSync(
|
||||
path.join(claudePluginsDir, "installed_plugins.json"),
|
||||
JSON.stringify({
|
||||
version: 2,
|
||||
plugins: {
|
||||
"code-simplifier@claude-plugins-official": [
|
||||
{
|
||||
installPath: pluginInstallPath,
|
||||
version: "1.0.0",
|
||||
scope: "user",
|
||||
installedAt: "2025-01-01T00:00:00Z",
|
||||
lastUpdated: "2025-01-01T00:00:00Z",
|
||||
},
|
||||
],
|
||||
},
|
||||
}),
|
||||
);
|
||||
|
||||
// Start each test with a clean provider + cache state.
|
||||
enableProvider("claude-plugins");
|
||||
clearFsCache();
|
||||
clearClaudePluginRootsCache();
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
fs.rmSync(tempHome, { recursive: true, force: true });
|
||||
// Restore global state so other tests in the suite are not affected.
|
||||
enableProvider("claude-plugins");
|
||||
clearFsCache();
|
||||
clearClaudePluginRootsCache();
|
||||
});
|
||||
|
||||
test("includes plugin agents when claude-plugins is enabled", async () => {
|
||||
const { agents } = await discoverAgents(tempHome, tempHome);
|
||||
expect(agents.map(a => a.name)).toContain("simplifier");
|
||||
});
|
||||
|
||||
test("excludes plugin agents when claude-plugins is disabled", async () => {
|
||||
disableProvider("claude-plugins");
|
||||
clearClaudePluginRootsCache();
|
||||
const { agents } = await discoverAgents(tempHome, tempHome);
|
||||
expect(agents.map(a => a.name)).not.toContain("simplifier");
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user