Commit Graph
19 Commits
Author SHA1 Message Date
can1357 7e4360d317 fix(discovery): preserve marketplace-root skill selection 2026-07-08 15:19:38 +02:00
roboomp c92cf0a905 fix(discovery): load Claude plugin skill paths that point at a SKILL.md directory
Claude plugin manifests may declare a `skills` path that resolves directly to a
directory whose `SKILL.md` IS the skill (e.g. `"skills": ["./"]` or a
subdirectory containing only `SKILL.md`). `scanSkillsFromDir` only scanned
`<dir>/<name>/SKILL.md` children, so the single-skill directory layout — the
common shape the Claude plugins reference documents for plugins shipping one
skill — silently dropped every array-form manifest entry that pointed at it.

Add an opt-in `includeSelf` flag to `ScanSkillsFromDirOptions`: when set,
`<dir>/SKILL.md` (if present) is loaded as a skill in addition to the existing
child scan. The Claude plugin skills loader opts in; every other provider
(agents, builtin, claude.ts, codex, github, omp-plugins, opencode) keeps the
strict child-scan semantic they rely on. Frontmatter `name` still wins over
the directory basename fallback.

Regression test: `skills: ["./single"]` where `./single/SKILL.md` is the only
skill file loads the skill under its frontmatter name.
2026-07-05 12:23:18 +00:00
roboomp c42d2b2907 fix(discovery): load file-form Claude plugin commands
Claude plugin manifests allow command path entries to name either directories
or flat `.md` command files. The array resolver was now preserving those file
paths, but `loadSlashCommands` still sent every resolved entry through
`loadFilesFromDir`, which only globs inside directories. A manifest such as
`{"commands":["./custom/deploy.md"]}` therefore replaced the default scan
and then loaded nothing.

Teach the command loader to stat each resolved entry: `.md` files are read as
single slash commands with the same plugin namespace and source metadata as
directory-loaded files; directories continue through `loadFilesFromDir`.
Missing entries keep the existing silent-empty behavior.

