15 Commits

Author SHA1 Message Date
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
can1357 3aea0bfb38 Merge PR #2714: fix(plugins): resolve directory extension manifest entries one level deep
Resolve directory extension manifest entries one level deep with manifest-first precedence (issue #2713). Supersedes #2723.
2026-06-16 14:53:39 +02:00
Asaf Mahlev a392798f59 test(plugins): isolate discovery test from real ~/.omp on all platforms
plugin-extensions-discovery.test.ts redirected XDG_DATA_HOME to a temp dir to isolate the plugins directory, but XDG is gated to Linux/macOS in dirs.ts, so on Windows getPluginsDir() still resolved to the real ~/.omp/plugins. The suite then wrote fixtures into -- and fs.rmSync'd the node_modules of -- the developer's real plugins directory, wiping installed plugins (green on Linux CI, destructive on Windows local).

Isolate the whole config root cross-platform: mock os.homedir() so configRoot = <tempHome>/.omp, AND clear the XDG_* vars in beforeEach (restored in afterEach). Clearing XDG is required because on Linux/macOS the resolver prefers $XDG_DATA_HOME/omp over the home config root when that dir exists, so an XDG-migrated environment would otherwise still resolve -- and these tests would rm -r -- the real plugins dir. Test-only; no production change.

Verified on Windows: real ~/.omp/plugins/package.json sha256 is unchanged across a full run; with XDG_DATA_HOME set to a sentinel containing an omp/ dir, no plugins dir is created there. 9/9 tests pass.
2026-06-16 03:04:21 +03:00
Asaf Mahlev b740faf6ce fix(plugins): resolve directory extension manifest entries one level deep
Installed pi packages declare their entry as `pi.extensions: ["./extensions"]` with the real module at `extensions/<name>/index.ts`, but the plugin manifest resolver only matched a file or a directory containing a direct index.{ts,js,mjs,cjs}. A directory whose entry sits one level below resolved to null, so `omp plugin install` rejected it ("declared extension entry not found on disk") and runtime load silently skipped it.

For the extensions key, resolveManifestEntryFiles now resolves a directory like OMP's configured-directory (-e) scanner: the directory's own package.json omp/pi extensions (authoritative -- a declared-but-missing entry is reported, not replaced by a decoy index), then a direct index.{ts,js,mjs,cjs}, then a one-level scan where each child directory is itself resolved manifest-first plus direct *.{ts,js,mjs,cjs} files. The directory expansion is gated to the extensions key; tools/hooks/commands keep direct-index resolution so a directory entry like `tools: "."` is unaffected.

Adds CHANGELOG Unreleased entry and regression tests for subdir-index, nested-manifest-over-index, missing-declared-entry, and key-aware (tools vs extensions) resolution. Verified: omp plugin install @zosmaai/pi-llm-wiki registers all 14 wiki_* tools; pi-mcp-adapter loads.
2026-06-16 03:01:07 +03:00
roboomp c4fa93e460 fix(plugins): preserved null package import exclusions
Kept explicit null package imports as exclusions so exact entries and active conditions do not fall through to wildcard or fallback targets.\n\nFixes #1889
2026-06-05 07:59:28 +00:00
roboomp 994ae513f5 fix(plugins): skipped non-source package import targets
Returned null from resolveSourceModuleFile when a package imports alias points at a JSON, WASM, or other non-code asset so the on-load rewrite hook no longer claims it and forces it through the JS loader. Bun resolves these targets natively. Added a regression where #schema maps to a .json file imported with a JSON type assertion.\n\nFixes #1889
2026-06-04 21:54:33 +00:00
roboomp 251d9152fc fix(plugins): honored package import condition order
Selected conditional package import targets by package.json object order for supported Bun runtime conditions, including node, instead of probing a fixed precedence list. Added a regression where node precedes import and must be selected for a plugin-local #src/* import.\n\nFixes #1889
2026-06-04 21:51:26 +00:00
roboomp 6e47ae8150 fix(plugins): matched side-effect imports in compat rewrite
Extended the legacy Pi, TypeBox, package-import alias, and extension graph regexes to recognise the bare \"import \\"specifier\\";\" shape so side-effect-only loads such as \"import \\"#src/register\\";\" walk into the source graph and get their legacy @(scope)/pi-* imports rewritten. Added a regression that loads a plugin with a side-effect alias import whose target contains a legacy scope import.\n\nFixes #1889
2026-06-04 21:49:06 +00:00
roboomp b2c6b7becf fix(plugins): loaded package import extensions
Resolved plugin-local package import aliases while loading extension source graphs so legacy Pi plugins with TypeScript source imports like #src/* register correctly under OMP. Added a regression covering legacy scope rewrites through a package import module.\n\nFixes #1889
2026-06-04 21:42:52 +00:00
ephraimduncan 93420c5782 fix(coding-agent/plugins): resolve directory manifest extension entries to their index.{ts,js,mjs,cjs}
Plugin manifests that declare a directory entry (e.g. pi-goal's
`"pi": { "extensions": [".pi/extensions/pi-goal"] }`) were
pushed through to the legacy module loader unchanged. `Bun.file()`
on a directory throws "Directories cannot be read like files",
so every such plugin failed to load.

`resolvePluginPaths` now routes each joined manifest entry through
`resolveManifestEntryFile`, which:
- returns the path as-is when it is a file,
- returns the directory's `index.{ts,js,mjs,cjs}` when it is a
  directory containing one of those files,
- otherwise returns null (skip).

This mirrors the documented native auto-discovery behavior in
`resolveExtensionEntries` and the candidate list in
`extensibility/custom-commands/loader.ts`.

Closes #1001.
2026-05-11 00:05:00 +00:00
jiwangyihao a157b878f4 fix(plugins): 避免预解析动态相对导入 2026-05-10 03:35:46 +08:00
jiwangyihao 40e8b37202 fix(plugins): 保留 legacy 扩展的 Node 内置导入 2026-05-10 03:24:02 +08:00
jiwangyihao 1226d30d21 test(plugins): 将 legacy Pi 回归覆盖插件发现链路 2026-05-10 03:21:02 +08:00
can1357 3f1d7c6882 test: isolated plugin discovery test with XDG_DATA_HOME environment variable
- Updated plugin extension discovery test to use XDG_DATA_HOME instead of HOME for environment isolation.
- Replaced manual path construction with getPluginsDir() utility for consistency.
- Added XDG directory structure setup and path cache rebuild to ensure correct plugin resolution.
2026-03-15 17:36:59 +01:00
can1357 b8e82008e3 feat(coding-agent): added extension filtering and granular capability identification
- Added `toExtensionId()` method to all capability types for granular extension identification and disabling.
- Added `disabledExtensions` and `includeDisabled` options to LoadOptions for filtering disabled capabilities by extension ID.
- Added plugin manifest support for `extensions` entry points with automatic discovery from installed plugins.
- Fixed skill loading to properly respect disabled skill names from custom directories.
- Improved cross-platform path handling by using `path.basename()` instead of string splitting in context file and state manager.
- Refactored capability index loading to validate source metadata and filter disabled extensions before processing.
2026-03-15 17:26:46 +01:00