@ev-ai/agent-hook 1.3.1 → 1.3.2
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/COLLECTED-DATA.md +2 -2
- package/README.md +5 -4
- package/dist/cli.mjs +38 -37
- package/dist/hook.mjs +32 -31
- package/dist/launcher-update.mjs +2 -2
- package/dist/launcher.mjs +1 -1
- package/dist/managed-hooks-snippet.cjs +1299 -2
- package/dist/managed-hooks-snippet.mjs +1316 -2
- package/dist/plugin-hooks.mjs +6 -1
- package/package.json +1 -1
package/COLLECTED-DATA.md
CHANGED
|
@@ -59,7 +59,7 @@ Every event also carries: UTC timestamp, `installation_id` (per-machine under `~
|
|
|
59
59
|
|
|
60
60
|
From runner stdin: session/conversation/turn ids (`prompt_id` / `prompt.id` / `generation_id` / `turn_id`), event name/source, status / `stop_reason` / SessionEnd `reason`, tool/skill name, `tool_use_id`, `permission_mode`, active `model` / Cursor `model_id`, `agent_id` / `agent_type`, Cursor `subagent_id` / `subagent_type` / `subagent_model` / `is_parallel_worker`, `effort` / `effort.level`, `duration_ms` / `duration`, Cursor shell `sandbox` (boolean), failure category fields (`failure_type`, `is_interrupt` — the message fields `error`, `error_details`, `error_message` are **not** forwarded), Claude `UserPromptExpansion` metadata (`command_name`, `expansion_type`, `command_source`), `cwd` (stdin when present; else `process.cwd()` when it is a git work tree or under `CURSOR_PROJECT_DIR`; else `CURSOR_PROJECT_DIR` — Cursor user-level hooks run from `~/.cursor`, which is not the workspace; extra Agents Window folders are not on the payload; the env path is never shipped as an env var; home prefix rewritten to `~` when the path is under the user home, otherwise absolute POSIX), and git-root-relative `cwd_relative` in addition when the session is inside a git repo and that resolved cwd is under the git root. `debug: true` on an untracked / home overlay is a third route to full stdin; it does not change the collector URL.
|
|
61
61
|
|
|
62
|
-
**Content fields (sent unless killed):** `
|
|
62
|
+
**Content fields (sent unless killed):** `tool_input`, `tool_response`, `last_assistant_message`, and Cursor top-level `command`. `prompt` is **opt-in**: it joins them only with `EV_AI_HOOK_CAPTURE_PROMPT=on` (the kill switch below still wins). Two per-event exclusions apply: `command` is dropped on `beforeMCPExecution` (MCP spawn argv carries credentials) and `last_assistant_message` on `StopFailure` (runner error prose). Oversize values are clipped head+tail to a shared per-string budget; if that still cannot reach the 256 KiB cap, the largest fields are dropped (`_dropped_keys`) so the event's metadata always ships rather than the whole POST being rejected. Kill switch: `EV_AI_HOOK_CAPTURE_CONTENT=off` or `capture_hook_input: "allowlist"`. Session titles, `command_args`, transcript paths, file paths, file contents, edits, MCP URLs, and runner error prose stay dropped. Full stdin dump: `capture_hook_input: "full"` or `EV_AI_HOOK_CAPTURE_FULL_INPUT=1` (still size-capped). The first token of a shell or MCP spawn command is also sent separately as payload `executable` (see above).
|
|
63
63
|
|
|
64
64
|
Install wires Claude `SessionStart` / `UserPromptExpansion` / `UserPromptSubmit` / `PreToolUse` (all tools) / `PostToolUse` / `PostToolUseFailure` / `PermissionDenied` / `Stop` / `StopFailure` / `SessionEnd` / `SubagentStart` / `SubagentStop`; Cursor `sessionStart` / `beforeSubmitPrompt` / `preToolUse` / `postToolUse` / `postToolUseFailure` / `beforeShellExecution` / `afterShellExecution` / `beforeReadFile` / `afterFileEdit` / `beforeMCPExecution` / `subagentStart` / `subagentStop` / `stop`; Codex `SessionStart` / `UserPromptSubmit` / `PreToolUse` (all tools) / `PostToolUse` / `Stop` / `SubagentStart` / `SubagentStop`. Re-run `install` to upgrade existing repos (Cursor-specific shell/read/edit/MCP events are added beside generic pre/post tool hooks; `runner_event` distinguishes the row).
|
|
65
65
|
|
|
@@ -79,7 +79,7 @@ Username and hostname *are* sent (per-member usage for the installing org). The
|
|
|
79
79
|
|
|
80
80
|
- Chat transcripts (the JSONL file), session titles, and keystrokes
|
|
81
81
|
- Tool error messages and stderr (a failure **class** is sent, never the message). Tool **result bodies** (`tool_response`) and **arguments** (`tool_input` / Cursor `command`) **are** sent unless `EV_AI_HOOK_CAPTURE_CONTENT=off`
|
|
82
|
-
- User **prompts**
|
|
82
|
+
- User **prompts** — dropped unless `EV_AI_HOOK_CAPTURE_PROMPT=on` (or full stdin capture). The last assistant message **is** sent unless `EV_AI_HOOK_CAPTURE_CONTENT=off`
|
|
83
83
|
- Cursor top-level `content` / `edits` / `file_path` from `afterFileEdit` / `beforeReadFile` stdin — those stay dropped. **Claude nests the same data inside `tool_input`** (Write `content`, Edit `old_string` / `new_string`), and `tool_response` carries read / command output, so on Claude those bodies **are** sent unless `EV_AI_HOOK_CAPTURE_CONTENT=off`
|
|
84
84
|
- Contents of skills, rules, commands, memory, or settings files **outside** the user-spec path (user-scope name+size listings still omit bodies). User-spec file-backed components **do** send capped `text` (once per content hash; may be deferred under the byte budget); `description` is derived server-side
|
|
85
85
|
- Hook **prompt** strings (only `action_kind` + `action_hash` for `prompt`-type actions). Hook **command** strings (`command` / `bash` / `powershell`) *are* sent, sanitized: home directory rewritten to `~`, URLs/tokens/secret-shaped args redacted, capped at 300 chars
|
package/README.md
CHANGED
|
@@ -8,7 +8,8 @@ This is an **opt-in, first-party observability agent** that an ev-ai customer in
|
|
|
8
8
|
|
|
9
9
|
- **Data goes to the customer's own collector.** The destination is the org's ev-ai endpoint (default `https://hooks.ev-ai.ai/{orgToken}/hook`, or a self-hosted collector via `--url`). It is not a third party from the org's perspective — the customer is the data controller.
|
|
10
10
|
- **It is consent-based and removable.** Nothing installs silently: the operator enables the ev-ai plugins (or runs file-wiring `install`), and uninstall / plugin disable removes ev-ai wiring. Non-managed hooks can be removed locally by the developer at any time.
|
|
11
|
-
- **
|
|
11
|
+
- **Prompt collection is opt-in.** User prompt bodies (`hook_input.prompt`) are dropped by default; set `EV_AI_HOOK_CAPTURE_PROMPT=on` to send them. Policy rules still match prompts locally either way.
|
|
12
|
+
- **Collection is opt-out for tool-arg / tool-result / last-assistant-message bodies.** Those three `hook_input` fields are sent by default (size-capped). Set `EV_AI_HOOK_CAPTURE_CONTENT=off` or `capture_hook_input: "allowlist"` to drop them (and the prompt, even when `EV_AI_HOOK_CAPTURE_PROMPT=on`). On Claude that includes file bodies written or read through a tool, which arrive nested in `tool_input` / `tool_response`. Session titles, chat transcripts, keystrokes, and runner error prose stay dropped. `env_vars` is a fixed allowlist of non-secret CI/runtime markers; API keys and proxy vars are never read. See [Privacy defaults](#privacy-defaults).
|
|
12
13
|
- **What it is not:** it is not spyware, not a keylogger, and not a data broker. It does not collect keystrokes, does not scrape the filesystem, and does not exfiltrate to any endpoint the operator did not configure. It does forward the bodies of tool calls the agent makes, unless content capture is turned off.
|
|
13
14
|
|
|
14
15
|
## What this package does on your machine
|
|
@@ -38,7 +39,7 @@ A plain list of every behavior a security reviewer or supply-chain scanner will
|
|
|
38
39
|
|
|
39
40
|
**Subprocesses.** `git`, and for OS / host detection `sw_vers`, `uname`, `lsb_release`, `tty`, `systemd-detect-virt`; `sqlite3` as a fallback reader for Cursor's `state.vscdb`. All are invoked with fixed argument lists (no shell) and short timeouts.
|
|
40
41
|
|
|
41
|
-
**Content capture.**
|
|
42
|
+
**Content capture.** Tool-argument, tool-result and last-assistant-message bodies are sent by default (size-capped). Turn them off with `EV_AI_HOOK_CAPTURE_CONTENT=off`. Prompt bodies are off by default; turn them on with `EV_AI_HOOK_CAPTURE_PROMPT=on`. See [Privacy defaults](#privacy-defaults).
|
|
42
43
|
|
|
43
44
|
**Shipped code is bundled and minified** (`dist/*.mjs`, built with esbuild from TypeScript).
|
|
44
45
|
|
|
@@ -169,7 +170,7 @@ The npx package's entry point is a small launcher. It runs the hook your collect
|
|
|
169
170
|
|
|
170
171
|
**Network.** Besides the collector POST, the launcher makes two kinds of request, both only on the npx path:
|
|
171
172
|
|
|
172
|
-
- `GET /{orgToken}/version` on the same collector, at most once per
|
|
173
|
+
- `GET /{orgToken}/version` on the same collector, at most once per 30 min per collector: on the first event in a new collector scope, then from a detached background refresh at session start. No request is made on other events.
|
|
173
174
|
- When the collector returns a signed envelope, a download of that release's `hook.mjs` from the signed URL (`https://…/{version}/hook.mjs`). The launcher verifies the envelope with a built-in public key, then checks the bytes against the signed SHA-512 before they are written to the cache. The launcher never downloads from npm and does not hardcode a CDN hostname.
|
|
174
175
|
|
|
175
176
|
**Kill switch.** `EV_AI_AUTO_UPDATE=0`, or `"auto_update": false` in `~/.ev-ai/config.json`, always runs the bundled hook and makes neither request. Ephemeral CI homes start cold on every run, so their first event makes the `/version` check (within a 3 s budget); set `EV_AI_AUTO_UPDATE=0` in CI if you want the pinned hook with no extra request.
|
|
@@ -201,7 +202,7 @@ Debug envelope logging: `EV_AI_HOOK_DEBUG=1` (redacted summary). Full envelope:
|
|
|
201
202
|
|
|
202
203
|
Full field-by-field inventory of what is POSTed: [COLLECTED-DATA.md](./COLLECTED-DATA.md).
|
|
203
204
|
|
|
204
|
-
- **`hook_input`**: metadata (session/tool ids, status, …) plus content fields by default — `
|
|
205
|
+
- **`hook_input`**: metadata (session/tool ids, status, …) plus content fields by default — `tool_input`, `tool_response`, `last_assistant_message`, and Cursor `command`. `prompt` is opt-in: `EV_AI_HOOK_CAPTURE_PROMPT=on` (also accepts `1` / `true`). Kill switch: `EV_AI_HOOK_CAPTURE_CONTENT=off` or untracked/tracked manifest `capture_hook_input: "allowlist"`. Session titles, transcript paths, runner error prose, and file/attachment paths stay dropped, as do the MCP spawn argv on `beforeMCPExecution` and the error prose `StopFailure` puts in `last_assistant_message`. Full stdin dump: untracked operator manifest `capture_hook_input: "full"`, `debug: true` on `~/.ev-ai/config.json`, or `EV_AI_HOOK_CAPTURE_FULL_INPUT=1` (still size-capped). `debug` does not change the collector URL. A **git-tracked** (committed) manifest cannot set `full` or `debug` — use the env var or an untracked operator / home overlay instead.
|
|
205
206
|
- **`env_vars`**: fixed allowlist only (CI markers, `GITHUB_*` context, vendor base-URL overrides). Gateway URL values (`*_BASE_URL`, etc.) are sent with host/path and non-sensitive query keys for proxy-substitution detection; embedded URL credentials (`user:pass@`) and credential-shaped query params (`key`, `api-key`, `token`, `sig`, …) are redacted. API keys and HTTP proxy vars are never read.
|
|
206
207
|
- **Transport**: collector URL must be `https` (or `http://localhost` / `127.0.0.1`, which is allowed only so a collector can be exercised on the same machine). Cleartext remote URLs are blocked (fail-open, no POST).
|
|
207
208
|
- **User spec / project directories.** Accepting home-directory inventory (`~/.claude`, `~/.cursor`, `~/.codex`) does not by itself describe the project walks. Those also inventory **gitignored** agent config in the working tree (`settings.local.json`, `CLAUDE.local.md`, uncommitted edits) and **every directory a session opens** — including a personal clone on a work machine (cwd walk always; repo walk when that clone has an origin remote) and a covering parent above the git root (for example `~/dev/CLAUDE.md` sitting above both work and personal clones). Disable the project walks with `EV_AI_HOOK_CWD_SPEC=off`. Disable home spec, project spec, and operator identity together with `EV_AI_HOOK_USER_SPEC=off`.
|