Add a regression test covering a mixed array of a direct command file and a
command directory while proving default `commands/` remains replaced unless
listed explicitly.
2026-07-05 12:16:02 +00:00
roboomp f276d80fc4 fix(discovery): honour per-field Claude plugin path merge semantics
Review feedback on #4610: array-form skills was silently replacing the
default `skills/` scan when the manifest declared any explicit entries.
Per the Claude plugins reference "Path behavior rules"
(https://code.claude.com/docs/en/plugins-reference#path-behavior-rules):

- `skills` ADDS to the default `skills/` scan
- `commands` / `slash-commands` REPLACE the default `commands/` scan

`resolvePluginDir` now takes an explicit `includeFallback` flag. `loadSkills`
passes `true` (fallback + declared entries, deduped by resolved absolute
path so a manifest may still list `./skills` alongside extras without
double-load); `loadSlashCommands` passes `false` (replace semantic
preserved). Deduplication keeps the fallback first and declared entries
in manifest order.

Regression tests cover both semantics: skills-array merges with default
`skills/`; commands-array replaces default `commands/` so a stray
`commands/default.md` no longer loads once the manifest declares an
alternative — matching Claude's documented behavior.
2026-07-05 12:09:22 +00:00
roboomp d9ef874e2b fix(discovery): accept array-form Claude plugin manifest paths
The Claude plugin manifest allows `commands`, `slash-commands`, and `skills`
to be either a single string or an array of strings — documented under
https://code.claude.com/docs/en/plugins-reference#path-behavior-rules and
used by real marketplace plugins such as addyosmani/agent-skills whose
plugin.json declares `"commands": ["./.claude/commands", "./commands"]`.

`resolvePluginDir` in `packages/coding-agent/src/discovery/claude-plugins.ts`
typed those manifest fields as `string` only, so array-shaped values were
silently dropped: no items loaded, no warning surfaced. Slash commands
(`spec`, `plan`, `build`, `test`, `review`) never appeared in the picker.

Normalize `string | string[]` at the resolver, load every in-root entry,
and emit one out-of-plugin-root warning per bad entry so misconfigured
paths remain observable. Skills and slash-command loaders now fan out over
the resolved directory list and merge warnings from all sources.

Fixes #4609
2026-07-05 12:02:47 +00:00
roboomp 7289cd4baf fix(mcp): expanded plugin env headers
Expanded environment variable placeholders in Claude marketplace plugin MCP url and headers before registration. Added a regression test covering context7-style HTTP server headers.\n\nFixes #3621
2026-06-27 03:16:45 +00:00
oldschoola a2854ba768 fix: migrate coding-agent tests from fs.rm to removeWithRetries
Migrate 203 test files (356 call sites) from fs.rm/fs.rmSync to
removeWithRetries/removeSyncWithRetries to reduce EBUSY test failures
on Windows. removeWithRetries is now exported from @oh-my-pi/pi-utils.

The migration uses a regex-based approach that:
- Replaces fs.rm(path, { recursive, force }) → removeWithRetries(path)
- Replaces fs.rmSync(path, { recursive, force }) → removeSyncWithRetries(path)
- Replaces fs.rm(path) → removeWithRetries(path) (no options)
- Skips fs.rm/fs.rmSync inside template literals (bun --eval scripts)
- Adds imports to existing @oh-my-pi/pi-utils import or creates new one
- Removes unused fs imports where fs.rm was the only fs usage (4 files)
2026-06-23 15:28:05 -07:00
roboomp 40ad1c6a7b style: bun run fix 2026-06-15 12:52:36 +00:00
roboomp b21385d13c fix(coding-agent): hid plugin skills from slash commands
Removed Claude marketplace plugin skill mirroring from slash-command discovery while keeping real plugin commands registered.\n\nFixes #2645
2026-06-15 12:52:12 +00:00
roboomp c1b27d2716 style: bun run fix 2026-06-14 07:12:50 +00:00
roboomp fde233278c fix(cli): synthesize plugin skill slash commands from directory basename
When a Claude plugin skill's SKILL.md frontmatter uses a display-style
name (e.g. `name: Understand Anything`), the synthesized slash command
inherited that text. `expandSlashCommand` splits the command at the
first whitespace, so `/understand` never resolved and the multi-word
form could not expand either.

Use `path.basename(path.dirname(skill.path))` so the slash command
always matches the documented `skills/<name>/SKILL.md` → `/<name>`
contract while the frontmatter still drives the description/body.

Fixes #2415
2026-06-14 07:12:42 +00:00
roboomp 0b444b83bf fix(cli): exposed claude plugin skills as slash commands
Loaded Claude Code marketplace plugin SKILL.md files into the slash-command capability so Claude-native plugin docs like /understand work in autocomplete and invocation.\n\nAdded a regression covering OMP installed plugin registries and bare slash-command expansion.\n\nFixes #2415
2026-06-12 19:28:35 +00:00
can1357 f53efd75ca test(coding-agent/discovery): updated discovery plugin name expectations in tests
- Updated listClaudePluginRoots test assertions to expect unprefixed skill identifiers.
- Adjusted both manifest and outside-skill discovery expectations to match the updated naming.
- Ensured the tests now look for plain skill names instead of namespaced values.
2026-06-02 11:16:56 +02:00
roboomp 8108394516 fix(discovery): honor manifest commands key for claude plugin slash commands
The ClaudePluginManifest interface was missing the `commands` field
(the standard Claude plugin format), and resolvePluginDir only checked
the legacy `slash-commands` key. Plugins declaring their command path
via `"commands": "..."` silently fell back to the hardcoded
`<plugin-root>/commands/` directory, which doesn't exist for
Claude-format plugins, so no slash commands were ever loaded.

Changes:
- Added `commands?: string` to ClaudePluginManifest.
- Changed resolvePluginDir to accept ReadonlyArray<keyof
  ClaudePluginManifest> and iterate in priority order; the first
  non-empty match wins.
- loadSlashCommands now passes ["commands", "slash-commands"] so
  the canonical Claude plugin key takes precedence over the legacy one.
- Added two regression tests: one covering the `commands` key in
  isolation, one verifying its precedence over `slash-commands` when
  both fields are present.

Fixes #1076
2026-05-15 02:10:22 +00:00
can1357 4490332822 test(coding-agent): avoid inline imports in claude plugin discovery tests 2026-04-23 22:54:59 +02:00
Parsifa1andcan1357 782a309f6f fix(coding-agent): fix untrusted path resolve 2026-04-23 22:51:01 +02:00
Parsifa1andcan1357 e56a33c857 fix(coding-agent): honor claude plugin manifest paths 2026-04-23 22:51:01 +02:00
can1357 9482a57135 fix(coding-agent): fixed plugin registry validation and precedence 2026-02-13 12:33:14 +01:00
kylesnowschwartz 7a6b42353e fix(coding-agent): respect plugin scope and handle multiple registry entries
- P1: Use root.scope instead of hardcoded 'user' level in claude-plugins provider
- P2: Iterate all registry entries per plugin ID, not just first one
- P3: Add home parameter to discoverAgents() for test isolation
- P4: Add test coverage for claude-plugins discovery (12 tests)
- P5: Cache listClaudePluginRoots results to avoid repeated parsing

Addresses issues found in adversarial review of PR #49
2026-02-13 11:11:05 +13:00