mirror of
https://github.com/NousResearch/hermes-agent.git
synced 2026-11-06 13:26:40 +00:00
A plugin.yaml alone does not make an agent half: desktop-only catalog plugins (agent-log, githermes, deepseek-whale) ship one beside desktop/plugin.js as metadata, and the previous commit's rule would plan an agent install for them that loads nothing. The old __init__.py requirement was what kept them desktop-only. Both inspectors now call a plugin.yaml folder an agent half when it has an agent payload beside the manifest: __init__.py, a dashboard tab or backend (dashboard/manifest.json), or a manifest-only language pack (provides_locales plus locales/, the loader's own rule). plugin.json stays an agent half on its own. The shared detection fixture gains the cron-bulletin shape, a dashboard-only package, the desktop-only shape and three language-pack cases; its existing cases are unchanged. Co-authored-by: dandacompany <128420625+dandacompany@users.noreply.github.com>
115 lines
5.5 KiB
JSON
115 lines
5.5 KiB
JSON
{
|
|
"schema": 1,
|
|
"doc": "Which halves a plugin folder ships. Both inspectors read these cases: the gateway's (hermes_cli/plugins_cmd_inspect.py detect_components) and native Desktop's (apps/desktop/electron/desktop-plugin-install.ts detectPluginComponents). A rule changed in one must change in both, and here. Each case is a folder named 'root' holding 'files'; agent_name falls back to that folder's name.",
|
|
"cases": [
|
|
{
|
|
"name": "yaml manifest with a package is an agent half named by the manifest",
|
|
"root": "folder-name",
|
|
"files": { "plugin.yaml": "name: from-manifest\nversion: 1.0.0\n", "__init__.py": "" },
|
|
"expect": { "agent": true, "desktop": false, "agent_name": "from-manifest" }
|
|
},
|
|
{
|
|
"name": "plugin.yml counts as the yaml manifest",
|
|
"root": "yml-plugin",
|
|
"files": { "plugin.yml": "name: yml-name\n", "__init__.py": "" },
|
|
"expect": { "agent": true, "desktop": false, "agent_name": "yml-name" }
|
|
},
|
|
{
|
|
"name": "a quoted manifest name is read without its quotes",
|
|
"root": "quoted",
|
|
"files": { "plugin.yaml": "name: \"quoted-name\"\n", "__init__.py": "" },
|
|
"expect": { "agent": true, "desktop": false, "agent_name": "quoted-name" }
|
|
},
|
|
{
|
|
"name": "a yaml manifest without a name falls back to the folder name",
|
|
"root": "unnamed-plugin",
|
|
"files": { "plugin.yaml": "version: 1.0.0\n", "__init__.py": "" },
|
|
"expect": { "agent": true, "desktop": false, "agent_name": "unnamed-plugin" }
|
|
},
|
|
{
|
|
"name": "a yaml manifest without __init__.py is not an agent half",
|
|
"root": "manifest-only",
|
|
"files": { "plugin.yaml": "name: manifest-only\n" },
|
|
"expect": { "agent": false, "desktop": false, "agent_name": null }
|
|
},
|
|
{
|
|
"name": "a manifest-only package with a dashboard backend and a desktop half installs both halves",
|
|
"root": "bulletin-repo",
|
|
"files": { "plugin.yaml": "name: bulletin\n", "dashboard/manifest.json": "{\"name\": \"bulletin\", \"api\": \"plugin_api.py\"}", "dashboard/plugin_api.py": "", "desktop/plugin.js": "export default {}\n" },
|
|
"expect": { "agent": true, "desktop": true, "agent_name": "bulletin" }
|
|
},
|
|
{
|
|
"name": "a manifest-only dashboard package without a desktop half is an agent half",
|
|
"root": "dashboard-only",
|
|
"files": { "plugin.yaml": "name: dash\n", "dashboard/manifest.json": "{}" },
|
|
"expect": { "agent": true, "desktop": false, "agent_name": "dash" }
|
|
},
|
|
{
|
|
"name": "a desktop plugin whose plugin.yaml is metadata stays desktop-only",
|
|
"root": "titlebar-widget",
|
|
"files": { "plugin.yaml": "name: titlebar-widget\nkind: standalone\n", "desktop/plugin.js": "export default {}\n" },
|
|
"expect": { "agent": false, "desktop": true, "agent_name": null }
|
|
},
|
|
{
|
|
"name": "a manifest-only language pack is an agent half",
|
|
"root": "lang-pack",
|
|
"files": { "plugin.yaml": "name: hermes-lang-xx\nprovides_locales:\n - id: xx\n endonym: Xx\n", "locales/xx.yaml": "common.save: Xx\n" },
|
|
"expect": { "agent": true, "desktop": false, "agent_name": "hermes-lang-xx" }
|
|
},
|
|
{
|
|
"name": "declared locales without a locales folder are not an agent half",
|
|
"root": "lang-no-folder",
|
|
"files": { "plugin.yaml": "name: lang-no-folder\nprovides_locales: [xx]\n" },
|
|
"expect": { "agent": false, "desktop": false, "agent_name": null }
|
|
},
|
|
{
|
|
"name": "an empty provides_locales declares no language pack",
|
|
"root": "lang-empty",
|
|
"files": { "plugin.yaml": "name: lang-empty\nprovides_locales: []\n", "locales/xx.yaml": "common.save: Xx\n" },
|
|
"expect": { "agent": false, "desktop": false, "agent_name": null }
|
|
},
|
|
{
|
|
"name": "a portable plugin.json is an agent half named by it",
|
|
"root": "portable",
|
|
"files": { "plugin.json": "{\"name\": \"portable-one\"}" },
|
|
"expect": { "agent": true, "desktop": false, "agent_name": "portable-one" }
|
|
},
|
|
{
|
|
"name": "a portable plugin.json without a name falls back to the folder name",
|
|
"root": "portable-unnamed",
|
|
"files": { "plugin.json": "{}" },
|
|
"expect": { "agent": true, "desktop": false, "agent_name": "portable-unnamed" }
|
|
},
|
|
{
|
|
"name": "the yaml manifest names the plugin when a plugin.json is present too",
|
|
"root": "both-manifests",
|
|
"files": { "plugin.yaml": "name: yaml-wins\n", "__init__.py": "", "plugin.json": "{\"name\": \"json-loses\"}" },
|
|
"expect": { "agent": true, "desktop": false, "agent_name": "yaml-wins" }
|
|
},
|
|
{
|
|
"name": "plugin.js at the root is a desktop half",
|
|
"root": "ui-plugin",
|
|
"files": { "plugin.js": "export default {}\n" },
|
|
"expect": { "agent": false, "desktop": true, "agent_name": null }
|
|
},
|
|
{
|
|
"name": "desktop/plugin.js beside an agent half makes a mixed package",
|
|
"root": "mixed",
|
|
"files": { "plugin.yaml": "name: mixed\n", "__init__.py": "", "desktop/plugin.js": "export default {}\n" },
|
|
"expect": { "agent": true, "desktop": true, "agent_name": "mixed" }
|
|
},
|
|
{
|
|
"name": "plugin.js in any other folder is not a desktop half",
|
|
"root": "elsewhere",
|
|
"files": { "ui/plugin.js": "export default {}\n" },
|
|
"expect": { "agent": false, "desktop": false, "agent_name": null }
|
|
},
|
|
{
|
|
"name": "a folder with neither half ships nothing",
|
|
"root": "readme-only",
|
|
"files": { "README.md": "nothing here\n" },
|
|
"expect": { "agent": false, "desktop": false, "agent_name": null }
|
|
}
|
|
]
|
|
}
|