feat: add ACP registry metadata for Zed

This commit is contained in:
mr-r0b0t 2026-05-14 14:43:27 -05:00 committed by Teknium
parent e8b9f5ff9a
commit 4c94396206
17 changed files with 683 additions and 75 deletions

View file

@ -0,0 +1,26 @@
# @nousresearch/hermes-agent-acp
ACP launcher for Hermes Agent.
This package is intended for clients such as Zed that install agents through the official ACP Registry. It launches the Python Hermes ACP server with:
```bash
uvx --from 'hermes-agent[acp]==0.13.0' hermes-acp
```
## Requirements
- Node.js 18+
- `uv` or `uvx` on PATH
- Hermes provider credentials configured with `hermes model`, or through Hermes' normal `~/.hermes/.env` / `~/.hermes/config.yaml` setup
## Commands
```bash
npx @nousresearch/hermes-agent-acp@0.13.0 --version
npx @nousresearch/hermes-agent-acp@0.13.0 --check
npx @nousresearch/hermes-agent-acp@0.13.0 --setup
npx @nousresearch/hermes-agent-acp@0.13.0
```
Normal no-argument mode reserves stdout for ACP JSON-RPC traffic. Diagnostics are emitted on stderr by Hermes.

View file

@ -0,0 +1,66 @@
#!/usr/bin/env node
'use strict';
const { spawn, spawnSync } = require('node:child_process');
const HERMES_AGENT_VERSION = '0.13.0';
const HERMES_SPEC = `hermes-agent[acp]==${HERMES_AGENT_VERSION}`;
function commandExists(command) {
const result = spawnSync(command, ['--version'], { stdio: 'ignore' });
return !result.error && result.status === 0;
}
function buildCommand(argv, exists = commandExists) {
if (exists('uvx')) {
return {
command: 'uvx',
args: ['--from', HERMES_SPEC, 'hermes-acp', ...argv],
};
}
if (exists('uv')) {
return {
command: 'uv',
args: ['tool', 'run', '--from', HERMES_SPEC, 'hermes-acp', ...argv],
};
}
return null;
}
function main() {
const argv = process.argv.slice(2);
const command = buildCommand(argv);
if (!command) {
console.error('Hermes Agent ACP requires uv or uvx to launch the Python package.');
console.error('Install uv from https://docs.astral.sh/uv/getting-started/installation/');
console.error('Then retry this agent from Zed.');
process.exit(127);
}
const child = spawn(command.command, command.args, {
stdio: 'inherit',
env: process.env,
});
child.on('error', (error) => {
console.error(`Failed to start Hermes Agent ACP: ${error.message}`);
process.exit(1);
});
child.on('exit', (code, signal) => {
if (signal) {
process.kill(process.pid, signal);
return;
}
process.exit(code ?? 0);
});
}
if (require.main === module) {
main();
}
module.exports = { buildCommand, HERMES_AGENT_VERSION, HERMES_SPEC };

View file

@ -0,0 +1,24 @@
{
"name": "@nousresearch/hermes-agent-acp",
"version": "0.13.0",
"description": "ACP launcher for Hermes Agent",
"bin": {
"hermes-agent-acp": "bin/hermes-agent-acp.js"
},
"files": [
"bin/",
"README.md"
],
"license": "MIT",
"repository": {
"type": "git",
"url": "git+https://github.com/NousResearch/hermes-agent.git",
"directory": "packages/hermes-agent-acp"
},
"engines": {
"node": ">=18"
},
"scripts": {
"test": "node --test"
}
}

View file

@ -0,0 +1,23 @@
'use strict';
const test = require('node:test');
const assert = require('node:assert/strict');
const { buildCommand, HERMES_SPEC } = require('../bin/hermes-agent-acp.js');
test('uses uvx when available and forwards args', () => {
const command = buildCommand(['--version'], (name) => name === 'uvx');
assert.equal(command.command, 'uvx');
assert.deepEqual(command.args, ['--from', HERMES_SPEC, 'hermes-acp', '--version']);
});
test('falls back to uv tool run and forwards setup args', () => {
const command = buildCommand(['--setup'], (name) => name === 'uv');
assert.equal(command.command, 'uv');
assert.deepEqual(command.args, ['tool', 'run', '--from', HERMES_SPEC, 'hermes-acp', '--setup']);
});
test('returns null when neither uvx nor uv is available', () => {
assert.equal(buildCommand([], () => false), null);
});