hermes-agent 0.14.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +111 -0
- package/bin/hermes-agent.js +5 -0
- package/lib/python-launcher.js +99 -0
- package/package.json +36 -0
- package/scripts/postinstall.js +33 -0
package/README.md
ADDED
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
# hermes-agent npm package
|
|
2
|
+
|
|
3
|
+
This repository publishes the npm bridge for
|
|
4
|
+
[NousResearch/Hermes-Agent](https://github.com/NousResearch/Hermes-Agent).
|
|
5
|
+
|
|
6
|
+
The npm package name is:
|
|
7
|
+
|
|
8
|
+
```bash
|
|
9
|
+
hermes-agent
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
The installed commands are:
|
|
13
|
+
|
|
14
|
+
```bash
|
|
15
|
+
hermes
|
|
16
|
+
hermes-agent
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
The npm package name `hermes` is already owned by another package on npm, so this
|
|
20
|
+
repository publishes `hermes-agent` and exposes `hermes` as a CLI binary.
|
|
21
|
+
|
|
22
|
+
## Install
|
|
23
|
+
|
|
24
|
+
Prerequisites:
|
|
25
|
+
|
|
26
|
+
- Node.js 20 or newer
|
|
27
|
+
- Python 3.11 or newer
|
|
28
|
+
- pip available for that Python installation
|
|
29
|
+
|
|
30
|
+
Install globally:
|
|
31
|
+
|
|
32
|
+
```bash
|
|
33
|
+
npm install -g hermes-agent
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
Use it:
|
|
37
|
+
|
|
38
|
+
```bash
|
|
39
|
+
hermes --help
|
|
40
|
+
hermes-agent --help
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
During npm installation, `postinstall` installs the matching Python package:
|
|
44
|
+
|
|
45
|
+
```bash
|
|
46
|
+
python -m pip install --upgrade hermes-agent==<npm package version>
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
## Automated publishing
|
|
50
|
+
|
|
51
|
+
`.github/workflows/npm-publish.yml` runs:
|
|
52
|
+
|
|
53
|
+
- manually with `workflow_dispatch`
|
|
54
|
+
- daily on a schedule
|
|
55
|
+
- when a tag matching `npm-v*` is pushed
|
|
56
|
+
|
|
57
|
+
The workflow:
|
|
58
|
+
|
|
59
|
+
1. Fetches the current Hermes Agent version from upstream `pyproject.toml`.
|
|
60
|
+
2. Updates `package.json` in the workflow workspace.
|
|
61
|
+
3. Skips publishing if `hermes-agent@<version>` already exists on npm.
|
|
62
|
+
4. Runs `npm test`.
|
|
63
|
+
5. Runs `npm pack --dry-run`.
|
|
64
|
+
6. Publishes to npm with the `NPM_TOKEN` GitHub Actions secret.
|
|
65
|
+
|
|
66
|
+
## GitHub setup
|
|
67
|
+
|
|
68
|
+
Create a GitHub repository named:
|
|
69
|
+
|
|
70
|
+
```text
|
|
71
|
+
hermes-agent-npm
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
Create a classic or automation npm token with publish access, then add it as a
|
|
75
|
+
GitHub Actions secret:
|
|
76
|
+
|
|
77
|
+
```text
|
|
78
|
+
Repository -> Settings -> Secrets and variables -> Actions -> New repository secret
|
|
79
|
+
Name: NPM_TOKEN
|
|
80
|
+
Value: your npm token
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
After the first package version exists on npm, this repository can be switched
|
|
84
|
+
back to npm trusted publishing if desired:
|
|
85
|
+
|
|
86
|
+
```text
|
|
87
|
+
npm package: hermes-agent
|
|
88
|
+
publisher: GitHub Actions
|
|
89
|
+
organization or user: wyrtensi
|
|
90
|
+
repository: hermes-agent-npm
|
|
91
|
+
workflow filename: npm-publish.yml
|
|
92
|
+
allowed action: npm publish
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
Then push this repository:
|
|
96
|
+
|
|
97
|
+
```bash
|
|
98
|
+
git remote add origin git@github.com:wyrtensi/hermes-agent-npm.git
|
|
99
|
+
git push -u origin main
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
After that, open GitHub Actions and run `Publish npm package` manually for the
|
|
103
|
+
first publish.
|
|
104
|
+
|
|
105
|
+
## Local checks
|
|
106
|
+
|
|
107
|
+
```bash
|
|
108
|
+
python scripts/sync_upstream_version.py
|
|
109
|
+
npm test
|
|
110
|
+
npm pack --dry-run
|
|
111
|
+
```
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
const { spawn, spawnSync } = require("node:child_process");
|
|
2
|
+
const path = require("node:path");
|
|
3
|
+
|
|
4
|
+
const packageJson = require("../package.json");
|
|
5
|
+
|
|
6
|
+
function getPythonCandidates(platform = process.platform) {
|
|
7
|
+
if (platform === "win32") {
|
|
8
|
+
return [
|
|
9
|
+
{ command: "py", args: ["-3"] },
|
|
10
|
+
{ command: "python", args: [] },
|
|
11
|
+
{ command: "python3", args: [] }
|
|
12
|
+
];
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
return [
|
|
16
|
+
{ command: "python3", args: [] },
|
|
17
|
+
{ command: "python", args: [] }
|
|
18
|
+
];
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
function findPython(candidates = getPythonCandidates()) {
|
|
22
|
+
for (const candidate of candidates) {
|
|
23
|
+
const result = spawnSync(
|
|
24
|
+
candidate.command,
|
|
25
|
+
[...candidate.args, "-c", "import sys; raise SystemExit(0 if sys.version_info >= (3, 11) else 1)"],
|
|
26
|
+
{ encoding: "utf8", windowsHide: true }
|
|
27
|
+
);
|
|
28
|
+
|
|
29
|
+
if (result.status === 0) {
|
|
30
|
+
return candidate;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
return null;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
function normalizeBinName(binName) {
|
|
38
|
+
const baseName = path.basename(binName || "hermes-agent").toLowerCase();
|
|
39
|
+
return baseName.replace(/(\.cmd|\.exe)$/i, "");
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function getPythonEntryPoint(binName) {
|
|
43
|
+
return normalizeBinName(binName) === "hermes" ? "hermes_cli.main" : "run_agent";
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
function getPythonCode(binName) {
|
|
47
|
+
const moduleName = getPythonEntryPoint(binName);
|
|
48
|
+
return `from ${moduleName} import main; raise SystemExit(main())`;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
function buildPythonInvocation(candidate, binName, userArgs) {
|
|
52
|
+
return {
|
|
53
|
+
command: candidate.command,
|
|
54
|
+
args: [...candidate.args, "-c", getPythonCode(binName), ...userArgs]
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
function getPythonPackageSpec() {
|
|
59
|
+
const version = packageJson.hermesAgent?.pythonPackageVersion || packageJson.version;
|
|
60
|
+
return `hermes-agent==${version}`;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
function runHermes(binName, userArgs, stdio = "inherit") {
|
|
64
|
+
const candidate = findPython();
|
|
65
|
+
|
|
66
|
+
if (!candidate) {
|
|
67
|
+
console.error("Hermes Agent requires Python 3.11 or newer.");
|
|
68
|
+
console.error("Install Python, then run: python -m pip install --upgrade " + getPythonPackageSpec());
|
|
69
|
+
return 1;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
const invocation = buildPythonInvocation(candidate, binName, userArgs);
|
|
73
|
+
const child = spawn(invocation.command, invocation.args, { stdio, windowsHide: false });
|
|
74
|
+
|
|
75
|
+
child.on("exit", (code, signal) => {
|
|
76
|
+
if (signal) {
|
|
77
|
+
process.kill(process.pid, signal);
|
|
78
|
+
return;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
process.exit(code ?? 1);
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
child.on("error", (error) => {
|
|
85
|
+
console.error(error.message);
|
|
86
|
+
process.exit(1);
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
return 0;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
module.exports = {
|
|
93
|
+
buildPythonInvocation,
|
|
94
|
+
findPython,
|
|
95
|
+
getPythonCandidates,
|
|
96
|
+
getPythonEntryPoint,
|
|
97
|
+
getPythonPackageSpec,
|
|
98
|
+
runHermes
|
|
99
|
+
};
|
package/package.json
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "hermes-agent",
|
|
3
|
+
"version": "0.14.0",
|
|
4
|
+
"description": "npm bridge for Hermes Agent 0.14.0: The self-improving AI agent \u2014 creates skills from experience, improves them during use, and runs anywhere",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"type": "commonjs",
|
|
7
|
+
"bin": {
|
|
8
|
+
"hermes": "bin/hermes-agent.js",
|
|
9
|
+
"hermes-agent": "bin/hermes-agent.js"
|
|
10
|
+
},
|
|
11
|
+
"scripts": {
|
|
12
|
+
"postinstall": "node scripts/postinstall.js",
|
|
13
|
+
"test": "node --test"
|
|
14
|
+
},
|
|
15
|
+
"repository": {
|
|
16
|
+
"type": "git",
|
|
17
|
+
"url": "git+https://github.com/wyrtensi/hermes-agent-npm.git"
|
|
18
|
+
},
|
|
19
|
+
"bugs": {
|
|
20
|
+
"url": "https://github.com/NousResearch/Hermes-Agent/issues"
|
|
21
|
+
},
|
|
22
|
+
"homepage": "https://github.com/NousResearch/Hermes-Agent#readme",
|
|
23
|
+
"engines": {
|
|
24
|
+
"node": ">=20.0.0"
|
|
25
|
+
},
|
|
26
|
+
"files": [
|
|
27
|
+
"bin/",
|
|
28
|
+
"lib/",
|
|
29
|
+
"scripts/postinstall.js",
|
|
30
|
+
"README.md"
|
|
31
|
+
],
|
|
32
|
+
"hermesAgent": {
|
|
33
|
+
"pythonPackageVersion": "0.14.0",
|
|
34
|
+
"upstreamRepository": "nousresearch/hermes-agent"
|
|
35
|
+
}
|
|
36
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
const { spawnSync } = require("node:child_process");
|
|
4
|
+
const { findPython, getPythonPackageSpec } = require("../lib/python-launcher");
|
|
5
|
+
|
|
6
|
+
const candidate = findPython();
|
|
7
|
+
const packageSpec = getPythonPackageSpec();
|
|
8
|
+
|
|
9
|
+
if (!candidate) {
|
|
10
|
+
console.error("Hermes Agent requires Python 3.11 or newer.");
|
|
11
|
+
console.error(`Install Python, then run: python -m pip install --upgrade ${packageSpec}`);
|
|
12
|
+
process.exit(1);
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
function runPip(extraArgs) {
|
|
16
|
+
return spawnSync(
|
|
17
|
+
candidate.command,
|
|
18
|
+
[...candidate.args, "-m", "pip", "install", "--upgrade", ...extraArgs, packageSpec],
|
|
19
|
+
{ stdio: "inherit", windowsHide: true }
|
|
20
|
+
);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
let result = runPip([]);
|
|
24
|
+
|
|
25
|
+
if (result.status !== 0) {
|
|
26
|
+
console.warn("Global pip install failed; retrying with --user.");
|
|
27
|
+
result = runPip(["--user"]);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
if (result.status !== 0) {
|
|
31
|
+
console.error(`Failed to install ${packageSpec}.`);
|
|
32
|
+
process.exit(result.status || 1);
|
|
33
|
+
}
|