@eventmodelers/cli 1.0.100 → 1.0.102

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 CHANGED
@@ -217,8 +217,8 @@ server to register by hand (`<baseUrl>/mcp`, header `x-token` from `$EVENTMODELE
217
217
  Run `init-agents --hosts <harness>` to install the skills for a harness that does not read
218
218
  `.claude/skills`. There are no subagents: self-directed work is done inline.
219
219
 
220
- **In a container.** `docker/agent/Dockerfile` runs the modeling agent with Claude Code, OpenCode and Codex all installed;
221
- `AGENT` (`claude` by default, `opencode` or `codex`) picks which one runs. Build from this directory and pass the board's
220
+ **In a container.** `docker/agent/Dockerfile` runs the modeling agent with Claude Code, OpenCode, Codex, Gemini CLI and Hermes all installed;
221
+ `AGENT` (`claude` by default, or `opencode`, `codex`, `gemini`, `hermes`) picks which one runs. Build from this directory and pass the board's
222
222
  credentials as env vars:
223
223
 
224
224
  ```bash
@@ -232,6 +232,15 @@ Claude authenticates with `ANTHROPIC_API_KEY`, or with your subscription via `CL
232
232
  once). The container is the sandbox, so the image sets `EVENTMODELERS_CODEX_NO_SANDBOX=1`, which makes the `codex` preset run
233
233
  `--dangerously-bypass-approvals-and-sandbox` instead of `--full-auto`.
234
234
 
235
+ Keys: `OPENAI_API_KEY` (codex), `GEMINI_API_KEY` (gemini), and for Hermes a provider key such as `OPENROUTER_API_KEY`. Hermes reads MCP
236
+ servers only from `~/.hermes/config.yaml`, so the images ship the eventmodelers server there (env references, no secret); outside
237
+ Docker the CLI logs the snippet to add. Run `hermes` in a container as `-e AGENT=hermes --model <provider/model>`.
238
+
239
+ **Any OpenAI-compatible endpoint with OpenCode.** `-e MODEL_BASE_URL=<url> -e MODEL_NAME=<id> [-e MODEL_API_KEY=...]` makes the
240
+ OpenCode container (`AGENT=opencode`, agent and build images) use that endpoint — a local Ollama/vLLM (`http://host.docker.internal:11434/v1`),
241
+ OpenRouter, LiteLLM or a company gateway — without writing an `opencode.json`. The entrypoint registers it as provider `custom` and runs
242
+ `--model custom/<MODEL_NAME>`. `MODEL_NAME` is required; other agents reject `MODEL_BASE_URL`.
243
+
235
244
  `--agent`, `--exec`, `--local-ai` and `--bash` each pick the runner, so pass at most one of them —
236
245
  any two together are rejected. For a local or self-hosted model use `--local-ai`, not `--agent`.
237
246
 
package/cli.js CHANGED
@@ -82,6 +82,9 @@ const AGENT_PRESETS = {
82
82
  opencode: { modeling: 'opencode run --standalone --auto', build: 'opencode run --standalone --auto --format json' },
83
83
  codex: { modeling: 'codex exec --full-auto', build: 'codex exec --json --full-auto' },
84
84
  gemini: { modeling: 'gemini --yolo -p', build: 'gemini --yolo --output-format stream-json -p' },
85
+ // -q takes the prompt, so the preset ends with it (the --model flag is inserted before it, below).
86
+ // -Q is the plain-text mode a modeling turn reads its answer from; --format stream-json is the build kit's.
87
+ hermes: { modeling: 'hermes chat --yolo -Q -q', build: 'hermes chat --yolo --format stream-json -q' },
85
88
  };
86
89
 
87
90
  function printAgentPresets() {
@@ -3630,7 +3633,11 @@ credentialFlags(program
3630
3633
  console.error('❌ --model does not apply to --exec — put the harness\'s own model flag in the command (e.g. --exec "opencode run --standalone -m <id>"), or use --agent.');
3631
3634
  process.exit(1);
3632
3635
  }
3633
- if (model && agentExec) opts.exec = `${agentExec} -m '${model.replace(/'/g, `'\\''`)}'`;
3636
+ if (model && agentExec) {
3637
+ const modelFlag = `-m '${model.replace(/'/g, `'\\''`)}'`;
3638
+ // A trailing -q takes the prompt as its value, so the model flag has to come before it.
3639
+ opts.exec = agentExec.endsWith(' -q') ? `${agentExec.slice(0, -3)}${modelFlag} -q` : `${agentExec} ${modelFlag}`;
3640
+ }
3634
3641
  else if (model && resolveLocalAiTarget(opts) !== null) process.env.LOCAL_AI_MODEL = model;
