Add plugin reconciliation app-server API (#41949)

## What changed

- Add the `plugin/reconcile` JSON-RPC method to synchronize installed remote plugin bundles and wait for required hook updates.
- Return affected plugin IDs with MCP, Apps, hooks, and skills refresh hints, plus remote update and materialization failures.
- Refresh loaded hook runtimes after relevant updates and return an empty result when plugins or backend authentication are unavailable.

## Testing

- Cover workspace and global bundle installs, unchanged passes, enablement changes, updates, removals, materialization failures, hook refreshes, and disabled plugins.

GitOrigin-RevId: 45c02518d71990d13eb09d56ed51505c91c66956
This commit is contained in:
Matthew Zeng authored and copyberry committed 2026-09-01 00:50:11 +00:00
1 parent c2e5692e2c
commit bfa9646787
21 files changed
+854 -2

No files matched your search

@@ -2521,6 +2521,30 @@
"title": "Plugin/installedRequest",
"type": "object"
},
{
"properties": {
"id": {
"$ref": "#/definitions/RequestId"
},
"method": {
"enum": [
"plugin/reconcile"
],
"title": "Plugin/reconcileRequestMethod",
"type": "string"
},
"params": {
"$ref": "#/definitions/PluginReconcileParams"
}
},
"required": [
"id",
"method",
"params"
],
"title": "Plugin/reconcileRequest",
"type": "object"
},
{
"properties": {
"id": {
@@ -12253,6 +12277,84 @@
"title": "PluginReadResponse",
"type": "object"
},
"PluginReconcileChangedPlugin": {
"description": "Runtime categories affected by this change, not just capabilities currently present. Flags describe declarations before runtime policy filtering. Updates OR the old and new bundle flags; enablement changes and cached reinstalls use the cached bundle; removals retain the old bundle's flags.",
"properties": {
"hasApps": {
"type": "boolean"
},
"hasHooks": {
"type": "boolean"
},
"hasMcps": {
"type": "boolean"
},
"hasSkills": {
"description": "Whether either bundle declares skill roots; not a validated inventory of enabled skills.",
"type": "boolean"
},
"id": {
"description": "Local plugin ID (`name@marketplace`), matching `PluginSummary.id`.",
"type": "string"
}
},
"required": [
"hasApps",
"hasHooks",
"hasMcps",
"hasSkills",
"id"
],
"type": "object"
},
"PluginReconcileParams": {
"$schema": "http://json-schema.org/draft-07/schema#",
"properties": {
"reason": {
"description": "Optional client-provided reason recorded with the reconciliation attempt.",
"type": [
"string",
"null"
]
}
},
"title": "PluginReconcileParams",
"type": "object"
},
"PluginReconcileResponse": {
"$schema": "http://json-schema.org/draft-07/schema#",
"description": "Bundle and installed-state changes observed by this pass, not a runtime-readiness acknowledgement or a cumulative diff since the client's last request. Other metadata-only changes are not listed.",
"properties": {
"changedPlugins": {
"description": "Plugins affected by bundle changes, enablement changes, or removals. Installed-state changes compare against the previous cached snapshot, including cached reinstalls. Removal hints survive cache cleanup failures; unchanged plugins are omitted.",
"items": {
"$ref": "#/definitions/PluginReconcileChangedPlugin"
},
"type": "array"
},
"failedMaterializationRemotePluginIds": {
"description": "Subset of failures for which the requested bundle could not be materialized. A previously cached version may still be available.",
"items": {
"type": "string"
},
"type": "array"
},
"failedRemotePluginIds": {
"description": "Backend remote plugin IDs whose bundle or identity update failed.",
"items": {
"type": "string"
},
"type": "array"
}
},
"required": [
"changedPlugins",
"failedMaterializationRemotePluginIds",
"failedRemotePluginIds"
],
"title": "PluginReconcileResponse",
"type": "object"
},
"PluginSearchResult": {
"properties": {
"marketplaceName": {