Skip to content

fix(plugins): backfill missing dependencies for audited plugin installs - #14

Closed
TSavo wants to merge 1 commit into
mainfrom
codex/linear-mention-wop-23-fix-install-missing-dependencies-ac
Closed

TSavo wants to merge 1 commit into
mainfrom
codex/linear-mention-wop-23-fix-install-missing-dependencies-ac

Conversation

@TSavo

@TSavo TSavo commented Feb 11, 2026

Copy link
Copy Markdown
Owner

Motivation

  • Several channel and provider plugins audited in WOP-23 were failing to install cleanly due to missing runtime/transitive dependencies, so installs need a targeted backfill to ensure the host app can load them.

Description

  • Added a PLUGIN_DEPENDENCY_BACKFILL map in src/plugins.ts listing the audited plugins and their required packages (slack, signal, whatsapp, imessage, webui, p2p, provider-anthropic, provider-kimi).
  • Implemented ensurePluginDependencies(pluginRoot, pluginName) which installs any backfilled dependencies via npm install and logs the action.
  • Invoked ensurePluginDependencies after dependency installation in all plugin install code paths (GitHub repo installs, local path installs, and npm package installs) so missing deps get applied regardless of source.
  • All changes are contained in src/plugins.ts and keep existing build/packaging behavior (still runs npm run build for TypeScript plugins when present).

Testing

  • Ran npm run build to verify TypeScript compiles successfully and the change does not break the build (succeeded).
  • Queried the npm registry for each backfilled package with a scripted node -e check to ensure the packages exist and are resolvable (succeeded).

Codex Task

Summary by CodeRabbit

  • New Features
    • Plugins now automatically have their required dependencies installed during setup, ensuring reliable installation and compatibility regardless of source (GitHub, local, or npm registry).

Copilot AI review requested due to automatic review settings February 11, 2026 23:49
@coderabbitai

coderabbitai Bot commented Feb 11, 2026

Copy link
Copy Markdown

Walkthrough

This PR introduces a plugin dependency backfill mechanism that automatically installs missing dependencies for plugins after npm installation. The mechanism applies to GitHub-sourced, local, and npm-installed plugins, ensuring dependencies are present before TypeScript plugins are built. GitHub sources are normalized to a canonical format.

Changes

Cohort / File(s) Summary
Plugin Dependency Backfill
src/plugins.ts
Added PLUGIN_DEPENDENCY_BACKFILL constant mapping plugin names to required dependencies, and ensurePluginDependencies() function to install missing packages. Integrated backfill calls into three plugin installation flows (GitHub, local, and npm sources) after npm install and before TypeScript compilation.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Poem

🐰 With whiskers twitched and paws of care,
We backfill deps with expert flair,
Three paths converge, one purpose true,
Each plugin gets what it is due! 📦✨

🚥 Pre-merge checks | ✅ 2 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and specifically describes the main change: adding a backfill mechanism for missing dependencies in audited plugin installations, which aligns with the primary objective of the PR.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch codex/linear-mention-wop-23-fix-install-missing-dependencies-ac

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds a targeted dependency backfill mechanism during plugin installation so audited plugins that are missing runtime/transitive deps can still be installed and loaded reliably.

Changes:

  • Introduced a PLUGIN_DEPENDENCY_BACKFILL map for specific audited plugins and their required packages.
  • Added ensurePluginDependencies(pluginRoot, pluginName) to install those dependencies post-install.
  • Hooked the backfill step into all plugin install paths (GitHub, local, npm).

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread src/plugins.ts

logger.info(`[plugins] Backfilling missing dependencies for ${pluginName}...`);
const depArgs = requiredDeps.map(dep => `"${dep}"`).join(" ");
execSync(`npm install ${depArgs}`, { cwd: pluginRoot, stdio: "inherit" });

Copilot AI Feb 11, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

npm install <dep...> will typically update the plugin’s package.json and/or package-lock.json (adding these deps as direct dependencies). For GitHub-installed plugins this can leave the repo dirty and can cause subsequent git pull to fail due to local changes. Consider installing backfilled deps without persisting them (e.g., npm install --no-save and possibly --no-package-lock) so backfill only affects node_modules.

Suggested change
execSync(`npm install ${depArgs}`, { cwd: pluginRoot, stdio: "inherit" });
execSync(`npm install --no-save --package-lock=false ${depArgs}`, { cwd: pluginRoot, stdio: "inherit" });

Copilot uses AI. Check for mistakes.
Comment thread src/plugins.ts
Comment on lines +273 to +274
logger.info(`[plugins] Backfilling missing dependencies for ${pluginName}...`);
const depArgs = requiredDeps.map(dep => `"${dep}"`).join(" ");

Copilot AI Feb 11, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ensurePluginDependencies always runs a second npm install even when all backfill packages are already present, which can significantly slow installs and introduces more variability in the installed tree. Consider checking for missing deps first (e.g., verify each dep exists under node_modules / can be resolved from pluginRoot) and only install the ones that are absent.

