agentic-memory-hermes 0.1.1__py3-none-any.whl
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.
- agentic_memory_hermes/README.md +184 -0
- agentic_memory_hermes/__init__.py +9 -0
- agentic_memory_hermes/hermes_plugin.py +70 -0
- agentic_memory_hermes/installer.py +180 -0
- agentic_memory_hermes/plugins/context_engine/agentic-memory/__init__.py +396 -0
- agentic_memory_hermes/plugins/context_engine/agentic-memory/plugin.yaml +3 -0
- agentic_memory_hermes/plugins/memory/agentic-memory/__init__.py +514 -0
- agentic_memory_hermes/plugins/memory/agentic-memory/cli.py +75 -0
- agentic_memory_hermes/plugins/memory/agentic-memory/plugin.yaml +8 -0
- agentic_memory_hermes-0.1.1.dist-info/METADATA +205 -0
- agentic_memory_hermes-0.1.1.dist-info/RECORD +13 -0
- agentic_memory_hermes-0.1.1.dist-info/WHEEL +4 -0
- agentic_memory_hermes-0.1.1.dist-info/entry_points.txt +5 -0
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
# Agentic Memory for Hermes Agent
|
|
2
|
+
|
|
3
|
+
This package is a showcase Hermes Agent integration for Agentic Memory. It ships
|
|
4
|
+
two Hermes provider plugins side by side:
|
|
5
|
+
|
|
6
|
+
- `plugins/memory/agentic-memory`
|
|
7
|
+
- a Hermes `MemoryProvider`
|
|
8
|
+
- recalls Agentic Memory context before model calls
|
|
9
|
+
- exposes explicit memory search/read tools
|
|
10
|
+
- persists completed turns to Agentic Memory in a background thread
|
|
11
|
+
- `plugins/context_engine/agentic-memory`
|
|
12
|
+
- a Hermes `ContextEngine`
|
|
13
|
+
- replaces default compression with Agentic Memory-backed context resolution
|
|
14
|
+
- keeps Hermes token counters and returns valid OpenAI-format messages
|
|
15
|
+
|
|
16
|
+
The directory layout follows the Hermes docs:
|
|
17
|
+
|
|
18
|
+
```text
|
|
19
|
+
plugins/
|
|
20
|
+
├── memory/
|
|
21
|
+
│ └── agentic-memory/
|
|
22
|
+
│ ├── __init__.py
|
|
23
|
+
│ ├── cli.py
|
|
24
|
+
│ └── plugin.yaml
|
|
25
|
+
└── context_engine/
|
|
26
|
+
└── agentic-memory/
|
|
27
|
+
├── __init__.py
|
|
28
|
+
└── plugin.yaml
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
## One-Command Install
|
|
32
|
+
|
|
33
|
+
Install the Hermes integration with `uvx` from the published wheel:
|
|
34
|
+
|
|
35
|
+
```bash
|
|
36
|
+
uvx --from https://github.com/jarmen423/agentic-memory/releases/download/hermes-v0.1.1/agentic_memory_hermes-0.1.1-py3-none-any.whl agentic-memory-hermes install --force
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
That command installs both Hermes plugin slots and configures Hermes to use
|
|
40
|
+
Agentic Memory:
|
|
41
|
+
|
|
42
|
+
- memory provider: `~/.hermes/plugins/agentic-memory`
|
|
43
|
+
- context engine: `~/.hermes/hermes-agent/plugins/context_engine/agentic-memory`
|
|
44
|
+
- `memory.provider = agentic-memory`
|
|
45
|
+
- `context.engine = agentic-memory`
|
|
46
|
+
|
|
47
|
+
For an isolated Hermes profile, pass the profile home explicitly:
|
|
48
|
+
|
|
49
|
+
```bash
|
|
50
|
+
uvx --from https://github.com/jarmen423/agentic-memory/releases/download/hermes-v0.1.1/agentic_memory_hermes-0.1.1-py3-none-any.whl agentic-memory-hermes install --force --hermes-home "$HERMES_HOME"
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
If you install the package directly into Hermes' own Python environment, Hermes
|
|
54
|
+
can also discover the plugin through the `hermes_agent.plugins` entry point:
|
|
55
|
+
|
|
56
|
+
```bash
|
|
57
|
+
~/.hermes/hermes-agent/venv/bin/pip install agentic-memory-hermes
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
Once the project is published to PyPI, the shorter command will be:
|
|
61
|
+
|
|
62
|
+
```bash
|
|
63
|
+
uvx agentic-memory-hermes install --force
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
## Manual Install Into Hermes
|
|
67
|
+
|
|
68
|
+
Copy the memory provider into the Hermes profile plugin directory, then copy
|
|
69
|
+
the context engine into the Hermes project plugin directory. Hermes v0.13 scans
|
|
70
|
+
those two plugin types differently:
|
|
71
|
+
|
|
72
|
+
```bash
|
|
73
|
+
cp -R packages/am-hermes/plugins/memory/agentic-memory \
|
|
74
|
+
~/.hermes/plugins/agentic-memory
|
|
75
|
+
|
|
76
|
+
cp -R packages/am-hermes/plugins/context_engine/agentic-memory \
|
|
77
|
+
~/.hermes/hermes-agent/plugins/context_engine/agentic-memory
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
Configure Hermes:
|
|
81
|
+
|
|
82
|
+
```bash
|
|
83
|
+
hermes memory setup
|
|
84
|
+
hermes config set memory.provider agentic-memory
|
|
85
|
+
hermes config set context.engine agentic-memory
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
The setup wizard writes non-secret configuration to:
|
|
89
|
+
|
|
90
|
+
```text
|
|
91
|
+
$HERMES_HOME/agentic-memory.json
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
Secrets are expected in the Hermes `.env` file via:
|
|
95
|
+
|
|
96
|
+
```bash
|
|
97
|
+
AGENTIC_MEMORY_API_KEY=...
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
If you need a managed account key during Hermes setup, use the
|
|
101
|
+
Hermes-attributed account URL:
|
|
102
|
+
|
|
103
|
+
```text
|
|
104
|
+
https://backend.agentmemorylabs.com/account/auth/google/start?connector_source=hermes
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
Direct website signups do not receive a free hosted runtime trial by default.
|
|
108
|
+
Connector-attributed signups can receive a configured trial when Agent Memory
|
|
109
|
+
Labs is running that acquisition campaign.
|
|
110
|
+
|
|
111
|
+
Optional environment overrides:
|
|
112
|
+
|
|
113
|
+
```bash
|
|
114
|
+
AGENTIC_MEMORY_BACKEND_URL=https://backend.agentmemorylabs.com
|
|
115
|
+
AGENTIC_MEMORY_DATA_PLANE_URL=
|
|
116
|
+
AGENTIC_MEMORY_WORKSPACE_ID=hermes
|
|
117
|
+
AGENTIC_MEMORY_DEVICE_ID=hermes-local
|
|
118
|
+
AGENTIC_MEMORY_AGENT_ID=hermes-agent
|
|
119
|
+
AGENTIC_MEMORY_PROJECT_ID=
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
For managed hosted accounts, `AGENTIC_MEMORY_BACKEND_URL` is the control-plane
|
|
123
|
+
URL. During setup the memory provider tries to fetch
|
|
124
|
+
`/product/account/runtime-route`; when the account runtime is ready it saves a
|
|
125
|
+
branded data-plane URL such as `https://rt-abc123.agentmemorylabs.app` in
|
|
126
|
+
`agentic-memory.json`. Normal memory and context calls then use that owned
|
|
127
|
+
runtime URL. Raw provider origins are not written to Hermes config.
|
|
128
|
+
|
|
129
|
+
## Troubleshooting
|
|
130
|
+
|
|
131
|
+
If Hermes reports `HTTP 403` with `error code: 1010`, the request was blocked
|
|
132
|
+
at the Cloudflare edge before it reached Agentic Memory. Check these first:
|
|
133
|
+
|
|
134
|
+
- `AGENTIC_MEMORY_BACKEND_URL` should normally be
|
|
135
|
+
`https://backend.agentmemorylabs.com`.
|
|
136
|
+
- `AGENTIC_MEMORY_DATA_PLANE_URL` should be empty unless setup saved a current
|
|
137
|
+
account runtime route in `~/.hermes/agentic-memory.json`.
|
|
138
|
+
- `AGENTIC_MEMORY_WORKSPACE_ID` should match the workspace bound to the API key
|
|
139
|
+
when using workspace-bound keys. Account-scoped keys can use the default
|
|
140
|
+
`hermes` workspace.
|
|
141
|
+
- `AGENTIC_MEMORY_API_KEY` must be present in the Hermes environment.
|
|
142
|
+
- Hosted edge rules must allow the `agentic-memory-hermes/0.1.0` User-Agent.
|
|
143
|
+
|
|
144
|
+
The plugin records background write failures instead of printing thread
|
|
145
|
+
tracebacks, so search/context tool errors are the canonical symptom to inspect.
|
|
146
|
+
|
|
147
|
+
## Backend Contract
|
|
148
|
+
|
|
149
|
+
The Hermes plugins use the same backend routes as the OpenClaw integration:
|
|
150
|
+
|
|
151
|
+
- `GET /product/account/runtime-route`
|
|
152
|
+
- `POST /openclaw/session/register`
|
|
153
|
+
- `POST /openclaw/memory/search`
|
|
154
|
+
- `POST /openclaw/memory/read`
|
|
155
|
+
- `POST /openclaw/memory/ingest-turn`
|
|
156
|
+
- `POST /openclaw/context/resolve`
|
|
157
|
+
|
|
158
|
+
That keeps this integration a thin host adapter. Agentic Memory remains the
|
|
159
|
+
system of record for storage, retrieval, project scope, and hosted/self-hosted
|
|
160
|
+
backend behavior.
|
|
161
|
+
|
|
162
|
+
## Verify From This Repo
|
|
163
|
+
|
|
164
|
+
The tests use local Hermes ABC shims so this module can be checked without a
|
|
165
|
+
Hermes checkout:
|
|
166
|
+
|
|
167
|
+
```powershell
|
|
168
|
+
.\.venv-agentic-memory\Scripts\python.exe -m pytest packages/am-hermes/tests -q
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
## WSL Paths
|
|
172
|
+
|
|
173
|
+
When this repo is checked out on Windows at `D:\code\agentic-memory`, the WSL
|
|
174
|
+
copy commands are:
|
|
175
|
+
|
|
176
|
+
```bash
|
|
177
|
+
mkdir -p ~/.hermes/plugins ~/.hermes/hermes-agent/plugins/context_engine
|
|
178
|
+
|
|
179
|
+
cp -R /mnt/d/code/agentic-memory/packages/am-hermes/plugins/memory/agentic-memory \
|
|
180
|
+
~/.hermes/plugins/agentic-memory
|
|
181
|
+
|
|
182
|
+
cp -R /mnt/d/code/agentic-memory/packages/am-hermes/plugins/context_engine/agentic-memory \
|
|
183
|
+
~/.hermes/hermes-agent/plugins/context_engine/agentic-memory
|
|
184
|
+
```
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
"""Installer package for the Agentic Memory Hermes Agent plugins.
|
|
2
|
+
|
|
3
|
+
The package does not implement the Hermes memory provider directly. Instead it
|
|
4
|
+
ships the two Hermes plugin directories as package data and exposes a small CLI
|
|
5
|
+
that copies them into the active Hermes profile.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
__version__ = "0.1.1"
|
|
9
|
+
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
"""Hermes entry-point wrapper for Agentic Memory plugins.
|
|
2
|
+
|
|
3
|
+
Hermes can discover Python packages that expose the `hermes_agent.plugins`
|
|
4
|
+
entry-point group, but the existing Hermes memory provider and context engine
|
|
5
|
+
live in file-based plugin directories because Hermes also supports direct
|
|
6
|
+
profile installs. This wrapper lets both distribution styles share the same
|
|
7
|
+
runtime code by loading those bundled plugin modules and forwarding Hermes'
|
|
8
|
+
registration context to each one.
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
from __future__ import annotations
|
|
12
|
+
|
|
13
|
+
import importlib.util
|
|
14
|
+
import sys
|
|
15
|
+
from importlib import resources
|
|
16
|
+
from pathlib import Path
|
|
17
|
+
from types import ModuleType
|
|
18
|
+
from typing import Any
|
|
19
|
+
|
|
20
|
+
PACKAGE_NAME = "agentic_memory_hermes"
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def _bundled_plugins_root() -> Path:
|
|
24
|
+
"""Return the bundled plugin directory from a wheel or source checkout."""
|
|
25
|
+
|
|
26
|
+
source_root = Path(__file__).resolve().parents[2] / "plugins"
|
|
27
|
+
if source_root.is_dir():
|
|
28
|
+
return source_root
|
|
29
|
+
|
|
30
|
+
packaged_root = resources.files(PACKAGE_NAME).joinpath("plugins")
|
|
31
|
+
if packaged_root.is_dir():
|
|
32
|
+
return Path(str(packaged_root))
|
|
33
|
+
|
|
34
|
+
raise FileNotFoundError("Could not locate bundled Hermes plugin files.")
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
def _load_plugin_module(relative_init: str, module_name: str) -> ModuleType:
|
|
38
|
+
"""Load one bundled Hermes plugin module from its `__init__.py` file."""
|
|
39
|
+
|
|
40
|
+
init_path = _bundled_plugins_root() / relative_init
|
|
41
|
+
spec = importlib.util.spec_from_file_location(module_name, init_path)
|
|
42
|
+
if spec is None or spec.loader is None:
|
|
43
|
+
raise ImportError(f"Cannot create module spec for {init_path}")
|
|
44
|
+
|
|
45
|
+
module = importlib.util.module_from_spec(spec)
|
|
46
|
+
sys.modules[module_name] = module
|
|
47
|
+
spec.loader.exec_module(module)
|
|
48
|
+
return module
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
def register(ctx: Any) -> None:
|
|
52
|
+
"""Register both Agentic Memory Hermes plugin surfaces.
|
|
53
|
+
|
|
54
|
+
Args:
|
|
55
|
+
ctx: Hermes' plugin registration context. It is expected to expose
|
|
56
|
+
`register_memory_provider` and `register_context_engine`.
|
|
57
|
+
"""
|
|
58
|
+
|
|
59
|
+
memory_module = _load_plugin_module(
|
|
60
|
+
"memory/agentic-memory/__init__.py",
|
|
61
|
+
"agentic_memory_hermes._memory_plugin",
|
|
62
|
+
)
|
|
63
|
+
context_module = _load_plugin_module(
|
|
64
|
+
"context_engine/agentic-memory/__init__.py",
|
|
65
|
+
"agentic_memory_hermes._context_engine_plugin",
|
|
66
|
+
)
|
|
67
|
+
|
|
68
|
+
memory_module.register(ctx)
|
|
69
|
+
context_module.register(ctx)
|
|
70
|
+
|
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
"""Install Agentic Memory's Hermes Agent plugins into a Hermes profile.
|
|
2
|
+
|
|
3
|
+
Hermes discovers memory providers and context engines from two different
|
|
4
|
+
directories. That makes a raw Python package insufficient by itself: after the
|
|
5
|
+
package is downloaded by `uvx` or `pipx`, the plugin files still need to be
|
|
6
|
+
placed under the user's Hermes home. This module is the bridge from package
|
|
7
|
+
manager install to Hermes' file-based plugin discovery.
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
from __future__ import annotations
|
|
11
|
+
|
|
12
|
+
import argparse
|
|
13
|
+
import os
|
|
14
|
+
import shutil
|
|
15
|
+
import subprocess
|
|
16
|
+
import sys
|
|
17
|
+
from importlib import resources
|
|
18
|
+
from pathlib import Path
|
|
19
|
+
|
|
20
|
+
PACKAGE_NAME = "agentic_memory_hermes"
|
|
21
|
+
PLUGIN_NAME = "agentic-memory"
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def _default_hermes_home() -> Path:
|
|
25
|
+
"""Return the Hermes profile home used by Hermes Agent.
|
|
26
|
+
|
|
27
|
+
Hermes honors `HERMES_HOME` for profile isolation. When that variable is
|
|
28
|
+
absent, Hermes defaults to `~/.hermes`.
|
|
29
|
+
"""
|
|
30
|
+
|
|
31
|
+
return Path(os.environ.get("HERMES_HOME", "~/.hermes")).expanduser()
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
def _bundled_plugins_root() -> Path:
|
|
35
|
+
"""Locate bundled plugin files in a wheel or in the source checkout.
|
|
36
|
+
|
|
37
|
+
Wheels include `agentic_memory_hermes/plugins` through Hatch's
|
|
38
|
+
`force-include` setting. During repo-local tests, the files live beside the
|
|
39
|
+
packaging metadata under `packages/am-hermes/plugins`, so the fallback keeps
|
|
40
|
+
the installer runnable before the wheel is built.
|
|
41
|
+
"""
|
|
42
|
+
|
|
43
|
+
source_root = Path(__file__).resolve().parents[2] / "plugins"
|
|
44
|
+
if source_root.is_dir():
|
|
45
|
+
return source_root
|
|
46
|
+
|
|
47
|
+
packaged_root = resources.files(PACKAGE_NAME).joinpath("plugins")
|
|
48
|
+
if packaged_root.is_dir():
|
|
49
|
+
return Path(str(packaged_root))
|
|
50
|
+
|
|
51
|
+
raise FileNotFoundError("Could not locate bundled Hermes plugin files.")
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
def _copy_tree(source: Path, target: Path, *, force: bool, dry_run: bool) -> None:
|
|
55
|
+
"""Copy one Hermes plugin directory to its discovery target.
|
|
56
|
+
|
|
57
|
+
Args:
|
|
58
|
+
source: Bundled plugin directory inside this package.
|
|
59
|
+
target: Hermes discovery directory to create.
|
|
60
|
+
force: Remove an existing target before copying.
|
|
61
|
+
dry_run: Print intended actions without touching the filesystem.
|
|
62
|
+
|
|
63
|
+
Raises:
|
|
64
|
+
FileExistsError: If the target exists and `force` is false.
|
|
65
|
+
"""
|
|
66
|
+
|
|
67
|
+
if target.exists() and not force:
|
|
68
|
+
raise FileExistsError(
|
|
69
|
+
f"{target} already exists. Re-run with --force to replace the installed plugin."
|
|
70
|
+
)
|
|
71
|
+
|
|
72
|
+
print(f"{'Would install' if dry_run else 'Installing'} {source} -> {target}")
|
|
73
|
+
if dry_run:
|
|
74
|
+
return
|
|
75
|
+
|
|
76
|
+
if target.exists():
|
|
77
|
+
shutil.rmtree(target)
|
|
78
|
+
target.parent.mkdir(parents=True, exist_ok=True)
|
|
79
|
+
ignore = shutil.ignore_patterns("__pycache__", "*.pyc", "*.pyo")
|
|
80
|
+
shutil.copytree(source, target, ignore=ignore)
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
def _run_hermes_config(key: str, value: str, *, dry_run: bool) -> bool:
|
|
84
|
+
"""Set one Hermes config key through Hermes' own CLI when available.
|
|
85
|
+
|
|
86
|
+
Returns:
|
|
87
|
+
True when the command was run successfully, or False when Hermes is not
|
|
88
|
+
on PATH or rejected the setting.
|
|
89
|
+
"""
|
|
90
|
+
|
|
91
|
+
command = ["hermes", "config", "set", key, value]
|
|
92
|
+
print(f"{'Would run' if dry_run else 'Running'}: {' '.join(command)}")
|
|
93
|
+
if dry_run:
|
|
94
|
+
return True
|
|
95
|
+
|
|
96
|
+
try:
|
|
97
|
+
subprocess.run(command, check=True)
|
|
98
|
+
except (FileNotFoundError, subprocess.CalledProcessError) as exc:
|
|
99
|
+
print(f"Warning: could not run {' '.join(command)} ({exc}).", file=sys.stderr)
|
|
100
|
+
return False
|
|
101
|
+
return True
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
def install(args: argparse.Namespace) -> int:
|
|
105
|
+
"""Install the memory provider and context engine into Hermes."""
|
|
106
|
+
|
|
107
|
+
hermes_home = Path(args.hermes_home).expanduser()
|
|
108
|
+
plugins_root = _bundled_plugins_root()
|
|
109
|
+
|
|
110
|
+
memory_source = plugins_root / "memory" / PLUGIN_NAME
|
|
111
|
+
context_source = plugins_root / "context_engine" / PLUGIN_NAME
|
|
112
|
+
memory_target = hermes_home / "plugins" / PLUGIN_NAME
|
|
113
|
+
context_target = hermes_home / "hermes-agent" / "plugins" / "context_engine" / PLUGIN_NAME
|
|
114
|
+
|
|
115
|
+
_copy_tree(memory_source, memory_target, force=args.force, dry_run=args.dry_run)
|
|
116
|
+
_copy_tree(context_source, context_target, force=args.force, dry_run=args.dry_run)
|
|
117
|
+
|
|
118
|
+
if args.configure:
|
|
119
|
+
_run_hermes_config("memory.provider", PLUGIN_NAME, dry_run=args.dry_run)
|
|
120
|
+
_run_hermes_config("context.engine", PLUGIN_NAME, dry_run=args.dry_run)
|
|
121
|
+
|
|
122
|
+
print("Agentic Memory Hermes plugin install complete.")
|
|
123
|
+
print(f"Hermes home: {hermes_home}")
|
|
124
|
+
print(f"Memory provider: {memory_target}")
|
|
125
|
+
print(f"Context engine: {context_target}")
|
|
126
|
+
return 0
|
|
127
|
+
|
|
128
|
+
|
|
129
|
+
def build_parser() -> argparse.ArgumentParser:
|
|
130
|
+
"""Build the command-line parser for the installer."""
|
|
131
|
+
|
|
132
|
+
parser = argparse.ArgumentParser(
|
|
133
|
+
prog="agentic-memory-hermes",
|
|
134
|
+
description="Install Agentic Memory's Hermes Agent plugins.",
|
|
135
|
+
)
|
|
136
|
+
subparsers = parser.add_subparsers(dest="command")
|
|
137
|
+
|
|
138
|
+
install_parser = subparsers.add_parser(
|
|
139
|
+
"install",
|
|
140
|
+
help="Copy Agentic Memory's Hermes plugins into the active Hermes profile.",
|
|
141
|
+
)
|
|
142
|
+
install_parser.add_argument(
|
|
143
|
+
"--hermes-home",
|
|
144
|
+
default=str(_default_hermes_home()),
|
|
145
|
+
help="Hermes profile home. Defaults to HERMES_HOME or ~/.hermes.",
|
|
146
|
+
)
|
|
147
|
+
install_parser.add_argument(
|
|
148
|
+
"--force",
|
|
149
|
+
action="store_true",
|
|
150
|
+
help="Replace existing Agentic Memory Hermes plugin directories.",
|
|
151
|
+
)
|
|
152
|
+
install_parser.add_argument(
|
|
153
|
+
"--no-configure",
|
|
154
|
+
dest="configure",
|
|
155
|
+
action="store_false",
|
|
156
|
+
help="Copy files only; do not run `hermes config set`.",
|
|
157
|
+
)
|
|
158
|
+
install_parser.add_argument(
|
|
159
|
+
"--dry-run",
|
|
160
|
+
action="store_true",
|
|
161
|
+
help="Show intended file copies and config commands without changing anything.",
|
|
162
|
+
)
|
|
163
|
+
install_parser.set_defaults(func=install, configure=True)
|
|
164
|
+
|
|
165
|
+
return parser
|
|
166
|
+
|
|
167
|
+
|
|
168
|
+
def main(argv: list[str] | None = None) -> int:
|
|
169
|
+
"""Entry point used by `uvx agentic-memory-hermes` and `pipx run`."""
|
|
170
|
+
|
|
171
|
+
parser = build_parser()
|
|
172
|
+
args = parser.parse_args(argv)
|
|
173
|
+
if not hasattr(args, "func"):
|
|
174
|
+
parser.print_help()
|
|
175
|
+
return 2
|
|
176
|
+
return args.func(args)
|
|
177
|
+
|
|
178
|
+
|
|
179
|
+
if __name__ == "__main__": # pragma: no cover
|
|
180
|
+
raise SystemExit(main())
|