refactor: move all site adapters to independent plugins - #216
Merged
Conversation
Contributor
🔴 Documentation update likely missing — low confidenceThe automated review found 5 likely missing documentation updates. Findings
Limitations
This review is advisory and does not block merging. |
…mments # Conflicts: # README.md # webcmd-plugin.json
migrate-cli-sites.mjs hardcoded webcmd: ">=0.6.0" for every plugin it generated a fresh manifest for, but package.json ships as 0.5.3 in this release. Every one of the 108 affected plugins (including linkedin) was uninstallable: `webcmd plugin install` hard-fails checkCompatibility() with "Plugin requires webcmd >=0.6.0, but current version is incompatible" before it ever reaches npm. Derive the floor from package.json's actual version instead of a literal, and regenerate the already-committed manifests (all plugins/*/webcmd-plugin.json + package.json, and the aggregated root webcmd-plugin.json catalog) to match. Update the two unit tests that had the old literal baked into their expectations.
… no sites Several e2e and smoke tests invoked site commands (hackernews, dictionary, google, imdb, apple-podcasts, yollomi, paperreview) and asserted on `list` output size/contents, assuming site adapters were bundled in core. After this migration core registers zero site commands until a plugin is installed, so these tests failed deterministically in any clean environment (e.g. `list` returns 0 commands, not >50). Add installFixturePlugin() to place a repo-local plugin directly under an isolated HOME's .webcmd/plugins/ (skipping `plugin install`'s npm step, which only resolves a peerDependency these fixture plugins don't otherwise need and which fails until the in-progress release is actually published). Each affected suite now installs the specific plugin(s) it exercises before running. The smoke test's "all expected sites registered" check is rewritten against the plugin catalog under plugins/, since that's the equivalent invariant post-migration.
webcmd-usage, webcmd-adapter-author, and webcmd-autofix (all shipped to npm under skills/**) still described a repo-root clis/ directory as the "official bundle" location for built-in adapters. That directory no longer exists — every main-repo site, official or community, lives under plugins/<site>/ now. Left the ~/.webcmd/clis/ references alone: that private local-iteration directory is unaffected by this migration.
Now that core ships zero bundled site adapters, an empty `list` (0 sites) is the expected default state on a fresh install rather than a sign something's broken. Point the user at `plugin search`/`plugin install` instead of leaving them looking at a bare zero-count line.
It's a build artifact (npm run build-plugin-manifest scans plugins/* via a Node loader and writes it fresh), read only by CI-time checks within the same run: check-plugin-command-parity, check-typed-error-lint, check-silent-column-drop, and convention-audit. Nothing reads it from a published package or at CLI/hosted runtime, so it doesn't need to be in the npm tarball or in git history — same treatment as hosted-contract.json, which was already gitignored for this reason.
Gitignoring it in 4aec6c5 broke the unit-test CI job: that job runs on a separate runner with a fresh checkout and only does `npm ci` + vitest, so the file no longer existed for the three test files that read it from the package root (hosted/availability, hosted/file-contract, build-manifest) — 5 tests failed with ENOENT. hosted-contract.json is safely gitignored only because `npm run build` always regenerates it. Give the plugin manifest the same guarantee instead of leaving it as a build artifact nothing in the install path produces. Costs ~0.9s per build.
Conflicts: - vitest.config.ts: keep main's src/browser test exclusion, drop the clis/** entry (clis/ no longer exists after the plugin migration). - src/cli.ts: keep both import sets (plugin discovery + browser run). - skills/webcmd-usage/SKILL.md: keep the plugin-architecture adapter bullet and main's rewritten browser-driving bullet. Also updated src/hosted/runner.test.ts: the hosted contract sorts browser commands, and main's new catalog order (tabs, bind, run, snapshot, close) is no longer alphabetical, so compare against the sorted catalog. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
adikulkarni006
approved these changes
Aug 6, 2026
…ilability The isLocalIpDomain function now strips port numbers from domain strings (e.g. '127.0.0.1:3000') before validating the IPv4 format. This ensures desktop-app adapters running on local IP addresses with ports are correctly classified as 'app' rather than 'site'. Includes regression tests to prevent port-handling regressions.
updatePlugin/updateAllPlugins now check for tracked-file modifications in both the standalone plugin directory and the shared monorepo clone before beginReplaceDir wipes them, with --force to opt out. Local (symlinked) installs are unaffected since they never go through beginReplaceDir.
git status --porcelain already omits gitignored paths (node_modules/dist never show up), so --untracked-files=no was only hiding the case the guard exists to catch: a new, unstaged command file. Drop the flag, label refusal entries as new-unstaged vs modified for clarity.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Add inline comments explaining that --update-env-vars on 'execute' is a per-execution override (not a job-spec mutation) and that workflow_dispatch runs should target main to avoid delisting plugins. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…t guard getDirtyFiles previously treated any git failure (missing binary, "detected dubious ownership in repository", permission errors) as "clean", letting beginReplaceDir silently destroy uncommitted work. It also ran `git status --porcelain` with no pathspec, which reports the whole enclosing repository rather than just the plugin directory, causing spurious refusals for plugins inside a larger repo (e.g. a dotfiles-tracked home directory). Now getDirtyFiles probes with `git rev-parse --git-dir` first: a genuine non-repository still proceeds, but any other failure refuses the update with a message pointing at --force. `git status` is scoped with `-- .` so only the plugin directory is considered. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…trhq/webcmd into feat/linkedin-post-comments
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
Moves every repository-owned site adapter from clis/ into its own independently installable package under plugins/. Webcmd core no longer bundles site commands, so plugin updates can ship independently without a core release.
The change also:
Example installation:
Final architecture
Verification
Type of Change
Checklist