@eventmodelers/cli 1.0.99 → 1.0.101
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 +16 -6
- package/cli.js +15 -2
- package/package.json +1 -1
- package/shared/build-kit/lib/mcp-register.js +15 -2
package/README.md
CHANGED
|
@@ -217,15 +217,25 @@ 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
|
|
221
|
-
(
|
|
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
|
+
credentials as env vars:
|
|
222
223
|
|
|
223
224
|
```bash
|
|
224
|
-
docker build -f docker/
|
|
225
|
-
docker run --rm -e
|
|
226
|
-
-e
|
|
225
|
+
docker build -f docker/agent/Dockerfile -t eventmodelers-agent .
|
|
226
|
+
docker run --rm -e AGENT=codex -e OPENAI_API_KEY \
|
|
227
|
+
-e EVENTMODELERS_TOKEN=... -e EVENTMODELERS_ORGANIZATION_ID=... -e EVENTMODELERS_BOARD_ID=... \
|
|
228
|
+
eventmodelers-agent --model gpt-5-codex
|
|
227
229
|
```
|
|
228
230
|
|
|
231
|
+
Claude authenticates with `ANTHROPIC_API_KEY`, or with your subscription via `CLAUDE_CODE_OAUTH_TOKEN` (run `claude setup-token`
|
|
232
|
+
once). The container is the sandbox, so the image sets `EVENTMODELERS_CODEX_NO_SANDBOX=1`, which makes the `codex` preset run
|
|
233
|
+
`--dangerously-bypass-approvals-and-sandbox` instead of `--full-auto`.
|
|
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
|
+
|
|
229
239
|
`--agent`, `--exec`, `--local-ai` and `--bash` each pick the runner, so pass at most one of them —
|
|
230
240
|
any two together are rejected. For a local or self-hosted model use `--local-ai`, not `--agent`.
|
|
231
241
|
|
|
@@ -734,7 +744,7 @@ The workflow then:
|
|
|
734
744
|
| `images` | Builds the six agent images for `linux/amd64` and `linux/arm64`, **scans each for credentials** (`.github/scripts/scan-image.sh`), and only then pushes it |
|
|
735
745
|
| `merge` | Combines the two architectures into one multi-arch image per name, tagged `:<tag>` and `:latest` |
|
|
736
746
|
|
|
737
|
-
Images land in `docker.io/nebulit/`: `eventmodelers-agent
|
|
747
|
+
Images land in `docker.io/nebulit/`: `eventmodelers-agent` (modeling) and `em-studio-buildkit-{node,java,dotnet}` (building); each carries all three agent CLIs and `AGENT` selects one. They run the CLI from the tagged checkout, not from npm, so they don't wait on the npm publish.
|
|
738
748
|
|
|
739
749
|
**One-time setup:** an `NPM_TOKEN` repo secret (an npm automation token allowed to publish `@eventmodelers/cli`). The images push with the built-in `GITHUB_TOKEN`; new GHCR packages start private, so make them public in the org's package settings if they should be pullable without a login.
|
|
740
750
|
|
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() {
|
|
@@ -116,7 +119,13 @@ function resolveAgentPreset(opts, loop) {
|
|
|
116
119
|
console.error('❌ --agent is mutually exclusive with --local-ai/--bash — pick one runner.');
|
|
117
120
|
process.exit(1);
|
|
118
121
|
}
|
|
119
|
-
|
|
122
|
+
const cmd = AGENT_PRESETS[name]?.[loop] ?? null;
|
|
123
|
+
// The docker images set this: Codex's own sandbox (landlock) can't start inside a container, and the
|
|
124
|
+
// container already is the sandbox — the flag Codex documents for externally sandboxed environments.
|
|
125
|
+
if (name === 'codex' && cmd && process.env.EVENTMODELERS_CODEX_NO_SANDBOX === '1') {
|
|
126
|
+
return cmd.replace('--full-auto', '--dangerously-bypass-approvals-and-sandbox');
|
|
127
|
+
}
|
|
128
|
+
return cmd;
|
|
120
129
|
}
|
|
121
130
|
|
|
122
131
|
const STACKS = {
|
|
@@ -3624,7 +3633,11 @@ credentialFlags(program
|
|
|
3624
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.');
|
|
3625
3634
|
process.exit(1);
|
|
3626
3635
|
}
|
|
3627
|
-
if (model && agentExec)
|
|
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
|
+
}
|
|
3628
3641
|
else if (model && resolveLocalAiTarget(opts) !== null) process.env.LOCAL_AI_MODEL = model;
|
|
3629
3642
|
// The default Claude runner: the build kit's ralph-claude.js reads RALPH_MODEL from the env it
|
|
3630
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.
|
|
3
|
+
"version": "1.0.101",
|
|
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
|
}
|