Merge remote-tracking branch 'origin/main' into ethie/pm-clean

# Conflicts:
#	hermes_cli/local_runtime/binaries.py
#	hermes_cli/plugins_cmd.py
#	hermes_constants.py
#	tests/test_hermes_constants.py
#	tests/tools/test_clipboard.py
#	tests/tools/test_voice_wsl_pipewire.py
#	tools/computer_use/cua_backend.py
#	tools/voice_mode.py
This commit is contained in:
ethernet
2026-09-22 09:55:47 -04:00
200 changed files with 13944 additions and 2595 deletions

View File

@@ -762,6 +762,26 @@ def _ensure_tree_readable(root: Path, plugins_dir: Path) -> None:
) from exc
def _refuse_unavailable_portable_plugin(plugin_name: str, tree: Path) -> None:
if not (tree / "plugin.json").is_file():
return
from hermes_cli.agent_plugins import load_agent_plugin
from hermes_platform.resolver.availability import availability
try:
package = load_agent_plugin(tree, tree.parent / ".hermes-install-data")
except ValueError as exc:
raise PluginOperationError(f"Plugin '{plugin_name}' is unavailable: {exc}.") from exc
for server_name, server_decl in package.server_declarations.items():
result = availability(server_decl.declaration)
if result.offerable:
continue
found = f", found version {result.version}" if result.version else ""
raise PluginOperationError(
f"Plugin '{plugin_name}' server '{server_name}' is unavailable: {result.state}{found}."
)
def _install_plugin_core(
identifier: str,
*,
@@ -829,6 +849,7 @@ def _install_plugin_core(
raise PluginOperationError(
"--no-deps cannot replace an active plugin. Retry without --no-deps; "
"PM must prepare its dependencies before publication.")
_refuse_unavailable_portable_plugin(plugin_name, tmp_target)
if before_swap is not None:
before_swap(manifest, tmp_target)