Suggested change
logger.info(`[plugins] Backfilling missing dependencies for ${pluginName}...`);
const depArgs = requiredDeps.map(dep => `"${dep}"`).join(" ");
// Only install dependencies that are actually missing from the plugin's node_modules
const missingDeps = requiredDeps.filter(dep => {
const depPath = join(pluginRoot, "node_modules", ...dep.split("/"));
return !existsSync(depPath);
});
if (!missingDeps.length) {
logger.info(`[plugins] All backfill dependencies already installed for ${pluginName}`);
return;
}
logger.info(`[plugins] Backfilling missing dependencies for ${pluginName}: ${missingDeps.join(", ")}`);
const depArgs = missingDeps.map(dep => `"${dep}"`).join(" ");

Copilot uses AI. Check for mistakes.
Comment thread src/plugins.ts
Comment on lines 378 to +379
execSync(`npm install "${npmPackage}"`, { cwd: pluginDir, stdio: "inherit" });
ensurePluginDependencies(pluginDir, npmPackage);

Copilot AI Feb 11, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For npm installs, npmPackage may include a version/range/dist-tag (e.g., wopr-plugin-slack@^1), which won’t match keys in PLUGIN_DEPENDENCY_BACKFILL and will skip the backfill. Prefer determining the plugin name from the installed package’s package.json (or otherwise stripping any @<version> suffix) before calling ensurePluginDependencies.

Copilot uses AI. Check for mistakes.
@TSavo

TSavo commented Feb 11, 2026

Copy link
Copy Markdown
Owner Author

Closing — hardcoded dependency map in core is the wrong approach. Plugins should declare their own deps in package.json. WOP-23 needs a structural monorepo solution, not a backfill band-aid.

@TSavo TSavo closed this Feb 11, 2026

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/plugins.ts (1)

368-379: ⚠️ Potential issue | 🟡 Minor

Use wopr-plugin-${shortName} for backfill dependency lookup.

When source is "wopr-slack", the current code passes npmPackage = "wopr-slack" to ensurePluginDependencies, but PLUGIN_DEPENDENCY_BACKFILL only has keys like "wopr-plugin-slack". The lookup fails, skipping dependency backfill for plugins installed via the wopr-<name> format.

Fix
     execSync(`npm install "${npmPackage}"`, { cwd: pluginDir, stdio: "inherit" });
-    ensurePluginDependencies(pluginDir, npmPackage);
+    ensurePluginDependencies(pluginDir, `wopr-plugin-${shortName}`);
🤖 Fix all issues with AI agents
In `@src/plugins.ts`:
- Around line 267-276: The ensurePluginDependencies function currently calls
execSync directly and can crash the whole install if a backfill install fails;
wrap the execSync call in a try/catch around the block that constructs depArgs
and runs execSync (referencing ensurePluginDependencies, pluginRoot, pluginName,
PLUGIN_DEPENDENCY_BACKFILL, requiredDeps, depArgs, execSync), and on error log a
warning/error with the error details and context (pluginName and depArgs) but do
not rethrow — allow the install to continue gracefully when backfill fails.
- Around line 256-265: PLUGIN_DEPENDENCY_BACKFILL currently lists packages
without version constraints; update the constant so each package string includes
a semver constraint (at minimum pin the major version) to prevent silent
breakage on major bumps—for example replace entries like "wopr-plugin-slack":
["@slack/bolt", "winston"] with explicit versioned entries such as
"@slack/bolt@^4.0.0" and "winston@^3.0.0" (or other known-compatible major
versions); apply this change to all entries in PLUGIN_DEPENDENCY_BACKFILL so
each dependency is version-pinned using caret or exact semver ranges.

Comment thread src/plugins.ts
Comment on lines +256 to +265
const PLUGIN_DEPENDENCY_BACKFILL: Record<string, readonly string[]> = {
"wopr-plugin-slack": ["@slack/bolt", "winston"],
"wopr-plugin-signal": ["winston"],
"wopr-plugin-whatsapp": ["@whiskeysockets/baileys", "pino", "qrcode-terminal", "winston"],
"wopr-plugin-imessage": ["winston"],
"wopr-plugin-webui": ["@kobalte/core", "solid-js"],
"wopr-plugin-p2p": ["discord.js", "hyperswarm", "winston"],
"wopr-plugin-provider-anthropic": ["@anthropic-ai/claude-agent-sdk", "@anthropic-ai/claude-code", "winston"],
"wopr-plugin-provider-kimi": ["@moonshot-ai/kimi-agent-sdk", "winston"],
};

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Pin dependency versions to avoid breaking changes.

All backfilled dependencies are installed without version constraints, so npm install will pull the latest major version each time. A semver-major bump in any of these packages (e.g., @slack/bolt, discord.js, hyperswarm) could silently break plugin loading.

Consider pinning at least major versions:

Example version pinning
 const PLUGIN_DEPENDENCY_BACKFILL: Record<string, readonly string[]> = {
-  "wopr-plugin-slack": ["@slack/bolt", "winston"],
+  "wopr-plugin-slack": ["@slack/bolt@^3", "winston@^3"],
   ...
 };