3635
3642
  // The default Claude runner: the build kit's ralph-claude.js reads RALPH_MODEL from the env it
3636
3643
  // inherits; the modeling loop takes it as runModeling's `model`.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@eventmodelers/cli",
3
- "version": "1.0.100",
3
+ "version": "1.0.102",
4
4
  "description": "Eventmodelers CLI — real-time Claude agent + skills for Claude Code, for any stack (Node, Supabase, Axon, OpenCQRS, UmaDB, Kurrent, or modeling-only)",
5
5
  "type": "module",
6
6
  "bin": {
@@ -1,8 +1,9 @@
1
- // Registers the eventmodelers MCP server with an external agent harness (OpenCode, Gemini, Codex),
1
+ // Registers the eventmodelers MCP server with an external agent harness (OpenCode, Gemini, Codex, Hermes),
2
2
  // for both loops that hand turns to one: the modeling loop (lib/modeling-exec.js) and the build
3
3
  // loop (ralph-exec.js).
4
4
 
5
5
  import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'fs';
6
+ import { homedir } from 'os';
6
7
  import { dirname, join } from 'path';
7
8
 
8
9
  // POSIX single-quote escaping: close, insert an escaped quote, reopen. A turn is multi-line
@@ -60,6 +61,18 @@ const MCP_REGISTRATIONS = {
60
61
  });
61
62
  return { command, file: ok ? '.gemini/settings.json' : null, manual: ok ? null : `add mcpServers.eventmodelers = ${JSON.stringify(entry)} to .gemini/settings.json` };
62
63
  },
64
+ // Hermes reads MCP servers from ~/.hermes/config.yaml only (there is no project-level file), so
65
+ // this never writes it — a user-wide file is not ours to rewrite. It reports the server as
66
+ // registered when the file already names it (the docker images ship it), and says what to add otherwise.
67
+ hermes: (command, _projectDir, url) => {
68
+ const file = join(process.env.HERMES_HOME || join(homedir(), '.hermes'), 'config.yaml');
69
+ const has = existsSync(file) && /^\s+eventmodelers:/m.test(readFileSync(file, 'utf8'));
70
+ return {
71
+ command,
72
+ file: null,
73
+ manual: has ? null : `add to ${file}:\nmcp_servers:\n eventmodelers:\n url: "${url}"\n headers:\n x-token: "\${EVENTMODELERS_TOKEN}"`,
74
+ };
75
+ },
63
76
  codex: (command, _projectDir, url) => ({
64
77
  // -c values are TOML; env_http_headers names the env var each header is read from.
65
78
  command: `${command} -c ${shellQuote(`mcp_servers.eventmodelers.url="${url}"`)} -c ${shellQuote('mcp_servers.eventmodelers.env_http_headers={x-token="EVENTMODELERS_TOKEN",x-agent-id="EVENTMODELERS_AGENT_ID"}')}`,
@@ -89,7 +102,7 @@ export function registerMcp(command, projectDir, baseUrl, log) {
89
102
  return { command, registered: false };
90
103
  }
91
104
  const reg = MCP_REGISTRATIONS[harness](command, projectDir, url);
92
- if (reg.manual) log(`MCP: could not update the ${harness} config (not plain JSON) — ${reg.manual}`);
105
+ if (reg.manual) log(`MCP: could not update the ${harness} config${harness === 'hermes' ? '' : ' (not plain JSON)'} — ${reg.manual}`);
93
106
  else log(`MCP: eventmodelers registered for ${harness}${reg.file ? ` in ${reg.file}` : ' via -c flags'}`);
94
107
  return { command: reg.command, registered: !reg.manual };
95
108
  }