hermes-action-bridge 0.3.0 → 0.5.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.
Files changed (61) hide show
  1. package/CHANGELOG.md +70 -0
  2. package/README.md +123 -22
  3. package/dist/adapters/hermes-cli.d.ts +14 -0
  4. package/dist/adapters/hermes-cli.js +80 -21
  5. package/dist/adapters/hermes-cli.js.map +1 -1
  6. package/dist/approvals.d.ts +35 -0
  7. package/dist/approvals.js +96 -0
  8. package/dist/approvals.js.map +1 -0
  9. package/dist/audit-log.d.ts +21 -0
  10. package/dist/audit-log.js +31 -0
  11. package/dist/audit-log.js.map +1 -0
  12. package/dist/capabilities.d.ts +29 -0
  13. package/dist/capabilities.js +24 -0
  14. package/dist/capabilities.js.map +1 -0
  15. package/dist/cli.js +205 -20
  16. package/dist/cli.js.map +1 -1
  17. package/dist/config.js +0 -6
  18. package/dist/config.js.map +1 -1
  19. package/dist/doctor.d.ts +8 -1
  20. package/dist/doctor.js +76 -13
  21. package/dist/doctor.js.map +1 -1
  22. package/dist/execution-gate.d.ts +5 -0
  23. package/dist/execution-gate.js +20 -0
  24. package/dist/execution-gate.js.map +1 -0
  25. package/dist/http-server.d.ts +18 -0
  26. package/dist/http-server.js +310 -0
  27. package/dist/http-server.js.map +1 -0
  28. package/dist/install/launcher.d.ts +3 -0
  29. package/dist/install/launcher.js +7 -0
  30. package/dist/install/launcher.js.map +1 -0
  31. package/dist/install/mcp-config.js +12 -3
  32. package/dist/install/mcp-config.js.map +1 -1
  33. package/dist/install/mcp-service.d.ts +44 -0
  34. package/dist/install/mcp-service.js +172 -0
  35. package/dist/install/mcp-service.js.map +1 -0
  36. package/dist/install/templates.js +38 -32
  37. package/dist/install/templates.js.map +1 -1
  38. package/dist/install/types.d.ts +1 -0
  39. package/dist/jobs.d.ts +51 -0
  40. package/dist/jobs.js +244 -0
  41. package/dist/jobs.js.map +1 -0
  42. package/dist/mcp-server.d.ts +32 -0
  43. package/dist/mcp-server.js +394 -25
  44. package/dist/mcp-server.js.map +1 -1
  45. package/dist/policy.js +9 -2
  46. package/dist/policy.js.map +1 -1
  47. package/dist/run.js +0 -1
  48. package/dist/run.js.map +1 -1
  49. package/dist/types.d.ts +2 -4
  50. package/dist/validation.d.ts +1 -0
  51. package/dist/validation.js +8 -0
  52. package/dist/validation.js.map +1 -0
  53. package/docs/ARCHITECTURE.md +69 -9
  54. package/docs/FUNCTIONAL-TESTS.md +27 -12
  55. package/examples/claude-code/SKILL.md +35 -29
  56. package/examples/codex/SKILL.md +35 -29
  57. package/package.json +5 -3
  58. package/plugins/hermes-action/.codex-plugin/plugin.json +30 -0
  59. package/plugins/hermes-action/.mcp.json +8 -0
  60. package/plugins/hermes-action/assets/app-icon.png +0 -0
  61. package/plugins/hermes-action/skills/hermes-action-bridge/SKILL.md +61 -0
package/CHANGELOG.md CHANGED
@@ -4,6 +4,76 @@ All notable changes to this project are documented here. The format is based on
4
4
  [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project adheres to
5
5
  [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
6
6
 
7
+ ## [Unreleased]
8
+
9
+ ## [0.5.0] - 2026-07-25
10
+
11
+ ### Added
12
+
13
+ - Complete Codex and Claude Code installation: `install all` now installs the
14
+ managed skills and registers a verified global MCP server through each
15
+ agent's native CLI using the absolute bridge launcher.
16
+ - `doctor` now detects missing/conflicting MCP registrations and performs a
17
+ token-free MCP initialize/list-tools handshake.
18
+ - Configuration-backed `hermes_capabilities`, concurrency-limited
19
+ asynchronous jobs (`submit`, `status`, `result`, `cancel`), and one-shot
20
+ two-phase actions (`prepare`, `approve`, `reject`).
21
+ - Privacy-preserving owner-only JSONL audit metadata for job and approval
22
+ transitions.
23
+ - Opt-in Streamable HTTP transport with loopback defaults and an authenticated,
24
+ Tailscale-only direct-listen mode.
25
+
26
+ ### Changed
27
+
28
+ - Native skills now prefer discoverable `hermes_*` MCP tools and clearly
29
+ separate Hermes-owned integrations from ordinary local coding work.
30
+ - The Codex plugin manifest now uses the supported `mcpServers` shape, ships in
31
+ the npm tarball, and shares the package version.
32
+ - Refreshed patched `fast-uri` and `postcss` releases in the lockfile and
33
+ documented why the remaining transitive Hono advisory is not reachable in
34
+ the bridge HTTP architecture.
35
+
36
+ ### Documentation
37
+
38
+ - Added a "Trusted presets (direct execution)" README section: how to define a `require_approval_for: []`
39
+ preset in user config to run `execute` actions without the approval gate, plus the safety trade-offs
40
+ (keep it in user scope, never allowlist `hermes-action run`).
41
+
42
+ ## [0.4.0] - 2026-07-03
43
+
44
+ Deterministic security model, per-call MCP overrides, and installer hardening.
45
+
46
+ ### Added
47
+
48
+ - MCP `hermes_run` now accepts `model`, `provider`, `maxTurns`, and `timeoutSeconds` overrides, so a
49
+ caller can pick a faster model or cap the tool-calling budget per request (previously only settable via a
50
+ preset).
51
+
52
+ ### Fixed
53
+
54
+ - `install mcp --write` on an empty or whitespace-only `.mcp.json` (e.g. after `touch`) now initializes it
55
+ instead of failing with "not valid JSON".
56
+ - `install mcp --write` no longer silently overwrites a customized `hermes-action` entry in `.mcp.json`; it
57
+ refuses with an actionable message so a custom command/args is never lost.
58
+ - Removed the non-functional `profile` option (`--profile`, `defaults.profile`, `preset.profile`). The
59
+ Hermes CLI has no per-invocation profile flag — profiles are switched globally with `hermes profile use`
60
+ — so a configured profile made the bridge emit an invalid `hermes --profile … chat` command. Target a
61
+ specific Hermes profile via `runtime.command` (e.g. a `hermes profile alias` wrapper) instead.
62
+
63
+ ### Changed
64
+
65
+ - **Policy is now deterministic and language-agnostic.** In `execute` mode the bridge downgrades to
66
+ `request-approval` by default — regardless of the prompt's wording or language — unless the preset is
67
+ explicitly trusted (empty `require_approval_for`) or `--yolo` is set. Previously the downgrade fired only
68
+ when an English keyword was detected, so non-English side-effecting prompts (e.g. `supprime…`, `paie…`)
69
+ silently ran in `execute`. Keyword risk detection is retained but is now **informational only** (surfaced
70
+ in the prompt envelope), never a security control. The real barrier is the host agent's approval prompt.
71
+
72
+ ### Documentation
73
+
74
+ - Documented the security model: host-agent approval is the deterministic barrier; do not allowlist
75
+ `hermes-action run` (`execute`/`yolo`) in the coding agent.
76
+
7
77
  ## [0.3.0] - 2026-06-30
8
78
 
9
79
  Execution robustness and large-context support.
package/README.md CHANGED
@@ -23,14 +23,16 @@ If an agent needs to do something outside its local coding session — research,
23
23
  ## Features
24
24
 
25
25
  - Generic `hermes-action run` command for one-shot delegation.
26
- - Configurable presets for skills, toolsets, provider/model, profile, source, and max turns.
27
- - Safety policy that can downgrade risky `execute` requests to `request-approval`, with optional per-preset overrides.
26
+ - Configurable presets for skills, toolsets, provider/model, source, and max turns.
27
+ - Deterministic, language-agnostic safety policy: downgrades `execute` to `request-approval` by default, with per-preset trust overrides.
28
28
  - Explicit `--yolo` mode for users who intentionally want to bypass bridge-level policy.
29
29
  - Context file injection with a per-file cap and a configurable aggregate budget (clear error instead of a cryptic `E2BIG`).
30
30
  - Automatic large-context delivery: an oversized prompt is handed to Hermes through a secure temp file instead of overflowing the command line.
31
31
  - Per-run timeouts (configurable, with per-mode defaults) that always reap the Hermes child process.
32
32
  - Dry-run mode for debugging the exact Hermes command, prompt, and computed prompt size.
33
- - Minimal MCP server exposing delegation tools: `hermes_run`, `hermes_plan`, `hermes_presets`, and `hermes_status`.
33
+ - Complete Codex and Claude Code installer: managed skill plus verified global MCP registration.
34
+ - MCP capability discovery, cancellable asynchronous jobs, and one-shot two-phase approvals with a privacy-preserving local audit log.
35
+ - Local stdio transport plus an opt-in, authenticated Streamable HTTP transport for Tailscale-restricted hosts.
34
36
  - No project-specific assumptions. All behavior is configured through YAML and CLI flags.
35
37
 
36
38
  ## Requirements
@@ -52,13 +54,20 @@ Install from npm:
52
54
  npm install -g hermes-action-bridge
53
55
  ```
54
56
 
55
- Then check it works:
57
+ Install the skill and MCP registration for Codex and Claude Code, then verify
58
+ the complete setup:
56
59
 
57
60
  ```bash
58
61
  hermes-action --version
62
+ hermes-action install all
59
63
  hermes-action doctor
60
64
  ```
61
65
 
66
+ Global installation is all-or-nothing for the requested agents. If Codex or
67
+ Claude Code is unavailable, conflicting, or cannot verify its user-scoped
68
+ stdio MCP entry, the command exits non-zero without installing the requested
69
+ skills. Use `--project` for an explicit skill-only setup.
70
+
62
71
  <details>
63
72
  <summary>From source (for development)</summary>
64
73
 
@@ -103,14 +112,16 @@ hermes-action run --dry-run --json "Summarize this project."
103
112
 
104
113
  ## Execution modes
105
114
 
106
- - `plan`: Hermes returns a plan only. No side effects.
115
+ - `plan`: Hermes is instructed to return a plan only. Treat it as open-world because configured tools remain available.
107
116
  - `draft`: Hermes produces an artifact only. No external side effects.
108
117
  - `execute`: Hermes may execute allowed actions, while still following Hermes' own safety rules.
109
- - `request-approval`: Hermes prepares the action and asks the human for approval before irreversible external effects.
118
+ - `request-approval`: Hermes prepares an action without executing it. MCP
119
+ callers should use `hermes_prepare` and then call `hermes_approve` only after
120
+ explicit human approval.
110
121
 
111
- If the bridge detects a risky request in `execute` mode, it can automatically switch to `request-approval` unless YOLO is enabled.
122
+ The guard is deterministic and language-agnostic: in `execute` mode the bridge switches to `request-approval` by default — regardless of the prompt's wording or language — unless the preset is explicitly trusted (empty `require_approval_for`) or `--yolo` is set. It does not try to infer risk from keywords. See [Security model](#security-model) for why the real barrier is your coding agent's own approval prompt.
112
123
 
113
- Risk categories:
124
+ Risk categories below are **informational only**: the bridge surfaces the ones it recognizes in the prompt envelope to help you and Hermes decide, but they never drive the mode. (Keyword matching is English-biased and trivially evaded, so it must not be a security control.)
114
125
 
115
126
  - `publish_external`
116
127
  - `send_message`
@@ -132,6 +143,30 @@ YOLO only bypasses the bridge policy. It does not remove Hermes Agent's own safe
132
143
 
133
144
  Use it only when the caller and environment are trusted.
134
145
 
146
+ ## Trusted presets (direct execution)
147
+
148
+ By default every `execute` is downgraded to `request-approval` — the right default when an agent might act unattended. When *you* are the one asking for an action and want it to run without that extra gate, define a **trusted preset**: one whose `require_approval_for` is an empty list. Put it in your **user** config so it is yours alone and available in every project:
149
+
150
+ ```yaml
151
+ # ~/.config/hermes-action/config.yaml (user scope, merged before any project config)
152
+ presets:
153
+ act:
154
+ description: Direct execution of an action I explicitly asked for (trusted).
155
+ require_approval_for: []
156
+ ```
157
+
158
+ Run actions through it — `execute` stays `execute`, with no downgrade and no `--yolo` needed:
159
+
160
+ ```bash
161
+ hermes-action run --preset act --mode execute "post the release note to #general"
162
+ ```
163
+
164
+ **Keep it safe:**
165
+
166
+ - A trusted preset relaxes only the bridge's own gate. The real barrier stays your coding agent's approval prompt, so **do not allowlist `hermes-action run` (`execute`/`yolo`)** (see [Security model](#security-model)).
167
+ - Keep it in your **user** config; it never ships in the public package, and the distributed `SKILL.md` stays cautious for everyone else.
168
+ - Reserve trusted presets for actions a human explicitly asks for. Leave the conservative default for anything an agent could trigger on its own.
169
+
135
170
  ## Configuration
136
171
 
137
172
  `hermes-action` loads config in this order:
@@ -222,6 +257,7 @@ hermes-action run [options] "request"
222
257
  hermes-action presets [--json]
223
258
  hermes-action status [--json]
224
259
  hermes-action mcp
260
+ hermes-action serve [--listen 127.0.0.1] [--port 8765]
225
261
  hermes-action install <claude-code|codex|all|mcp> [options]
226
262
  hermes-action uninstall <claude-code|codex|all|mcp> [options]
227
263
  hermes-action doctor [--json] [--probe]
@@ -234,7 +270,6 @@ Common `run` options:
234
270
  --preset <name>
235
271
  --context <path...>
236
272
  --config <path>
237
- --profile <name>
238
273
  --provider <name>
239
274
  --model <name>
240
275
  --max-turns <number>
@@ -247,17 +282,24 @@ Common `run` options:
247
282
 
248
283
  ## Native agent skills
249
284
 
250
- Instead of pasting instructions by hand, install a native skill so Claude Code and Codex know when to delegate to Hermes. The skill is the same open-standard `SKILL.md` for both agents; the CLI stays the deterministic execution layer.
285
+ Instead of pasting instructions and MCP snippets by hand, run the complete
286
+ installer. It installs the open-standard skill and registers the local stdio
287
+ MCP server through each agent's own CLI:
251
288
 
252
289
  ```bash
253
- hermes-action doctor # check Node, Hermes, agents, and installed skills
254
- hermes-action install all # ~/.claude/skills and ~/.codex/skills
290
+ hermes-action install all # skills + global MCP for both agents
291
+ hermes-action doctor # verifies skills, registrations, and MCP handshake
255
292
  hermes-action install claude-code --print # preview, write nothing
256
293
  hermes-action install codex --project-hint # also add a marker block to AGENTS.md
257
294
  hermes-action uninstall all
258
295
  ```
259
296
 
260
- Install behavior is safe by default: it never modifies `CLAUDE.md` / `AGENTS.md` unless you pass `--project-hint`, refuses to overwrite a file it did not generate, and is idempotent. Use `--project` for a project-local skill and `--dry-run` to preview operations.
297
+ Install behavior is safe by default: it uses a stable absolute bridge path,
298
+ does not depend on an interactive `PATH`, never modifies `CLAUDE.md` /
299
+ `AGENTS.md` unless you pass `--project-hint`, and refuses to overwrite either a
300
+ foreign skill or a customized MCP entry. Re-running it is idempotent. Use
301
+ `--project` for a project-local skill only and `--dry-run` to preview
302
+ operations.
261
303
 
262
304
  The generated skill is shown in [`examples/claude-code/SKILL.md`](examples/claude-code/SKILL.md). Project-hint usage is documented in [`examples/claude-code/CLAUDE.md`](examples/claude-code/CLAUDE.md) and [`examples/codex/AGENTS.md`](examples/codex/AGENTS.md).
263
305
 
@@ -272,15 +314,20 @@ codex plugin add hermes-action@hermes-action-bridge
272
314
 
273
315
  This registers the `hermes-action` MCP server and the Hermes delegation skill in Codex. Hermes Agent must be installed locally — the plugin runs `npx -y hermes-action-bridge mcp`.
274
316
 
317
+ > **Faster MCP startup:** `npx` re-resolves the package on every server start.
318
+ > The native installer registers the absolute global launcher instead.
319
+
275
320
  ## MCP configuration
276
321
 
277
- Print the config snippet for your client (Claude Code / Cursor / VS Code use JSON; Codex uses TOML):
322
+ Register the global MCP server for Codex and Claude Code without reinstalling
323
+ their skills:
278
324
 
279
325
  ```bash
280
326
  hermes-action install mcp
281
327
  ```
282
328
 
283
- For Claude Code, write or merge the project `.mcp.json` directly (preserving other servers):
329
+ For other JSON MCP clients, or a Claude Code project-scoped configuration,
330
+ write or merge `.mcp.json` directly while preserving other servers:
284
331
 
285
332
  ```bash
286
333
  hermes-action install mcp --write
@@ -322,12 +369,56 @@ hermes-action mcp
322
369
 
323
370
  Exposed tools:
324
371
 
325
- - `hermes_run`: delegate a request to Hermes.
372
+ - `hermes_run`: delegate a request to Hermes. Optional overrides: `mode`, `preset`, `contextFiles`, `yolo`, `dryRun`, and — to trade cost for speed on simple tasks — `model`, `provider`, `maxTurns`, `timeoutSeconds`.
326
373
  - `hermes_plan`: shortcut for `hermes_run` with `mode=plan`.
374
+ - `hermes_capabilities`: report configured presets, skills, toolsets, runtime, and policy without inventing live integrations.
327
375
  - `hermes_presets`: list configured presets.
328
376
  - `hermes_status`: check the configured Hermes runtime command.
377
+ - `hermes_submit`, `hermes_job_status`, `hermes_result`, `hermes_cancel`:
378
+ manage bounded, process-local asynchronous jobs.
379
+ - `hermes_prepare`, `hermes_approve`, `hermes_reject`: create and consume a
380
+ short-lived one-shot approval before execution.
381
+
382
+ The MCP surface delegates to Hermes instead of mirroring every Hermes tool.
383
+ Jobs and approvals are intentionally process-local: restarting the MCP server
384
+ clears them. Audit events are written as owner-only JSONL metadata under
385
+ `$XDG_STATE_HOME/hermes-action/audit.jsonl` (or
386
+ `~/.local/state/hermes-action/audit.jsonl`) without prompt, context, token, or
387
+ full result content.
329
388
 
330
- The MCP surface is intentionally small. The bridge delegates to Hermes instead of exposing every Hermes tool one by one.
389
+ ## Remote MCP over Tailscale
390
+
391
+ The HTTP transport is opt-in and loopback-only by default:
392
+
393
+ ```bash
394
+ hermes-action serve --listen 127.0.0.1 --port 8765
395
+ ```
396
+
397
+ Prefer placing Tailscale Serve in front of that loopback endpoint. Forwarded
398
+ `*.ts.net` requests still require a bearer token, so start the loopback server
399
+ with `--token-env`:
400
+
401
+ ```bash
402
+ export HERMES_ACTION_HTTP_TOKEN="<at-least-32-random-bytes>"
403
+ hermes-action serve \
404
+ --listen 127.0.0.1 \
405
+ --port 8765 \
406
+ --token-env HERMES_ACTION_HTTP_TOKEN
407
+ ```
408
+
409
+ For direct tailnet listening, the bridge accepts only an explicit Tailscale
410
+ IPv4 address and requires the same bearer-token setup:
411
+
412
+ ```bash
413
+ hermes-action serve \
414
+ --listen 100.64.0.10 \
415
+ --port 8765 \
416
+ --allow-tailnet \
417
+ --token-env HERMES_ACTION_HTTP_TOKEN
418
+ ```
419
+
420
+ The token is never accepted as a CLI value or stored in bridge configuration.
421
+ Public/wildcard and non-Tailscale addresses are refused.
331
422
 
332
423
  ## Development
333
424
 
@@ -348,12 +439,22 @@ Functional tests use a fake Hermes binary to verify command construction, prompt
348
439
  - [Changelog](CHANGELOG.md): release history.
349
440
  - [Security policy](SECURITY.md): how to report a vulnerability.
350
441
 
351
- ## Security notes
442
+ ## Security model
443
+
444
+ Direct CLI and `hermes_run` usage assumes a **supervised host agent**: Claude
445
+ Code / Codex ask you to approve the command or tool call. For MCP side effects,
446
+ prefer the bridge's additional, testable two-phase flow:
447
+ `hermes_prepare` returns a local no-tool summary and opaque approval ID, and
448
+ `hermes_approve` consumes the unchanged request exactly once after the human
449
+ approves it.
450
+
451
+ The bridge's own guard is a secondary net: `execute` is downgraded to `request-approval` by default unless a preset is trusted (empty `require_approval_for`) or `--yolo` is set. The bridge never injects `--yolo` or a bypass flag on its own.
352
452
 
353
- - Do not put secrets in `.hermes-action.yaml`.
354
- - Keep provider credentials in Hermes Agent, your OS keychain, or the relevant platform's secure store.
355
- - Use `request-approval` for public posting, outbound email/messages, deletes, payments, credential changes, and git pushes.
356
- - Treat `--yolo` as a trusted-local-mode escape hatch, not as a default.
453
+ - **Do not allowlist / auto-approve `hermes-action run`, `hermes_run`, or
454
+ `hermes_approve`**. A command-pattern allowlist cannot distinguish a safe
455
+ plan from an execution with side effects.
456
+ - Do not put secrets in `.hermes-action.yaml`. Keep provider credentials in Hermes Agent, your OS keychain, or the platform's secure store.
457
+ - Treat `--yolo` as a trusted-local escape hatch, not a default.
357
458
 
358
459
  ## Also by the author
359
460
 
@@ -1,3 +1,17 @@
1
1
  import type { AdapterResult, BridgeConfig, EffectiveRun } from "../types.js";
2
2
  export declare function buildHermesCliArgs(run: EffectiveRun, prompt?: string, extraToolsets?: string[]): string[];
3
+ /** A started Hermes process. `cancel` is idempotent and asks the child to stop gracefully before forcing it. */
4
+ export interface HermesCliExecution {
5
+ result: Promise<AdapterResult>;
6
+ cancel: () => boolean;
7
+ }
8
+ export interface HermesCliStartOptions {
9
+ maxOutputBytes?: number | undefined;
10
+ }
11
+ /**
12
+ * Start a Hermes CLI invocation without awaiting it. Consumers that need asynchronous work can retain
13
+ * the cancellation handle; `runHermesCli` below remains the backward-compatible awaitable wrapper.
14
+ */
15
+ export declare function startHermesCli(config: BridgeConfig, run: EffectiveRun, dryRun: boolean, options?: HermesCliStartOptions): HermesCliExecution;
16
+ /** Backward-compatible synchronous facade for CLI callers. */
3
17
  export declare function runHermesCli(config: BridgeConfig, run: EffectiveRun, dryRun: boolean): Promise<AdapterResult>;
@@ -15,8 +15,6 @@ const maxTimeoutMs = 2_147_483_647;
15
15
  const largePromptThresholdBytes = 917_504;
16
16
  export function buildHermesCliArgs(run, prompt = buildHermesPrompt(run), extraToolsets = []) {
17
17
  const args = ["chat", "-Q", "--source", run.source, "--max-turns", String(run.maxTurns)];
18
- if (run.profile)
19
- args.unshift("--profile", run.profile);
20
18
  if (run.provider)
21
19
  args.push("--provider", run.provider);
22
20
  if (run.model)
@@ -40,7 +38,15 @@ function filePointerPrompt(path) {
40
38
  "Never reveal secrets.",
41
39
  ].join("\n");
42
40
  }
43
- export async function runHermesCli(config, run, dryRun) {
41
+ /**
42
+ * Start a Hermes CLI invocation without awaiting it. Consumers that need asynchronous work can retain
43
+ * the cancellation handle; `runHermesCli` below remains the backward-compatible awaitable wrapper.
44
+ */
45
+ export function startHermesCli(config, run, dryRun, options = {}) {
46
+ const maxOutputBytes = options.maxOutputBytes;
47
+ if (maxOutputBytes !== undefined && (!Number.isSafeInteger(maxOutputBytes) || maxOutputBytes <= 0)) {
48
+ throw new Error("maxOutputBytes must be a positive safe integer");
49
+ }
44
50
  const prompt = buildHermesPrompt(run);
45
51
  const promptBytes = Buffer.byteLength(prompt, "utf8");
46
52
  const isLarge = promptBytes > largePromptThresholdBytes;
@@ -48,7 +54,20 @@ export async function runHermesCli(config, run, dryRun) {
48
54
  const args = isLarge ? buildHermesCliArgs(run, filePointerPrompt("<temp-file>"), ["file"]) : buildHermesCliArgs(run, prompt);
49
55
  const command = [config.runtime.command, ...args];
50
56
  const stdout = JSON.stringify({ command, prompt, promptBytes, promptChars: prompt.length, delivery: isLarge ? "temp-file" : "argv" }, null, 2);
51
- return { ok: true, exitCode: 0, stdout, stderr: "", command, prompt, dryRun: true };
57
+ const captured = captureChunk(stdout, 0, maxOutputBytes);
58
+ return {
59
+ result: Promise.resolve({
60
+ ok: true,
61
+ exitCode: 0,
62
+ stdout: captured.value,
63
+ stderr: "",
64
+ command,
65
+ prompt,
66
+ dryRun: true,
67
+ outputTruncated: captured.truncated,
68
+ }),
69
+ cancel: () => false,
70
+ };
52
71
  }
53
72
  // Large envelopes can't ride argv (E2BIG); write them to a secure temp file the child reads itself.
54
73
  // tmpDir is set only after a successful write so a failed write cleans up and never leaks an empty dir.
@@ -71,22 +90,27 @@ export async function runHermesCli(config, run, dryRun) {
71
90
  }
72
91
  })();
73
92
  const command = [config.runtime.command, ...args];
74
- return new Promise((resolve) => {
75
- const child = spawn(config.runtime.command, args, { stdio: ["ignore", "pipe", "pipe"] });
93
+ let cancelRequested = false;
94
+ let settled = false;
95
+ let killTimer;
96
+ let child;
97
+ const result = new Promise((resolve) => {
98
+ const spawned = spawn(config.runtime.command, args, { stdio: ["ignore", "pipe", "pipe"] });
99
+ child = spawned;
76
100
  let stdout = "";
77
101
  let stderr = "";
102
+ let capturedBytes = 0;
103
+ let outputTruncated = false;
78
104
  let timedOut = false;
79
- let killTimer;
80
105
  const timeoutMs = Math.min(run.timeoutSeconds * 1000, maxTimeoutMs);
81
106
  const timer = setTimeout(() => {
82
107
  timedOut = true;
83
- child.kill("SIGTERM");
84
- killTimer = setTimeout(() => child.kill("SIGKILL"), killGraceMs);
108
+ child?.kill("SIGTERM");
109
+ killTimer = setTimeout(() => child?.kill("SIGKILL"), killGraceMs);
85
110
  }, timeoutMs);
86
111
  // 'error' and 'close' can both fire (e.g. spawn ENOENT); guard so cleanup and resolve run exactly once.
87
112
  // The temp file is removed here on every settle path. Only an uncatchable SIGKILL of the bridge itself
88
113
  // would leave it behind; mkdtemp + 0600 + the OS temp reaper bound that residual risk.
89
- let settled = false;
90
114
  const settle = (result) => {
91
115
  if (settled)
92
116
  return;
@@ -104,26 +128,61 @@ export async function runHermesCli(config, run, dryRun) {
104
128
  }
105
129
  resolve(result);
106
130
  };
107
- child.stdout.setEncoding("utf8");
108
- child.stderr.setEncoding("utf8");
109
- child.stdout.on("data", (chunk) => {
110
- stdout += chunk;
131
+ spawned.stdout.setEncoding("utf8");
132
+ spawned.stderr.setEncoding("utf8");
133
+ spawned.stdout.on("data", (chunk) => {
134
+ const captured = captureChunk(chunk, capturedBytes, maxOutputBytes);
135
+ stdout += captured.value;
136
+ capturedBytes += captured.bytes;
137
+ outputTruncated ||= captured.truncated;
111
138
  });
112
- child.stderr.on("data", (chunk) => {
113
- stderr += chunk;
139
+ spawned.stderr.on("data", (chunk) => {
140
+ const captured = captureChunk(chunk, capturedBytes, maxOutputBytes);
141
+ stderr += captured.value;
142
+ capturedBytes += captured.bytes;
143
+ outputTruncated ||= captured.truncated;
114
144
  });
115
- child.on("error", (error) => {
116
- settle({ ok: false, exitCode: 127, stdout, stderr: `${stderr}${error.message}`, command, prompt, dryRun: false });
145
+ spawned.on("error", (error) => {
146
+ settle({ ok: false, exitCode: 127, stdout, stderr: `${stderr}${error.message}`, command, prompt, dryRun: false, outputTruncated });
117
147
  });
118
- child.on("close", (code) => {
148
+ spawned.on("close", (code) => {
119
149
  if (timedOut) {
120
150
  const message = `Hermes timed out after ${run.timeoutSeconds}s and was terminated.`;
121
- settle({ ok: false, exitCode: code ?? 124, stdout, stderr: stderr ? `${stderr}\n${message}` : message, command, prompt, dryRun: false, timedOut: true });
151
+ settle({ ok: false, exitCode: code ?? 124, stdout, stderr: stderr ? `${stderr}\n${message}` : message, command, prompt, dryRun: false, outputTruncated, timedOut: true });
122
152
  return;
123
153
  }
124
154
  const exitCode = code ?? 1;
125
- settle({ ok: exitCode === 0, exitCode, stdout, stderr, command, prompt, dryRun: false });
155
+ settle({ ok: exitCode === 0, exitCode, stdout, stderr, command, prompt, dryRun: false, outputTruncated });
126
156
  });
127
157
  });
158
+ const cancel = () => {
159
+ if (settled || cancelRequested || !child)
160
+ return false;
161
+ if (!child.kill("SIGTERM"))
162
+ return false;
163
+ cancelRequested = true;
164
+ killTimer = setTimeout(() => child?.kill("SIGKILL"), killGraceMs);
165
+ return true;
166
+ };
167
+ return { result, cancel };
168
+ }
169
+ /** Backward-compatible synchronous facade for CLI callers. */
170
+ export async function runHermesCli(config, run, dryRun) {
171
+ return startHermesCli(config, run, dryRun).result;
172
+ }
173
+ function captureChunk(chunk, capturedBytes, maxOutputBytes) {
174
+ if (maxOutputBytes === undefined)
175
+ return { value: chunk, bytes: Buffer.byteLength(chunk, "utf8"), truncated: false };
176
+ const remaining = Math.max(0, maxOutputBytes - capturedBytes);
177
+ if (remaining === 0)
178
+ return { value: "", bytes: 0, truncated: chunk.length > 0 };
179
+ const buffer = Buffer.from(chunk, "utf8");
180
+ if (buffer.length <= remaining)
181
+ return { value: chunk, bytes: buffer.length, truncated: false };
182
+ let end = remaining;
183
+ while (end > 0 && (buffer[end] ?? 0) >= 0x80 && (buffer[end] ?? 0) < 0xc0)
184
+ end -= 1;
185
+ const value = buffer.subarray(0, end).toString("utf8");
186
+ return { value, bytes: Buffer.byteLength(value, "utf8"), truncated: true };
128
187
  }
129
188
  //# sourceMappingURL=hermes-cli.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"hermes-cli.js","sourceRoot":"","sources":["../../src/adapters/hermes-cli.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"hermes-cli.js","sourceRoot":"","sources":["../../src/adapters/hermes-cli.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,35 @@
1
+ import type { EffectiveRun } from "./types.js";
2
+ export type ApprovalStatus = "awaiting_approval" | "approved" | "rejected" | "expired";
3
+ export interface ApprovalRequest {
4
+ id: string;
5
+ status: ApprovalStatus;
6
+ createdAt: string;
7
+ expiresAt: string;
8
+ requestedMode: EffectiveRun["requestedMode"];
9
+ effectiveMode: EffectiveRun["mode"];
10
+ presetName: string;
11
+ detectedRisks: EffectiveRun["detectedRisks"];
12
+ }
13
+ export interface ConsumedApproval {
14
+ approval: ApprovalRequest;
15
+ run: EffectiveRun;
16
+ }
17
+ export interface ApprovalStoreOptions {
18
+ ttlMs?: number | undefined;
19
+ maxPending?: number | undefined;
20
+ now?: () => Date;
21
+ createId?: () => string;
22
+ onExpired?: ((approval: ApprovalRequest) => void) | undefined;
23
+ }
24
+ export interface ApprovalStore {
25
+ prepare(run: EffectiveRun): ApprovalRequest;
26
+ get(approvalId: string): ApprovalRequest | undefined;
27
+ approve(approvalId: string): ConsumedApproval | undefined;
28
+ reject(approvalId: string): ApprovalRequest | undefined;
29
+ cleanup(): number;
30
+ }
31
+ /**
32
+ * One-shot, in-process approvals. A stored run is returned exactly once by `approve`; callers must
33
+ * execute that unchanged run rather than accepting new execution options at approval time.
34
+ */
35
+ export declare function createApprovalStore(options?: ApprovalStoreOptions): ApprovalStore;