🤖 Prompt for AI Agents
In `@src/plugins.ts` around lines 256 - 265, PLUGIN_DEPENDENCY_BACKFILL currently
lists packages without version constraints; update the constant so each package
string includes a semver constraint (at minimum pin the major version) to
prevent silent breakage on major bumps—for example replace entries like
"wopr-plugin-slack": ["@slack/bolt", "winston"] with explicit versioned entries
such as "@slack/bolt@^4.0.0" and "winston@^3.0.0" (or other known-compatible
major versions); apply this change to all entries in PLUGIN_DEPENDENCY_BACKFILL
so each dependency is version-pinned using caret or exact semver ranges.

Comment thread src/plugins.ts
Comment on lines +267 to +276
function ensurePluginDependencies(pluginRoot: string, pluginName?: string): void {
if (!pluginName) return;

const requiredDeps = PLUGIN_DEPENDENCY_BACKFILL[pluginName];
if (!requiredDeps?.length) return;

logger.info(`[plugins] Backfilling missing dependencies for ${pluginName}...`);
const depArgs = requiredDeps.map(dep => `"${dep}"`).join(" ");
execSync(`npm install ${depArgs}`, { cwd: pluginRoot, stdio: "inherit" });
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Wrap execSync in a try/catch to avoid aborting the entire install on a backfill failure.

If any backfill dependency fails to install (transient network issue, yanked package, etc.), the unhandled exception aborts the plugin installation entirely. Since this is a backfill — not the primary install — it should degrade gracefully.

Suggested fix
 function ensurePluginDependencies(pluginRoot: string, pluginName?: string): void {
   if (!pluginName) return;

   const requiredDeps = PLUGIN_DEPENDENCY_BACKFILL[pluginName];
   if (!requiredDeps?.length) return;

   logger.info(`[plugins] Backfilling missing dependencies for ${pluginName}...`);
-  const depArgs = requiredDeps.map(dep => `"${dep}"`).join(" ");
-  execSync(`npm install ${depArgs}`, { cwd: pluginRoot, stdio: "inherit" });
+  const depArgs = requiredDeps.map(dep => `"${dep}"`).join(" ");
+  try {
+    execSync(`npm install ${depArgs}`, { cwd: pluginRoot, stdio: "inherit" });
+  } catch (err: any) {
+    logger.warn(`[plugins] Backfill install failed for ${pluginName}: ${err.message}`);
+  }
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
function ensurePluginDependencies(pluginRoot: string, pluginName?: string): void {
if (!pluginName) return;
const requiredDeps = PLUGIN_DEPENDENCY_BACKFILL[pluginName];
if (!requiredDeps?.length) return;
logger.info(`[plugins] Backfilling missing dependencies for ${pluginName}...`);
const depArgs = requiredDeps.map(dep => `"${dep}"`).join(" ");
execSync(`npm install ${depArgs}`, { cwd: pluginRoot, stdio: "inherit" });
}
function ensurePluginDependencies(pluginRoot: string, pluginName?: string): void {
if (!pluginName) return;
const requiredDeps = PLUGIN_DEPENDENCY_BACKFILL[pluginName];
if (!requiredDeps?.length) return;
logger.info(`[plugins] Backfilling missing dependencies for ${pluginName}...`);
const depArgs = requiredDeps.map(dep => `"${dep}"`).join(" ");
try {
execSync(`npm install ${depArgs}`, { cwd: pluginRoot, stdio: "inherit" });
} catch (err: any) {
logger.warn(`[plugins] Backfill install failed for ${pluginName}: ${err.message}`);
}
}
🤖 Prompt for AI Agents
In `@src/plugins.ts` around lines 267 - 276, The ensurePluginDependencies function
currently calls execSync directly and can crash the whole install if a backfill
install fails; wrap the execSync call in a try/catch around the block that
constructs depArgs and runs execSync (referencing ensurePluginDependencies,
pluginRoot, pluginName, PLUGIN_DEPENDENCY_BACKFILL, requiredDeps, depArgs,
execSync), and on error log a warning/error with the error details and context
(pluginName and depArgs) but do not rethrow — allow the install to continue
gracefully when backfill fails.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: cad3c44740

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/plugins.ts

// Use npm to install
execSync(`npm install "${npmPackage}"`, { cwd: pluginDir, stdio: "inherit" });
ensurePluginDependencies(pluginDir, npmPackage);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Canonicalize npm package name before backfill lookup

The npm install path now calls ensurePluginDependencies(pluginDir, npmPackage), but npmPackage is not guaranteed to be the canonical key used in PLUGIN_DEPENDENCY_BACKFILL (for example, the same branch accepts wopr-<name> aliases and npm specifiers like @version). Because ensurePluginDependencies does an exact key lookup (e.g. wopr-plugin-p2p), these valid install inputs skip the backfill entirely, so the audited plugins can still be installed without their required runtime dependencies.

Useful? React with 👍 / 👎.

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

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants