Skip to content

feat(plugins): Support hybrid plugin bundles - #169

Open
gricha wants to merge 3 commits into
mainfrom
feat/hybrid-plugin-bundles
Open

feat(plugins): Support hybrid plugin bundles#169
gricha wants to merge 3 commits into
mainfrom
feat/hybrid-plugin-bundles

Conversation

@gricha

@gricha gricha commented Aug 22, 2026

Copy link
Copy Markdown
Member

Allow valid Agent Plugins v1 roots to coexist with authored Claude, Cursor, or Codex manifests and legacy root resources instead of rejecting migration bundles. The portable root remains the source of truth for identity, metadata, skills, MCP, and target output. Target adapters ignore reproducible native manifests and generate managed adapters; they retain native manifests byte-for-byte only as matching-client fallbacks for commands, hooks, custom fields, or other behavior the portable model cannot express. Native-only imports keep their existing conservative behavior, and generated adapters are never read back as source input.

Discovery and installed-bundle provenance now track retained fallbacks explicitly, validate fallback identity and paths at the matching selected-target boundary, and prevent native resources from leaking into other clients. Install, sync, list, and doctor expose the durable compatibility state, while lifecycle reconciliation handles managed-to-fallback and fallback-to-managed transitions without changing agents.toml or agents.lock. Invalid portable roots still fail without downgrading to native or generalized legacy parsing.

Fixes #161

@vercel

vercel Bot commented Aug 22, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
dotagents Ready Ready Preview Aug 23, 2026 1:31am

Request Review

@gricha
gricha marked this pull request as ready for review August 22, 2026 20:14
@github-actions github-actions Bot added the risk: high PR risk score: high label Aug 22, 2026
Comment on lines +276 to +284
const plugin = plugins.find((plugin) => plugin.name === entry.name);
if (
plugin?.nativeSource === target.agent ||
plugin?.authoredNativeInterfaces?.[target.agent] !== undefined ||
!plugin && await hasRecordedAuthoredPluginInterface(
join(canonicalPluginDir, entry.name),
target.agent,
)
) {continue;}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Bug: An uncaught exception in prunePluginOutputs can crash CLI commands like sync and remove if a plugin's marker file is corrupted. The call to hasRecordedAuthoredPluginInterface should be wrapped in a try-catch block.
Severity: HIGH

Suggested Fix

Wrap the call to hasRecordedAuthoredPluginInterface within the loop in prunePluginOutputs in a try-catch block. This will prevent a corrupted marker file for a single plugin from crashing the entire command. The error should be handled gracefully, for example by logging a warning and continuing the pruning process.

Prompt for AI Agent
Review the code at the location below. A potential bug has been identified by an AI
agent. Verify if this is a real issue. If it is, propose a fix; if not, explain why it's
not valid.

Location: packages/dotagents/src/plugins/runtime/writer.ts#L276-L284

Potential issue: The `prunePluginOutputs` function does not handle errors that may arise
from its call to `hasRecordedAuthoredPluginInterface`. This downstream function can
throw an error if it encounters a corrupted plugin marker file (e.g.,
`.dotagents-authored-interfaces`). Because the call is not wrapped in a `try-catch`
block, the error propagates uncaught up the call stack. This will crash user-facing CLI
commands like `dotagents sync`, `dotagents remove`, or `dotagents install` when they
operate on a plugin with a corrupted marker file that is being removed or is otherwise
not in the current configuration.

Did we get this right? 👍 / 👎 to inform future reviews.

Comment thread packages/dotagents/src/plugins/runtime/writer.ts
Comment thread packages/dotagents/src/cli/commands/sync.ts

@cursor cursor 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.

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 486d280. Configure here.

Comment thread packages/dotagents/src/plugins/store.ts
…ndles

# Conflicts:
#	packages/dotagents/src/cli/index.test.ts
#	packages/dotagents/src/plugins/store.ts
Comment on lines +279 to +284
installedPlugin?.nativeSource === target.agent ||
installedPlugin?.authoredNativeInterfaces?.[target.agent]?.fallback === true ||
!installedPlugin && await hasRecordedNativePluginFallback(
join(canonicalPluginDir, entry.name),
target.agent,
)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Bug: The sync and remove commands can crash due to an unhandled exception when pruning an orphaned plugin with a corrupted .dotagents-native-fallbacks marker file.
Severity: MEDIUM

Suggested Fix

Wrap the call to hasRecordedNativePluginFallback within the prunePluginOutputs function in a try-catch block. Log the error and continue the pruning process instead of allowing the command to crash.

Prompt for AI Agent
Review the code at the location below. A potential bug has been identified by an AI
agent. Verify if this is a real issue. If it is, propose a fix; if not, explain why it's
not valid.

Location: packages/dotagents/src/plugins/runtime/writer.ts#L279-L284

Potential issue: The `prunePluginOutputs` function calls
`hasRecordedNativePluginFallback` for orphaned plugin directories that are not listed in
`agents.toml`. If the `.dotagents-native-fallbacks` marker file in one of these
directories is corrupted, for instance through manual user edits, the
`hasRecordedNativePluginFallback` function will throw an exception. This exception is
not caught, which causes the `sync` or `remove` command to crash, preventing the cleanup
of orphaned plugin artifacts if a marker file has become invalid.

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

Labels

risk: high PR risk score: high

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Plugin with a standard $schema root manifest + native/legacy components fails to install

1 participant