feat(runtime): add project-local adapter and plugin discovery under ./.opencli/#1426
Open
Benjamin-eecs wants to merge 1 commit into
Open
Conversation
There was a problem hiding this comment.
Pull request overview
Adds runtime gating for built-in adapter discovery (disable all or filter by site) and introduces project-local discovery under ./.opencli/ so repositories can ship adapters/plugins alongside source.
Changes:
- Load
~/.opencli/config.json+ env (OPENCLI_DISABLE_BUILTINS,OPENCLI_DISABLED_SITES) to skip built-ins entirely or filter specific built-in sites. - Add project-local discovery directories (
./.opencli/clis,./.opencli/plugins) and a compat shim for project-local package-export imports. - Add unit tests covering config resolution, discovery filtering (manifest + FS scan), and custom plugin dir discovery; update docs with new extension path and config.
Reviewed changes
Copilot reviewed 6 out of 6 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
| src/main.ts | Loads runtime config, conditionally discovers built-ins with filtering, and adds project-local CLI/plugin discovery to the startup order. |
| src/discovery.ts | Adds project-local path helpers + compat shim; updates discoverClis API and implements disabledSites filtering; allows discoverPlugins(dir) for project-local plugins. |
| src/discovery-filter.test.ts | Tests site filtering for both FS and manifest fast paths, plus project-local discovery helper behavior. |
| src/config.ts | Implements config/env parsing and normalization for disableBuiltins and disabledSites. |
| src/config.test.ts | Verifies config/env precedence and parsing behaviors (truthy env, additive disabled sites, malformed JSON handling). |
| docs/guide/extending-opencli.md | Documents project-local adapters/plugins and built-in disabling/filtering. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| return null; | ||
| } catch (err) { | ||
| const code = (err as NodeJS.ErrnoException).code; | ||
| if (code === 'ENOENT') return null; |
Comment on lines
+141
to
+146
| ```text | ||
| my-project/ | ||
| .opencli/ | ||
| clis/<site>/<command>.js # adapters local to this project | ||
| plugins/<plugin>/<file>.js # plugins local to this project | ||
| ``` |
| plugins/<plugin>/<file>.js # plugins local to this project | ||
| ``` | ||
|
|
||
| Project-local commands are discovered when `opencli` runs from a directory that contains `./.opencli/`. The discovery order is `built-in → user (~/.opencli) → project (./.opencli)`, so a project adapter overrides a user adapter, which in turn overrides a built-in adapter with the same `site/command`. |
55c5f38 to
e4cfbf8
Compare
8e80705 to
3baa379
Compare
cf7b422 to
fc8668f
Compare
6bfca56 to
853e1fd
Compare
…/.opencli/
Adds a project-local discovery step that loads adapters from
`./.opencli/clis/<site>/<command>.js` and plugins from
`./.opencli/plugins/<plugin>/` when opencli runs inside a project.
Mirrors the existing user-level layer at `~/.opencli/`: same import
surface (`@jackwener/opencli/registry`), same compat shim mechanism,
so a repo can check project-specific adapters into VCS and they
override built-ins for that working directory.
Discovery order (last wins on collision):
built-in
-> ~/.opencli/clis
-> ./.opencli/clis
-> ~/.opencli/plugins
-> ./.opencli/plugins
Pure addition. No flags, env vars, or config file. External CLIs
(gh, ntn, tg, ...) are passthrough binaries on a separate
registration path and are unaffected.
Closes the project-isolation half of jackwener#1423. The "disable built-ins"
half is intentionally deferred: recent work (jackwener#1559 notion -> ntn
migration, jackwener#1544 -cli suffix drop) suggests built-in adapter scope
will shrink organically via external-CLI replacement, which
addresses the underlying AI-agent tool-list concern more directly
than a runtime flag.
Changes:
- src/discovery.ts: add projectOpenCliDir / projectClisDir /
projectPluginsDir helpers, add ensureProjectCliCompatShims
(reuses ensureUserCliCompatShims with a project root), widen
discoverPlugins to take an optional dir parameter so project
plugins can be discovered from ./.opencli/plugins/.
- src/main.ts: thread the new helpers, call
ensureProjectCliCompatShims in the parallel startup block, run
discoverClis(PROJECT_CLIS) after USER_CLIS, and
discoverPlugins(PROJECT_PLUGINS) after the default plugins pass.
- docs/guide/extending-opencli.md: document the project-local
layout and discovery order.
- src/discovery-project.test.ts: 3 tests covering the path helpers,
project-local adapter discovery, and project-local plugin
discovery.
853e1fd to
fb62bef
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Description
Adds a project-local discovery step that loads adapters from
./.opencli/clis/<site>/<command>.jsand plugins from./.opencli/plugins/<plugin>/when opencli runs inside a project. Mirrors the existing user-level layer at~/.opencli/(same import surface, same compat shim mechanism), so a repo can check project-specific adapters into VCS and they override built-ins for that working directory.Closes #1423.
Discovery order
Last wins on collision (mirrors existing
registerCommandsemantics insrc/registry.ts):A project adapter shadows a user adapter, which shadows a built-in. External CLIs (
gh,ntn,tg,discord,wx, ...) are passthrough binaries on a separate registration path (src/external.ts/external-clis.yaml) and are unaffected.Scope
Implements the project-isolation half of #1423 only. The disable-builtins half is left out; external-CLI replacement (#1559, #1544) is already cutting the built-in surface, so a runtime flag can wait for a follow-up if it's still useful after that migration settles.
Type of Change
Checklist
Implementation
src/discovery.tsprojectOpenCliDir(cwd?)/projectClisDir(cwd?)/projectPluginsDir(cwd?): path helpers, default toprocess.cwd(). Lazy resolution so they pick up the actual working directory at invocation time.ensureProjectCliCompatShims(cwd?): thin wrapper that calls existingensureUserCliCompatShims(baseDir)with a project-localbaseDir, but only when./.opencli/already exists. Silent no-op when the project has no.opencli/directory, so projects that don't use the feature pay zero startup cost.discoverPlugins(dir = PLUGINS_DIR): widen the existing signature with an optionaldirparameter so project-local plugins can be loaded from./.opencli/plugins/using the same flat-file scan.src/main.tsPROJECT_CLIS/PROJECT_PLUGINSconstants.ensureProjectCliCompatShims()added to the parallel startup block alongside the existing user-level setup.await discoverClis(PROJECT_CLIS)after the user-CLI pass.await discoverPlugins(PROJECT_PLUGINS)after the default plugins pass.src/discovery-project.test.tsThree tests covering:
cwd.discoverClis(projectDir)registers an adapter dropped into a project-local site directory.discoverPlugins(projectDir)registers a plugin dropped into a project-local plugin directory.docs/guide/extending-opencli.mdAdds a "Project-local adapters and plugins" section documenting the
./.opencli/layout and the discovery order. Adds a row to the extension-paths table at the top.Screenshots / Output
A project adapter with the same
site/commandas a built-in overrides the built-in for the duration ofcd my-project; leave the directory and the built-in is back.Test plan
npx vitest run src/discovery-project.test.ts: 3 passednpm run build: manifest compiles, 813 entries, no path leaksnpx tsc --noEmit: clean./.opencli/clis/<site>/<cmd>.jsis present./.opencli/directory pays zero startup cost (early-return inensureProjectCliCompatShims)./.opencli/clis/twitter/search.jsshould win over the bundledtwitter/search.js).