Skip to content

fix(cli): discover adapters authored with registerCommand - #423

Open
ankitranjan7 wants to merge 1 commit into
mainfrom
fix/cli-adapter-discovery
Open

fix(cli): discover adapters authored with registerCommand#423
ankitranjan7 wants to merge 1 commit into
mainfrom
fix/cli-adapter-discovery

Conversation

@ankitranjan7

Copy link
Copy Markdown
Contributor

An adapter in ~/.webcmd/clis/ authored with registerCommand — a public export of @agentrhq/webcmd/registry — was never imported, so webcmd quotes list said the site was not installed while webcmd adapter status listed the same command as present.

The problem

Discovery gated every candidate file through a regex over its source text: /\b(?:cli|registerSiteAuthCommands|onStartup|onBeforeExecute|onAfterExecute)\s*\(/. Three consequences:

  1. registerCommand( is not in that list, so a file using the public export was silently never imported.
  2. The regex matches comments and strings — appending // cli( to the same file flipped it to discoverable.
  3. adapter status reads the filesystem, so it reported commands discovery had refused to load.

What changed

  1. Gate on the runtime import, not on call syntax (src/discovery.ts). A file can only register anything by importing the runtime, so discovery now tests for an import of @agentrhq/webcmd/{registry,plugin-runtime,hooks}. That covers every authoring style instead of an enumerated list of call names, and a call-shaped comment no longer decides anything. Helper modules that never import the runtime are still skipped, so their side effects still do not run at startup. Chosen over deleting the gate entirely, which would execute every helper module in an adapter directory at startup.
  2. cli() is the only authoring API (src/registry-api.ts). registerCommand is removed from the public export surface: it takes the raw/lazy manifest shape used by the manifest fast path, not the authoring shape, and adapters written against it died at execution with has no func or pipeline. It is undocumented and unused outside the runtime. An adapter importing it now fails loudly at load with the missing-export error, instead of registering a command that cannot run.
  3. Load failures are recorded and lead the error (src/discovery.ts). Every failed import is kept with its site, absolute path, and cause; missingPluginGuidance reports those instead of Site "X" is not installed. when the site has failing files.
  4. adapter status agrees with availability (src/cli.ts). Each row carries loadError; the table annotates (failed to load: …) and the JSON output gained a loadError field.

Before / After

Before (node dist/src/main.js, HOME in a temp dir, adapter uses registerCommand):

$ webcmd quotes list
Site "quotes" is not installed.
Search: webcmd plugin search quotes
Install using the installSource returned by search.

$ webcmd adapter status
Local adapters in ~/.webcmd/clis/ (1 sites):

  quotes
    user adapter: quotes/list

After, same adapter:

$ webcmd quotes list
⚠  Failed to load adapter /tmp/…/.webcmd/clis/quotes/list.js: The requested module '@agentrhq/webcmd/registry' does not provide an export named 'registerCommand'
Site "quotes" has adapter files that failed to load:
  /tmp/…/.webcmd/clis/quotes/list.js
    The requested module '@agentrhq/webcmd/registry' does not provide an export named 'registerCommand'
Fix the file, then re-run. Adapters call cli({ ... }) from '@agentrhq/webcmd/registry'
and must declare access: 'read' | 'write' and func.

$ webcmd adapter status
Local adapters in ~/.webcmd/clis/ (1 sites):

  quotes
    user adapter: quotes/list (failed to load: The requested module '@agentrhq/webcmd/registry' does not provide an export named 'registerCommand')

After, same file rewritten with cli({ …, access: 'read', func }):

$ webcmd quotes list
- quote: hi

Tests

src/discovery.test.ts gains five cases: a cli() adapter in a temp HOME registers; a file whose only cli( is a comment registers nothing and records no failure; a module missing access records the real cause and missingPluginGuidance leads with it rather than "is not installed"; an adapter importing registerCommand does not register and its failure names the export; failed files are recorded by the absolute path adapter status keys off. src/cli.test.ts covers the new loadError JSON field.

npm run typecheck clean. npx vitest run --project unit: 2708 passed, 1 skipped, 0 failed (the suite needs npm run build first — 120 hosted/manifest tests fail without dist/ on main too). npm run build clean.

🤖 Generated with Claude Code

Discovery gated every candidate file through a regex over its source text
(`\b(?:cli|registerSiteAuthCommands|onStartup|...)\s*\(`), so a user adapter
written with `registerCommand` — a public export of
`@agentrhq/webcmd/registry` — was never imported, while `adapter status`
still listed it. The regex also matched comments and strings, so `// cli(`
was enough to flip a file to discoverable.

Gate on the runtime import specifier instead of on call syntax: a file can
only register anything by importing the runtime, so this covers every
authoring style and stops matching call-like comments. Helper modules that
never import the runtime are still skipped.

`registerCommand` is dropped from the public export surface: it takes the
raw/lazy manifest shape (`func`, `_lazy`, `_modulePath`), not the authoring
shape, and adapters written against it failed at execution with "has no func
or pipeline". `cli()` is now the only way to author an adapter.

Load failures are recorded and surfaced: `missingPluginGuidance` leads with
the real cause and file path instead of "Site X is not installed", and
`adapter status` annotates each file that discovery refused to load.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@github-actions

Copy link
Copy Markdown
Contributor

🟠 Maintainer review suggested — low confidence

The automated review could not reach a fully supported conclusion.

Limitations

  • The automated review returned an invalid structured result.

This review is advisory and does not block merging.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant