@ev-ai/agent-hook 1.0.6 → 1.0.7
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 +17 -10
- package/README.md +48 -57
- package/dist/cli.mjs +20 -16
- package/dist/hook.mjs +15 -11
- package/dist/plugin-hooks.mjs +6 -6
- package/package.json +4 -26
package/COLLECTED-DATA.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Collected data
|
|
2
2
|
|
|
3
|
-
What `@
|
|
3
|
+
What `@ev-ai/agent-hook` POSTs to the ev-ai collector (`POST /{orgToken}/hook`, default `https://hooks.ev-ai.ai/{orgToken}/hook`). Auth is the org path id in the URL — no Bearer header and not in the JSON body. See [README.md](./README.md) for install and privacy defaults.
|
|
4
4
|
|
|
5
5
|
## Tracked events
|
|
6
6
|
|
|
@@ -10,17 +10,20 @@ What `@evalon-ai/agent-hook` POSTs to the Evalon collector (`POST /{orgToken}/ho
|
|
|
10
10
|
| `session_end` | Session stops |
|
|
11
11
|
| `tool_invoked` | Tool, skill, MCP, shell, or file-edit hook fires |
|
|
12
12
|
|
|
13
|
-
Every event also carries: UTC timestamp, `installation_id`, runner `platform` (`claude` / `cursor` / `codex`), `platform_agent_id` (Layer-1 inventory join key: `{owner}/{repo}:{scopePath/}{markerDir}`, e.g. `acme/my-app:.claude` or `acme/my-app:apps/web/.cursor`), `session_id`, `turn_id`, raw `runner_event` name, `agent_hook_version`, `host_arch`, and `
|
|
13
|
+
Every event also carries: UTC timestamp, `installation_id` (per-machine under `~/.ev-ai/agent-hook/installation.json`; on ephemeral CI/cloud homes derived from platform seeds such as `GITHUB_REPOSITORY_ID`+`GITHUB_ACTOR` / `CODESPACE_NAME`, or pinned via `EV_AI_HOOK_INSTALLATION_ID`), runner `platform` (`claude` / `cursor` / `codex`), `platform_agent_id` (Layer-1 inventory join key: `{owner}/{repo}:{scopePath/}{markerDir}`, e.g. `acme/my-app:.claude` or `acme/my-app:apps/web/.cursor`), `session_id`, `turn_id`, raw `runner_event` name, `agent_hook_version`, `host_arch`, `node_version`, and `build_ms` (wall-clock milliseconds to assemble the envelope before the collector POST; not tool/session duration).
|
|
14
14
|
|
|
15
15
|
## Tracked data points
|
|
16
16
|
|
|
17
17
|
### On `session_start`
|
|
18
18
|
|
|
19
|
-
- **Host** — hostname, OS / version, username, shell, TTY, runtime context (interactive /
|
|
19
|
+
- **Host** — hostname, OS / version, username, shell, TTY, runtime context (`interactive` / `github_actions` / `claude_remote` / `cursor_cloud` / `codespaces` / `managed` / `container` / `cron`). `managed` covers generic `CI=true` plus named platforms that often omit it (`TF_BUILD`, `JENKINS_URL`, `BUILDKITE`, `CIRCLECI`, `GITLAB_CI`, `CODEBUILD_BUILD_ID`, `DRONE`, …). `container` covers `/.dockerenv`, k8s (`KUBERNETES_SERVICE_HOST`), and VS Code / Codespaces-style remote containers (`REMOTE_CONTAINERS` / `DEVCONTAINER`). Optional virt and cloud provider / region / instance id. Cloud metadata is probed only for non-interactive contexts; interactive laptop sessions skip IMDS entirely. Non-interactive probes are cached locally for 24h per context.
|
|
20
20
|
- **Git** — origin remote (credentials stripped), branch, HEAD SHA, dirty flag
|
|
21
|
-
- **Env (allowlist only)** — CI markers (`CI`, `GITHUB_*`, `GITLAB_CI`, …), `NODE_ENV`, `TERM_PROGRAM`, vendor base-URL overrides (`ANTHROPIC_BASE_URL`, `OPENAI_BASE_URL`, …), Claude Bedrock/Vertex flags. API keys and proxy vars are never read. Gateway URLs have embedded credentials and credential-shaped query params (`key`, `api-key`, `token`, `sig`, …) redacted.
|
|
21
|
+
- **Env (allowlist only)** — CI markers (`CI`, `GITHUB_*`, `GITLAB_CI`, `CIRCLECI`, `BUILDKITE`, `TF_BUILD`, …), actor identity markers (`GITHUB_ACTOR`, `GITLAB_USER_*`, `BUILD_REQUESTEDFOR*`, `BUILDKITE_BUILD_CREATOR*`, `BUILD_USER*`, `CHANGE_AUTHOR*`, `CIRCLE_USERNAME`, `CODEBUILD_INITIATOR`, `DRONE_COMMIT_AUTHOR*`, `EV_AI_HOOK_OPERATOR_*`, `GIT_AUTHOR_*`, `GIT_COMMITTER_*`, `EMAIL`, …), cloud session markers (`CLAUDE_CODE_REMOTE`, `CURSOR_AGENT`, `CODESPACES`), `NODE_ENV`, `TERM_PROGRAM`, vendor base-URL overrides (`ANTHROPIC_BASE_URL`, `OPENAI_BASE_URL`, …), Claude Bedrock/Vertex flags. API keys and proxy vars are never read. Gateway URLs have embedded credentials and credential-shaped query params (`key`, `api-key`, `token`, `sig`, …) redacted.
|
|
22
22
|
- **MCP inventory** — declared server **names** (and discovery source), not commands/URLs/env
|
|
23
23
|
- **User-scope config** — `cli_version` (claude / agent|cursor-agent / codex `--version`); model (Claude; SessionStart stdin `model` preferred over settings-file), Claude-only `claude_version` mirror; presence/size of global settings / memory / MCP files; name+size listings of global skills, commands, subagents, rules (full listing when the hash changed or every 10th session start as a repair re-send; capped at 500 entries per list with `truncated: true` when capped). File **contents** are not sent.
|
|
24
|
+
- **User spec (home-dir components)** — per-component delta of skills / commands / rules / memory / subagents / hooks / MCP servers / plugins from `~/.claude`, `~/.cursor`, `~/.codex`, `~/.agents`. Walked on the **first** `session_start` for a runner and again only after a **14-hour cooldown** (`user_spec_collected_at_ms` in `self-config-cache.json`); mid-cooldown session starts skip the home walk and omit `user_spec*` / `operator`. Each upsert row carries `kind`, path-derived `name`, home-relative `path`, capped file `text` (≤20_000 chars) for file-backed kinds, `content_hash`, `origin` (`user` or `plugin:<name>@<marketplace>`), `enabled`, optional `trigger` / `attributes`. Frontmatter fields (`name`, `description`, …) are not parsed on the client — the collector derives them from `text`. Only **changed or new** components are sent (`user_spec`); removals are explicit tombstones (`user_spec_removed: [{ path, name }]`). Unchanged scope after a cooldown refresh → hash/count/truncated scalars alone. First walk is a full authoritative snapshot (`user_spec_full: true`). File `text` is shipped **once per `content_hash`** (later sends omit the body when that hash was already delivered); under the ~300 KiB user-spec byte budget, overflowing bodies are deferred (`user_spec_text_deferred`) before rows are dropped. Self-config / operator caches commit only after a successful collector POST. Hook rows send `action_kind` + `action_hash` only — never the command string. MCP rows send name + transport only. Plugin rows never include `installPath` / `projectPath`. Disabled with `EV_AI_HOOK_USER_SPEC=off`.
|
|
25
|
+
- **Operator identity** — on the first user-spec collect for an installation (and again when the 14-hour user-spec cooldown elapses): `git_user_name` / `git_user_email` from `git config` when set (`identity_source: "git_config"`). When unset, tries `GIT_AUTHOR_NAME`/`GIT_AUTHOR_EMAIL`, then `GIT_COMMITTER_*`, then `EMAIL` (`identity_source: "git_env"`). Bot-shaped git identity (`*[bot]*`, `action@github.com`, `noreply@anthropic.com`, `cursoragent@cursor.com`, …) is skipped so CI/cloud actor env vars can win: explicit `EV_AI_HOOK_OPERATOR_NAME` / `EV_AI_HOOK_OPERATOR_EMAIL` → `identity_source: "configured"`; then `GITHUB_ACTOR` / `GITHUB_TRIGGERING_ACTOR` / `GITHUB_USER` → `"github"`; `GITLAB_USER_*` → `"gitlab"`; Azure DevOps `BUILD_REQUESTEDFOR*` → `"azure_devops"`; Buildkite `BUILDKITE_BUILD_CREATOR*` → `"buildkite"`; Jenkins `BUILD_USER*` / `CHANGE_AUTHOR*` → `"jenkins"`; CircleCI `CIRCLE_USERNAME` → `"circleci"`; CodeBuild `CODEBUILD_INITIATOR` → `"codebuild"`; Drone/Woodpecker `DRONE_COMMIT_AUTHOR*` → `"drone"`. When those are also absent, falls back to the HEAD commit author from `git log -1` (`identity_source: "git_log"`). Claude Code remote (`CLAUDE_CODE_REMOTE`) and Cursor cloud (`CURSOR_AGENT`) without a git or CI actor are tagged `identity_source: "cloud"` with null name/email (no synthetic email). CI/cloud actor sources also set `platform_login` (GitHub/GitLab/CircleCI/CodeBuild/Jenkins `BUILD_USER_ID`/Drone login) so the collector can join installations to members without inventing a noreply email. Omitted while user-spec is on cooldown and in steady state when unchanged. Never invents an OS username. Disabled with the same `EV_AI_HOOK_USER_SPEC=off` opt-out.
|
|
26
|
+
- **Cloud identity bootstrap** — Cursor cloud agents do not fire `sessionStart`. On the first `tool_invoked` / skill event when operator identity has never been sent (any runtime context — cloud VMs with a pseudo-TTY often look `interactive`), the hook POSTs a lightweight `session_start` (`run_meta.trigger: cloud_identity_bootstrap`) with host/context/operator — no home user-spec walk, and no `cli_version` / `model` / `user_scope` / `hook_input` (those stay unset so the collector never treats bootstrap nulls as a probed empty config). Debounced in-process and across concurrent hook processes via an exclusive claim lock beside `installation.json` (`cloud-bootstrap.lock`); skipped when `EV_AI_HOOK_USER_SPEC=off`.
|
|
24
27
|
- **Permission keys (Claude)** — each rule as `{ key, mode }` where `mode` is the list it came from (`allow` / `deny` / `ask`), so a blocked rule is never mistaken for a permitted one. Absolute POSIX / Windows / `~`-anchored paths inside a rule are replaced with `<path>` (`Bash(find /Users/me/repo -name x)` → `Bash(find <path> -name x)`) — the rule shape is the posture signal, the operator's home layout is not. Capped at 200 rules, 200 characters each.
|
|
25
28
|
- **Allowlisted hook metadata** — see below (includes SessionStart `model`, `permission_mode`, …)
|
|
26
29
|
|
|
@@ -46,9 +49,11 @@ Every event also carries: UTC timestamp, `installation_id`, runner `platform` (`
|
|
|
46
49
|
|
|
47
50
|
### Hook metadata (default)
|
|
48
51
|
|
|
49
|
-
From runner stdin, only: 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`, 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` — never `prompt` / `command_args`), and git-root-relative `cwd_relative` (never absolute `cwd`). Session titles, tool args, prompts, shell commands, file contents, and tool result bodies are dropped unless the operator opts into full capture (`capture_hook_input: "full"` or `
|
|
52
|
+
From runner stdin, only: 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`, 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` — never `prompt` / `command_args`), and git-root-relative `cwd_relative` (never absolute `cwd`). Session titles, tool args, prompts, shell commands, file contents, and tool result bodies are dropped unless the operator opts into full capture (`capture_hook_input: "full"` or `EV_AI_HOOK_CAPTURE_FULL_INPUT=1`).
|
|
50
53
|
|
|
51
|
-
Install wires Claude `SessionStart` / `UserPromptExpansion` / `PreToolUse` (all tools) / `PostToolUse` / `PostToolUseFailure` / `PermissionDenied` / `Stop` / `StopFailure` / `SessionEnd` / `SubagentStart` / `SubagentStop`; Cursor `sessionStart` / `beforeSubmitPrompt` / `preToolUse` / `postToolUse` / `postToolUseFailure` / `subagentStart` / `subagentStop` / `stop`; Codex `SessionStart` / `UserPromptSubmit` / `PreToolUse` (all tools) / `PostToolUse` / `Stop`. Re-run `install` to upgrade existing repos (Cursor upgrades strip retired `beforeShellExecution` / `afterFileEdit` / `beforeMCPExecution`
|
|
54
|
+
Install wires Claude `SessionStart` / `UserPromptExpansion` / `PreToolUse` (all tools) / `PostToolUse` / `PostToolUseFailure` / `PermissionDenied` / `Stop` / `StopFailure` / `SessionEnd` / `SubagentStart` / `SubagentStop`; Cursor `sessionStart` / `beforeSubmitPrompt` / `preToolUse` / `postToolUse` / `postToolUseFailure` / `subagentStart` / `subagentStop` / `stop`; Codex `SessionStart` / `UserPromptSubmit` / `PreToolUse` (all tools) / `PostToolUse` / `Stop`. Re-run `install` to upgrade existing repos (Cursor upgrades strip retired `beforeShellExecution` / `afterFileEdit` / `beforeMCPExecution` ev-ai hooks).
|
|
55
|
+
|
|
56
|
+
When Cursor loads Claude (or Codex) file hooks as third-party configs alongside `.cursor/hooks.json`, the binary drops the foreign `--runner` twin so `platform` stays `cursor` and events are not duplicated. Claude Code and Codex hosts are unaffected.
|
|
52
57
|
|
|
53
58
|
## PII we do not send
|
|
54
59
|
|
|
@@ -57,11 +62,13 @@ Username and hostname *are* sent (per-member usage for the installing org). The
|
|
|
57
62
|
- Prompts, chat transcripts, session titles, and keystrokes
|
|
58
63
|
- Tool arguments, shell commands, and file / code contents
|
|
59
64
|
- Tool error messages, stderr, and result bodies (a failure **class** is sent, never the message)
|
|
60
|
-
- Contents of skills, rules, commands, memory, or settings files (
|
|
65
|
+
- 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
|
|
66
|
+
- Hook command / prompt strings from the home directory (only `action_kind` + `action_hash`)
|
|
61
67
|
- API keys, tokens, and other secret env vars
|
|
62
68
|
- HTTP(S) proxy credentials and proxy env vars
|
|
63
69
|
- Embedded credentials in git remotes and gateway URLs (`user:pass@` stripped; credential-shaped query params redacted)
|
|
64
|
-
- MCP server commands, args, env blocks, and URLs (name/
|
|
65
|
-
-
|
|
66
|
-
-
|
|
70
|
+
- MCP server commands, args, env blocks, and URLs (name/transport only)
|
|
71
|
+
- Plugin `installPath` / `projectPath` (absolute / home paths)
|
|
72
|
+
- OS username as an identity substitute (git `user.name` / `user.email`, CI actor logins via `platform_login`, or CI emails are sent when available; OS username is still only present via the existing host username field)
|
|
73
|
+
- Home-directory absolute paths (rewritten to home-relative before send), local IP addresses, and listening ports
|
|
67
74
|
- Data to any endpoint other than the org-configured collector
|
package/README.md
CHANGED
|
@@ -1,30 +1,19 @@
|
|
|
1
|
-
# @
|
|
1
|
+
# @ev-ai/agent-hook
|
|
2
2
|
|
|
3
|
-
Cross-runner runtime telemetry hook for **Claude Code**, **Cursor**, and **OpenAI Codex**. Each session (and selected tool/MCP events) POSTs a runtime envelope to your
|
|
3
|
+
Cross-runner runtime telemetry hook for **Claude Code**, **Cursor**, and **OpenAI Codex**. Each session (and selected tool/MCP events) POSTs a runtime envelope to your ev-ai collector at `POST /{orgToken}/hook`.
|
|
4
4
|
|
|
5
5
|
## What this is (and isn't)
|
|
6
6
|
|
|
7
|
-
This is an **opt-in, first-party observability agent** that an
|
|
7
|
+
This is an **opt-in, first-party observability agent** that an ev-ai customer installs on their own developers' machines / CI to get an inventory and runtime view of **their own org's AI coding-agent usage**. It is the AI-coding-agent equivalent of an EDR/telemetry sensor or an APM agent: the org deploys it, on its own hosts, to send data **to its own collector**.
|
|
8
8
|
|
|
9
|
-
- **Data goes to the customer's own collector.** The destination is the org's
|
|
10
|
-
- **It is consent-based and removable.** Nothing installs silently: the operator enables the
|
|
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
|
+
- **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
|
- **Collection is deliberately minimized.** `hook_input` defaults to an allowlist of safe metadata (session/tool ids, status) — tool arguments, prompts, file contents, and shell commands are dropped unless the operator explicitly opts into full capture. `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
12
|
- **What it is not:** it is not spyware, not a keylogger, and not a data broker. It does not collect keystrokes, file contents, or credentials, and it does not exfiltrate to any endpoint the operator did not configure.
|
|
13
13
|
|
|
14
|
-
## Registry access
|
|
15
|
-
|
|
16
|
-
The package is distributed on **GitHub Packages**, so every machine that installs it needs these two lines in `~/.npmrc` with a token that can read packages from the `evalon-ai` org:
|
|
17
|
-
|
|
18
|
-
```
|
|
19
|
-
@evalon-ai:registry=https://npm.pkg.github.com
|
|
20
|
-
//npm.pkg.github.com/:_authToken=<TOKEN>
|
|
21
|
-
```
|
|
22
|
-
|
|
23
|
-
Put the token only on the `_authToken` line — never inside the registry URL.
|
|
24
|
-
|
|
25
14
|
## Install
|
|
26
15
|
|
|
27
|
-
**Primary path:** enable the
|
|
16
|
+
**Primary path:** enable the ev-ai **runner plugins** (Claude / Cursor / Codex) from the hosted marketplace. Their hooks pin `npx -y @ev-ai/agent-hook@<ver> --runner …`. Your repo commits only a shared `collector_url` manifest plus plugin enablement — not per-event blocks in `.claude/settings.json` / `.cursor/hooks.json` / `.codex/hooks.json`.
|
|
28
17
|
|
|
29
18
|
**Fallback:** the `install` CLI merges hooks into those three config files directly.
|
|
30
19
|
|
|
@@ -33,21 +22,21 @@ Put the token only on the `_authToken` line — never inside the registry URL.
|
|
|
33
22
|
1. Write the org destination (manifest only):
|
|
34
23
|
|
|
35
24
|
```bash
|
|
36
|
-
npx @
|
|
37
|
-
--url https://hooks.
|
|
25
|
+
npx @ev-ai/agent-hook@X.Y.Z configure \
|
|
26
|
+
--url https://hooks.ev-ai.ai/<your-org-path-id>/hook
|
|
38
27
|
```
|
|
39
28
|
|
|
40
29
|
`--url` must be the full ingest URL ending in `/{orgToken}/hook`. Prefer a long opaque hex org path id (64 lowercase hex chars). Safe to commit in private repos — auth is in the URL path, not a Bearer header.
|
|
41
30
|
|
|
42
|
-
2. Enable the Claude / Cursor / Codex plugins
|
|
43
|
-
3. Commit the shared manifest (`.claude/
|
|
31
|
+
2. Enable the Claude / Cursor / Codex plugins from the hosted marketplace.
|
|
32
|
+
3. Commit the shared manifest (`.claude/ev-ai-runtime-report.json`) plus plugin enablement **or** the file-wired hook configs (not both for the same events). Restart runners.
|
|
44
33
|
|
|
45
34
|
Plugins pin an exact package version, never `@latest`.
|
|
46
35
|
|
|
47
|
-
**Migrating from file-wiring:** strip
|
|
36
|
+
**Migrating from file-wiring:** strip ev-ai per-event blocks while keeping the manifest:
|
|
48
37
|
|
|
49
38
|
```bash
|
|
50
|
-
npx @
|
|
39
|
+
npx @ev-ai/agent-hook@X.Y.Z migrate-to-plugin
|
|
51
40
|
```
|
|
52
41
|
|
|
53
42
|
Then enable plugins. Do not leave both plugin and file hooks active — that double-POSTs.
|
|
@@ -61,93 +50,95 @@ Then enable plugins. Do not leave both plugin and file hooks active — that dou
|
|
|
61
50
|
One-time wiring by the repo owner. Teammates pull committed hook configs and need **Node only**.
|
|
62
51
|
|
|
63
52
|
```bash
|
|
64
|
-
npx @
|
|
65
|
-
--url https://hooks.
|
|
53
|
+
npx @ev-ai/agent-hook@latest install \
|
|
54
|
+
--url https://hooks.ev-ai.ai/<your-org-path-id>/hook
|
|
66
55
|
```
|
|
67
56
|
|
|
68
57
|
When Claude Code already has native OTEL enabled (managed/user/project settings), install **skips** the Claude hook to avoid duplicate events. Cursor and Codex are still wired. Override with `--force`:
|
|
69
58
|
|
|
70
59
|
```bash
|
|
71
|
-
npx @
|
|
72
|
-
--url https://hooks.
|
|
60
|
+
npx @ev-ai/agent-hook@latest install \
|
|
61
|
+
--url https://hooks.ev-ai.ai/<token>/hook \
|
|
73
62
|
--force
|
|
74
63
|
```
|
|
75
64
|
|
|
76
65
|
Skip a vendor entirely with `--no-claude`, `--no-cursor`, or `--no-codex`:
|
|
77
66
|
|
|
78
67
|
```bash
|
|
79
|
-
npx @
|
|
80
|
-
--url https://hooks.
|
|
68
|
+
npx @ev-ai/agent-hook@latest install \
|
|
69
|
+
--url https://hooks.ev-ai.ai/<token>/hook \
|
|
81
70
|
--no-cursor --no-codex
|
|
82
71
|
```
|
|
83
72
|
|
|
73
|
+
Keep Claude and Cursor both wired. Cursor also loads `.claude/settings.json` as third-party hooks; the binary suppresses those Claude/Codex-tagged twin invocations when it detects a Cursor host, so each event posts once as `platform: cursor`. Real Claude Code sessions still use the Claude hooks unchanged.
|
|
74
|
+
|
|
84
75
|
Wired command shape (auth is in the committed `collector_url`). The per-event command is **pinned to the installer's version** (not `@latest`):
|
|
85
76
|
|
|
86
77
|
```bash
|
|
87
|
-
npx -y @
|
|
78
|
+
npx -y @ev-ai/agent-hook@1.0.6 --runner cursor
|
|
88
79
|
```
|
|
89
80
|
|
|
90
|
-
You can optionally put the collector URL on the hook command itself — `--url` (or `--token` + optional `--base-url`) overrides any shared manifest, so `.claude/
|
|
81
|
+
You can optionally put the collector URL on the hook command itself — `--url` (or `--token` + optional `--base-url`) overrides any shared manifest, so `.claude/ev-ai-runtime-report.json` is not required:
|
|
91
82
|
|
|
92
83
|
```json
|
|
93
84
|
{
|
|
94
|
-
"command": "npx -y @
|
|
85
|
+
"command": "npx -y @ev-ai/agent-hook@1.0.6 --runner claude --url 'https://hooks.ev-ai.ai/<orgToken>/hook'"
|
|
95
86
|
}
|
|
96
87
|
```
|
|
97
88
|
|
|
98
|
-
**Commit** `.claude/
|
|
89
|
+
**Commit** `.claude/ev-ai-runtime-report.json` (contains `collector_url`) plus `.claude/settings.json`, `.cursor/hooks.json`, and `.codex/hooks.json` when using this path (or omit the manifest if every wired command already has `--url`). Do **not** also enable the ev-ai plugins for the same events — that double-posts.
|
|
99
90
|
|
|
100
|
-
Install is **additive**: existing non-
|
|
91
|
+
Install is **additive**: existing non-ev-ai hooks are kept; re-install replaces only ev-ai-owned entries. Uninstall removes only ev-ai entries (and the ev-ai manifest).
|
|
101
92
|
|
|
102
93
|
### Alternative — CDN binary (no Node at hook time)
|
|
103
94
|
|
|
104
95
|
For environments where Node is not on PATH when runners fire hooks (typically with file-wiring or a future plugin that bundles a binary):
|
|
105
96
|
|
|
106
97
|
```bash
|
|
107
|
-
curl -fsSL https://cdn.
|
|
108
|
-
--url https://hooks.
|
|
98
|
+
curl -fsSL https://cdn.ev-ai.ai/agent-hook/install.sh | sh -s -- -- \
|
|
99
|
+
--url https://hooks.ev-ai.ai/<token>/hook
|
|
109
100
|
```
|
|
110
101
|
|
|
111
102
|
Pin a specific release:
|
|
112
103
|
|
|
113
104
|
```bash
|
|
114
|
-
AGENT_HOOK_VERSION=1.0.6 curl -fsSL https://cdn.
|
|
115
|
-
--url https://hooks.
|
|
105
|
+
AGENT_HOOK_VERSION=1.0.6 curl -fsSL https://cdn.ev-ai.ai/agent-hook/install.sh | sh -s -- -- \
|
|
106
|
+
--url https://hooks.ev-ai.ai/<token>/hook
|
|
116
107
|
```
|
|
117
108
|
|
|
118
|
-
The installer downloads a **standalone binary** (~50–100MB) for your OS/arch, verifies SHA256, caches it under `~/.
|
|
109
|
+
The installer downloads a **standalone binary** (~50–100MB) for your OS/arch, verifies SHA256, caches it under `~/.ev-ai/agent-hook/<version>/`, copies it into the git repo at `.ev-ai/agent-hook/ev-ai-agent-hook`, and wires all three runners with `--delivery binary` (default for the compiled installer).
|
|
119
110
|
|
|
120
111
|
Wired command shape (git-root-relative path + `--runner`):
|
|
121
112
|
|
|
122
113
|
```bash
|
|
123
|
-
"$(git rev-parse --show-toplevel)/.
|
|
114
|
+
"$(git rev-parse --show-toplevel)/.ev-ai/agent-hook/ev-ai-agent-hook" --runner cursor
|
|
124
115
|
```
|
|
125
116
|
|
|
126
|
-
**Install per machine** for the binary path: each collaborator runs install once to download their platform binary into `.
|
|
117
|
+
**Install per machine** for the binary path: each collaborator runs install once to download their platform binary into `.ev-ai/agent-hook/` (gitignored).
|
|
127
118
|
|
|
128
119
|
Force npx delivery from Node even when a global binary pin exists:
|
|
129
120
|
|
|
130
121
|
```bash
|
|
131
|
-
npx @
|
|
132
|
-
--url https://hooks.
|
|
122
|
+
npx @ev-ai/agent-hook@latest install \
|
|
123
|
+
--url https://hooks.ev-ai.ai/<token>/hook \
|
|
133
124
|
--delivery npx
|
|
134
125
|
```
|
|
135
126
|
|
|
136
127
|
### Identity and runtime notes
|
|
137
128
|
|
|
138
|
-
Each developer's `installation_id` is created on first hook fire and stored under `~/.
|
|
129
|
+
Each developer's `installation_id` is created on first hook fire and stored once per machine under `~/.ev-ai/agent-hook/installation.json` (shared across all repos on that machine). Ephemeral CI/cloud homes (no durable `~/.ev-ai`) derive a stable id from platform seeds (e.g. GitHub Actions `GITHUB_REPOSITORY_ID` + `GITHUB_ACTOR`, Codespaces `CODESPACE_NAME`) so collector rows do not churn every run. Pin explicitly with `EV_AI_HOOK_INSTALLATION_ID` (8–64 chars `[A-Za-z0-9._-]`) when the environment has no actor seed (Claude Code remote / Cursor cloud).
|
|
139
130
|
|
|
140
|
-
Per-event execution uses `npx` (primary) or the pinned binary (CDN path). The runner-facing process **acks immediately** (`{"continue":true}` + exit 0) after draining stdin and spawning a detached `__work` child that collects + POSTs — **except teardown events**, which stay in-process and await the HTTP POST so a runner that tears down the process tree on exit cannot kill the worker mid-flight. Teardown = Claude `SessionEnd` / `StopFailure`, Codex `Stop` (its only end signal), and `SubagentStop`. Per-turn Claude `Stop` / Cursor `stop` fire at the end of **every turn** (not teardown), so they detach like tool events and never block the runner between turns. Set `
|
|
131
|
+
Per-event execution uses `npx` (primary) or the pinned binary (CDN path). The runner-facing process **acks immediately** (`{"continue":true}` + exit 0) after draining stdin and spawning a detached `__work` child that collects + POSTs — **except teardown events**, which stay in-process and await the HTTP POST so a runner that tears down the process tree on exit cannot kill the worker mid-flight. Teardown = Claude `SessionEnd` / `StopFailure`, Codex `Stop` (its only end signal), and `SubagentStop`. Per-turn Claude `Stop` / Cursor `stop` fire at the end of **every turn** (not teardown), so they detach like tool events and never block the runner between turns. Set `EV_AI_HOOK_SYNC=1` to keep all events in-process for debugging.
|
|
141
132
|
|
|
142
133
|
### Gitignore (recommended)
|
|
143
134
|
|
|
144
135
|
```gitignore
|
|
145
|
-
/.
|
|
136
|
+
/.ev-ai/
|
|
146
137
|
```
|
|
147
138
|
|
|
148
|
-
Do **not** gitignore `.claude/
|
|
139
|
+
Do **not** gitignore `.claude/ev-ai-runtime-report.json` when using a committed org path id — teammates need it to post without env vars. Keep the repo private; rotate the path id via your org settings if it leaks.
|
|
149
140
|
|
|
150
|
-
For the **plugin** path, do not add
|
|
141
|
+
For the **plugin** path, do not add ev-ai per-event hooks to `.claude/settings.json` / `.cursor/hooks.json` / `.codex/hooks.json`. For the **file-wiring** fallback, add those files only if your repo does not already track other hook settings you need to share.
|
|
151
142
|
|
|
152
143
|
## Fail-open contract
|
|
153
144
|
|
|
@@ -156,42 +147,42 @@ For the **plugin** path, do not add Evalon per-event hooks to `.claude/settings.
|
|
|
156
147
|
- Teardown events stay in-process (sync POST) — Claude `SessionEnd` / `StopFailure`, Codex `Stop`, and `SubagentStop`, because the runner may kill detached children when the session/worker tree is torn down
|
|
157
148
|
- POST / spawn failures log to stderr only
|
|
158
149
|
|
|
159
|
-
Debug envelope logging: `
|
|
150
|
+
Debug envelope logging: `EV_AI_HOOK_DEBUG=1` (redacted summary). Full envelope: `EV_AI_HOOK_DEBUG=full`. Force all events in-process: `EV_AI_HOOK_SYNC=1`.
|
|
160
151
|
|
|
161
152
|
## Privacy defaults
|
|
162
153
|
|
|
163
154
|
Full field-by-field inventory of what is POSTed: [COLLECTED-DATA.md](./COLLECTED-DATA.md).
|
|
164
155
|
|
|
165
|
-
- **`hook_input`**: allowlisted metadata only (`session_id`, `tool_name`, `status`, …). Tool args / prompts / session titles are dropped. Opt-in full stdin: untracked operator manifest `capture_hook_input: "full"` or `
|
|
156
|
+
- **`hook_input`**: allowlisted metadata only (`session_id`, `tool_name`, `status`, …). Tool args / prompts / session titles are dropped. Opt-in full stdin: untracked operator manifest `capture_hook_input: "full"` or `EV_AI_HOOK_CAPTURE_FULL_INPUT=1` (still size-capped). A **git-tracked** (committed) manifest cannot set `full` — use the env var or an untracked operator manifest instead.
|
|
166
157
|
- **`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.
|
|
167
158
|
- **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).
|
|
168
159
|
|
|
169
160
|
## Uninstall
|
|
170
161
|
|
|
171
|
-
**Plugin path:** disable / uninstall the
|
|
162
|
+
**Plugin path:** disable / uninstall the ev-ai marketplace plugins, then remove or rotate the shared manifest.
|
|
172
163
|
|
|
173
|
-
**File-wiring → plugin:** keep the manifest, strip only
|
|
164
|
+
**File-wiring → plugin:** keep the manifest, strip only ev-ai file hooks:
|
|
174
165
|
|
|
175
166
|
```bash
|
|
176
|
-
npx @
|
|
167
|
+
npx @ev-ai/agent-hook migrate-to-plugin
|
|
177
168
|
```
|
|
178
169
|
|
|
179
170
|
**File-wiring full uninstall** (also deletes the shared manifest):
|
|
180
171
|
|
|
181
172
|
```bash
|
|
182
|
-
npx @
|
|
173
|
+
npx @ev-ai/agent-hook uninstall
|
|
183
174
|
```
|
|
184
175
|
|
|
185
176
|
Or via the CDN-installed binary:
|
|
186
177
|
|
|
187
178
|
```bash
|
|
188
|
-
"$HOME/.
|
|
179
|
+
"$HOME/.ev-ai/agent-hook/current/ev-ai-agent-hook" uninstall
|
|
189
180
|
```
|
|
190
181
|
|
|
191
182
|
Or:
|
|
192
183
|
|
|
193
184
|
```bash
|
|
194
|
-
curl -fsSL https://cdn.
|
|
185
|
+
curl -fsSL https://cdn.ev-ai.ai/agent-hook/install.sh | sh -s -- uninstall
|
|
195
186
|
```
|
|
196
187
|
|
|
197
|
-
`uninstall` removes
|
|
188
|
+
`uninstall` removes ev-ai-owned hook entries from Claude/Cursor/Codex config files (leaves other hooks intact) and deletes `ev-ai-runtime-report.json` manifest(s) in the current git repo. Does not remove `~/.ev-ai/agent-hook/` (pinned binary) or `~/.ev-ai/agent-hook/` (per-machine identity).
|
package/dist/cli.mjs
CHANGED
|
@@ -1,19 +1,23 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
|
-
import{realpathSync as
|
|
4
|
-
`)}function
|
|
5
|
-
`)}catch(s){let
|
|
6
|
-
`,{encoding:"utf8",flag:"wx"})}
|
|
7
|
-
|
|
8
|
-
|
|
3
|
+
import{realpathSync as Xa}from"node:fs";import{resolve as qa}from"node:path";import{fileURLToPath as Za,pathToFileURL as Qa}from"node:url";var io="https://hooks.ev-ai.ai";function Ie(e,t=io){let n=t.replace(/\/+$/,""),r=e.trim();return`${n}/${r}/hook`}var Re=".claude/ev-ai-runtime-report.json",Xt="node_modules/@ev-ai/agent-hook/dist/hook.mjs",J="ev-ai-agent-hook",qt="https://cdn.ev-ai.ai/agent-hook",ze=`current/${J}`,Ye=`.ev-ai/agent-hook/${J}`,Zt=5e3,Qt=5e3,Xe=3e3;var qe=3e3,en=1500,tn=4*1024,nn=32*1024,ao=4*1024,H="1.0.7",Ce=`@ev-ai/agent-hook@${H}`,rn="ev-ai runtime report",on=["claude","cursor","codex"];import{chmodSync as jn,cpSync as Bn,existsSync as F,mkdirSync as ut,readdirSync as Do,readFileSync as Fo,rmSync as be,symlinkSync as jo,writeFileSync as Bo}from"node:fs";import{homedir as j}from"node:os";import{basename as $o,dirname as dt,isAbsolute as Go,join as h,relative as $n,resolve as Dn,sep as Ko}from"node:path";import{fileURLToPath as Jo}from"node:url";var co=new Set(["localhost","127.0.0.1","[::1]","::1"]),sn=/^[A-Za-z0-9._~-]+$/;function an(e){for(let t=0;t<e.length;t++){let n=e.charCodeAt(t);if(n<=32||n===127||n===39)return!0}return!1}function xe(e){try{let t=new URL(e);return t.protocol==="https:"?!0:t.protocol==="http:"?co.has(t.hostname):!1}catch{return!1}}function ae(e){let t;try{t=new URL(e)}catch{return`invalid URL (got: ${e})`}if(!xe(e))return`must be https (or http on localhost / 127.0.0.1 / ::1) (got: ${e})`;let n=lo(e);if(!n)return`must end with /{orgToken}/hook (got: ${e})`;if(!sn.test(n))return`org token must match ${sn.source} (got: ${n})`;if(an(e))return`must not contain whitespace, control characters, or single quotes (got: ${e})`;if(an(t.pathname))return`pathname must not contain whitespace, control characters, or single quotes (got: ${e})`}function ce(e){return new URL(e).toString()}function lo(e){try{let n=new URL(e).pathname.split("/").filter(r=>r.length>0);if(n.length>=2&&n[n.length-1]==="hook"){let r=n[n.length-2];return r.length>0?r:void 0}return}catch{return}}function Ze(e){try{let t=new URL(e),n=t.pathname.split("/").filter(r=>r.length>0);return n.length>=2&&n[n.length-1]==="hook"&&(n[n.length-2]="***",t.pathname=`/${n.join("/")}`),t.toString()}catch{return"<invalid-url>"}}function cn(e){if(e.collector_url)return e.collector_url;let t=e.repo_ingest_token?.trim();return t?Ie(t):""}import{createHash as Sn,randomBytes as So}from"node:crypto";import{existsSync as En,mkdirSync as yn,readFileSync as kn,unlinkSync as In,writeFileSync as Rn}from"node:fs";import{homedir as tt}from"node:os";import{dirname as nt,join as rt,resolve as Eo}from"node:path";import{randomBytes as uo}from"node:crypto";import{existsSync as fn,mkdirSync as fo,readdirSync as po,readFileSync as mo,renameSync as ln,statSync as pn,unlinkSync as un,writeFileSync as go}from"node:fs";import{basename as ho,dirname as dn,join as mn,relative as _o}from"node:path";function d(e){process.stderr.write(`[ev-ai-agent-hook] ${e}
|
|
4
|
+
`)}function z(e,t){fo(dn(e),{recursive:!0});let n=mn(dn(e),`.${ho(e)}.${process.pid}.${uo(4).toString("hex")}.tmp`);try{go(n,t,"utf8");try{ln(n,e)}catch(r){let o=r instanceof Error&&"code"in r?r.code:void 0;if(o==="EEXIST"||o==="EPERM"||o==="EACCES"){un(e),ln(n,e);return}throw r}}catch(r){try{un(n)}catch{}throw r}}function Ae(){return new Date().toISOString().replace(/\.\d{3}Z$/,"Z")}function gn(){process.stdout.write('{"continue":true}')}function E(e){let t=process.env[e];return t===void 0||t===""?void 0:t}async function le(){return new Promise(e=>{let t="";if(process.stdin.isTTY){e("");return}process.stdin.setEncoding("utf8"),process.stdin.on("data",n=>{t+=n}),process.stdin.on("end",()=>{e(t)}),process.stdin.on("error",()=>{e(t)}),process.stdin.resume()})}async function et(e){return new Promise(t=>{let n="",r=!1,o=i=>{r||(r=!0,clearTimeout(s),t(i||"{}"))},s=setTimeout(()=>{o(n)},e);if(process.stdin.isTTY){o("{}");return}process.stdin.setEncoding("utf8"),process.stdin.on("data",i=>{n+=i}),process.stdin.on("end",()=>{o(n)}),process.stdin.on("error",()=>{o(n)}),process.stdin.resume()})}async function D(e,t,n=3e3,r={}){let{execFile:o}=await import("node:child_process"),{promisify:s}=await import("node:util"),i=s(o);try{let{stdout:a}=await i(e,t,{timeout:n,windowsHide:!0,maxBuffer:1048576,cwd:r.cwd});return{ok:!0,stdout:a.trim()}}catch(a){let c=a,u=typeof c.code=="number"?c.code:typeof c.status=="number"?c.status:void 0;return{ok:!1,code:u,spawnFailed:u===void 0}}}async function C(e,t,n=3e3,r={}){let o=await D(e,t,n,r);return o.ok?o.stdout:""}async function M(e=process.cwd()){return await C("git",["rev-parse","--show-toplevel"],2e3,{cwd:e})||e}function v(e,t){try{return JSON.parse(e)}catch{return t}}var Qe=new Map;function ne(e,t){let n=Qe.get(e);if(n!==void 0)return n;try{let r=v(mo(e,"utf8"),t);return Qe.set(e,r),r}catch{return Qe.set(e,t),t}}function ue(e){return typeof e=="string"?e:""}function Y(e,t){let n=e[t];if(typeof n=="string"||typeof n=="number"||typeof n=="boolean")return n;if(!t.includes("."))return;let r=t.split("."),o=e;for(let s of r){if(o===null||typeof o!="object"||Array.isArray(o))return;o=o[s]}if(typeof o=="string"||typeof o=="number"||typeof o=="boolean")return o}function m(e,t){let n=Y(e,t);return typeof n=="string"?n:""}var X=500;function de(e,t=2){if(!fn(e))return{entries:[],truncated:!1};let n=[],r=!1,o=(s,i)=>{if(i>t||r)return;let a;try{a=po(s,{withFileTypes:!0})}catch{return}for(let c of a){if(r)return;let u=mn(s,c.name);if(c.isDirectory()){o(u,i+1);continue}if(c.isFile()){try{n.push({name:_o(e,u),size:pn(u).size})}catch{continue}if(n.length>=X){r=!0;return}}}};return o(e,1),{entries:n,truncated:r}}function fe(e){return fn(e)?{present:!0,size:pn(e).size}:{present:!1,size:0}}var yo="installation.json",ko="cloud-bootstrap.lock",Io=6e4;function Cn(e,t,n){let r=`${e}:${t??""}`;return n?`${n}:${r}`:r}function ot(e=tt()){return rt(e,".ev-ai","agent-hook")}function Ro(e=tt()){return rt(ot(e),yo)}function xn(e){return rt(nt(e),ko)}function An(){return So(8).toString("hex")}function Te(e){return Sn("sha256").update(e).digest("hex").slice(0,16)}function k(e){if(e===void 0)return null;let t=e.trim();return t.length>0?t:null}function Tn(e){return/^[A-Za-z0-9._-]{8,64}$/.test(e)}function Co(e=process.env){let t=k(e.EV_AI_HOOK_INSTALLATION_ID);if(t){if(!Tn(t)){d(`WARN: ignoring EV_AI_HOOK_INSTALLATION_ID (expected 8\u201364 chars [A-Za-z0-9._-], got length ${t.length})`);return}return t}}function xo(e=process.env){if(k(e.GITHUB_ACTIONS)){let t=k(e.GITHUB_REPOSITORY_ID)??k(e.GITHUB_REPOSITORY),n=k(e.GITHUB_ACTOR)??k(e.GITHUB_TRIGGERING_ACTOR)??k(e.GITHUB_USER);if(t&&n)return Te(`github_actions|${t}|${n}`)}if(k(e.CODESPACES)||k(e.CODESPACE_NAME)){let t=k(e.CODESPACE_NAME);if(t)return Te(`codespaces|${t}`);let n=k(e.GITHUB_REPOSITORY_ID)??k(e.GITHUB_REPOSITORY),r=k(e.GITHUB_USER)??k(e.GITHUB_ACTOR);if(n&&r)return Te(`codespaces|${n}|${r}`)}if(k(e.GITLAB_CI)){let t=k(e.CI_PROJECT_ID)??k(e.CI_PROJECT_PATH),n=k(e.GITLAB_USER_LOGIN)??k(e.GITLAB_USER_EMAIL)??k(e.GITLAB_USER_NAME);if(t&&n)return Te(`gitlab|${t}|${n}`)}return null}function hn(e,t){if(e&&Tn(e))return e;e&&d(`WARN: ignoring installation id override (expected 8\u201364 chars [A-Za-z0-9._-], got length ${e.length})`);let n=Co(t);if(n)return n;let r=xo(t);return r||An()}async function Ao(e){let n=await C("git",["config","--get","remote.origin.url"],2e3,{cwd:e})||Eo(e);return Sn("sha256").update(n).digest("hex").slice(0,16)}function To(e){if(!e||typeof e!="object"||Array.isArray(e))return;let t={};for(let[n,r]of Object.entries(e))typeof r=="string"&&r.length>0&&(t[n]=r);return Object.keys(t).length>0?t:void 0}function Oo(e){try{let t=JSON.parse(e);if(typeof t.installation_id!="string"||t.installation_id.length===0)return;let n=To(t.platform_agent_ids);return{installation_id:t.installation_id,...n?{platform_agent_ids:n}:{},...typeof t.operator_identity_hash=="string"?{operator_identity_hash:t.operator_identity_hash}:{},...typeof t.operator_identity_sent_at=="string"?{operator_identity_sent_at:t.operator_identity_sent_at}:{}}}catch{return}}function q(e){if(En(e))try{return Oo(kn(e,"utf8"))}catch{}}function st(e){return q(e)}function On(e,t,n){let r=q(e);if(!r||r.operator_identity_hash===t&&r.operator_identity_sent_at===n)return;let o={...r,operator_identity_hash:t,operator_identity_sent_at:n};try{z(e,`${JSON.stringify(o,null,2)}
|
|
5
|
+
`)}catch(s){let i=s instanceof Error?s.message:String(s);d(`WARN: operator identity cache write failed open: ${i}`)}}function vn(e,t=Date.now()){if(!e)return!0;if(q(e)?.operator_identity_hash)return!1;let n=xn(e);try{if(En(n)){let r=Number.NaN;try{r=Number(kn(n,"utf8").trim())}catch{}let o=t-r;if(Number.isFinite(o)&&o>=0&&o<Io)return!1;try{In(n)}catch{}}}catch{}try{return yn(nt(n),{recursive:!0}),Rn(n,`${t}
|
|
6
|
+
`,{encoding:"utf8",flag:"wx"}),!0}catch(r){if(Pn(r))return!1;let o=r instanceof Error?r.message:String(r);return d(`WARN: cloud bootstrap claim failed open: ${o}`),!0}}function bn(e){if(e)try{In(xn(e))}catch{}}function wn(e,t){let r=q(e)?.platform_agent_ids?.[t];return typeof r=="string"&&r.length>0?r:void 0}function Un(e,t,n){if(!n)return;let r=q(e);if(!r||r.platform_agent_ids?.[t]===n)return;let o={installation_id:r.installation_id,platform_agent_ids:{...r.platform_agent_ids,[t]:n},...r.operator_identity_hash?{operator_identity_hash:r.operator_identity_hash}:{},...r.operator_identity_sent_at?{operator_identity_sent_at:r.operator_identity_sent_at}:{}};try{z(e,`${JSON.stringify(o,null,2)}
|
|
7
|
+
`)}catch(s){let i=s instanceof Error?s.message:String(s);d(`WARN: platform_agent_id cache write failed open: ${i}`)}}function Pn(e){return e instanceof Error&&"code"in e&&e.code==="EEXIST"}function vo(e,t){yn(nt(e),{recursive:!0}),Rn(e,`${JSON.stringify(t,null,2)}
|
|
8
|
+
`,{encoding:"utf8",flag:"wx"})}function _n(e,t){try{return vo(e,t),t}catch(n){if(!Pn(n))throw n;return q(e)}}async function Oe(e,t={}){let n=t.home??tt(),r=t.env??process.env,o=await Ao(e),s=Ro(n),i=q(s);if(i)return{installationId:i.installation_id,storePath:s,repoKey:o};let a=hn(t.overrideId,r),c=_n(s,{installation_id:a});if(c)return{installationId:c.installation_id,storePath:s,repoKey:o};let u=hn(void 0,r),l=_n(s,{installation_id:u===a?An():u});if(l)return{installationId:l.installation_id,storePath:s,repoKey:o};throw new Error(`Failed to create installation record at ${s}`)}import{existsSync as it,readFileSync as bo}from"node:fs";import{dirname as wo,join as Nn,relative as Uo}from"node:path";var ve=[Re,".cursor/ev-ai-runtime-report.json",".codex/ev-ai-runtime-report.json"];async function Po(e=process.cwd(),t){let n=E("EV_AI_HOOK_MANIFEST");if(n&&it(n))return n;let r=t??await M(e);for(let o of ve){let s=Nn(r,o);if(it(s))return s}for(let o of ve){let s=Nn(e,o);if(it(s))return s}}async function No(e,t){let n=t??await M(wo(e)),r=Uo(n,e),o=await D("git",["ls-files","--error-unmatch",r],2e3,{cwd:n});return o.ok?!0:o.code===1?!1:(d(`WARN: git ls-files failed for manifest ${e} (code=${String(o.code)}); treating as tracked`),!0)}function Mo(e){let t=bo(e,"utf8");return v(t,{})}function Lo(){return{schema_version:2,mcp_servers:[]}}async function Mn(e=process.cwd()){let t=await M(e),n=await Po(e,t),r=n?Mo(n):Lo();delete r.installation_id;let o=n?await No(n,t):!1;r.capture_hook_input==="full"&&n&&o&&(d(`WARN: ignoring capture_hook_input=full in git-tracked manifest ${n}; use EV_AI_HOOK_CAPTURE_FULL_INPUT=1 or an untracked operator manifest`),delete r.capture_hook_input);let{installationId:s,storePath:i,repoKey:a}=await Oe(t);return{manifestPath:n??i,manifest:r,installationId:s,installationStorePath:i,repoKey:a,collectorUrl:cn(r),platformAgentId:r.platform_agent_id??"",gitRoot:t}}function Ln(e){return{schema_version:2,...e?{collector_url:e}:{},mcp_servers:[]}}var Ho=["darwin-arm64","darwin-x64","linux-arm64","linux-x64"];function at(e=process.platform,t=process.arch){if(e==="darwin")return t==="arm64"?"darwin-arm64":t==="x64"?"darwin-x64":void 0;if(e==="linux")return t==="arm64"?"linux-arm64":t==="x64"?"linux-x64":void 0}function Hn(e=process.platform,t=process.arch){let n=at(e,t);if(!n)throw new Error(`Unsupported platform ${e}-${t}. Supported: ${Ho.join(", ")}.`);return n}function ct(e){return`compile-out/bin/${e}/ev-ai-agent-hook`}function Vo(e,t){let n=e.collectorUrl?.trim();if(!n)throw new Error(`${t} requires --url <https://hooks.ev-ai.ai/{orgToken}/hook>`);let r=ae(n);if(r)throw new Error(`collector URL rejected: ${r}`);return ce(n)}function Wo(e){let t=e.collectorUrl?.trim();if(!t)return;let n=ae(t);if(n)throw new Error(`collector URL rejected: ${n}`);return ce(t)}function zo(e){return Vo(e,"install")}function Gn(e){let t={};for(let n=0;n<e.length;n++){let r=e[n];if(r==="--url"){let o=e[n+1];o&&!o.startsWith("--")&&(t.collectorUrl=o,n+=1);continue}if(r==="--collector-url")throw new Error("--collector-url was renamed to --url")}return t}function Kn(e){let t={};for(let n=0;n<e.length;n++){let r=e[n];if(r==="--url"){let o=e[n+1];o&&!o.startsWith("--")&&(t.collectorUrl=o,n+=1);continue}if(r==="--collector-url")throw new Error("--collector-url was renamed to --url");if(r==="--update")throw new Error("--update was removed; use the `update` command instead of `install --update`");if(r==="--delivery"){let o=e[n+1];(o==="npx"||o==="binary"||o==="local")&&(t.delivery=o,n+=1);continue}if(r==="--force"){t.force=!0;continue}if(r==="--no-claude"){t.skipClaude=!0;continue}if(r==="--no-cursor"){t.skipCursor=!0;continue}if(r==="--no-codex"){t.skipCodex=!0;continue}}return t}function Jn(e=process.execPath){return Vn(e)?"binary":"npx"}function Yo(){return h(j(),".ev-ai","agent-hook")}function Xo(e=j()){return h(e,".ev-ai","agent-hook",ze)}function qo(){let e=dt(Jo(import.meta.url)),t=h(e,"hook.mjs");return F(t)?t:h(e,"..","dist","hook.mjs")}function Vn(e=process.execPath){return $o(e)===J}function Wn(e,t){let n=$n(Dn(e),Dn(t));return!n.startsWith("..")&&!Go(n)}function we(e){return e.split(Ko).join("/")}function Zo(e){return`node "$(git rev-parse --show-toplevel)/${we(e)}"`}function Qo(e){return`"$(git rev-parse --show-toplevel)/${we(e)}"`}function es(e){return h(e,Ye)}function zn(e,t){let n=es(e);ut(dt(n),{recursive:!0}),Bn(t,n,{force:!0});try{jn(n,493)}catch{}return n}function ts(e){let t=h(Yo(),"current");try{be(t,{recursive:!0,force:!0})}catch{}jo(e,t,process.platform==="win32"?"junction":"dir")}function Yn(e,t=H,n=j()){let r=h(n,".ev-ai","agent-hook",t),o=h(r,J);ut(r,{recursive:!0}),Bn(e,o,{force:!0});try{jn(o,493)}catch{}return ts(r),h(n,".ev-ai","agent-hook",ze)}function Xn(e){let t=at();if(!t)return;let n=[h(e,ct(t)),h(e,"packages","agent-hook",ct(t))];for(let r of n)if(F(r)&&Wn(e,r))return r}function ns(e=j()){let t=Xo(e);return F(t)?t:void 0}function rs(e,t=j()){let n=ns(t);return n||(Vn()?Yn(process.execPath,H,t):Xn(e))}function os(e,t=j()){let n=Xn(e);if(!n)throw new Error(`update requires a locally compiled binary \u2014 run this package\u2019s build:hook-binary script first.
|
|
9
|
+
To install a released binary instead: curl -fsSL https://cdn.ev-ai.ai/agent-hook/install.sh | sh`);let r=Yn(n,H,t),o=zn(e,n);return{sourcePath:n,projectPath:o,globalPath:r}}function Fn(e){let t=[h(e,"packages","agent-hook","dist","hook.mjs"),h(e,Xt)],n=qo();F(n)&&Wn(e,n)&&t.unshift(n);for(let r of t){if(!F(r))continue;let o=we($n(e,r));return{command:Zo(o),hookPath:o,strategy:"dev_mjs"}}}function ss(e=Ce){return`npx -y ${e}`}function is(e,t=j(),n=Jn()){if(n==="npx")return{command:ss(),hookPath:Ce,strategy:"npx"};if(n==="local"){let s=Fn(e);if(s)return s;throw new Error("local delivery requires packages/agent-hook/dist/hook.mjs (or node_modules/@ev-ai/agent-hook/dist/hook.mjs) under the git root \u2014 run yarn workspace @ev-ai/agent-hook build first")}let r=rs(e,t);if(r){zn(e,r);let s=we(Ye);return{command:Qo(s),hookPath:s,strategy:"project_binary"}}let o=Fn(e);if(o)return o;throw new Error(`ev-ai-agent-hook binary not found. Install from CDN:
|
|
10
|
+
curl -fsSL ${qt}/install.sh | sh
|
|
9
11
|
Or use npx delivery:
|
|
10
|
-
npx ${
|
|
11
|
-
`,"utf8")}function I(e){if(C(e))try{return JSON.parse(ho(e,"utf8"))}catch(t){throw t instanceof SyntaxError?new Error(`Invalid JSON in ${e} \u2014 fix or remove the file`,{cause:t}):t}}function Fo(e,t){let n=vt(t.collectorUrl),o={...e,schema_version:e?.schema_version??n.schema_version};return t.collectorUrl!==void 0?o.collector_url=t.collectorUrl:o.collector_url=e?.collector_url??n.collector_url,delete o.repo_ingest_token,delete o.installation_id,o.mcp_servers??=n.mcp_servers,o}function Do(e){return(e.schema_version??2)===2&&e.collector_url===void 0&&(e.mcp_servers?.length??0)===0&&e.platform_agent_id===void 0&&e.capture_hook_input===void 0&&e.repo_ingest_token===void 0}function Ut(e,t){let n=f(e,D),o=I(n),r=Fo(o,t);return t.collectorUrl!==void 0||C(n)||!Do(r)?(T(n,r),{manifestPath:n,wrote:!0}):{manifestPath:void 0,wrote:!1}}function Oe(e){if(e===null||typeof e!="object")return!1;let t=e,n=String(t.CLAUDE_CODE_ENABLE_TELEMETRY??"").toLowerCase();return n==="1"||n==="true"?!0:Object.keys(t).some(o=>o.startsWith("OTEL_"))}function $o(e=process.platform){switch(e){case"darwin":return"/Library/Application Support/ClaudeCode";case"win32":return f(process.env.ProgramFiles??"C:\\Program Files","ClaudeCode");default:return"/etc/claude-code"}}function Bo(e=process.platform){let t=$o(e),n=[f(t,"managed-settings.json")],o=f(t,"managed-settings.d");try{if(!C(o))return n;let r=go(o).filter(s=>s.endsWith(".json")&&!s.startsWith(".")).sort().map(s=>f(o,s));n.push(...r)}catch{}return n}function Ko(e){if(Oe(process.env))return!0;let t=A();return[...Bo(),f(t,".claude","settings.json"),f(t,".claude","remote-settings.json"),f(e,".claude","settings.json"),f(e,".claude","settings.local.json")].some(o=>{try{let r=I(o);return r?Oe(r.env):!1}catch{return!1}})}function Go(e){try{let t=I(f(e,".claude","settings.json"));return t?Oe(t.env):!1}catch{return!1}}function jt(e){return Array.isArray(e)?e:[]}function le(e){let t=[],n=o=>!!o&&typeof o=="object"&&Lt(o.command);for(let o of jt(e)){if(!o||typeof o!="object"){t.push(o);continue}let r=Array.isArray(o.hooks)?o.hooks:[],s=r.filter(a=>!n(a));if(!(s.length===0&&r.some(n))){if(s.length!==r.length){t.push({...o,hooks:s});continue}t.push(o)}}return t}function Ft(e,t){return[...le(e),...t]}function He(e){return Array.isArray(e)?e.filter(t=>!t||typeof t!="object"?!0:!Lt(t.command)):[]}function Jo(e,t){return[...He(e),{command:t}]}function Wo(e){let t=()=>({hooks:[{type:"command",command:e}]});return{SessionStart:[t()],UserPromptExpansion:[t()],PreToolUse:[t()],PostToolUse:[t()],PostToolUseFailure:[t()],PermissionDenied:[t()],Stop:[t()],StopFailure:[t()],SessionEnd:[t()],SubagentStart:[t()],SubagentStop:[t()]}}function Vo(e){let t={type:"command",command:e,statusMessage:nt},n=()=>({hooks:[t]});return{SessionStart:[n()],UserPromptSubmit:[n()],PreToolUse:[n()],PostToolUse:[n()],Stop:[n()]}}var zo=["sessionStart","beforeSubmitPrompt","preToolUse","postToolUse","postToolUseFailure","subagentStart","subagentStop","stop"],Yo=["beforeMCPExecution","beforeShellExecution","afterFileEdit"];function Xo(e){let t={...e};for(let n of Yo){if(!(n in t))continue;let o=He(t[n]);o.length===0?delete t[n]:t[n]=o}return t}function qo(e,t,n={}){let o=f(e,".claude/settings.json"),r=Ne(t,"claude"),s=I(o)??{};if(Ko(e)&&!n.force){if(s.hooks&&typeof s.hooks=="object"){let p={...s.hooks};for(let m of Object.keys(p))p[m]=le(p[m]),jt(p[m]).length===0&&delete p[m];Object.keys(p).length===0?delete s.hooks:s.hooks=p,T(o,s)}return!1}let i=s.hooks&&typeof s.hooks=="object"?s.hooks:{},c=Wo(r),u={...i};for(let[p,m]of Object.entries(c))u[p]=Ft(i[p],m);return s.hooks=u,T(o,s),!0}function Zo(e,t){let n=f(e,".cursor/hooks.json"),o=Ne(t,"cursor"),r=I(n)??{},s=r.hooks&&typeof r.hooks=="object"?r.hooks:{},a=Xo({...s});for(let i of zo)a[i]=Jo(a[i],o);T(n,{...r,version:typeof r.version=="number"?r.version:1,hooks:a})}function Qo(e,t){let n=f(e,".codex/hooks.json"),o=Ne(t,"codex"),r=I(n)??{},s=r.hooks&&typeof r.hooks=="object"?r.hooks:{},a=Vo(o),i={...s};for(let[c,u]of Object.entries(a))i[c]=Ft(s[c],u);T(n,{...r,hooks:i})}function er(e){let t=f(e,".claude/settings.json"),n=I(t);if(!n?.hooks||typeof n.hooks!="object")return;let o={...n.hooks},r=!1;for(let s of Object.keys(o)){let a=o[s],i=le(a);JSON.stringify(a)!==JSON.stringify(i)&&(r=!0),i.length===0?delete o[s]:o[s]=i}r&&(Object.keys(o).length===0?delete n.hooks:n.hooks=o,T(t,n),l(`Removed Evalon hooks from ${t}`))}function tr(e){let t=f(e,".cursor/hooks.json"),n=I(t);if(!n?.hooks||typeof n.hooks!="object")return;let o={...n.hooks},r=!1,s=0;for(let a of Object.keys(o)){let i=o[a],c=He(i);JSON.stringify(i)!==JSON.stringify(c)&&(r=!0),c.length===0?delete o[a]:(o[a]=c,s+=c.length)}if(r){if(s===0&&Object.keys(o).length===0&&Object.keys(n).filter(i=>i!=="hooks"&&i!=="version").length===0){ae(t,{force:!0}),l(`Removed ${t}`);return}T(t,{...n,hooks:o}),l(`Removed Evalon hooks from ${t}`)}}function nr(e){let t=f(e,".codex/hooks.json"),n=I(t);if(!n?.hooks||typeof n.hooks!="object")return;let o={...n.hooks},r=!1,s=0;for(let a of Object.keys(o)){let i=o[a],c=le(i);JSON.stringify(i)!==JSON.stringify(c)&&(r=!0),c.length===0?delete o[a]:(o[a]=c,s+=c.length)}if(r){if(s===0&&Object.keys(o).length===0&&Object.keys(n).filter(i=>i!=="hooks").length===0){ae(t,{force:!0}),l(`Removed ${t}`);return}T(t,{...n,hooks:o}),l(`Removed Evalon hooks from ${t}`)}}function Me(e=process.platform,t=process.arch,n={}){if(e==="win32")throw new Error("Windows install is not supported yet. Use macOS/Linux, or wait for phase-2 native commands.");(n.requireBinaryArch??!0)&&wt(e,t)}async function Dt(e={}){let t=xo(e);e.collectorUrl=t;let n=e.skipClaude===!0,o=e.skipCursor===!0,r=e.skipCodex===!0;if(n&&o&&r)throw new Error("at least one runner must be wired; refuse --no-claude --no-cursor --no-codex together");let s=e.delivery??Ot();Me(process.platform,process.arch,{requireBinaryArch:s==="binary"});let a=e.cwd??process.cwd(),i=await w(a),{command:c,hookPath:u,strategy:p}=jo(i,A(),s),m=I(f(i,D)),{installationId:E,storePath:k}=await se(i,{overrideId:e.installationId,migrateFromManifestId:m?.installation_id}),{manifestPath:O,wrote:v}=Ut(i,e),y=[];return n?l("Skipped Claude hook \u2014 --no-claude"):qo(i,c,{force:e.force})?(y.push("Claude"),e.force&&Go(i)&&l("Forced Claude hook despite project native OTEL \u2014 expect duplicate session/tool events")):l("Skipped Claude hook \u2014 native OTEL telemetry already enabled (avoids duplicate events); pass --force to wire anyway"),o?l("Skipped Cursor hook \u2014 --no-cursor"):(Zo(i,c),y.push("Cursor")),r?l("Skipped Codex hook \u2014 --no-codex"):(Qo(i,c),y.push("Codex")),l(`Installed hook (${p}) at ${u}`),l(`Installation identity ${E} at ${k}`),v&&O?l(`Shared manifest written to ${O}`):l("Using package default collector config (no shared manifest file needed)"),l(y.length>0?`Wired ${y.join(", ")} hooks in ${i} (commands include --runner)`:`No runner hooks wired in ${i} (Claude skipped by OTEL; Cursor/Codex excluded via flags)`),p==="npx"?l("Hook commands use npx and may be committed; teammates need Node on PATH only (no install step, no env vars when collector_url is in the shared manifest)."):p==="project_binary"&&l("Hook commands are git-root-relative and may be committed; each collaborator runs install once to populate .evalon/agent-hook/ (gitignored)."),v&&O&&e.collectorUrl&&l("Shared manifest includes collector_url \u2014 commit it with hook configs so teammates post without env vars."),{gitRoot:i,hookPath:u,manifestPath:O,installationStorePath:k,strategy:p}}async function $t(e=process.cwd()){Me(process.platform,process.arch,{requireBinaryArch:!0});let t=await w(e),{projectPath:n,globalPath:o}=Mo(t);l(`Refreshed ${o}`),l(`Refreshed ${n}`),l("Hook configs and shared manifest left unchanged")}async function Bt(e={}){let t=Io(e);e.collectorUrl=t,Me(process.platform,process.arch,{requireBinaryArch:!1});let n=e.cwd??process.cwd(),o=await w(n),{manifestPath:r,wrote:s}=Ut(o,e);if(t!==void 0&&(!r||!s))throw new Error("configure failed to write shared collector manifest");return s&&r?l(`Wrote ${r}`):t===void 0&&l("No --url given and no shared manifest yet \u2014 pass --url <\u2026/{orgToken}/hook> to write collector destination."),l("Manifest only \u2014 enable Evalon marketplace plugins (https://github.com/evalon-ai/marketplace). Do not also run file-wiring install for the same events."),{gitRoot:o,manifestPath:r}}function Kt(e){for(let t of[()=>er(e),()=>tr(e),()=>nr(e)])try{t()}catch(n){let o=n instanceof Error?n.message:String(n);l(`WARN: strip skipped a hook file: ${o}`)}}async function Gt(e=process.cwd()){let t=await w(e);return Kt(t),l("Stripped Evalon file-wired hooks; shared collector manifest left in place."),l("Next: enable Evalon marketplace plugins (https://github.com/evalon-ai/marketplace), then restart runners."),{gitRoot:t}}async function Jt(e=process.cwd()){let t=await w(e);Kt(t);for(let n of ie){let o=f(t,n);if(C(o))try{ae(o,{force:!0}),l(`Removed ${o}`)}catch(r){let s=r instanceof Error?r.message:String(r);l(`WARN: uninstall could not remove ${o}: ${s}`)}}}var or={claude:".claude",cursor:".cursor",codex:".codex"};function ue(e){let n=e.replace(/^\/+|\/+$/g,"").toLowerCase().split("/").filter(Boolean);return n.length<2?"":n.join("/")}function rr(e){if(!e)return"";let t=e.replace(/^([a-z]+:\/\/)[^/@]+@/i,"$1");t=t.replace(/\.git$/i,"");let n=t.match(/^git@[^:]+:(.+)$/);if(n?.[1])return ue(n[1]);let o=t.match(/^ssh:\/\/[^/]+\/(.+)$/i);if(o?.[1])return ue(o[1]);t=t.replace(/^https:\/\//i,""),t=t.replace(/^http:\/\//i,""),t=t.replace(/^ssh:\/\//i,"");let r=t.match(/^[^/]+\/(.+)$/);return r?.[1]?ue(r[1]):ue(t)}async function Le(e=process.cwd()){let t=await R("git",["rev-parse","--is-inside-work-tree"],2e3,{cwd:e});if(!t.ok||t.stdout!=="true")return null;let[n,o,r,s]=await Promise.all([R("git",["remote","get-url","origin"],2e3,{cwd:e}),R("git",["branch","--show-current"],2e3,{cwd:e}),R("git",["rev-parse","HEAD"],2e3,{cwd:e}),R("git",["status","--porcelain"],2e3,{cwd:e})]),a=n.ok?n.stdout:null;return{remote:a===null?null:a.replace(/^([a-z]+:\/\/)[^/@]+@/i,"$1"),branch:o.ok?o.stdout:null,head:r.ok?r.stdout:null,dirty:s.ok?s.stdout.length>0:null}}async function Wt(e,t,n,o=process.cwd(),r,s){if(t)return t;let a=or[n];if(!a)return"";let i=_t(n,e.scope_path);if(s){let k=kt(s,i);if(k)return k}let c=r??await Le(o),u=c?.remote?rr(c.remote):"";if(u||(u=process.env.GITHUB_REPOSITORY??""),!u)return"";let p=e.scope_path??"",m=p?`${p}/`:"",E=`${u}:${m}${a}`;return s&&yt(s,i,E),E}import{existsSync as sr,readFileSync as ir}from"node:fs";import{hostname as ar,userInfo as cr}from"node:os";function Vt(){if(g("GITHUB_ACTIONS"))return"github_actions";let e=g("CI");if(e&&e!=="false"&&e!=="0")return"managed";try{if(sr("/.dockerenv")||ir("/proc/1/environ","utf8").includes("container="))return"container"}catch{}return process.stdin.isTTY||process.stdout.isTTY||g("TERM")?"interactive":"cron"}async function zt(){return await h("systemd-detect-virt",[],1e3)}async function Yt(){let e=process.platform==="darwin"?"Darwin":process.platform==="win32"?"Windows_NT":"Linux",t="";if(process.platform==="darwin")t=await h("sw_vers",["-productVersion"],1e3);else if(process.platform==="linux"){try{let{readFileSync:s}=await import("node:fs"),a=s("/etc/os-release","utf8"),i=a.match(/^PRETTY_NAME="?([^"\n]+)"?/m)?.[1],c=a.match(/^VERSION_ID="?([^"\n]+)"?/m)?.[1];t=i??c??""}catch{t=await h("lsb_release",["-sd"],1e3).then(s=>s.replace(/^"|"$/g,""))}t||(t=await h("uname",["-r"],1e3))}else t=await h("ver",[],1e3);let n=process.env.USER??cr().username??"",o=(process.env.SHELL??"").split(/[/\\]/).pop()??"",r="";try{r=await h("tty",[],500),r.includes("not a tty")&&(r="")}catch{r=""}return{os:e,os_version:t||null,user:n||null,shell:o||null,tty:r||null}}function Xt(){return ar()}import{existsSync as lr,readFileSync as ur}from"node:fs";import{homedir as qt}from"node:os";import{join as dr}from"node:path";var fr="cloud-cache.json",pr=1440*60*1e3,mr=900*1e3;function gr(e=qt()){return dr(be(e),fr)}function hr(e){if(!lr(e))return;let t=_(ur(e,"utf8"),{});if(!(typeof t.context!="string"||typeof t.probed_at!="number"||t.result!==null&&t.result!==void 0&&typeof t.result!="object"))return{context:t.context,probed_at:t.probed_at,result:t.result??null}}function _r(e,t){try{L(e,`${JSON.stringify(t)}
|
|
12
|
-
`)}catch(n){let
|
|
13
|
-
`)
|
|
14
|
-
`);return Ar("sha256").update(n).digest("hex").slice(0,16)}function de(e,t,n=!1){let o=$r(e),r=e.length;return t===o?n?{hash:o,count:r,truncated:n}:{hash:o,count:r}:n?{hash:o,count:r,entries:e,truncated:n}:{hash:o,count:r,entries:e}}function Br(e){return on(e)?_(rn(e,"utf8"),{}):{}}function Kr(e,t){try{L(e,`${JSON.stringify(t)}
|
|
15
|
-
`)
|
|
16
|
-
|
|
17
|
-
`);if(t<0)return null;let n;try{n=JSON.parse(e.slice(0,t))}catch{return null}return{meta:n,body:e.slice(t+1)}}async function ge(e,t=fetch){let n=await e(),o=ys(n);if(!o)return;let{meta:r,body:s}=o,a={"Content-Type":"application/json"};try{await t(r.url,{method:"POST",headers:a,body:s,signal:AbortSignal.timeout(Number(r.timeoutMs))})}catch{}}async function Ss(e,t,n){let o=wn(e);l(`POST event=${e} url=${we(n)} size=${t.length} platform=${process.platform}`);let r={"Content-Type":"application/json"},s=Date.now();try{let a=await fetch(n,{method:"POST",headers:r,body:t,signal:AbortSignal.timeout(o)}),i=Date.now()-s;if(a.ok)return l(`POST outcome=ok elapsed_ms=${i} http=${a.status}`),!0;let c=(await a.text()).slice(0,200).replace(/[\n\r]/g,"");return l(`POST outcome=fail elapsed_ms=${i} http=${a.status} body=${c}`),!1}catch(a){let i=Date.now()-s,c=a instanceof Error?a.message:String(a);return l(`POST outcome=fail elapsed_ms=${i} http=000 body=${c}`),!1}}async function xn(e,t,n,o,r){try{let s=o(e,t,{detached:!0,stdio:["pipe","ignore","ignore"],windowsHide:!0});s.on("error",()=>{}),s.stdin.on("error",()=>{});let a=!1;return await new Promise(i=>{let c=setTimeout(()=>{if(!a){l(`WARN: ${r} stdin handoff timed out \u2014 continuing fail-open`);try{s.stdin.destroy()}catch{}}i()},Qe),u=()=>{a=!0,clearTimeout(c),i()};s.stdin.end(n,()=>u()),s.stdin.once("error",()=>u())}),s.unref(),s}catch(s){let a=s instanceof Error?s.message:String(s);return l(`WARN: ${r} spawn failed open: ${a}`),null}}async function Es(e,t,n,o=vn,r=ks){let s=wn(e),a=_s(n,s,t),{command:i,args:c}=r();return xn(i,c,a,o,"detached post")}async function bn(e,t,n=vn,o=In){let{command:r,args:s}=o(Ge,t);return xn(r,s,e,n,"detached work")}async function z(e,t,n,o,r){if(!r){l("WARN: collector URL missing \u2014 pass --url on the hook command or set collector_url in manifest");return}if(!ee(r)){l(`WARN: collector URL blocked (https required): ${we(r)}`);return}let s=o(e,t,n),a=`${JSON.stringify(s)}
|
|
18
|
-
|
|
19
|
-
`)
|
|
12
|
+
npx ${Ce} install`)}function qn(e){return typeof e!="string"?!1:e.includes("@ev-ai/agent-hook")||e.includes("agent-hook/dist/hook")||e.includes(".ev-ai/agent-hook")||e.includes(J)||/(?:^|[\s/"'])ev-ai-agent-hook(?:$|[\s"'])/.test(e)}function ft(e,t){return`${e.replace(/\s+--runner(?:=|\s+)\S+/g,"").trimEnd()} --runner ${t}`}function V(e,t){ut(dt(e),{recursive:!0}),Bo(e,`${JSON.stringify(t,null,2)}
|
|
13
|
+
`,"utf8")}function B(e){if(F(e))try{return JSON.parse(Fo(e,"utf8"))}catch(t){throw t instanceof SyntaxError?new Error(`Invalid JSON in ${e} \u2014 fix or remove the file`,{cause:t}):t}}function as(e,t){let n=Ln(t.collectorUrl),r={...e,schema_version:e?.schema_version??n.schema_version};return t.collectorUrl!==void 0?r.collector_url=t.collectorUrl:r.collector_url=e?.collector_url??n.collector_url,delete r.repo_ingest_token,delete r.installation_id,r.mcp_servers??=n.mcp_servers,r}function cs(e){return(e.schema_version??2)===2&&e.collector_url===void 0&&(e.mcp_servers?.length??0)===0&&e.platform_agent_id===void 0&&e.capture_hook_input===void 0&&e.repo_ingest_token===void 0}function Zn(e,t){let n=h(e,Re),r=B(n),o=as(r,t);return t.collectorUrl!==void 0||F(n)||!cs(o)?(V(n,o),{manifestPath:n,wrote:!0}):{manifestPath:void 0,wrote:!1}}function lt(e){if(e===null||typeof e!="object")return!1;let t=e,n=String(t.CLAUDE_CODE_ENABLE_TELEMETRY??"").toLowerCase();return n==="1"||n==="true"?!0:Object.keys(t).some(r=>r.startsWith("OTEL_"))}function ls(e=process.platform){switch(e){case"darwin":return"/Library/Application Support/ClaudeCode";case"win32":return h(process.env.ProgramFiles??"C:\\Program Files","ClaudeCode");default:return"/etc/claude-code"}}function us(e=process.platform){let t=ls(e),n=[h(t,"managed-settings.json")],r=h(t,"managed-settings.d");try{if(!F(r))return n;let o=Do(r).filter(s=>s.endsWith(".json")&&!s.startsWith(".")).sort().map(s=>h(r,s));n.push(...o)}catch{}return n}function ds(e){if(lt(process.env))return!0;let t=j();return[...us(),h(t,".claude","settings.json"),h(t,".claude","remote-settings.json"),h(e,".claude","settings.json"),h(e,".claude","settings.local.json")].some(r=>{try{let o=B(r);return o?lt(o.env):!1}catch{return!1}})}function fs(e){try{let t=B(h(e,".claude","settings.json"));return t?lt(t.env):!1}catch{return!1}}function Qn(e){return Array.isArray(e)?e:[]}function Ue(e){let t=[],n=r=>!!r&&typeof r=="object"&&qn(r.command);for(let r of Qn(e)){if(!r||typeof r!="object"){t.push(r);continue}let o=Array.isArray(r.hooks)?r.hooks:[],s=o.filter(i=>!n(i));if(!(s.length===0&&o.some(n))){if(s.length!==o.length){t.push({...r,hooks:s});continue}t.push(r)}}return t}function er(e,t){return[...Ue(e),...t]}function pt(e){return Array.isArray(e)?e.filter(t=>!t||typeof t!="object"?!0:!qn(t.command)):[]}function ps(e,t){return[...pt(e),{command:t}]}function ms(e){let t=()=>({hooks:[{type:"command",command:e}]});return{SessionStart:[t()],UserPromptExpansion:[t()],PreToolUse:[t()],PostToolUse:[t()],PostToolUseFailure:[t()],PermissionDenied:[t()],Stop:[t()],StopFailure:[t()],SessionEnd:[t()],SubagentStart:[t()],SubagentStop:[t()]}}function gs(e){let t={type:"command",command:e,statusMessage:rn},n=()=>({hooks:[t]});return{SessionStart:[n()],UserPromptSubmit:[n()],PreToolUse:[n()],PostToolUse:[n()],Stop:[n()]}}var hs=["sessionStart","beforeSubmitPrompt","preToolUse","postToolUse","postToolUseFailure","subagentStart","subagentStop","stop"],_s=["beforeMCPExecution","beforeShellExecution","afterFileEdit"];function Ss(e){let t={...e};for(let n of _s){if(!(n in t))continue;let r=pt(t[n]);r.length===0?delete t[n]:t[n]=r}return t}function Es(e,t,n={}){let r=h(e,".claude/settings.json"),o=ft(t,"claude"),s=B(r)??{};if(ds(e)&&!n.force){if(s.hooks&&typeof s.hooks=="object"){let l={...s.hooks};for(let f of Object.keys(l))l[f]=Ue(l[f]),Qn(l[f]).length===0&&delete l[f];Object.keys(l).length===0?delete s.hooks:s.hooks=l,V(r,s)}return!1}let a=s.hooks&&typeof s.hooks=="object"?s.hooks:{},c=ms(o),u={...a};for(let[l,f]of Object.entries(c))u[l]=er(a[l],f);return s.hooks=u,V(r,s),!0}function ys(e,t){let n=h(e,".cursor/hooks.json"),r=ft(t,"cursor"),o=B(n)??{},s=o.hooks&&typeof o.hooks=="object"?o.hooks:{},i=Ss({...s});for(let a of hs)i[a]=ps(i[a],r);V(n,{...o,version:typeof o.version=="number"?o.version:1,hooks:i})}function ks(e,t){let n=h(e,".codex/hooks.json"),r=ft(t,"codex"),o=B(n)??{},s=o.hooks&&typeof o.hooks=="object"?o.hooks:{},i=gs(r),a={...s};for(let[c,u]of Object.entries(i))a[c]=er(s[c],u);V(n,{...o,hooks:a})}function Is(e){let t=h(e,".claude/settings.json"),n=B(t);if(!n?.hooks||typeof n.hooks!="object")return;let r={...n.hooks},o=!1;for(let s of Object.keys(r)){let i=r[s],a=Ue(i);JSON.stringify(i)!==JSON.stringify(a)&&(o=!0),a.length===0?delete r[s]:r[s]=a}o&&(Object.keys(r).length===0?delete n.hooks:n.hooks=r,V(t,n),d(`Removed ev-ai hooks from ${t}`))}function Rs(e){let t=h(e,".cursor/hooks.json"),n=B(t);if(!n?.hooks||typeof n.hooks!="object")return;let r={...n.hooks},o=!1,s=0;for(let i of Object.keys(r)){let a=r[i],c=pt(a);JSON.stringify(a)!==JSON.stringify(c)&&(o=!0),c.length===0?delete r[i]:(r[i]=c,s+=c.length)}if(o){if(s===0&&Object.keys(r).length===0&&Object.keys(n).filter(a=>a!=="hooks"&&a!=="version").length===0){be(t,{force:!0}),d(`Removed ${t}`);return}V(t,{...n,hooks:r}),d(`Removed ev-ai hooks from ${t}`)}}function Cs(e){let t=h(e,".codex/hooks.json"),n=B(t);if(!n?.hooks||typeof n.hooks!="object")return;let r={...n.hooks},o=!1,s=0;for(let i of Object.keys(r)){let a=r[i],c=Ue(a);JSON.stringify(a)!==JSON.stringify(c)&&(o=!0),c.length===0?delete r[i]:(r[i]=c,s+=c.length)}if(o){if(s===0&&Object.keys(r).length===0&&Object.keys(n).filter(a=>a!=="hooks").length===0){be(t,{force:!0}),d(`Removed ${t}`);return}V(t,{...n,hooks:r}),d(`Removed ev-ai hooks from ${t}`)}}function mt(e=process.platform,t=process.arch,n={}){if(e==="win32")throw new Error("Windows install is not supported yet. Use macOS/Linux, or wait for phase-2 native commands.");(n.requireBinaryArch??!0)&&Hn(e,t)}async function tr(e={}){let t=zo(e);e.collectorUrl=t;let n=e.skipClaude===!0,r=e.skipCursor===!0,o=e.skipCodex===!0;if(n&&r&&o)throw new Error("at least one runner must be wired; refuse --no-claude --no-cursor --no-codex together");let s=e.delivery??Jn();mt(process.platform,process.arch,{requireBinaryArch:s==="binary"});let i=e.cwd??process.cwd(),a=await M(i),{command:c,hookPath:u,strategy:l}=is(a,j(),s),{installationId:f,storePath:g}=await Oe(a,{overrideId:e.installationId}),{manifestPath:p,wrote:_}=Zn(a,e),R=[];return n?d("Skipped Claude hook \u2014 --no-claude"):Es(a,c,{force:e.force})?(R.push("Claude"),e.force&&fs(a)&&d("Forced Claude hook despite project native OTEL \u2014 expect duplicate session/tool events")):d("Skipped Claude hook \u2014 native OTEL telemetry already enabled (avoids duplicate events); pass --force to wire anyway"),r?d("Skipped Cursor hook \u2014 --no-cursor"):(ys(a,c),R.push("Cursor")),o?d("Skipped Codex hook \u2014 --no-codex"):(ks(a,c),R.push("Codex")),d(`Installed hook (${l}) at ${u}`),d(`Installation identity ${f} at ${g}`),_&&p?d(`Shared manifest written to ${p}`):d("Using package default collector config (no shared manifest file needed)"),d(R.length>0?`Wired ${R.join(", ")} hooks in ${a} (commands include --runner)`:`No runner hooks wired in ${a} (Claude skipped by OTEL; Cursor/Codex excluded via flags)`),l==="npx"?d("Hook commands use npx and may be committed; teammates need Node on PATH only (no install step, no env vars when collector_url is in the shared manifest)."):l==="project_binary"?d("Hook commands are git-root-relative and may be committed; each collaborator runs install once to populate .ev-ai/agent-hook/ (gitignored)."):l==="dev_mjs"&&d("Hook commands use node + monorepo packages/agent-hook/dist/hook.mjs (local delivery; rebuild with yarn workspace @ev-ai/agent-hook build)."),_&&p&&e.collectorUrl&&d("Shared manifest includes collector_url \u2014 commit it with hook configs so teammates post without env vars."),{gitRoot:a,hookPath:u,manifestPath:p,installationStorePath:g,strategy:l}}async function nr(e=process.cwd()){mt(process.platform,process.arch,{requireBinaryArch:!0});let t=await M(e),{projectPath:n,globalPath:r}=os(t);d(`Refreshed ${r}`),d(`Refreshed ${n}`),d("Hook configs and shared manifest left unchanged")}async function rr(e={}){let t=Wo(e);e.collectorUrl=t,mt(process.platform,process.arch,{requireBinaryArch:!1});let n=e.cwd??process.cwd(),r=await M(n),{manifestPath:o,wrote:s}=Zn(r,e);if(t!==void 0&&(!o||!s))throw new Error("configure failed to write shared collector manifest");return s&&o?d(`Wrote ${o}`):t===void 0&&d("No --url given and no shared manifest yet \u2014 pass --url <\u2026/{orgToken}/hook> to write collector destination."),d("Manifest only \u2014 enable ev-ai marketplace plugins. Do not also run file-wiring install for the same events."),{gitRoot:r,manifestPath:o}}function or(e){for(let t of[()=>Is(e),()=>Rs(e),()=>Cs(e)])try{t()}catch(n){let r=n instanceof Error?n.message:String(n);d(`WARN: strip skipped a hook file: ${r}`)}}async function sr(e=process.cwd()){let t=await M(e);return or(t),d("Stripped ev-ai file-wired hooks; shared collector manifest left in place."),d("Next: enable ev-ai marketplace plugins, then restart runners."),{gitRoot:t}}async function ir(e=process.cwd()){let t=await M(e);or(t);for(let n of ve){let r=h(t,n);if(F(r))try{be(r,{force:!0}),d(`Removed ${r}`)}catch(o){let s=o instanceof Error?o.message:String(o);d(`WARN: uninstall could not remove ${r}: ${s}`)}}}var xs={claude:".claude",cursor:".cursor",codex:".codex"};function pe(e){let n=e.replace(/^\/+|\/+$/g,"").toLowerCase().split("/").filter(Boolean);return n.length<2?"":n.join("/")}function As(e){if(!e)return"";let t=e.replace(/^([a-z]+:\/\/)[^/@]+@/i,"$1");t=t.replace(/\.git$/i,"");let n=t.match(/^git@[^:]+:(.+)$/);if(n?.[1])return pe(n[1]);let r=t.match(/^ssh:\/\/[^/]+\/(.+)$/i);if(r?.[1])return pe(r[1]);t=t.replace(/^https:\/\//i,""),t=t.replace(/^http:\/\//i,""),t=t.replace(/^ssh:\/\//i,"");let o=t.match(/^[^/]+\/(.+)$/);return o?.[1]?pe(o[1]):pe(t)}async function me(e=process.cwd()){let t=await D("git",["rev-parse","--is-inside-work-tree"],2e3,{cwd:e});if(!t.ok||t.stdout!=="true")return null;let[n,r,o,s]=await Promise.all([D("git",["remote","get-url","origin"],2e3,{cwd:e}),D("git",["branch","--show-current"],2e3,{cwd:e}),D("git",["rev-parse","HEAD"],2e3,{cwd:e}),D("git",["status","--porcelain"],2e3,{cwd:e})]),i=n.ok?n.stdout:null;return{remote:i===null?null:i.replace(/^([a-z]+:\/\/)[^/@]+@/i,"$1"),branch:r.ok?r.stdout:null,head:o.ok?o.stdout:null,dirty:s.ok?s.stdout.length>0:null}}async function ar(e,t,n,r=process.cwd(),o,s,i){if(t)return t;let a=xs[n];if(!a)return"";let c=Cn(n,e.scope_path,i);if(s){let _=wn(s,c);if(_)return _}let u=o??await me(r),l=u?.remote?As(u.remote):"";if(l||(l=pe(process.env.GITHUB_REPOSITORY??"")),!l)return"";let f=e.scope_path??"",g=f?`${f}/`:"",p=`${l}:${g}${a}`;return s&&Un(s,c,p),p}import{existsSync as Ts,readFileSync as Os}from"node:fs";import{hostname as vs,userInfo as bs}from"node:os";function Pe(e){if(e===void 0||e==="")return!1;let t=e.trim().toLowerCase();return t!=="0"&&t!=="false"&&t!=="no"}var ws=["GITLAB_CI","CIRCLECI","BUILDKITE","TF_BUILD","JENKINS_URL","JENKINS_HOME","CODEBUILD_BUILD_ID","DRONE","DRONE_BUILD_NUMBER","TEAMCITY_VERSION","TRAVIS","APPVEYOR","BITBUCKET_BUILD_NUMBER"];function Us(){return ws.some(e=>!!E(e))}function Ps(){if(E("KUBERNETES_SERVICE_HOST")||Pe(E("REMOTE_CONTAINERS"))||Pe(E("DEVCONTAINER")))return!0;try{if(Ts("/.dockerenv")||Os("/proc/1/environ","utf8").includes("container="))return!0}catch{}return!1}function gt(){if(E("GITHUB_ACTIONS"))return"github_actions";if(Pe(E("CLAUDE_CODE_REMOTE")))return"claude_remote";if(Pe(E("CURSOR_AGENT")))return"cursor_cloud";if(E("CODESPACES")||E("CODESPACE_NAME"))return"codespaces";if(Us())return"managed";let e=E("CI");return e&&e!=="false"&&e!=="0"?"managed":Ps()?"container":process.stdin.isTTY||process.stdout.isTTY||E("TERM")?"interactive":"cron"}async function ht(){return await C("systemd-detect-virt",[],1e3)}function Ns(e=process.env,t=bs){for(let n of["USER","LOGNAME","USERNAME"]){let r=e[n];if(typeof r=="string"){let o=r.trim();if(o.length>0)return o}}try{return t().username??""}catch{return""}}async function _t(){let e=process.platform==="darwin"?"Darwin":process.platform==="win32"?"Windows_NT":"Linux",t="";if(process.platform==="darwin")t=await C("sw_vers",["-productVersion"],1e3);else if(process.platform==="linux"){try{let{readFileSync:s}=await import("node:fs"),i=s("/etc/os-release","utf8"),a=i.match(/^PRETTY_NAME="?([^"\n]+)"?/m)?.[1],c=i.match(/^VERSION_ID="?([^"\n]+)"?/m)?.[1];t=a??c??""}catch{t=await C("lsb_release",["-sd"],1e3).then(s=>s.replace(/^"|"$/g,""))}t||(t=await C("uname",["-r"],1e3))}else t=await C("ver",[],1e3);let n=Ns(),r=(process.env.SHELL??"").split(/[/\\]/).pop()??"",o="";try{o=await C("tty",[],500),o.includes("not a tty")&&(o="")}catch{o=""}return{os:e,os_version:t||null,user:n||null,shell:r||null,tty:o||null}}function St(){return vs()}import{existsSync as Ms,readFileSync as Ls}from"node:fs";import{homedir as cr}from"node:os";import{join as Hs}from"node:path";var Ds="cloud-cache.json",Fs=1440*60*1e3,js=900*1e3;function Bs(e=cr()){return Hs(ot(e),Ds)}function $s(e){if(!Ms(e))return;let t=v(Ls(e,"utf8"),{});if(!(typeof t.context!="string"||typeof t.probed_at!="number"||t.result!==null&&t.result!==void 0&&typeof t.result!="object"))return{context:t.context,probed_at:t.probed_at,result:t.result??null}}function Gs(e,t){try{z(e,`${JSON.stringify(t)}
|
|
14
|
+
`)}catch(n){let r=n instanceof Error?n.message:String(n);d(`WARN: cloud cache write failed open: ${r}`)}}function Ks(e,t,n){if(!e||e.context!==t)return!1;let r=e.result===null?js:Fs;return n-e.probed_at<r}async function Js(e){let t=await fetch("http://169.254.169.254/latest/api/token",{method:"PUT",headers:{"X-aws-ec2-metadata-token-ttl-seconds":"60"},signal:AbortSignal.timeout(e)}).catch(()=>{});if(!t?.ok)return;let n=(await t.text()).trim();if(!n)return;let r={"X-aws-ec2-metadata-token":n},[o,s]=await Promise.all([fetch("http://169.254.169.254/latest/meta-data/placement/region",{headers:r,signal:AbortSignal.timeout(e)}).catch(()=>{}),fetch("http://169.254.169.254/latest/meta-data/instance-id",{headers:r,signal:AbortSignal.timeout(e)}).catch(()=>{})]);if(!o?.ok&&!s?.ok)return;let i=o?.ok?(await o.text()).trim():"",a=s?.ok?(await s.text()).trim():"";if(!(!i&&!a))return{provider:"aws",region:i,instance_id:a}}async function Vs(e){let t=await fetch("http://metadata.google.internal/computeMetadata/v1/instance/?recursive=true",{headers:{"Metadata-Flavor":"Google"},signal:AbortSignal.timeout(e)}).catch(()=>{});if(!t?.ok)return;let n=await t.json(),r=typeof n.zone=="string"?n.zone.split("/").pop()??"":"",o=n.id===void 0?"":String(n.id);if(!(!r&&!o))return{provider:"gcp",region:r,instance_id:o}}async function Ws(e){let t=await fetch("http://169.254.169.254/metadata/instance?api-version=2021-02-01",{headers:{Metadata:"true"},signal:AbortSignal.timeout(e)}).catch(()=>{});if(!t?.ok)return;let n=await t.json(),r=n.compute?.location??"",o=n.compute?.vmId??"";if(!(!r&&!o))return{provider:"azure",region:r,instance_id:o}}async function zs(e){let t=await Promise.allSettled([Js(e),Vs(e),Ws(e)]);for(let n of t)if(n.status==="fulfilled"&&n.value)return n.value;return null}async function Et(e,t){if(e==="interactive")return null;let n=t?.home??cr(),r=t?.timeoutMs??1e3,o=t?.nowMs??Date.now(),s=Bs(n),i=$s(s);if(Ks(i,e,o))return i.result;let a=await zs(r);return Gs(s,{context:e,probed_at:o,result:a}),a}import{existsSync as Ys}from"node:fs";import{homedir as Xs}from"node:os";import{join as yt}from"node:path";function kt(e,t,n){if(!Ys(e))return;let r=ne(e,{});for(let o of Object.keys(r.mcpServers??{}))n.set(o,{name:o,source:t})}async function It(e,t=process.cwd(),n="claude",r=Xs()){let o=new Map;for(let s of e.mcp_servers??[])s.name&&o.set(s.name,{name:s.name,source:"manifest"});return n==="claude"&&kt(yt(r,".claude.json"),"claude_json_user",o),kt(yt(t,".mcp.json"),"mcp_json",o),kt(yt(t,".cursor/mcp.json"),"cursor_mcp",o),[...o.values()]}var qs=["CI","GITHUB_ACTIONS","GITLAB_CI","CIRCLECI","BUILDKITE","TF_BUILD","JENKINS_URL","JENKINS_HOME","CODEBUILD_BUILD_ID","DRONE","DRONE_BUILD_NUMBER","TEAMCITY_VERSION","TRAVIS","APPVEYOR","BITBUCKET_BUILD_NUMBER","KUBERNETES_SERVICE_HOST","REMOTE_CONTAINERS","DEVCONTAINER","GITHUB_REPOSITORY","GITHUB_REPOSITORY_ID","GITHUB_REF","GITHUB_SHA","GITHUB_RUN_ID","GITHUB_WORKFLOW","GITHUB_ACTOR","GITHUB_TRIGGERING_ACTOR","GITHUB_ACTOR_ID","GITHUB_USER","GITLAB_USER_LOGIN","GITLAB_USER_NAME","GITLAB_USER_EMAIL","BUILD_REQUESTEDFOR","BUILD_REQUESTEDFOREMAIL","BUILDKITE_BUILD_CREATOR","BUILDKITE_BUILD_CREATOR_EMAIL","BUILD_USER","BUILD_USER_ID","BUILD_USER_EMAIL","CHANGE_AUTHOR","CHANGE_AUTHOR_EMAIL","CIRCLE_USERNAME","CODEBUILD_INITIATOR","DRONE_COMMIT_AUTHOR","DRONE_COMMIT_AUTHOR_NAME","DRONE_COMMIT_AUTHOR_EMAIL","EV_AI_HOOK_OPERATOR_NAME","EV_AI_HOOK_OPERATOR_EMAIL","GIT_AUTHOR_NAME","GIT_AUTHOR_EMAIL","GIT_COMMITTER_NAME","GIT_COMMITTER_EMAIL","EMAIL","RUNNER_OS","RUNNER_ARCH","NODE_ENV","TERM_PROGRAM","CLAUDE_CODE_REMOTE","CLAUDE_CODE_REMOTE_SESSION_ID","CURSOR_AGENT","CODESPACES","CODESPACE_NAME","ANTHROPIC_BASE_URL","OPENAI_BASE_URL","OPENAI_API_BASE","AZURE_OPENAI_ENDPOINT","GOOGLE_GEMINI_BASE_URL","GEMINI_API_BASE","CLAUDE_CODE_USE_BEDROCK","CLAUDE_CODE_USE_VERTEX"],Zs=new Set(["key","api-key","api_key","apikey","token","sig","signature","access_token","password","pwd","secret","client_secret"]);function Qs(e){try{let t=new URL(e);(t.username||t.password)&&(t.username="",t.password="");for(let[n]of t.searchParams)Zs.has(n.toLowerCase())&&t.searchParams.set(n,"[redacted]");return t.toString()}catch{return e}}function Rt(e=process.env){return qs.map(t=>Object.prototype.hasOwnProperty.call(e,t)?{name:t,present:!0,value:Qs(e[t]??"")}:{name:t,present:!1})}import{createHash as ei}from"node:crypto";function I(e){return ei("sha256").update(e).digest("hex").slice(0,16)}function $(e,t){return`${e}\0${t}`}function lr(e){let t=e.indexOf("\0");return t<=0?null:{path:e.slice(0,t),name:e.slice(t+1)}}function Ct(e){let n=[...e].sort((r,o)=>{let s=r.path.localeCompare(o.path);return s!==0?s:r.name.localeCompare(o.name)}).map(r=>`${r.path}|${r.name}|${r.content_hash}`).join(`
|
|
15
|
+
`);return I(n)}function ti(e,t,n="git_config",r=null){return I(`${e??""}|${t??""}|${r??""}|${n}`)}function ni(e){let t=null,n=null;for(let r of e.split(`
|
|
16
|
+
`)){let o=r.trim();if(!o)continue;let s=o.indexOf(" ");if(s<=0)continue;let i=o.slice(0,s).toLowerCase(),a=o.slice(s+1).trim();a&&(i==="user.name"?t=a:i==="user.email"&&(n=a))}return{git_user_name:t,git_user_email:n,platform_login:null}}async function ri(e,t=C){let n=await t("git",["config","--get-regexp","^user\\.(name|email)$"],2e3,{cwd:e});return ni(n)}function oi(e=process.env){let t=S(e.GIT_AUTHOR_NAME),n=S(e.GIT_AUTHOR_EMAIL);if(t||n)return{git_user_name:t,git_user_email:n,platform_login:null,identity_source:"git_env"};let r=S(e.GIT_COMMITTER_NAME),o=S(e.GIT_COMMITTER_EMAIL);if(r||o)return{git_user_name:r,git_user_email:o,platform_login:null,identity_source:"git_env"};let s=S(e.EMAIL);return s?{git_user_name:null,git_user_email:s,platform_login:null,identity_source:"git_env"}:null}async function si(e,t=C){let n=await t("git",["log","-1","--format=%an%x00%ae"],2e3,{cwd:e});if(!n)return null;let r=n.indexOf("\0"),o=(r>=0?n.slice(0,r):n).trim(),s=(r>=0?n.slice(r+1):"").trim();return!o&&!s?null:{git_user_name:o||null,git_user_email:s||null,platform_login:null,identity_source:"git_log"}}function G(e,t,n,r=null){return!e&&!t&&!r?null:{git_user_name:e,git_user_email:t,platform_login:r,identity_source:n}}function ii(e=process.env){let t=G(S(e.EV_AI_HOOK_OPERATOR_NAME),S(e.EV_AI_HOOK_OPERATOR_EMAIL),"configured");if(t)return t;let n=S(e.GITHUB_ACTOR)??S(e.GITHUB_TRIGGERING_ACTOR)??S(e.GITHUB_USER),r=G(n,null,"github",n);if(r)return r;let o=S(e.GITLAB_USER_LOGIN),s=G(S(e.GITLAB_USER_NAME)??o,S(e.GITLAB_USER_EMAIL),"gitlab",o);if(s)return s;let i=G(S(e.BUILD_REQUESTEDFOR),S(e.BUILD_REQUESTEDFOREMAIL),"azure_devops");if(i)return i;let a=G(S(e.BUILDKITE_BUILD_CREATOR),S(e.BUILDKITE_BUILD_CREATOR_EMAIL),"buildkite");if(a)return a;let c=G(S(e.BUILD_USER)??S(e.CHANGE_AUTHOR),S(e.BUILD_USER_EMAIL)??S(e.CHANGE_AUTHOR_EMAIL),"jenkins",S(e.BUILD_USER_ID));if(c)return c;let u=S(e.CIRCLE_USERNAME),l=G(u,null,"circleci",u);if(l)return l;let f=S(e.CODEBUILD_INITIATOR),g=G(f,null,"codebuild",f);if(g)return g;let p=G(S(e.DRONE_COMMIT_AUTHOR)??S(e.DRONE_COMMIT_AUTHOR_NAME),S(e.DRONE_COMMIT_AUTHOR_EMAIL),"drone",S(e.DRONE_COMMIT_AUTHOR));return p||(ur(e.CLAUDE_CODE_REMOTE)||ur(e.CURSOR_AGENT)?{git_user_name:null,git_user_email:null,platform_login:null,identity_source:"cloud"}:null)}function xt(e){return!!((e.git_user_name??e.git_user_email)&&!li(e.git_user_name,e.git_user_email))}function S(e){if(e===void 0)return null;let t=e.trim();return t.length>0?t:null}function ur(e){if(e===void 0||e==="")return!1;let t=e.trim().toLowerCase();return t!=="0"&&t!=="false"&&t!=="no"}var ai=new Set(["action@github.com","noreply@github.com","noreply@anthropic.com","cursoragent@cursor.com"]),ci=new Set(["github-actions","github actions","dependabot","renovate","cursoragent","cursor agent"]);function li(e,t){let n=(e??"").trim().toLowerCase(),r=(t??"").trim().toLowerCase();if(!n&&!r)return!1;if(n.includes("[bot]")||ci.has(n)||r.includes("[bot]")||ai.has(r))return!0;if(r.endsWith("@users.noreply.github.com")){let o=r.slice(0,r.indexOf("@")),s=o.includes("+")?o.slice(o.indexOf("+")+1):o;if(s.endsWith("bot")||s.includes("[bot]"))return!0}return!1}async function ui(e,t=C,n=process.env){let r=await ri(e,t);if(xt(r))return{...r,identity_source:"git_config"};let o=oi(n);if(o&&xt(o))return o;let s=ii(n);if(s&&(s.git_user_name||s.git_user_email||s.platform_login))return s;let i=await si(e,t);return i&&xt(i)?i:s||(r.git_user_name||r.git_user_email?{...r,identity_source:"git_config"}:o||i||{git_user_name:null,git_user_email:null,platform_login:null,identity_source:"git_config"})}async function Ne(e){let{gitRoot:t,installationStorePath:n,forceResend:r}=e,o=e.exec??C,s=e.env??process.env,i=await ui(t,o,s),a=ti(i.git_user_name,i.git_user_email,i.identity_source,i.platform_login),u=(n?st(n):void 0)?.operator_identity_hash;if(!(r||u!==void 0&&u!==a||!u))return{commit:()=>{}};let p=n;return{operator:i,commit:()=>{p&&On(p,a,Ae())}}}function At(e){return e?!st(e)?.operator_identity_hash:!0}function dr(e){return!0}import{existsSync as Pi,readFileSync as Ni}from"node:fs";import{homedir as Or}from"node:os";import{join as P}from"node:path";import{basename as wi,join as re}from"node:path";import{existsSync as fr,readdirSync as di}from"node:fs";import{basename as fi,dirname as pi,relative as mi}from"node:path";var Me=class{constructor(t){this.home=t}components=[];truncated=!1;pluginExpandRemaining;homeRel(t){let n=mi(this.home,t).replace(/\\/g,"/");if(!n||n.startsWith("..")){let r=pi(t);return`external/${I(r)}/${fi(t)}`}return n}get atGlobalCap(){return this.truncated||this.components.length>=X}get pluginBudgetSpent(){return this.pluginExpandRemaining!==void 0&&this.pluginExpandRemaining<=0}readEntries(t){if(!fr(t))return[];try{return di(t,{withFileTypes:!0})}catch{return[]}}readJson(t,n){if(fr(t))return ne(t,n)}push(t){return this.components.length>=X?(this.truncated=!0,!1):this.pluginExpandRemaining!==void 0&&this.pluginExpandRemaining<=0?!1:(this.pluginExpandRemaining!==void 0&&(this.pluginExpandRemaining-=1),this.components.push(t),!0)}withPluginExpandCap(t,n){let r=this.pluginExpandRemaining;this.pluginExpandRemaining=t;try{let o=n(),s=t-(this.pluginExpandRemaining??0);return{result:o,expanded:s}}finally{this.pluginExpandRemaining=r}}};import{existsSync as Tt,readFileSync as gi,statSync as hi}from"node:fs";import{basename as mr,join as ge,relative as gr}from"node:path";var Ot=2e4,_i=4;function Si(e){return e.length<=Ot?e:`${e.slice(0,Ot-1)}\u2026`}function Ei(e){try{let t=gi(e),n=t.toString("utf8");return{hash:I(t),length:t.length,text:Si(n)}}catch{return null}}var pr={HOOK:"EVENT",COMMAND:"EXPLICIT_INVOCATION",MEMORY:void 0,MCP_SERVER:void 0,PLUGIN:void 0,SKILL:"UNSPECIFIED",RULE:"UNSPECIFIED",SUBAGENT:"UNSPECIFIED"};function yi(e){return e in pr?pr[e]:"UNSPECIFIED"}function Le(e,t){let n=Ei(t.absolutePath);if(!n)return!1;let r=t.name??mr(t.absolutePath).replace(/\.(md|mdc|toml)$/i,""),o={kind:t.kind,name:r,path:e.homeRel(t.absolutePath),text:n.text,content_hash:n.hash,content_length:n.length,origin:t.origin,enabled:t.enabled},s=yi(t.kind);return s&&(o.trigger=s),e.push(o)}function ki(e,t,n){let r=gr(e,t).replace(/\\/g,"/");return!r||r.startsWith("..")?mr(t).replace(/\.(md|mdc|toml)$/i,""):n?r.replace(/\.(md|mdc|toml)$/i,""):r}function Q(e,t){let{dir:n,kind:r,origin:o,enabled:s,nested:i,extensions:a}=t;vt(e,{walkRoot:n,currentDir:n,depth:0,kind:r,origin:o,enabled:s,nested:i,extensions:a})}function vt(e,t){let{walkRoot:n,currentDir:r,depth:o,kind:s,origin:i,enabled:a,nested:c,extensions:u}=t;if(!(o>_i))for(let l of e.readEntries(r)){if(e.atGlobalCap){e.truncated=!0;return}if(e.pluginBudgetSpent)return;if(c){if(!l.isDirectory())continue;let p=ge(r,l.name,c);if(Tt(p)){let _=gr(n,ge(r,l.name)).replace(/\\/g,"/");Le(e,{absolutePath:p,kind:s,origin:i,enabled:a,name:_||l.name});continue}vt(e,{walkRoot:n,currentDir:ge(r,l.name),depth:o+1,kind:s,origin:i,enabled:a,nested:c,extensions:u});continue}if(l.isDirectory()){vt(e,{walkRoot:n,currentDir:ge(r,l.name),depth:o+1,kind:s,origin:i,enabled:a,nested:c,extensions:u});continue}if(!l.isFile()||!u)continue;let f=l.name.toLowerCase();if(!u.some(p=>f.endsWith(p)))continue;let g=ge(r,l.name);Le(e,{absolutePath:g,kind:s,origin:i,enabled:a,name:ki(n,g,!0)})}}function hr(e){for(let t of e)if(Tt(t))try{if(hi(t).size>0)return t}catch{continue}return e.find(t=>Tt(t))}function Ii(e){if(e.prompt||e.type==="prompt")return"prompt";let t=e.command??e.bash??e.powershell??"";return/\bnpx\b/i.test(t)?"npx":/\.(sh|bash|zsh|js|mjs|cjs|ts|py)(\s|$|"|')/i.test(t)||/^(\.\/|~\/|\/|[A-Za-z]:[\\/])/.test(t.trim())?"script":"inline"}function Ri(e){return Array.isArray(e.hooks)&&e.hooks.length>0?e.hooks:[{type:e.type,command:e.command,bash:e.bash,powershell:e.powershell,prompt:e.prompt}]}function Ci(e,t,n,r){let o=e.homeRel(t);for(let[s,i]of Object.entries(n))if(!(!Array.isArray(i)||e.truncated))for(let a of i){if(!a||typeof a!="object"||e.truncated)continue;let c=a;for(let u of Ri(c)){if(e.truncated)return;let l=u.command??u.bash??u.prompt??u.powershell??c.powershell??"",f=Ii({type:u.type??c.type,command:u.command??c.command,bash:u.bash??c.bash,powershell:u.powershell??c.powershell,prompt:u.prompt??c.prompt}),g=typeof c.matcher=="string"?c.matcher:"",p=I(l),_=g?`${s}:${g}:${f}:${p}`:`${s}:${f}:${p}`,R=`${s}|${g}|${f}|${l}`;e.push({kind:"HOOK",name:_,path:o,content_hash:I(R),origin:r,enabled:!0,trigger:"EVENT",attributes:{event:s,...g?{matcher:g}:{},action_kind:f,action_hash:p}})}}}function he(e,t,n){let r=e.readJson(t,{});!r?.hooks||typeof r.hooks!="object"||Ci(e,t,r.hooks,n)}var _r={claude:{skillRoots:[".claude/skills"],dirs:[{dir:".claude/agents",kind:"SUBAGENT",extensions:[".md"]},{dir:".claude/commands",kind:"COMMAND",extensions:[".md"]}],memory:[".claude/CLAUDE.md"],hooks:[".claude/settings.json"],mcpJson:[".claude.json"],plugins:"claude"},cursor:{skillRoots:[".cursor/skills",".cursor/skills-cursor"],dirs:[{dir:".cursor/agents",kind:"SUBAGENT",extensions:[".md"]},{dir:".cursor/commands",kind:"COMMAND",extensions:[".md"]},{dir:".cursor/rules",kind:"RULE",extensions:[".mdc",".md"]}],memory:[".cursor/AGENTS.md"],hooks:[".cursor/hooks.json"],mcpJson:[".cursor/mcp.json"],plugins:"cursor"},codex:{skillRoots:[".agents/skills",".codex/skills"],dirs:[{dir:".codex/agents",kind:"SUBAGENT",extensions:[".toml",".md"]},{dir:".codex/prompts",kind:"COMMAND",extensions:[".md"]}],memory:[".codex/AGENTS.override.md",".codex/AGENTS.md"],hooks:[".codex/hooks.json"],mcpToml:[".codex/config.toml"]}};import{existsSync as xi,readFileSync as Ai}from"node:fs";function Ti(e){if(!e||typeof e!="object"||Array.isArray(e))return"unknown";let t=e;return typeof t.type=="string"&&t.type.length>0?t.type:typeof t.url=="string"?"http":typeof t.command=="string"?"stdio":"unknown"}function Sr(e,t,n){let o=e.readJson(t,{})?.mcpServers;if(!o||typeof o!="object")return;let s=e.homeRel(t);for(let[i,a]of Object.entries(o)){if(e.truncated)return;let c=Ti(a);e.push({kind:"MCP_SERVER",name:i,path:s,content_hash:I(`${i}|${c}`),origin:n,enabled:!0,attributes:{transport:c}})}}function Er(e,t,n){if(!xi(t))return;let r;try{r=Ai(t,"utf8")}catch{return}let o=e.homeRel(t),s=/^\[mcp_servers(?:\.(\w+)|\."([^"]+)"|\.'([^']+)')\]\s*$/gm,i;for(;(i=s.exec(r))!==null;){if(e.truncated)return;let a=i[1]??i[2]??i[3];if(!a)continue;let c=r.slice(i.index+i[0].length),u=c.search(/^\[/m),l=u===-1?c:c.slice(0,u),f="unknown";/^\s*url\s*=/m.test(l)?f="http":/^\s*command\s*=/m.test(l)&&(f="stdio"),e.push({kind:"MCP_SERVER",name:a,path:o,content_hash:I(`${a}|${f}`),origin:n,enabled:!0,attributes:{transport:f}})}}import{existsSync as Oi,readdirSync as vi}from"node:fs";import{join as A}from"node:path";var yr=50;function bt(e,t,n,r){if(!Oi(t))return{componentCount:0,expandTruncated:!1};let o=e.components.length,{expanded:s}=e.withPluginExpandCap(yr,()=>{Q(e,{dir:A(t,"skills"),kind:"SKILL",origin:n,enabled:r,nested:"SKILL.md"}),Q(e,{dir:A(t,"commands"),kind:"COMMAND",origin:n,enabled:r,extensions:[".md"]}),Q(e,{dir:A(t,"agents"),kind:"SUBAGENT",origin:n,enabled:r,extensions:[".md"]})});he(e,A(t,"hooks","hooks.json"),n),he(e,A(t,"hooks.json"),n);let i=e.components.length-o,a=s>=yr;return{componentCount:i,expandTruncated:a}}function wt(e,t){e.push({kind:"PLUGIN",name:t.pluginKey,path:t.rowPath,content_hash:t.contentHash,origin:"user",enabled:t.enabled,attributes:{...t.marketplace?{marketplace:t.marketplace}:{},...t.version?{version:t.version}:{},scope:t.scope,component_count:t.componentCount,...t.expandTruncated?{expand_truncated:!0}:{}}})}function kr(e){let t=A(e.home,".claude/plugins/installed_plugins.json"),n=e.readJson(t,{});if(!n)return;let r=n.plugins??{},s=e.readJson(A(e.home,".claude/settings.json"),{})?.enabledPlugins??{},i=e.homeRel(t);for(let[a,c]of Object.entries(r)){if(e.truncated)return;let u=Array.isArray(c)?c:[c],l=u[0]??{},f=s[a]===!0,g=a.includes("@")?a.split("@").slice(1).join("@"):"",p=typeof l.version=="string"?l.version:"",_=typeof l.scope=="string"?l.scope:"user",R=`plugin:${a}`,b=0,x=!1;for(let w of u)if(typeof w.installPath=="string"&&w.installPath.length>0){let W=bt(e,w.installPath,R,f);b+=W.componentCount,x=x||W.expandTruncated}wt(e,{pluginKey:a,rowPath:i,enabled:f,scope:_,version:p||void 0,marketplace:g||void 0,componentCount:b,expandTruncated:x,contentHash:I(`${a}|${p}|${_}|${f}|${b}`)})}}function bi(e){let t=e,n="";try{let r=vi(e,{withFileTypes:!0}).filter(o=>o.isDirectory()).map(o=>o.name);if(r.length===1&&r[0])t=A(e,r[0]),n=r[0];else if(r.length>1){let o=[...r].sort(),s=o[o.length-1];s&&(t=A(e,s),n=s)}}catch{}return{installPath:t,version:n}}function Ir(e){let t=[{base:A(e.home,".cursor/plugins/local"),scope:"local"},{base:A(e.home,".cursor/plugins/cache"),scope:"cache"}];for(let{base:n,scope:r}of t)if(!e.truncated)for(let o of e.readEntries(n)){if(!o.isDirectory()||e.truncated)continue;if(r==="local"){let i=o.name,a=A(n,o.name),c=`plugin:${i}`,{componentCount:u,expandTruncated:l}=bt(e,a,c,!0);wt(e,{pluginKey:i,rowPath:e.homeRel(a),enabled:!0,scope:"local",componentCount:u,expandTruncated:l,contentHash:I(`${i}|local|${u}`)});continue}let s=o.name;for(let i of e.readEntries(A(n,s))){if(!i.isDirectory()||e.truncated)continue;let a=A(n,s,i.name),{installPath:c,version:u}=bi(a),l=`${i.name}@${s}`,f=`plugin:${l}`,{componentCount:g,expandTruncated:p}=bt(e,c,f,!0);wt(e,{pluginKey:l,rowPath:e.homeRel(c),enabled:!0,scope:"cache",version:u||void 0,marketplace:s,componentCount:g,expandTruncated:p,contentHash:I(`${l}|${u}|${g}`)})}}}function Ut(e,t){let n=_r[e],r=new Me(t),o="user";if(!n)return{components:[],truncated:!1};for(let i of n.skillRoots)Q(r,{dir:re(t,i),kind:"SKILL",origin:o,enabled:!0,nested:"SKILL.md"});for(let i of n.dirs)Q(r,{dir:re(t,i.dir),kind:i.kind,origin:o,enabled:!0,extensions:i.extensions});let s=hr(n.memory.map(i=>re(t,i)));s&&Le(r,{absolutePath:s,kind:"MEMORY",origin:o,enabled:!0,name:wi(s)});for(let i of n.hooks)he(r,re(t,i),o);for(let i of n.mcpJson??[])Sr(r,re(t,i),o);for(let i of n.mcpToml??[])Er(r,re(t,i),o);return n.plugins==="claude"?kr(r):n.plugins==="cursor"&&Ir(r),{components:r.components,truncated:r.truncated}}function Pt(e,t,n={}){let r=n.truncated===!0,o=Ct(e),s=new Set(e.map(l=>$(l.path,l.name)));if(n.forceFull===!0||t===void 0)return{hash:o,count:e.length,truncated:r,full:!0,upserts:e,removed:[],unchanged:!1};let a=[],c=t;for(let l of e){let f=$(l.path,l.name);c[f]!==l.content_hash&&a.push(l)}let u=[];if(!r){for(let l of Object.keys(c))if(!s.has(l)){let f=lr(l);f&&u.push(f)}}return{hash:o,count:e.length,truncated:r,full:!1,upserts:a,removed:u,unchanged:a.length===0&&u.length===0}}var Cr=3e5,Ui=new Set(["HOOK","MCP_SERVER","PLUGIN"]);function Nt(e,t,n){let r=new Set(t.map(s=>$(s.path,s.name))),o=[];for(let s of e)s.text!==void 0&&(n.has(s.content_hash)||r.has($(s.path,s.name))||o.push(s));return o}function Mt(e,t,n){let r=new Set(e);for(let s of t)r.add(s);let o=new Set(n.map(s=>s.content_hash));return[...r].filter(s=>o.has(s))}function Rr(e){return Buffer.byteLength(JSON.stringify(e),"utf8")}function xr(e){if(e.text===void 0)return e;let{text:t,...n}=e;return n}function Lt(e,t=Cr){let n=[],r=[];for(let l of e)Ui.has(l.kind)?n.push(l):r.push(l);r.sort((l,f)=>(l.text?.length??0)-(f.text?.length??0));let o=[...n,...r],s=[],i=2,a=0,c=0,u=[];for(let l of o){let f=s.length>0?1:0,g=Rr(l)+f;if(i+g<=t){s.push(l),i+=g,l.text!==void 0&&u.push(l.content_hash);continue}if(l.text!==void 0){let p=xr(l),_=Rr(p)+f;if(i+_<=t){s.push(p),i+=_,a+=1;continue}}c+=1}return{components:s,textDeferredCount:a,droppedCount:c,textHashesSent:u}}function Ht(e,t){return t.size===0?e:e.map(n=>n.text===void 0||!t.has(n.content_hash)?n:xr(n))}var Mi={claude:{skills:".claude/skills",subagents:".claude/agents",commands:".claude/commands",memory:".claude/CLAUDE.md",settings:".claude/settings.json"},cursor:{skills:[".cursor/skills",".cursor/skills-cursor"],subagents:".cursor/agents",commands:".cursor/commands",rules:".cursor/rules",mcp:".cursor/mcp.json"},codex:{skills:[".agents/skills",".codex/skills"],subagents:".codex/agents",commands:".codex/prompts",memory:".codex/AGENTS.md",settings:".codex/config.toml"}},Li=200,Ar=200,Hi=["allow","deny","ask"],Di=/(?<=^|[\s(,=:])(?:~|[A-Za-z]:)?[\\/][^\s,)]+/g,Dt="<path>",Fi=new RegExp(`${Dt}(?:\\s+[A-Za-z.][^\\s,)]*[\\\\/][^\\s,)]*)+`,"g");function ji(e){let t=e.replace(Di,Dt).replace(Fi,Dt);return t.length>Ar?`${t.slice(0,Ar)}...`:t}function Tr(e){let t=ne(e,{}),n=[];for(let r of Hi)for(let o of t.permissions?.[r]??[])typeof o=="string"&&o.length>0&&n.push({key:ji(o),mode:r});return{model:t.model??"",permissionKeys:n}}var Bi=10,$i=840*60*1e3,Gi="self-config-cache.json";function Ft(){return E("EV_AI_HOOK_USER_SPEC")?.toLowerCase()==="off"}function Ki(e,t=Date.now()){return e===void 0||!Number.isFinite(e)?!0:t-e>=$i}var Ji={claude:["claude"],cursor:["agent","cursor-agent"],codex:["codex"]};async function Vi(e,t=C){let n=Ji[e];if(!n||n.length===0)return null;let r=async o=>{let s=n[o];if(s===void 0)return null;let a=((await t(s,["--version"],2e3)).split(`
|
|
17
|
+
`)[0]??"").trim();return a||r(o+1)};return r(0)}function Wi(e=Or()){return P(e,".ev-ai","agent-hook",Gi)}function zi(e){let n=[...e].sort((r,o)=>r.name.localeCompare(o.name)).map(r=>`${r.name}:${r.size}`).join(`
|
|
18
|
+
`);return I(n)}function He(e,t,n=!1){let r=zi(e),o=e.length;return t===r?n?{hash:r,count:o,truncated:n}:{hash:r,count:o}:n?{hash:r,count:o,entries:e,truncated:n}:{hash:r,count:o,entries:e}}function Yi(e){return Pi(e)?v(Ni(e,"utf8"),{}):{}}function Xi(e,t){try{z(e,`${JSON.stringify(t)}
|
|
19
|
+
`)}catch(n){let r=n instanceof Error?n.message:String(n);d(`WARN: self-config cache write failed open: ${r}`)}}function qi(e,t,n,r){let o={...e,send_count:n};for(let s of Object.keys(t)){let i=t[s];i.entries!==void 0&&(o[s]=i.hash)}return r&&(o.user_spec_collected_at_ms=r.collectedAtMs,r.included&&(o.user_spec=r.hash,o.user_spec_components=r.componentHashes),o.user_spec_text_hashes=r.textHashes),o}async function vr(e,t=process.cwd(),n=Or(),r={}){let o=e==="claude",s=r.gitRoot??t,i=await Vi(e),a="",c=[];if(o){let U=Tr(P(n,".claude/settings.json")),L=Tr(P(t,".claude/settings.local.json"));a=L.model||U.model,c=[...U.permissionKeys,...L.permissionKeys].slice(0,Li)}let u=Mi[e]??{},l={present:!1,size:0},f=U=>{let L=Array.isArray(U)?U:U?[U]:[],y=[],K=!1;for(let Je of L){let O=de(P(n,Je));if(y=y.concat(O.entries),K=K||O.truncated,y.length>=X){y=y.slice(0,X),K=!0;break}}return{entries:y,truncated:K}},g=Wi(n),p=Yi(g),_=p[e]??{},R=(_.send_count??0)+1,b=R>0&&R%Bi===0,x=U=>b?void 0:_[U],w=f(u.skills),W=u.subagents?de(P(n,u.subagents)):{entries:[],truncated:!1},Ke=u.commands?de(P(n,u.commands)):{entries:[],truncated:!1},Vt=u.rules?de(P(n,u.rules)):{entries:[],truncated:!1},ie={skills:He(w.entries,x("skills"),w.truncated),subagents:He(W.entries,x("subagents"),W.truncated),commands:He(Ke.entries,x("commands"),Ke.truncated),rules:He(Vt.entries,x("rules"),Vt.truncated)},T={runner_platform:e,config_scope:"user",cli_version:i,claude_version:o?i:null,model:o&&a||null,permission_keys:c,user_scope:{skills:ie.skills,subagents:ie.subagents,commands:ie.commands,rules:ie.rules,memory:u.memory?fe(P(n,u.memory)):l,settings:u.settings?fe(P(n,u.settings)):l,mcp:u.mcp?fe(P(n,u.mcp)):l},local_settings:o?fe(P(t,".claude/settings.local.json")):l},Wt=null,zt=()=>{},Yt=r.nowMs??Date.now();if(!Ft()&&Ki(_.user_spec_collected_at_ms,Yt)){let U=_.user_spec_collected_at_ms!==void 0,L=Ut(e,n),y=Pt(L.components,_.user_spec_components,{forceFull:!_.user_spec_components,truncated:L.truncated}),K=new Set(_.user_spec_text_hashes??[]),Je=Nt(L.components,y.upserts,K),O=Lt(Ht([...y.upserts,...Je],K));T.user_spec_hash=y.hash,T.user_spec_count=y.count,T.user_spec_truncated=y.truncated||O.droppedCount>0,(O.components.length>0||y.removed.length>0||y.full)&&(y.full&&(T.user_spec_full=!0),O.components.length>0&&(T.user_spec=O.components),y.removed.length>0&&!T.user_spec_truncated&&(T.user_spec_removed=y.removed),O.textDeferredCount>0&&(T.user_spec_text_deferred=O.textDeferredCount));let Ve=y.full?{}:{..._.user_spec_components??{}};if(!T.user_spec_truncated)for(let te of y.removed)delete Ve[$(te.path,te.name)];for(let te of O.components)Ve[$(te.path,te.name)]=te.content_hash;Wt={hash:y.hash,componentHashes:Ve,textHashes:Mt(K,O.textHashesSent,L.components),included:O.components.length>0||y.removed.length>0&&!T.user_spec_truncated||y.full,collectedAtMs:Yt};let We=await Ne({gitRoot:s,installationStorePath:r.installationStorePath,forceResend:U});We.operator&&(T.operator=We.operator),zt=We.commit}let so=qi(_,ie,R,Wt);return{config:T,commit:()=>{p[e]=so,Xi(g,p),zt()}}}function oe(e,t,n){let r={installation_id:n.installationId};return n.platformAgentId&&(r.platform_agent_id=n.platformAgentId),n.sessionId&&(r.session_id=n.sessionId),n.turnId&&(r.turn_id=n.turnId),{schema_version:2,event:e,timestamp:Ae(),session_id:n.sessionId||null,turn_id:n.turnId||null,installation_id:n.installationId,platform:n.runnerPlatform,platform_agent_id:n.platformAgentId||null,runner_event:n.runnerEvent||null,agent_hook_version:H,host_arch:process.arch,node_version:process.version,correlation:r,payload:t}}import{existsSync as Kr}from"node:fs";import{spawn as Jr}from"node:child_process";import{basename as Ia}from"node:path";import{fileURLToPath as Ra}from"node:url";var br=/(?:^|\/|[\s"'=(])(?:\.cursor\/|\.claude\/|\.agents\/)skills(?:-cursor)?\/([^/]+)\/SKILL\.md/i,wr=/(?:^|\/|[\s"'=(])\.codex\/commands\/([^/]+)\.md\b/i,Zi=/(?:^|\s)\/([a-z][a-z0-9-]{1,63})\b/gi,Qi=new Set(["applications","app","bin","boot","data","dev","etc","home","lib","media","mnt","node_modules","opt","pkg","private","proc","projects","repos","run","sbin","src","srv","sys","tmp","usr","users","var","volumes","workspace","workspaces"]),ea=new Set(["read","read_file","view"]),ta=new Set(["bash","shell","zsh"]);function na(e){let t=e.replace(/\\/g,"/");return br.exec(t)?.[1]??null}function ra(e){let t=e.replace(/\\/g,"/"),r=wr.exec(t)?.[1];return r?r.toLowerCase():null}function oa(e){return na(e)??ra(e)}function sa(e){for(let t of["path","file_path","target_file"]){let n=e[t];if(typeof n=="string"&&n.length>0)return n}return null}function Ur(e){if(typeof e=="string")try{let t=JSON.parse(e);return Ur(t)}catch{return null}return!e||typeof e!="object"?null:sa(e)}function ia(e){if(!e||typeof e!="object")return null;let t=e.command;return typeof t=="string"&&t.length>0?t:null}function aa(e){let t=e.replace(/\\/g,"/"),n=br.exec(t);if(n?.[1])return n[1];let o=wr.exec(t)?.[1];return o?o.toLowerCase():null}function ca(e){return typeof e.tool_name=="string"?e.tool_name:typeof e.tool=="string"?e.tool:""}function Pr(e){let t=ca(e).toLowerCase();if(ea.has(t)){let n=Ur(e.tool_input);return n?oa(n):null}if(ta.has(t)){let n=ia(e.tool_input);return n?aa(n):null}return null}function la(e){let t=new Set,n=[];for(let r of e.matchAll(Zi)){let o=r[1]?.toLowerCase();!o||t.has(o)||Qi.has(o)||(t.add(o),n.push(o))}return n}function ua(e){return ue(e.prompt)}function Nr(e){let t=m(e,"command_name");if(t){let r=m(e,"expansion_type");if(r&&r!=="slash_command")return[];let o=t.replace(/^\//,"").toLowerCase();return o?[o]:[]}let n=ua(e);return n?la(n):[]}function jt(e){return e!==void 0&&on.includes(e)}function De(e,t){let n=e[t+1];return n&&!n.startsWith("--")?{value:n,next:t+1}:{next:t}}function Fe(e){let t,n,r,o,s;for(let i=0;i<e.length;i++){let a=e[i];if(a!==void 0){if(a==="--runner"){let c=De(e,i);t=c.value,i=c.next;continue}if(a.startsWith("--runner=")){t=a.slice(9);continue}if(a==="--url"){let c=De(e,i);c.value&&(r=c.value),i=c.next;continue}if(a.startsWith("--url=")){r=a.slice(6);continue}if(a==="--token"){let c=De(e,i);c.value&&(o=c.value),i=c.next;continue}if(a.startsWith("--token=")){o=a.slice(8);continue}if(a==="--base-url"){let c=De(e,i);c.value&&(s=c.value),i=c.next;continue}if(a.startsWith("--base-url=")){s=a.slice(11);continue}!a.startsWith("-")&&n===void 0&&(n=a)}}return{runner:jt(t)?t:void 0,event:n,collectorUrl:r,orgToken:o,baseUrl:s}}function Bt(e){let t=e.collectorUrl?.trim(),n;if(t)n=t;else{let o=e.orgToken?.trim();o&&(n=Ie(o,e.baseUrl?.trim()??void 0))}if(!n)return;let r=ae(n);if(r){d(`WARN: ignoring --url/--token collector override: ${r}`);return}return ce(n)}function Mr(e,t){if(m(e,"conversation_id"))return!0;if(t==="")return!1;let n=t[0];return n?.toLowerCase()===n}function da(){return!!(E("CURSOR_VERSION")??E("CURSOR_PROJECT_DIR"))}function $t(e,t,n){return e!=="claude"&&e!=="codex"?!1:Mr(t,n)?!0:da()}function Gt(e,t,n,r){if(Mr(e,t))return"cursor";if(jt(r))return r;let o=m(e,"conversation_id"),s=m(e,"turn_id"),i=m(e,"session_id"),a=t.toLowerCase(),c="unknown";return o||t===a&&t!==""?c="cursor":s?c="codex":(i||a==="sessionstart"||a==="sessionend"||a==="stop"||a==="stopfailure"||a==="pretooluse"||a==="posttooluse"||a==="posttoolusefailure"||a==="permissiondenied"||a==="subagentstart"||a==="subagentstop"||a==="userpromptexpansion")&&(c="claude"),jt(n)&&(c=n),c}function je(e,t){let n=e.toLowerCase();return n==="sessionend"||n==="stopfailure"||n==="subagentstop"?!0:n==="stop"&&t==="codex"}function fa(e){switch(e){case"sessionstart":return"session_start";case"stop":case"sessionend":case"stopfailure":return"session_end";case"pretooluse":case"posttooluse":case"posttoolusefailure":case"permissiondenied":case"beforemcpexecution":case"beforeshellexecution":case"afterfileedit":case"subagentstart":case"subagentstop":return"tool_invoked";case"beforesubmitprompt":case"userpromptexpansion":case"userpromptsubmit":return"skill_invoked";default:return""}}function Lr(e){let t=e.toLowerCase();return t==="posttooluse"?!0:t==="posttoolusefailure"||t==="permissiondenied"?!1:null}function Hr(e,t,n){let r=m(e,"session_id")||m(e,"conversation_id"),o=m(e,"prompt.id")||m(e,"prompt_id")||m(e,"generation_id")||m(e,"turn_id"),s=m(e,"hook_event_name")||m(e,"event"),i=m(e,"source"),a=Gt(e,s,t,n);return{sessionId:r,turnId:o,runnerEvent:s,hookSource:i,runnerPlatform:a}}var pa=["session_start","session_end","tool_invoked","skill_invoked"];function ma(e){return pa.includes(e)}function Dr(e,t){return e&&ma(e)?e:fa(t.toLowerCase())}function Fr(e){let t=m(e,"tool_name")||m(e,"tool")||null,n=e.tool_input,o=(n&&typeof n=="object"?ue(n.skill)||ue(n.skill_name):"")||m(e,"skill_name")||null;return o??=Pr(e),{toolName:t,skillName:o}}var ga=/^[A-Za-z][A-Za-z0-9_.:-]{0,63}$/;function jr(e){for(let t of["subagent_type","agent_type"]){let n=m(e,t);if(n&&ga.test(n))return n}return null}function Br(e){let t=Y(e,"duration_ms");if(typeof t=="number")return t;let n=Y(e,"duration");return typeof n=="number"?n:null}var ha="error",_a="interrupted",Sa="permission_denied",Ea=/^[A-Za-z][A-Za-z0-9_.-]{0,63}$/;function Kt(e){return Ea.test(e)?e:null}function ya(e){for(let t of["failure_type","error_type"]){let n=Kt(m(e,t));if(n)return n}return null}function $r(e,t){return Y(e,"is_interrupt")===!0?_a:t.toLowerCase()==="permissiondenied"?Sa:ya(e)??ha}function ka(e,t){let n=null;for(let r of t)r&&(e===r||e.startsWith(`${r}_`)||e.startsWith(`${r}-`))&&(n===null||r.length>n.length)&&(n=r);return n}function Gr(e,t=[]){if(!e)return{mcpServer:null,mcpTool:null};let n=/^mcp__(.+?)__(.+)$/i.exec(e);if(n?.[1]&&n[2])return{mcpServer:n[1],mcpTool:n[2]};if(/^MCP:/i.test(e)){let r=e.slice(4);if(!r)return{mcpServer:null,mcpTool:null};let o=r.indexOf(":");return o>0?{mcpServer:r.slice(0,o),mcpTool:r.slice(o+1)||null}:{mcpServer:ka(r,t),mcpTool:r}}return{mcpServer:null,mcpTool:null}}var _e="__post",Be="__work";function Ca(e,t){let n=e.payload,r=n&&typeof n=="object"&&!Array.isArray(n)?Object.keys(n):[],o=e.correlation&&typeof e.correlation=="object"?Object.keys(e.correlation):[];return JSON.stringify({event:e.event,schema_version:e.schema_version,agent_hook_version:e.agent_hook_version,host_arch:e.host_arch,node_version:e.node_version,build_ms:e.build_ms,body_bytes:t,correlation_keys:o,payload_keys:r})}function Vr(e){switch(e){case"session_start":return Zt;case"session_end":return Qt;case"tool_invoked":case"skill_invoked":return Xe;default:return Xe}}function xa(e,t,n){return`${JSON.stringify({url:e,timeoutMs:t})}
|
|
20
|
+
${n}`}function Wr(e,t=[],n=process.execPath,r=import.meta.url,o=Kr){if(Ia(n)===J)return{command:n,args:[e,...t]};let s=Ra(r);return o(s)?{command:n,args:[s,e,...t]}:{command:n,args:[e,...t]}}function Aa(e=process.execPath,t=import.meta.url,n=Kr){return Wr(_e,[],e,t,n)}function Ta(e){let t=e.indexOf(`
|
|
21
|
+
`);if(t<0)return null;let n;try{n=JSON.parse(e.slice(0,t))}catch{return null}return{meta:n,body:e.slice(t+1)}}async function $e(e,t=fetch){let n=await e(),r=Ta(n);if(!r)return;let{meta:o,body:s}=r,i={"Content-Type":"application/json"};try{await t(o.url,{method:"POST",headers:i,body:s,signal:AbortSignal.timeout(Number(o.timeoutMs))})}catch{}}async function Oa(e,t,n){let r=Vr(e);d(`POST event=${e} url=${Ze(n)} size=${t.length} platform=${process.platform}`);let o={"Content-Type":"application/json"},s=Date.now();try{let i=await fetch(n,{method:"POST",headers:o,body:t,signal:AbortSignal.timeout(r)}),a=Date.now()-s;if(i.ok)return d(`POST outcome=ok elapsed_ms=${a} http=${i.status}`),!0;let c=(await i.text()).slice(0,200).replace(/[\n\r]/g,"");return d(`POST outcome=fail elapsed_ms=${a} http=${i.status} body=${c}`),!1}catch(i){let a=Date.now()-s,c=i instanceof Error?i.message:String(i);return d(`POST outcome=fail elapsed_ms=${a} http=000 body=${c}`),!1}}async function zr(e,t,n,r,o){try{let s=r(e,t,{detached:!0,stdio:["pipe","ignore","ignore"],windowsHide:!0});s.on("error",()=>{}),s.stdin.on("error",()=>{});let i=!1;return await new Promise(a=>{let c=setTimeout(()=>{if(!i){d(`WARN: ${o} stdin handoff timed out \u2014 continuing fail-open`);try{s.stdin.destroy()}catch{}}a()},en),u=()=>{i=!0,clearTimeout(c),a()};s.stdin.end(n,()=>u()),s.stdin.once("error",()=>u())}),s.unref(),s}catch(s){let i=s instanceof Error?s.message:String(s);return d(`WARN: ${o} spawn failed open: ${i}`),null}}async function va(e,t,n,r=Jr,o=Aa){let s=Vr(e),i=xa(n,s,t),{command:a,args:c}=o();return zr(a,c,i,r,"detached post")}async function Yr(e,t,n=Jr,r=Wr){let{command:o,args:s}=r(Be,t);return zr(o,s,e,n,"detached work")}async function se(e,t,n,r,o,s){if(!o)return d("WARN: collector URL missing \u2014 pass --url on the hook command or set collector_url in manifest"),!1;if(!xe(o))return d(`WARN: collector URL blocked (https required): ${Ze(o)}`),!1;let i=r(e,t,n);s!==void 0&&(i.build_ms=Math.max(0,Date.now()-s));let a=`${JSON.stringify(i)}
|
|
22
|
+
`,c=E("EV_AI_HOOK_DEBUG");c==="full"?d(`DEBUG envelope=${JSON.stringify(i)}`):c==="1"&&d(`DEBUG summary=${Ca(i,Buffer.byteLength(a,"utf8"))}`);let u=process.argv.includes(Be),l=E("EV_AI_HOOK_SYNC")==="1";return je(n.runnerEvent,n.runnerPlatform)||u||l?Oa(e,a,o):(await va(e,a,o),!1)}import{relative as ba,resolve as Jt,sep as Xr}from"node:path";var wa=["session_id","conversation_id","turn_id","generation_id","prompt.id","prompt_id","hook_event_name","event","source","status","stop_reason","reason","tool_name","tool","tool_use_id","skill_name","command_name","expansion_type","command_source","permission_mode","model","model_id","agent_id","agent_type","subagent_id","subagent_type","subagent_model","is_parallel_worker","effort","effort.level","duration_ms","duration","failure_type","is_interrupt"];function Ua(e){return e.capture_hook_input==="full"?!0:e.capture_hook_input==="allowlist"?!1:E("EV_AI_HOOK_CAPTURE_FULL_INPUT")==="1"}function Pa(e){let t={};for(let n of wa){let r=Y(e,n);r!==void 0&&(t[n]=r)}return t}function Na(e,t){if(typeof e!="string"||e.length===0||!t)return null;let n=Jt(e),r=Jt(t),o=ba(r,n);return!o||o==="."?".":o.startsWith(`..${Xr}`)||o===".."||Jt(r,o)!==n?null:o.split(Xr).join("/")}function qr(e,t){let n=JSON.stringify(e),r=Buffer.byteLength(n,"utf8");if(r<=t)return e;let o=Object.entries(e).filter(([i,a])=>!i.startsWith("_")&&(typeof a=="string"||typeof a=="number"||typeof a=="boolean")).sort((i,a)=>Buffer.byteLength(JSON.stringify(i[1]),"utf8")-Buffer.byteLength(JSON.stringify(a[1]),"utf8")),s={_truncated:!0,_original_bytes:r};for(let[i,a]of o){let c={...s,[i]:a};if(Buffer.byteLength(JSON.stringify(c),"utf8")>t)break;s[i]=a}return s}function Se(e,t,n={}){let r=n.gitRoot!==void 0?Na(e.cwd,n.gitRoot):null;if(Ua(t)){let s={...e};return delete s.cwd,delete s.transcript_path,r!==null&&(s.cwd_relative=r),qr(s,nn)}let o=Pa(e);return r!==null&&(o.cwd_relative=r),qr(o,tn)}import{createReadStream as Ma}from"node:fs";import{stat as La}from"node:fs/promises";import{basename as Ha,resolve as Da}from"node:path";import{createInterface as Fa}from"node:readline";var ja=1024*1024;function Ba(e){let t=e.replace(/\\/g,"/");return t.includes("/.claude/projects/")&&Ha(t).endsWith(".jsonl")}async function Zr(e){if(!e||!Ba(e))return null;try{let t=Da(e),n=await La(t);if(!n.isFile())return null;let r=Math.max(0,n.size-ja),o=[],s=Fa({input:Ma(t,{encoding:"utf8",start:r}),crlfDelay:1/0});for await(let i of s)i.length!==0&&o.push(i);r>0&&o.length>0&&o.shift();for(let i=o.length-1;i>=0;i--){let a=o[i];if(a)try{let c=JSON.parse(a);if(c.type!=="assistant")continue;let u=c.message;if(!u||typeof u!="object")continue;let l=u.model;if(typeof l=="string"&&l.length>0)return l}catch{continue}}return null}catch{return null}}function ye(e){return{sessionId:e.sessionId,turnId:e.turnId,installationId:e.manifest.installationId,runnerPlatform:e.runnerPlatform,platformAgentId:e.platformAgentId,runnerEvent:e.runnerEvent}}function $a(...e){for(let t of e)if(t)return t;return null}function N(e,t,n){if(e.status==="fulfilled")return e.value;let r=e.reason instanceof Error?e.reason.message:String(e.reason);return d(`WARN: ${n} failed open: ${r}`),t}function Ga(e){let t={present:!1,size:0},n={hash:"",count:0};return{config:{runner_platform:e,config_scope:"user",cli_version:null,claude_version:null,model:null,permission_keys:[],user_scope:{skills:n,subagents:n,commands:n,rules:n,memory:t,settings:t,mcp:t},local_settings:t},commit:()=>{}}}function Ka(e,t){return{runner_platform:e,config_scope:"user",...t?{operator:t}:{}}}var ee=new Set,Ee=null;async function Qr(e){if(Ft())return;let t=e.manifest.installationId,n=e.manifest.installationStorePath;if(ee.has(t))return;if(!At(n)){ee.add(t);return}let r=gt();if(dr(r)){if(Ee){await Ee;return}Ee=(async()=>{if(ee.has(t)||!At(n)){ee.add(t);return}if(!vn(n)){ee.add(t);return}let o=!1;try{let s=Date.now(),{gitRoot:i}=e.manifest,a=String(e.runnerPlatform),[c,u,l,f,g]=await Promise.allSettled([me(i),ht(),Et(r),_t(),Ne({gitRoot:i,installationStorePath:n,forceResend:!1})]),p=N(c,null,"gitSnapshot"),_=N(u,"","detectVirt"),R=N(l,null,"probeCloud"),b=N(f,{},"hostEnv"),x=N(g,{commit:()=>{}},"resolveOperatorForSend");await ke(e,i,p);let w={identity:{host:St(),context:r,virt:_||null,cloud:R,git:p},host_env:b,env_vars:Rt(),self_config:Ka(a,x.operator),run_meta:{trigger:"cloud_identity_bootstrap"}};o=!!await se("session_start",w,ye(e),oe,e.manifest.collectorUrl,s),o&&(x.commit(),ee.add(t))}finally{bn(n)}})().finally(()=>{Ee=null}),await Ee}}async function ke(e,t,n){try{let r=n===void 0?await me(t):n;e.platformAgentId=await ar(e.manifest.manifest,e.platformAgentId,String(e.runnerPlatform),t,r,e.manifest.installationStorePath,e.manifest.repoKey)}catch(r){let o=r instanceof Error?r.message:String(r);d(`WARN: derivePlatformAgentId failed open: ${o}`)}}async function Ja(e){let t=Date.now(),{gitRoot:n}=e.manifest,r=gt(),o=String(e.runnerPlatform),[s,i,a,c,u,l]=await Promise.allSettled([me(n),ht(),Et(r),_t(),It(e.manifest.manifest,n,o),vr(o,n,void 0,{installationStorePath:e.manifest.installationStorePath,gitRoot:n})]),f=N(s,null,"gitSnapshot"),g=N(i,"","detectVirt"),p=N(a,null,"probeCloud"),_=N(c,{},"hostEnv"),R=N(u,[],"mcpDeclared"),b=N(l,Ga(o),"selfConfig"),x=b.config;await ke(e,n,f);let w=m(e.hookInput,"model");w&&(x.model=w);let W={identity:{host:St(),context:r,virt:g||null,cloud:p,git:f},host_env:_,env_vars:Rt(),mcp:{declared:R},self_config:x,run_meta:{trigger:e.hookSource||"startup"},hook_input:Se(e.hookInput,e.manifest.manifest,{gitRoot:n})};await se("session_start",W,ye(e),oe,e.manifest.collectorUrl,t)&&(b.commit(),ee.add(e.manifest.installationId))}async function Va(e){let t=Date.now(),{gitRoot:n}=e.manifest;await ke(e,n);let r=$a(m(e.hookInput,"status"),m(e.hookInput,"stop_reason"),m(e.hookInput,"reason"),Kt(m(e.hookInput,"error"))),o=e.runnerPlatform==="claude"?await Zr(m(e.hookInput,"transcript_path")):null,s=Se(e.hookInput,e.manifest.manifest,{gitRoot:n});o&&(s.model=o),await se("session_end",{status:r,...o?{model:o}:{},hook_input:s},ye(e),oe,e.manifest.collectorUrl,t)}async function Wa(e){let t=Date.now(),n=Nr(e.hookInput);if(n.length===0)return;await Qr(e);let{gitRoot:r}=e.manifest;await ke(e,r);let o=Se(e.hookInput,e.manifest.manifest,{gitRoot:r}),s=ye(e);await Promise.all(n.map(i=>se("tool_invoked",{tool_name:"Skill",skill_name:i,success:null,duration_ms:null,hook_input:o},s,oe,e.manifest.collectorUrl,t)))}async function za(e){let t=Date.now();await Qr(e);let{gitRoot:n}=e.manifest;await ke(e,n);let{toolName:r,skillName:o}=Fr(e.hookInput),s=Br(e.hookInput),i=Lr(e.runnerEvent),a=i===!1?$r(e.hookInput,e.runnerEvent):null,c=await It(e.manifest.manifest,e.manifest.gitRoot,String(e.runnerPlatform)).catch(()=>[]),{mcpServer:u,mcpTool:l}=Gr(r,c.map(g=>g.name)),f=jr(e.hookInput);await se("tool_invoked",{tool_name:r,skill_name:o,success:i,duration_ms:s,...a?{failure_reason:a}:{},...u?{mcp_server:u}:{},...l?{mcp_tool:l}:{},...f?{subagent_type:f}:{},hook_input:Se(e.hookInput,e.manifest.manifest,{gitRoot:n})},ye(e),oe,e.manifest.collectorUrl,t)}async function eo(e){switch(e.internalEvent){case"session_start":await Ja(e);return;case"session_end":await Va(e);return;case"skill_invoked":await Wa(e);return;case"tool_invoked":await za(e);return;default:return}}function to(e){return e!=="session_start"&&e!=="session_end"&&e!=="tool_invoked"&&e!=="skill_invoked"&&e!==""}async function no(e,t,n,r){let o=t??await et(qe),s=v(o,{}),i=await Mn();if(!i)return;r&&(i.collectorUrl=r);let a=Hr(s,i.manifest.platform,n),c=Dr(e,a.runnerEvent);if(!c){d(`WARN: unknown hook event '${a.runnerEvent}'; skipping telemetry`);return}let u={hookInput:s,sessionId:a.sessionId,turnId:a.turnId,runnerEvent:a.runnerEvent,runnerPlatform:a.runnerPlatform,hookSource:a.hookSource,internalEvent:c,manifest:i,platformAgentId:i.platformAgentId};if(to(c)){d(`WARN: unsupported internal event '${c}'`);return}await eo(u)}function Ya(e,t){if(E("EV_AI_HOOK_SYNC")==="1")return!0;let n=Fe(e),r=v(t,{}),o=n.event??(m(r,"hook_event_name")||m(r,"event")),s=Gt(r,o,void 0,n.runner);return je(o,s)}async function ro(e=process.argv.slice(2)){if(e[0]===_e){try{await $e(le)}catch{}return 0}if(e[0]===Be){try{let t=Fe(e.slice(1)),n=await le(),r=v(n,{}),o=t.event??(m(r,"hook_event_name")||m(r,"event"));if($t(t.runner,r,o))return 0;await no(t.event,n,t.runner,Bt(t))}catch(t){let n=t instanceof Error?t.message:String(t);d(`WARN: detached work failed open: ${n}`)}return 0}try{let t=await et(qe),n=Fe(e),r=Bt(n),o=v(t,{}),s=n.event??(m(o,"hook_event_name")||m(o,"event"));if($t(n.runner,o,s))return 0;Ya(e,t)?await no(n.event,t,n.runner,r):await Yr(t,e)}catch(t){let n=t instanceof Error?t.message:String(t);d(`WARN: hook failed open: ${n}`)}finally{gn()}return 0}function Ge(){d("Usage: ev-ai-agent-hook <configure|install|migrate-to-plugin|update|uninstall|--version>"),d(" configure [--url <\u2026/{orgToken}/hook>]"),d(" (manifest only \u2014 pair with marketplace plugins)"),d(" install --url <\u2026/{orgToken}/hook>"),d(" [--delivery npx|binary|local] [--force]"),d(" [--no-claude] [--no-cursor] [--no-codex]"),d(" (fallback: merge hooks into .claude / .cursor / .codex configs)"),d(" (writes collector_url to shared manifest; hook commands use --runner only)"),d(" migrate-to-plugin"),d(" (strip ev-ai file hooks; keep collector manifest)"),d(" update (refresh binary pins from a local build; leaves hook configs alone)"),d(" uninstall"),d("Hook mode: --runner <platform> [--url <\u2026/hook>|--token <orgToken>] [event]"),d(" (--url/--token optional overrides; else collector_url from manifest)")}function oo(e){return e.includes("--help")||e.includes("-h")}async function ec(e=process.argv.slice(2)){let[t,...n]=e;if(t===_e){try{await $e(le)}catch{}return 0}return t==="--version"||t==="-V"?(process.stdout.write(`${H}
|
|
23
|
+
`),0):t==="configure"?oo(n)?(Ge(),0):(await rr(Gn(n)),0):t==="install"?oo(n)?(Ge(),0):(await tr(Kn(n)),0):t==="migrate-to-plugin"?(await sr(),0):t==="update"?(await nr(),0):t==="uninstall"?(await ir(),0):t==="help"||t==="--help"||t==="-h"?(Ge(),0):t===void 0?(Ge(),1):ro(e)}function tc(e,t,n=Xa){if(!t)return!1;try{return e===Qa(qa(t)).href?!0:n(Za(e))===n(t)}catch{return!1}}tc(import.meta.url,process.argv[1])&&process.env.VITEST===void 0&&ec().then(e=>{process.exit(e)}).catch(e=>{let t=e instanceof Error?e.message:String(e);d(t),process.exit(1)});export{tc as isCliEntrypoint,ec as main};
|
package/dist/hook.mjs
CHANGED
|
@@ -1,12 +1,16 @@
|
|
|
1
|
-
var
|
|
2
|
-
`)}function
|
|
3
|
-
`)}catch(s){let
|
|
4
|
-
`,{encoding:"utf8",flag:"wx"})}
|
|
5
|
-
`)}catch(
|
|
6
|
-
`)[
|
|
7
|
-
`);return
|
|
8
|
-
`)}catch(n){let r=n instanceof Error?n.message:String(n);u(`WARN: self-config cache write failed open: ${r}`)}}function Zn(t,e,n){let r={...t,send_count:n};for(let o of Object.keys(e)){let s=e[o];s.entries!==void 0&&(r[o]=s.hash)}return r}async function oe(t,e=process.cwd(),n=re()){let r=t==="claude",o=await Vn(t),s="",a=[];if(r){let h=te(_(n,".claude/settings.json")),H=te(_(e,".claude/settings.local.json"));s=H.model||h.model,a=[...h.permissionKeys,...H.permissionKeys].slice(0,Un)}let i=Fn[t]??{},c={present:!1,size:0},d=h=>{let H=Array.isArray(h)?h:h?[h]:[],v=[],F=!1;for(let $e of H){let kt=N(_(n,$e));if(v=v.concat(kt.entries),F=F||kt.truncated,v.length>=K){v=v.slice(0,K),F=!0;break}}return{entries:v,truncated:F}},f=Gn(n),k=Yn(f),y=k[t]??{},E=(y.send_count??0)+1,q=E>0&&E%Bn===0,I=h=>q?void 0:y[h],C=d(i.skills),M=i.subagents?N(_(n,i.subagents)):{entries:[],truncated:!1},yt=i.commands?N(_(n,i.commands)):{entries:[],truncated:!1},Et=i.rules?N(_(n,i.rules)):{entries:[],truncated:!1},T={skills:W(C.entries,I("skills"),C.truncated),subagents:W(M.entries,I("subagents"),M.truncated),commands:W(yt.entries,I("commands"),yt.truncated),rules:W(Et.entries,I("rules"),Et.truncated)};return k[t]=Zn(y,T,E),Xn(f,k),{runner_platform:t,config_scope:"user",cli_version:o,claude_version:r?o:null,model:r&&s||null,permission_keys:a,user_scope:{skills:T.skills,subagents:T.subagents,commands:T.commands,rules:T.rules,memory:i.memory?P(_(n,i.memory)):c,settings:i.settings?P(_(n,i.settings)):c,mcp:i.mcp?P(_(n,i.mcp)):c},local_settings:r?P(_(e,".claude/settings.local.json")):c}}function b(t,e,n){let r={installation_id:n.installationId};return n.platformAgentId&&(r.platform_agent_id=n.platformAgentId),n.sessionId&&(r.session_id=n.sessionId),n.turnId&&(r.turn_id=n.turnId),{schema_version:2,event:t,timestamp:Mt(),session_id:n.sessionId||null,turn_id:n.turnId||null,installation_id:n.installationId,platform:n.runnerPlatform,platform_agent_id:n.platformAgentId||null,runner_event:n.runnerEvent||null,agent_hook_version:et,host_arch:process.arch,node_version:process.version,correlation:r,payload:e}}import{existsSync as Re}from"node:fs";import{spawn as ve}from"node:child_process";import{basename as Rr}from"node:path";import{fileURLToPath as vr}from"node:url";var qn=new Set(["localhost","127.0.0.1","[::1]","::1"]),se=/^[A-Za-z0-9._~-]+$/;function ie(t){for(let e=0;e<t.length;e++){let n=t.charCodeAt(e);if(n<=32||n===127||n===39)return!0}return!1}function V(t){try{let e=new URL(t);return e.protocol==="https:"?!0:e.protocol==="http:"?qn.has(e.hostname):!1}catch{return!1}}function ae(t){let e;try{e=new URL(t)}catch{return`invalid URL (got: ${t})`}if(!V(t))return`must be https (or http on localhost / 127.0.0.1 / ::1) (got: ${t})`;let n=Qn(t);if(!n)return`must end with /{orgToken}/hook (got: ${t})`;if(!se.test(n))return`org token must match ${se.source} (got: ${n})`;if(ie(t))return`must not contain whitespace, control characters, or single quotes (got: ${t})`;if(ie(e.pathname))return`pathname must not contain whitespace, control characters, or single quotes (got: ${t})`}function ce(t){return new URL(t).toString()}function Qn(t){try{let n=new URL(t).pathname.split("/").filter(r=>r.length>0);if(n.length>=2&&n[n.length-1]==="hook"){let r=n[n.length-2];return r.length>0?r:void 0}return}catch{return}}function ut(t){try{let e=new URL(t),n=e.pathname.split("/").filter(r=>r.length>0);return n.length>=2&&n[n.length-1]==="hook"&&(n[n.length-2]="***",e.pathname=`/${n.join("/")}`),e.toString()}catch{return"<invalid-url>"}}function le(t){if(t.collector_url)return t.collector_url;let e=t.repo_ingest_token?.trim();return e?U(e):""}var ue=/(?:^|\/|[\s"'=(])(?:\.cursor\/|\.claude\/|\.agents\/)skills(?:-cursor)?\/([^/]+)\/SKILL\.md/i,de=/(?:^|\/|[\s"'=(])\.codex\/commands\/([^/]+)\.md\b/i,tr=/(?:^|\s)\/([a-z][a-z0-9-]{1,63})\b/gi,er=new Set(["applications","app","bin","boot","data","dev","etc","home","lib","media","mnt","node_modules","opt","pkg","private","proc","projects","repos","run","sbin","src","srv","sys","tmp","usr","users","var","volumes","workspace","workspaces"]),nr=new Set(["read","read_file","view"]),rr=new Set(["bash","shell","zsh"]);function or(t){let e=t.replace(/\\/g,"/");return ue.exec(e)?.[1]??null}function sr(t){let e=t.replace(/\\/g,"/"),r=de.exec(e)?.[1];return r?r.toLowerCase():null}function ir(t){return or(t)??sr(t)}function ar(t){for(let e of["path","file_path","target_file"]){let n=t[e];if(typeof n=="string"&&n.length>0)return n}return null}function fe(t){if(typeof t=="string")try{let e=JSON.parse(t);return fe(e)}catch{return null}return!t||typeof t!="object"?null:ar(t)}function cr(t){if(!t||typeof t!="object")return null;let e=t.command;return typeof e=="string"&&e.length>0?e:null}function lr(t){let e=t.replace(/\\/g,"/"),n=ue.exec(e);if(n?.[1])return n[1];let o=de.exec(e)?.[1];return o?o.toLowerCase():null}function ur(t){return typeof t.tool_name=="string"?t.tool_name:typeof t.tool=="string"?t.tool:""}function pe(t){let e=ur(t).toLowerCase();if(nr.has(e)){let n=fe(t.tool_input);return n?ir(n):null}if(rr.has(e)){let n=cr(t.tool_input);return n?lr(n):null}return null}function dr(t){let e=new Set,n=[];for(let r of t.matchAll(tr)){let o=r[1]?.toLowerCase();!o||e.has(o)||er.has(o)||(e.add(o),n.push(o))}return n}function fr(t){return x(t.prompt)}function me(t){let e=l(t,"command_name");if(e){let r=l(t,"expansion_type");if(r&&r!=="slash_command")return[];let o=e.replace(/^\//,"").toLowerCase();return o?[o]:[]}let n=fr(t);return n?dr(n):[]}function dt(t){return t!==void 0&&Tt.includes(t)}function G(t,e){let n=t[e+1];return n&&!n.startsWith("--")?{value:n,next:e+1}:{next:e}}function J(t){let e,n,r,o,s;for(let a=0;a<t.length;a++){let i=t[a];if(i!==void 0){if(i==="--runner"){let c=G(t,a);e=c.value,a=c.next;continue}if(i.startsWith("--runner=")){e=i.slice(9);continue}if(i==="--url"){let c=G(t,a);c.value&&(r=c.value),a=c.next;continue}if(i.startsWith("--url=")){r=i.slice(6);continue}if(i==="--token"){let c=G(t,a);c.value&&(o=c.value),a=c.next;continue}if(i.startsWith("--token=")){o=i.slice(8);continue}if(i==="--base-url"){let c=G(t,a);c.value&&(s=c.value),a=c.next;continue}if(i.startsWith("--base-url=")){s=i.slice(11);continue}!i.startsWith("-")&&n===void 0&&(n=i)}}return{runner:dt(e)?e:void 0,event:n,collectorUrl:r,orgToken:o,baseUrl:s}}function ft(t){let e=t.collectorUrl?.trim(),n;if(e)n=e;else{let o=t.orgToken?.trim();o&&(n=U(o,t.baseUrl?.trim()??void 0))}if(!n)return;let r=ae(n);if(r){u(`WARN: ignoring --url/--token collector override: ${r}`);return}return ce(n)}function pr(t,e){return l(t,"conversation_id")?!0:e!==""&&e===e.toLowerCase()}function pt(t,e,n,r){if(pr(t,e))return"cursor";if(dt(r))return r;let o=l(t,"conversation_id"),s=l(t,"turn_id"),a=l(t,"session_id"),i=e.toLowerCase(),c="unknown";return o||e===i&&e!==""?c="cursor":s?c="codex":(a||i==="sessionstart"||i==="sessionend"||i==="stop"||i==="stopfailure"||i==="pretooluse"||i==="posttooluse"||i==="posttoolusefailure"||i==="permissiondenied"||i==="subagentstart"||i==="subagentstop"||i==="userpromptexpansion")&&(c="claude"),dt(n)&&(c=n),c}function Y(t,e){let n=t.toLowerCase();return n==="sessionend"||n==="stopfailure"||n==="subagentstop"?!0:n==="stop"&&e==="codex"}function mr(t){switch(t){case"sessionstart":return"session_start";case"stop":case"sessionend":case"stopfailure":return"session_end";case"pretooluse":case"posttooluse":case"posttoolusefailure":case"permissiondenied":case"beforemcpexecution":case"beforeshellexecution":case"afterfileedit":case"subagentstart":case"subagentstop":return"tool_invoked";case"beforesubmitprompt":case"userpromptexpansion":case"userpromptsubmit":return"skill_invoked";default:return""}}function ge(t){let e=t.toLowerCase();return e==="posttooluse"?!0:e==="posttoolusefailure"||e==="permissiondenied"?!1:null}function _e(t,e,n){let r=l(t,"session_id")||l(t,"conversation_id"),o=l(t,"prompt.id")||l(t,"prompt_id")||l(t,"generation_id")||l(t,"turn_id"),s=l(t,"hook_event_name")||l(t,"event"),a=l(t,"source"),i=pt(t,s,e,n);return{sessionId:r,turnId:o,runnerEvent:s,hookSource:a,runnerPlatform:i}}var gr=["session_start","session_end","tool_invoked","skill_invoked"];function _r(t){return gr.includes(t)}function he(t,e){return t&&_r(t)?t:mr(e.toLowerCase())}function Se(t){let e=l(t,"tool_name")||l(t,"tool")||null,n=t.tool_input,o=(n&&typeof n=="object"?x(n.skill)||x(n.skill_name):"")||l(t,"skill_name")||null;return o??=pe(t),{toolName:e,skillName:o}}var hr=/^[A-Za-z][A-Za-z0-9_.:-]{0,63}$/;function ye(t){for(let e of["subagent_type","agent_type"]){let n=l(t,e);if(n&&hr.test(n))return n}return null}function Ee(t){let e=R(t,"duration_ms");if(typeof e=="number")return e;let n=R(t,"duration");return typeof n=="number"?n:null}var Sr="error",yr="interrupted",Er="permission_denied",kr=/^[A-Za-z][A-Za-z0-9_.-]{0,63}$/;function mt(t){return kr.test(t)?t:null}function Ir(t){for(let e of["failure_type","error_type"]){let n=mt(l(t,e));if(n)return n}return null}function ke(t,e){return R(t,"is_interrupt")===!0?yr:e.toLowerCase()==="permissiondenied"?Er:Ir(t)??Sr}function Ie(t){if(!t)return{mcpServer:null,mcpTool:null};let e=/^mcp__(.+?)__(.+)$/i.exec(t);if(e?.[1]&&e[2])return{mcpServer:e[1],mcpTool:e[2]};if(/^MCP:/i.test(t)){let n=t.slice(4);if(!n)return{mcpServer:null,mcpTool:null};let r=n.indexOf(":");return r>0?{mcpServer:n.slice(0,r),mcpTool:n.slice(r+1)||null}:{mcpServer:null,mcpTool:n}}return{mcpServer:null,mcpTool:null}}var gt="__post",_t="__work";function wr(t,e){let n=t.payload,r=n&&typeof n=="object"&&!Array.isArray(n)?Object.keys(n):[],o=t.correlation&&typeof t.correlation=="object"?Object.keys(t.correlation):[];return JSON.stringify({event:t.event,schema_version:t.schema_version,agent_hook_version:t.agent_hook_version,host_arch:t.host_arch,node_version:t.node_version,body_bytes:e,correlation_keys:o,payload_keys:r})}function we(t){switch(t){case"session_start":return Rt;case"session_end":return vt;case"tool_invoked":case"skill_invoked":return Q;default:return Q}}function Ar(t,e,n){return`${JSON.stringify({url:t,timeoutMs:e})}
|
|
9
|
-
${n}`}function Ae(t,e=[],n=process.execPath,r=import.meta.url,o=Re){if(Rr(n)===D)return{command:n,args:[t,...e]};let s=vr(r);return o(s)?{command:n,args:[s,t,...e]}:{command:n,args:[t,...e]}}function Cr(t=process.execPath,e=import.meta.url,n=Re){return Ae(gt,[],t,e,n)}function Tr(t){let e=t.indexOf(`
|
|
10
|
-
`)
|
|
11
|
-
|
|
1
|
+
var dr="https://hooks.ev-ai.ai";function le(e,t=dr){let n=t.replace(/\/+$/,""),r=e.trim();return`${n}/${r}/hook`}var Tt=".claude/ev-ai-runtime-report.json";var ue="ev-ai-agent-hook";var fi=`current/${ue}`,mi=`.ev-ai/agent-hook/${ue}`,At=5e3,kt=5e3,xe=3e3;var Ue=3e3,Ot=1500,xt=4*1024,Ut=32*1024,pr=4*1024,be="1.0.7",gi=`@ev-ai/agent-hook@${be}`;var bt=["claude","cursor","codex"];import{createHash as Bt,randomBytes as yr}from"node:crypto";import{existsSync as $t,mkdirSync as Gt,readFileSync as Kt,unlinkSync as jt,writeFileSync as Vt}from"node:fs";import{homedir as Me}from"node:os";import{dirname as Le,join as Pe,resolve as Ir}from"node:path";import{randomBytes as fr}from"node:crypto";import{existsSync as Mt,mkdirSync as mr,readdirSync as gr,readFileSync as _r,renameSync as wt,statSync as Lt,unlinkSync as Nt,writeFileSync as hr}from"node:fs";import{basename as Er,dirname as vt,join as Pt,relative as Sr}from"node:path";function m(e){process.stderr.write(`[ev-ai-agent-hook] ${e}
|
|
2
|
+
`)}function B(e,t){mr(vt(e),{recursive:!0});let n=Pt(vt(e),`.${Er(e)}.${process.pid}.${fr(4).toString("hex")}.tmp`);try{hr(n,t,"utf8");try{wt(n,e)}catch(r){let o=r instanceof Error&&"code"in r?r.code:void 0;if(o==="EEXIST"||o==="EPERM"||o==="EACCES"){Nt(e),wt(n,e);return}throw r}}catch(r){try{Nt(n)}catch{}throw r}}function de(){return new Date().toISOString().replace(/\.\d{3}Z$/,"Z")}function Dt(){process.stdout.write('{"continue":true}')}function E(e){let t=process.env[e];return t===void 0||t===""?void 0:t}async function Ne(){return new Promise(e=>{let t="";if(process.stdin.isTTY){e("");return}process.stdin.setEncoding("utf8"),process.stdin.on("data",n=>{t+=n}),process.stdin.on("end",()=>{e(t)}),process.stdin.on("error",()=>{e(t)}),process.stdin.resume()})}async function ve(e){return new Promise(t=>{let n="",r=!1,o=i=>{r||(r=!0,clearTimeout(s),t(i||"{}"))},s=setTimeout(()=>{o(n)},e);if(process.stdin.isTTY){o("{}");return}process.stdin.setEncoding("utf8"),process.stdin.on("data",i=>{n+=i}),process.stdin.on("end",()=>{o(n)}),process.stdin.on("error",()=>{o(n)}),process.stdin.resume()})}async function L(e,t,n=3e3,r={}){let{execFile:o}=await import("node:child_process"),{promisify:s}=await import("node:util"),i=s(o);try{let{stdout:a}=await i(e,t,{timeout:n,windowsHide:!0,maxBuffer:1048576,cwd:r.cwd});return{ok:!0,stdout:a.trim()}}catch(a){let c=a,l=typeof c.code=="number"?c.code:typeof c.status=="number"?c.status:void 0;return{ok:!1,code:l,spawnFailed:l===void 0}}}async function R(e,t,n=3e3,r={}){let o=await L(e,t,n,r);return o.ok?o.stdout:""}async function pe(e=process.cwd()){return await R("git",["rev-parse","--show-toplevel"],2e3,{cwd:e})||e}function O(e,t){try{return JSON.parse(e)}catch{return t}}var we=new Map;function W(e,t){let n=we.get(e);if(n!==void 0)return n;try{let r=O(_r(e,"utf8"),t);return we.set(e,r),r}catch{return we.set(e,t),t}}function Q(e){return typeof e=="string"?e:""}function $(e,t){let n=e[t];if(typeof n=="string"||typeof n=="number"||typeof n=="boolean")return n;if(!t.includes("."))return;let r=t.split("."),o=e;for(let s of r){if(o===null||typeof o!="object"||Array.isArray(o))return;o=o[s]}if(typeof o=="string"||typeof o=="number"||typeof o=="boolean")return o}function p(e,t){let n=$(e,t);return typeof n=="string"?n:""}var G=500;function q(e,t=2){if(!Mt(e))return{entries:[],truncated:!1};let n=[],r=!1,o=(s,i)=>{if(i>t||r)return;let a;try{a=gr(s,{withFileTypes:!0})}catch{return}for(let c of a){if(r)return;let l=Pt(s,c.name);if(c.isDirectory()){o(l,i+1);continue}if(c.isFile()){try{n.push({name:Sr(e,l),size:Lt(l).size})}catch{continue}if(n.length>=G){r=!0;return}}}};return o(e,1),{entries:n,truncated:r}}function ee(e){return Mt(e)?{present:!0,size:Lt(e).size}:{present:!1,size:0}}var Rr="installation.json",Cr="cloud-bootstrap.lock",Tr=6e4;function zt(e,t,n){let r=`${e}:${t??""}`;return n?`${n}:${r}`:r}function De(e=Me()){return Pe(e,".ev-ai","agent-hook")}function Ar(e=Me()){return Pe(De(e),Rr)}function Wt(e){return Pe(Le(e),Cr)}function Jt(){return yr(8).toString("hex")}function fe(e){return Bt("sha256").update(e).digest("hex").slice(0,16)}function y(e){if(e===void 0)return null;let t=e.trim();return t.length>0?t:null}function Yt(e){return/^[A-Za-z0-9._-]{8,64}$/.test(e)}function kr(e=process.env){let t=y(e.EV_AI_HOOK_INSTALLATION_ID);if(t){if(!Yt(t)){m(`WARN: ignoring EV_AI_HOOK_INSTALLATION_ID (expected 8\u201364 chars [A-Za-z0-9._-], got length ${t.length})`);return}return t}}function Or(e=process.env){if(y(e.GITHUB_ACTIONS)){let t=y(e.GITHUB_REPOSITORY_ID)??y(e.GITHUB_REPOSITORY),n=y(e.GITHUB_ACTOR)??y(e.GITHUB_TRIGGERING_ACTOR)??y(e.GITHUB_USER);if(t&&n)return fe(`github_actions|${t}|${n}`)}if(y(e.CODESPACES)||y(e.CODESPACE_NAME)){let t=y(e.CODESPACE_NAME);if(t)return fe(`codespaces|${t}`);let n=y(e.GITHUB_REPOSITORY_ID)??y(e.GITHUB_REPOSITORY),r=y(e.GITHUB_USER)??y(e.GITHUB_ACTOR);if(n&&r)return fe(`codespaces|${n}|${r}`)}if(y(e.GITLAB_CI)){let t=y(e.CI_PROJECT_ID)??y(e.CI_PROJECT_PATH),n=y(e.GITLAB_USER_LOGIN)??y(e.GITLAB_USER_EMAIL)??y(e.GITLAB_USER_NAME);if(t&&n)return fe(`gitlab|${t}|${n}`)}return null}function Ht(e,t){if(e&&Yt(e))return e;e&&m(`WARN: ignoring installation id override (expected 8\u201364 chars [A-Za-z0-9._-], got length ${e.length})`);let n=kr(t);if(n)return n;let r=Or(t);return r||Jt()}async function xr(e){let n=await R("git",["config","--get","remote.origin.url"],2e3,{cwd:e})||Ir(e);return Bt("sha256").update(n).digest("hex").slice(0,16)}function Ur(e){if(!e||typeof e!="object"||Array.isArray(e))return;let t={};for(let[n,r]of Object.entries(e))typeof r=="string"&&r.length>0&&(t[n]=r);return Object.keys(t).length>0?t:void 0}function br(e){try{let t=JSON.parse(e);if(typeof t.installation_id!="string"||t.installation_id.length===0)return;let n=Ur(t.platform_agent_ids);return{installation_id:t.installation_id,...n?{platform_agent_ids:n}:{},...typeof t.operator_identity_hash=="string"?{operator_identity_hash:t.operator_identity_hash}:{},...typeof t.operator_identity_sent_at=="string"?{operator_identity_sent_at:t.operator_identity_sent_at}:{}}}catch{return}}function K(e){if($t(e))try{return br(Kt(e,"utf8"))}catch{}}function He(e){return K(e)}function Xt(e,t,n){let r=K(e);if(!r||r.operator_identity_hash===t&&r.operator_identity_sent_at===n)return;let o={...r,operator_identity_hash:t,operator_identity_sent_at:n};try{B(e,`${JSON.stringify(o,null,2)}
|
|
3
|
+
`)}catch(s){let i=s instanceof Error?s.message:String(s);m(`WARN: operator identity cache write failed open: ${i}`)}}function Zt(e,t=Date.now()){if(!e)return!0;if(K(e)?.operator_identity_hash)return!1;let n=Wt(e);try{if($t(n)){let r=Number.NaN;try{r=Number(Kt(n,"utf8").trim())}catch{}let o=t-r;if(Number.isFinite(o)&&o>=0&&o<Tr)return!1;try{jt(n)}catch{}}}catch{}try{return Gt(Le(n),{recursive:!0}),Vt(n,`${t}
|
|
4
|
+
`,{encoding:"utf8",flag:"wx"}),!0}catch(r){if(tn(r))return!1;let o=r instanceof Error?r.message:String(r);return m(`WARN: cloud bootstrap claim failed open: ${o}`),!0}}function Qt(e){if(e)try{jt(Wt(e))}catch{}}function qt(e,t){let r=K(e)?.platform_agent_ids?.[t];return typeof r=="string"&&r.length>0?r:void 0}function en(e,t,n){if(!n)return;let r=K(e);if(!r||r.platform_agent_ids?.[t]===n)return;let o={installation_id:r.installation_id,platform_agent_ids:{...r.platform_agent_ids,[t]:n},...r.operator_identity_hash?{operator_identity_hash:r.operator_identity_hash}:{},...r.operator_identity_sent_at?{operator_identity_sent_at:r.operator_identity_sent_at}:{}};try{B(e,`${JSON.stringify(o,null,2)}
|
|
5
|
+
`)}catch(s){let i=s instanceof Error?s.message:String(s);m(`WARN: platform_agent_id cache write failed open: ${i}`)}}function tn(e){return e instanceof Error&&"code"in e&&e.code==="EEXIST"}function wr(e,t){Gt(Le(e),{recursive:!0}),Vt(e,`${JSON.stringify(t,null,2)}
|
|
6
|
+
`,{encoding:"utf8",flag:"wx"})}function Ft(e,t){try{return wr(e,t),t}catch(n){if(!tn(n))throw n;return K(e)}}async function nn(e,t={}){let n=t.home??Me(),r=t.env??process.env,o=await xr(e),s=Ar(n),i=K(s);if(i)return{installationId:i.installation_id,storePath:s,repoKey:o};let a=Ht(t.overrideId,r),c=Ft(s,{installation_id:a});if(c)return{installationId:c.installation_id,storePath:s,repoKey:o};let l=Ht(void 0,r),u=Ft(s,{installation_id:l===a?Jt():l});if(u)return{installationId:u.installation_id,storePath:s,repoKey:o};throw new Error(`Failed to create installation record at ${s}`)}var Nr={claude:".claude",cursor:".cursor",codex:".codex"};function te(e){let n=e.replace(/^\/+|\/+$/g,"").toLowerCase().split("/").filter(Boolean);return n.length<2?"":n.join("/")}function vr(e){if(!e)return"";let t=e.replace(/^([a-z]+:\/\/)[^/@]+@/i,"$1");t=t.replace(/\.git$/i,"");let n=t.match(/^git@[^:]+:(.+)$/);if(n?.[1])return te(n[1]);let r=t.match(/^ssh:\/\/[^/]+\/(.+)$/i);if(r?.[1])return te(r[1]);t=t.replace(/^https:\/\//i,""),t=t.replace(/^http:\/\//i,""),t=t.replace(/^ssh:\/\//i,"");let o=t.match(/^[^/]+\/(.+)$/);return o?.[1]?te(o[1]):te(t)}async function ne(e=process.cwd()){let t=await L("git",["rev-parse","--is-inside-work-tree"],2e3,{cwd:e});if(!t.ok||t.stdout!=="true")return null;let[n,r,o,s]=await Promise.all([L("git",["remote","get-url","origin"],2e3,{cwd:e}),L("git",["branch","--show-current"],2e3,{cwd:e}),L("git",["rev-parse","HEAD"],2e3,{cwd:e}),L("git",["status","--porcelain"],2e3,{cwd:e})]),i=n.ok?n.stdout:null;return{remote:i===null?null:i.replace(/^([a-z]+:\/\/)[^/@]+@/i,"$1"),branch:r.ok?r.stdout:null,head:o.ok?o.stdout:null,dirty:s.ok?s.stdout.length>0:null}}async function rn(e,t,n,r=process.cwd(),o,s,i){if(t)return t;let a=Nr[n];if(!a)return"";let c=zt(n,e.scope_path,i);if(s){let h=qt(s,c);if(h)return h}let l=o??await ne(r),u=l?.remote?vr(l.remote):"";if(u||(u=te(process.env.GITHUB_REPOSITORY??"")),!u)return"";let d=e.scope_path??"",g=d?`${d}/`:"",f=`${u}:${g}${a}`;return s&&en(s,c,f),f}import{existsSync as Mr,readFileSync as Lr}from"node:fs";import{hostname as Pr,userInfo as Dr}from"node:os";function me(e){if(e===void 0||e==="")return!1;let t=e.trim().toLowerCase();return t!=="0"&&t!=="false"&&t!=="no"}var Hr=["GITLAB_CI","CIRCLECI","BUILDKITE","TF_BUILD","JENKINS_URL","JENKINS_HOME","CODEBUILD_BUILD_ID","DRONE","DRONE_BUILD_NUMBER","TEAMCITY_VERSION","TRAVIS","APPVEYOR","BITBUCKET_BUILD_NUMBER"];function Fr(){return Hr.some(e=>!!E(e))}function Br(){if(E("KUBERNETES_SERVICE_HOST")||me(E("REMOTE_CONTAINERS"))||me(E("DEVCONTAINER")))return!0;try{if(Mr("/.dockerenv")||Lr("/proc/1/environ","utf8").includes("container="))return!0}catch{}return!1}function Fe(){if(E("GITHUB_ACTIONS"))return"github_actions";if(me(E("CLAUDE_CODE_REMOTE")))return"claude_remote";if(me(E("CURSOR_AGENT")))return"cursor_cloud";if(E("CODESPACES")||E("CODESPACE_NAME"))return"codespaces";if(Fr())return"managed";let e=E("CI");return e&&e!=="false"&&e!=="0"?"managed":Br()?"container":process.stdin.isTTY||process.stdout.isTTY||E("TERM")?"interactive":"cron"}async function Be(){return await R("systemd-detect-virt",[],1e3)}function $r(e=process.env,t=Dr){for(let n of["USER","LOGNAME","USERNAME"]){let r=e[n];if(typeof r=="string"){let o=r.trim();if(o.length>0)return o}}try{return t().username??""}catch{return""}}async function $e(){let e=process.platform==="darwin"?"Darwin":process.platform==="win32"?"Windows_NT":"Linux",t="";if(process.platform==="darwin")t=await R("sw_vers",["-productVersion"],1e3);else if(process.platform==="linux"){try{let{readFileSync:s}=await import("node:fs"),i=s("/etc/os-release","utf8"),a=i.match(/^PRETTY_NAME="?([^"\n]+)"?/m)?.[1],c=i.match(/^VERSION_ID="?([^"\n]+)"?/m)?.[1];t=a??c??""}catch{t=await R("lsb_release",["-sd"],1e3).then(s=>s.replace(/^"|"$/g,""))}t||(t=await R("uname",["-r"],1e3))}else t=await R("ver",[],1e3);let n=$r(),r=(process.env.SHELL??"").split(/[/\\]/).pop()??"",o="";try{o=await R("tty",[],500),o.includes("not a tty")&&(o="")}catch{o=""}return{os:e,os_version:t||null,user:n||null,shell:r||null,tty:o||null}}function Ge(){return Pr()}import{existsSync as Gr,readFileSync as Kr}from"node:fs";import{homedir as on}from"node:os";import{join as jr}from"node:path";var Vr="cloud-cache.json",zr=1440*60*1e3,Wr=900*1e3;function Jr(e=on()){return jr(De(e),Vr)}function Yr(e){if(!Gr(e))return;let t=O(Kr(e,"utf8"),{});if(!(typeof t.context!="string"||typeof t.probed_at!="number"||t.result!==null&&t.result!==void 0&&typeof t.result!="object"))return{context:t.context,probed_at:t.probed_at,result:t.result??null}}function Xr(e,t){try{B(e,`${JSON.stringify(t)}
|
|
7
|
+
`)}catch(n){let r=n instanceof Error?n.message:String(n);m(`WARN: cloud cache write failed open: ${r}`)}}function Zr(e,t,n){if(!e||e.context!==t)return!1;let r=e.result===null?Wr:zr;return n-e.probed_at<r}async function Qr(e){let t=await fetch("http://169.254.169.254/latest/api/token",{method:"PUT",headers:{"X-aws-ec2-metadata-token-ttl-seconds":"60"},signal:AbortSignal.timeout(e)}).catch(()=>{});if(!t?.ok)return;let n=(await t.text()).trim();if(!n)return;let r={"X-aws-ec2-metadata-token":n},[o,s]=await Promise.all([fetch("http://169.254.169.254/latest/meta-data/placement/region",{headers:r,signal:AbortSignal.timeout(e)}).catch(()=>{}),fetch("http://169.254.169.254/latest/meta-data/instance-id",{headers:r,signal:AbortSignal.timeout(e)}).catch(()=>{})]);if(!o?.ok&&!s?.ok)return;let i=o?.ok?(await o.text()).trim():"",a=s?.ok?(await s.text()).trim():"";if(!(!i&&!a))return{provider:"aws",region:i,instance_id:a}}async function qr(e){let t=await fetch("http://metadata.google.internal/computeMetadata/v1/instance/?recursive=true",{headers:{"Metadata-Flavor":"Google"},signal:AbortSignal.timeout(e)}).catch(()=>{});if(!t?.ok)return;let n=await t.json(),r=typeof n.zone=="string"?n.zone.split("/").pop()??"":"",o=n.id===void 0?"":String(n.id);if(!(!r&&!o))return{provider:"gcp",region:r,instance_id:o}}async function eo(e){let t=await fetch("http://169.254.169.254/metadata/instance?api-version=2021-02-01",{headers:{Metadata:"true"},signal:AbortSignal.timeout(e)}).catch(()=>{});if(!t?.ok)return;let n=await t.json(),r=n.compute?.location??"",o=n.compute?.vmId??"";if(!(!r&&!o))return{provider:"azure",region:r,instance_id:o}}async function to(e){let t=await Promise.allSettled([Qr(e),qr(e),eo(e)]);for(let n of t)if(n.status==="fulfilled"&&n.value)return n.value;return null}async function Ke(e,t){if(e==="interactive")return null;let n=t?.home??on(),r=t?.timeoutMs??1e3,o=t?.nowMs??Date.now(),s=Jr(n),i=Yr(s);if(Zr(i,e,o))return i.result;let a=await to(r);return Xr(s,{context:e,probed_at:o,result:a}),a}import{existsSync as no}from"node:fs";import{homedir as ro}from"node:os";import{join as je}from"node:path";function Ve(e,t,n){if(!no(e))return;let r=W(e,{});for(let o of Object.keys(r.mcpServers??{}))n.set(o,{name:o,source:t})}async function ze(e,t=process.cwd(),n="claude",r=ro()){let o=new Map;for(let s of e.mcp_servers??[])s.name&&o.set(s.name,{name:s.name,source:"manifest"});return n==="claude"&&Ve(je(r,".claude.json"),"claude_json_user",o),Ve(je(t,".mcp.json"),"mcp_json",o),Ve(je(t,".cursor/mcp.json"),"cursor_mcp",o),[...o.values()]}var oo=["CI","GITHUB_ACTIONS","GITLAB_CI","CIRCLECI","BUILDKITE","TF_BUILD","JENKINS_URL","JENKINS_HOME","CODEBUILD_BUILD_ID","DRONE","DRONE_BUILD_NUMBER","TEAMCITY_VERSION","TRAVIS","APPVEYOR","BITBUCKET_BUILD_NUMBER","KUBERNETES_SERVICE_HOST","REMOTE_CONTAINERS","DEVCONTAINER","GITHUB_REPOSITORY","GITHUB_REPOSITORY_ID","GITHUB_REF","GITHUB_SHA","GITHUB_RUN_ID","GITHUB_WORKFLOW","GITHUB_ACTOR","GITHUB_TRIGGERING_ACTOR","GITHUB_ACTOR_ID","GITHUB_USER","GITLAB_USER_LOGIN","GITLAB_USER_NAME","GITLAB_USER_EMAIL","BUILD_REQUESTEDFOR","BUILD_REQUESTEDFOREMAIL","BUILDKITE_BUILD_CREATOR","BUILDKITE_BUILD_CREATOR_EMAIL","BUILD_USER","BUILD_USER_ID","BUILD_USER_EMAIL","CHANGE_AUTHOR","CHANGE_AUTHOR_EMAIL","CIRCLE_USERNAME","CODEBUILD_INITIATOR","DRONE_COMMIT_AUTHOR","DRONE_COMMIT_AUTHOR_NAME","DRONE_COMMIT_AUTHOR_EMAIL","EV_AI_HOOK_OPERATOR_NAME","EV_AI_HOOK_OPERATOR_EMAIL","GIT_AUTHOR_NAME","GIT_AUTHOR_EMAIL","GIT_COMMITTER_NAME","GIT_COMMITTER_EMAIL","EMAIL","RUNNER_OS","RUNNER_ARCH","NODE_ENV","TERM_PROGRAM","CLAUDE_CODE_REMOTE","CLAUDE_CODE_REMOTE_SESSION_ID","CURSOR_AGENT","CODESPACES","CODESPACE_NAME","ANTHROPIC_BASE_URL","OPENAI_BASE_URL","OPENAI_API_BASE","AZURE_OPENAI_ENDPOINT","GOOGLE_GEMINI_BASE_URL","GEMINI_API_BASE","CLAUDE_CODE_USE_BEDROCK","CLAUDE_CODE_USE_VERTEX"],so=new Set(["key","api-key","api_key","apikey","token","sig","signature","access_token","password","pwd","secret","client_secret"]);function io(e){try{let t=new URL(e);(t.username||t.password)&&(t.username="",t.password="");for(let[n]of t.searchParams)so.has(n.toLowerCase())&&t.searchParams.set(n,"[redacted]");return t.toString()}catch{return e}}function We(e=process.env){return oo.map(t=>Object.prototype.hasOwnProperty.call(e,t)?{name:t,present:!0,value:io(e[t]??"")}:{name:t,present:!1})}import{createHash as ao}from"node:crypto";function I(e){return ao("sha256").update(e).digest("hex").slice(0,16)}function P(e,t){return`${e}\0${t}`}function sn(e){let t=e.indexOf("\0");return t<=0?null:{path:e.slice(0,t),name:e.slice(t+1)}}function Je(e){let n=[...e].sort((r,o)=>{let s=r.path.localeCompare(o.path);return s!==0?s:r.name.localeCompare(o.name)}).map(r=>`${r.path}|${r.name}|${r.content_hash}`).join(`
|
|
8
|
+
`);return I(n)}function co(e,t,n="git_config",r=null){return I(`${e??""}|${t??""}|${r??""}|${n}`)}function lo(e){let t=null,n=null;for(let r of e.split(`
|
|
9
|
+
`)){let o=r.trim();if(!o)continue;let s=o.indexOf(" ");if(s<=0)continue;let i=o.slice(0,s).toLowerCase(),a=o.slice(s+1).trim();a&&(i==="user.name"?t=a:i==="user.email"&&(n=a))}return{git_user_name:t,git_user_email:n,platform_login:null}}async function uo(e,t=R){let n=await t("git",["config","--get-regexp","^user\\.(name|email)$"],2e3,{cwd:e});return lo(n)}function po(e=process.env){let t=_(e.GIT_AUTHOR_NAME),n=_(e.GIT_AUTHOR_EMAIL);if(t||n)return{git_user_name:t,git_user_email:n,platform_login:null,identity_source:"git_env"};let r=_(e.GIT_COMMITTER_NAME),o=_(e.GIT_COMMITTER_EMAIL);if(r||o)return{git_user_name:r,git_user_email:o,platform_login:null,identity_source:"git_env"};let s=_(e.EMAIL);return s?{git_user_name:null,git_user_email:s,platform_login:null,identity_source:"git_env"}:null}async function fo(e,t=R){let n=await t("git",["log","-1","--format=%an%x00%ae"],2e3,{cwd:e});if(!n)return null;let r=n.indexOf("\0"),o=(r>=0?n.slice(0,r):n).trim(),s=(r>=0?n.slice(r+1):"").trim();return!o&&!s?null:{git_user_name:o||null,git_user_email:s||null,platform_login:null,identity_source:"git_log"}}function D(e,t,n,r=null){return!e&&!t&&!r?null:{git_user_name:e,git_user_email:t,platform_login:r,identity_source:n}}function mo(e=process.env){let t=D(_(e.EV_AI_HOOK_OPERATOR_NAME),_(e.EV_AI_HOOK_OPERATOR_EMAIL),"configured");if(t)return t;let n=_(e.GITHUB_ACTOR)??_(e.GITHUB_TRIGGERING_ACTOR)??_(e.GITHUB_USER),r=D(n,null,"github",n);if(r)return r;let o=_(e.GITLAB_USER_LOGIN),s=D(_(e.GITLAB_USER_NAME)??o,_(e.GITLAB_USER_EMAIL),"gitlab",o);if(s)return s;let i=D(_(e.BUILD_REQUESTEDFOR),_(e.BUILD_REQUESTEDFOREMAIL),"azure_devops");if(i)return i;let a=D(_(e.BUILDKITE_BUILD_CREATOR),_(e.BUILDKITE_BUILD_CREATOR_EMAIL),"buildkite");if(a)return a;let c=D(_(e.BUILD_USER)??_(e.CHANGE_AUTHOR),_(e.BUILD_USER_EMAIL)??_(e.CHANGE_AUTHOR_EMAIL),"jenkins",_(e.BUILD_USER_ID));if(c)return c;let l=_(e.CIRCLE_USERNAME),u=D(l,null,"circleci",l);if(u)return u;let d=_(e.CODEBUILD_INITIATOR),g=D(d,null,"codebuild",d);if(g)return g;let f=D(_(e.DRONE_COMMIT_AUTHOR)??_(e.DRONE_COMMIT_AUTHOR_NAME),_(e.DRONE_COMMIT_AUTHOR_EMAIL),"drone",_(e.DRONE_COMMIT_AUTHOR));return f||(an(e.CLAUDE_CODE_REMOTE)||an(e.CURSOR_AGENT)?{git_user_name:null,git_user_email:null,platform_login:null,identity_source:"cloud"}:null)}function Ye(e){return!!((e.git_user_name??e.git_user_email)&&!ho(e.git_user_name,e.git_user_email))}function _(e){if(e===void 0)return null;let t=e.trim();return t.length>0?t:null}function an(e){if(e===void 0||e==="")return!1;let t=e.trim().toLowerCase();return t!=="0"&&t!=="false"&&t!=="no"}var go=new Set(["action@github.com","noreply@github.com","noreply@anthropic.com","cursoragent@cursor.com"]),_o=new Set(["github-actions","github actions","dependabot","renovate","cursoragent","cursor agent"]);function ho(e,t){let n=(e??"").trim().toLowerCase(),r=(t??"").trim().toLowerCase();if(!n&&!r)return!1;if(n.includes("[bot]")||_o.has(n)||r.includes("[bot]")||go.has(r))return!0;if(r.endsWith("@users.noreply.github.com")){let o=r.slice(0,r.indexOf("@")),s=o.includes("+")?o.slice(o.indexOf("+")+1):o;if(s.endsWith("bot")||s.includes("[bot]"))return!0}return!1}async function Eo(e,t=R,n=process.env){let r=await uo(e,t);if(Ye(r))return{...r,identity_source:"git_config"};let o=po(n);if(o&&Ye(o))return o;let s=mo(n);if(s&&(s.git_user_name||s.git_user_email||s.platform_login))return s;let i=await fo(e,t);return i&&Ye(i)?i:s||(r.git_user_name||r.git_user_email?{...r,identity_source:"git_config"}:o||i||{git_user_name:null,git_user_email:null,platform_login:null,identity_source:"git_config"})}async function ge(e){let{gitRoot:t,installationStorePath:n,forceResend:r}=e,o=e.exec??R,s=e.env??process.env,i=await Eo(t,o,s),a=co(i.git_user_name,i.git_user_email,i.identity_source,i.platform_login),l=(n?He(n):void 0)?.operator_identity_hash;if(!(r||l!==void 0&&l!==a||!l))return{commit:()=>{}};let f=n;return{operator:i,commit:()=>{f&&Xt(f,a,de())}}}function Xe(e){return e?!He(e)?.operator_identity_hash:!0}function cn(e){return!0}import{existsSync as $o,readFileSync as Go}from"node:fs";import{homedir as An}from"node:os";import{join as w}from"node:path";import{basename as Fo,join as J}from"node:path";import{existsSync as ln,readdirSync as So}from"node:fs";import{basename as yo,dirname as Io,relative as Ro}from"node:path";var _e=class{constructor(t){this.home=t}components=[];truncated=!1;pluginExpandRemaining;homeRel(t){let n=Ro(this.home,t).replace(/\\/g,"/");if(!n||n.startsWith("..")){let r=Io(t);return`external/${I(r)}/${yo(t)}`}return n}get atGlobalCap(){return this.truncated||this.components.length>=G}get pluginBudgetSpent(){return this.pluginExpandRemaining!==void 0&&this.pluginExpandRemaining<=0}readEntries(t){if(!ln(t))return[];try{return So(t,{withFileTypes:!0})}catch{return[]}}readJson(t,n){if(ln(t))return W(t,n)}push(t){return this.components.length>=G?(this.truncated=!0,!1):this.pluginExpandRemaining!==void 0&&this.pluginExpandRemaining<=0?!1:(this.pluginExpandRemaining!==void 0&&(this.pluginExpandRemaining-=1),this.components.push(t),!0)}withPluginExpandCap(t,n){let r=this.pluginExpandRemaining;this.pluginExpandRemaining=t;try{let o=n(),s=t-(this.pluginExpandRemaining??0);return{result:o,expanded:s}}finally{this.pluginExpandRemaining=r}}};import{existsSync as Ze,readFileSync as Co,statSync as To}from"node:fs";import{basename as dn,join as re,relative as pn}from"node:path";var Qe=2e4,Ao=4;function ko(e){return e.length<=Qe?e:`${e.slice(0,Qe-1)}\u2026`}function Oo(e){try{let t=Co(e),n=t.toString("utf8");return{hash:I(t),length:t.length,text:ko(n)}}catch{return null}}var un={HOOK:"EVENT",COMMAND:"EXPLICIT_INVOCATION",MEMORY:void 0,MCP_SERVER:void 0,PLUGIN:void 0,SKILL:"UNSPECIFIED",RULE:"UNSPECIFIED",SUBAGENT:"UNSPECIFIED"};function xo(e){return e in un?un[e]:"UNSPECIFIED"}function he(e,t){let n=Oo(t.absolutePath);if(!n)return!1;let r=t.name??dn(t.absolutePath).replace(/\.(md|mdc|toml)$/i,""),o={kind:t.kind,name:r,path:e.homeRel(t.absolutePath),text:n.text,content_hash:n.hash,content_length:n.length,origin:t.origin,enabled:t.enabled},s=xo(t.kind);return s&&(o.trigger=s),e.push(o)}function Uo(e,t,n){let r=pn(e,t).replace(/\\/g,"/");return!r||r.startsWith("..")?dn(t).replace(/\.(md|mdc|toml)$/i,""):n?r.replace(/\.(md|mdc|toml)$/i,""):r}function j(e,t){let{dir:n,kind:r,origin:o,enabled:s,nested:i,extensions:a}=t;qe(e,{walkRoot:n,currentDir:n,depth:0,kind:r,origin:o,enabled:s,nested:i,extensions:a})}function qe(e,t){let{walkRoot:n,currentDir:r,depth:o,kind:s,origin:i,enabled:a,nested:c,extensions:l}=t;if(!(o>Ao))for(let u of e.readEntries(r)){if(e.atGlobalCap){e.truncated=!0;return}if(e.pluginBudgetSpent)return;if(c){if(!u.isDirectory())continue;let f=re(r,u.name,c);if(Ze(f)){let h=pn(n,re(r,u.name)).replace(/\\/g,"/");he(e,{absolutePath:f,kind:s,origin:i,enabled:a,name:h||u.name});continue}qe(e,{walkRoot:n,currentDir:re(r,u.name),depth:o+1,kind:s,origin:i,enabled:a,nested:c,extensions:l});continue}if(u.isDirectory()){qe(e,{walkRoot:n,currentDir:re(r,u.name),depth:o+1,kind:s,origin:i,enabled:a,nested:c,extensions:l});continue}if(!u.isFile()||!l)continue;let d=u.name.toLowerCase();if(!l.some(f=>d.endsWith(f)))continue;let g=re(r,u.name);he(e,{absolutePath:g,kind:s,origin:i,enabled:a,name:Uo(n,g,!0)})}}function fn(e){for(let t of e)if(Ze(t))try{if(To(t).size>0)return t}catch{continue}return e.find(t=>Ze(t))}function bo(e){if(e.prompt||e.type==="prompt")return"prompt";let t=e.command??e.bash??e.powershell??"";return/\bnpx\b/i.test(t)?"npx":/\.(sh|bash|zsh|js|mjs|cjs|ts|py)(\s|$|"|')/i.test(t)||/^(\.\/|~\/|\/|[A-Za-z]:[\\/])/.test(t.trim())?"script":"inline"}function wo(e){return Array.isArray(e.hooks)&&e.hooks.length>0?e.hooks:[{type:e.type,command:e.command,bash:e.bash,powershell:e.powershell,prompt:e.prompt}]}function No(e,t,n,r){let o=e.homeRel(t);for(let[s,i]of Object.entries(n))if(!(!Array.isArray(i)||e.truncated))for(let a of i){if(!a||typeof a!="object"||e.truncated)continue;let c=a;for(let l of wo(c)){if(e.truncated)return;let u=l.command??l.bash??l.prompt??l.powershell??c.powershell??"",d=bo({type:l.type??c.type,command:l.command??c.command,bash:l.bash??c.bash,powershell:l.powershell??c.powershell,prompt:l.prompt??c.prompt}),g=typeof c.matcher=="string"?c.matcher:"",f=I(u),h=g?`${s}:${g}:${d}:${f}`:`${s}:${d}:${f}`,x=`${s}|${g}|${d}|${u}`;e.push({kind:"HOOK",name:h,path:o,content_hash:I(x),origin:r,enabled:!0,trigger:"EVENT",attributes:{event:s,...g?{matcher:g}:{},action_kind:d,action_hash:f}})}}}function oe(e,t,n){let r=e.readJson(t,{});!r?.hooks||typeof r.hooks!="object"||No(e,t,r.hooks,n)}var mn={claude:{skillRoots:[".claude/skills"],dirs:[{dir:".claude/agents",kind:"SUBAGENT",extensions:[".md"]},{dir:".claude/commands",kind:"COMMAND",extensions:[".md"]}],memory:[".claude/CLAUDE.md"],hooks:[".claude/settings.json"],mcpJson:[".claude.json"],plugins:"claude"},cursor:{skillRoots:[".cursor/skills",".cursor/skills-cursor"],dirs:[{dir:".cursor/agents",kind:"SUBAGENT",extensions:[".md"]},{dir:".cursor/commands",kind:"COMMAND",extensions:[".md"]},{dir:".cursor/rules",kind:"RULE",extensions:[".mdc",".md"]}],memory:[".cursor/AGENTS.md"],hooks:[".cursor/hooks.json"],mcpJson:[".cursor/mcp.json"],plugins:"cursor"},codex:{skillRoots:[".agents/skills",".codex/skills"],dirs:[{dir:".codex/agents",kind:"SUBAGENT",extensions:[".toml",".md"]},{dir:".codex/prompts",kind:"COMMAND",extensions:[".md"]}],memory:[".codex/AGENTS.override.md",".codex/AGENTS.md"],hooks:[".codex/hooks.json"],mcpToml:[".codex/config.toml"]}};import{existsSync as vo,readFileSync as Mo}from"node:fs";function Lo(e){if(!e||typeof e!="object"||Array.isArray(e))return"unknown";let t=e;return typeof t.type=="string"&&t.type.length>0?t.type:typeof t.url=="string"?"http":typeof t.command=="string"?"stdio":"unknown"}function gn(e,t,n){let o=e.readJson(t,{})?.mcpServers;if(!o||typeof o!="object")return;let s=e.homeRel(t);for(let[i,a]of Object.entries(o)){if(e.truncated)return;let c=Lo(a);e.push({kind:"MCP_SERVER",name:i,path:s,content_hash:I(`${i}|${c}`),origin:n,enabled:!0,attributes:{transport:c}})}}function _n(e,t,n){if(!vo(t))return;let r;try{r=Mo(t,"utf8")}catch{return}let o=e.homeRel(t),s=/^\[mcp_servers(?:\.(\w+)|\."([^"]+)"|\.'([^']+)')\]\s*$/gm,i;for(;(i=s.exec(r))!==null;){if(e.truncated)return;let a=i[1]??i[2]??i[3];if(!a)continue;let c=r.slice(i.index+i[0].length),l=c.search(/^\[/m),u=l===-1?c:c.slice(0,l),d="unknown";/^\s*url\s*=/m.test(u)?d="http":/^\s*command\s*=/m.test(u)&&(d="stdio"),e.push({kind:"MCP_SERVER",name:a,path:o,content_hash:I(`${a}|${d}`),origin:n,enabled:!0,attributes:{transport:d}})}}import{existsSync as Po,readdirSync as Do}from"node:fs";import{join as T}from"node:path";var hn=50;function et(e,t,n,r){if(!Po(t))return{componentCount:0,expandTruncated:!1};let o=e.components.length,{expanded:s}=e.withPluginExpandCap(hn,()=>{j(e,{dir:T(t,"skills"),kind:"SKILL",origin:n,enabled:r,nested:"SKILL.md"}),j(e,{dir:T(t,"commands"),kind:"COMMAND",origin:n,enabled:r,extensions:[".md"]}),j(e,{dir:T(t,"agents"),kind:"SUBAGENT",origin:n,enabled:r,extensions:[".md"]})});oe(e,T(t,"hooks","hooks.json"),n),oe(e,T(t,"hooks.json"),n);let i=e.components.length-o,a=s>=hn;return{componentCount:i,expandTruncated:a}}function tt(e,t){e.push({kind:"PLUGIN",name:t.pluginKey,path:t.rowPath,content_hash:t.contentHash,origin:"user",enabled:t.enabled,attributes:{...t.marketplace?{marketplace:t.marketplace}:{},...t.version?{version:t.version}:{},scope:t.scope,component_count:t.componentCount,...t.expandTruncated?{expand_truncated:!0}:{}}})}function En(e){let t=T(e.home,".claude/plugins/installed_plugins.json"),n=e.readJson(t,{});if(!n)return;let r=n.plugins??{},s=e.readJson(T(e.home,".claude/settings.json"),{})?.enabledPlugins??{},i=e.homeRel(t);for(let[a,c]of Object.entries(r)){if(e.truncated)return;let l=Array.isArray(c)?c:[c],u=l[0]??{},d=s[a]===!0,g=a.includes("@")?a.split("@").slice(1).join("@"):"",f=typeof u.version=="string"?u.version:"",h=typeof u.scope=="string"?u.scope:"user",x=`plugin:${a}`,v=0,C=!1;for(let U of l)if(typeof U.installPath=="string"&&U.installPath.length>0){let F=et(e,U.installPath,x,d);v+=F.componentCount,C=C||F.expandTruncated}tt(e,{pluginKey:a,rowPath:i,enabled:d,scope:h,version:f||void 0,marketplace:g||void 0,componentCount:v,expandTruncated:C,contentHash:I(`${a}|${f}|${h}|${d}|${v}`)})}}function Ho(e){let t=e,n="";try{let r=Do(e,{withFileTypes:!0}).filter(o=>o.isDirectory()).map(o=>o.name);if(r.length===1&&r[0])t=T(e,r[0]),n=r[0];else if(r.length>1){let o=[...r].sort(),s=o[o.length-1];s&&(t=T(e,s),n=s)}}catch{}return{installPath:t,version:n}}function Sn(e){let t=[{base:T(e.home,".cursor/plugins/local"),scope:"local"},{base:T(e.home,".cursor/plugins/cache"),scope:"cache"}];for(let{base:n,scope:r}of t)if(!e.truncated)for(let o of e.readEntries(n)){if(!o.isDirectory()||e.truncated)continue;if(r==="local"){let i=o.name,a=T(n,o.name),c=`plugin:${i}`,{componentCount:l,expandTruncated:u}=et(e,a,c,!0);tt(e,{pluginKey:i,rowPath:e.homeRel(a),enabled:!0,scope:"local",componentCount:l,expandTruncated:u,contentHash:I(`${i}|local|${l}`)});continue}let s=o.name;for(let i of e.readEntries(T(n,s))){if(!i.isDirectory()||e.truncated)continue;let a=T(n,s,i.name),{installPath:c,version:l}=Ho(a),u=`${i.name}@${s}`,d=`plugin:${u}`,{componentCount:g,expandTruncated:f}=et(e,c,d,!0);tt(e,{pluginKey:u,rowPath:e.homeRel(c),enabled:!0,scope:"cache",version:l||void 0,marketplace:s,componentCount:g,expandTruncated:f,contentHash:I(`${u}|${l}|${g}`)})}}}function nt(e,t){let n=mn[e],r=new _e(t),o="user";if(!n)return{components:[],truncated:!1};for(let i of n.skillRoots)j(r,{dir:J(t,i),kind:"SKILL",origin:o,enabled:!0,nested:"SKILL.md"});for(let i of n.dirs)j(r,{dir:J(t,i.dir),kind:i.kind,origin:o,enabled:!0,extensions:i.extensions});let s=fn(n.memory.map(i=>J(t,i)));s&&he(r,{absolutePath:s,kind:"MEMORY",origin:o,enabled:!0,name:Fo(s)});for(let i of n.hooks)oe(r,J(t,i),o);for(let i of n.mcpJson??[])gn(r,J(t,i),o);for(let i of n.mcpToml??[])_n(r,J(t,i),o);return n.plugins==="claude"?En(r):n.plugins==="cursor"&&Sn(r),{components:r.components,truncated:r.truncated}}function rt(e,t,n={}){let r=n.truncated===!0,o=Je(e),s=new Set(e.map(u=>P(u.path,u.name)));if(n.forceFull===!0||t===void 0)return{hash:o,count:e.length,truncated:r,full:!0,upserts:e,removed:[],unchanged:!1};let a=[],c=t;for(let u of e){let d=P(u.path,u.name);c[d]!==u.content_hash&&a.push(u)}let l=[];if(!r){for(let u of Object.keys(c))if(!s.has(u)){let d=sn(u);d&&l.push(d)}}return{hash:o,count:e.length,truncated:r,full:!1,upserts:a,removed:l,unchanged:a.length===0&&l.length===0}}var In=3e5,Bo=new Set(["HOOK","MCP_SERVER","PLUGIN"]);function ot(e,t,n){let r=new Set(t.map(s=>P(s.path,s.name))),o=[];for(let s of e)s.text!==void 0&&(n.has(s.content_hash)||r.has(P(s.path,s.name))||o.push(s));return o}function st(e,t,n){let r=new Set(e);for(let s of t)r.add(s);let o=new Set(n.map(s=>s.content_hash));return[...r].filter(s=>o.has(s))}function yn(e){return Buffer.byteLength(JSON.stringify(e),"utf8")}function Rn(e){if(e.text===void 0)return e;let{text:t,...n}=e;return n}function it(e,t=In){let n=[],r=[];for(let u of e)Bo.has(u.kind)?n.push(u):r.push(u);r.sort((u,d)=>(u.text?.length??0)-(d.text?.length??0));let o=[...n,...r],s=[],i=2,a=0,c=0,l=[];for(let u of o){let d=s.length>0?1:0,g=yn(u)+d;if(i+g<=t){s.push(u),i+=g,u.text!==void 0&&l.push(u.content_hash);continue}if(u.text!==void 0){let f=Rn(u),h=yn(f)+d;if(i+h<=t){s.push(f),i+=h,a+=1;continue}}c+=1}return{components:s,textDeferredCount:a,droppedCount:c,textHashesSent:l}}function at(e,t){return t.size===0?e:e.map(n=>n.text===void 0||!t.has(n.content_hash)?n:Rn(n))}var Ko={claude:{skills:".claude/skills",subagents:".claude/agents",commands:".claude/commands",memory:".claude/CLAUDE.md",settings:".claude/settings.json"},cursor:{skills:[".cursor/skills",".cursor/skills-cursor"],subagents:".cursor/agents",commands:".cursor/commands",rules:".cursor/rules",mcp:".cursor/mcp.json"},codex:{skills:[".agents/skills",".codex/skills"],subagents:".codex/agents",commands:".codex/prompts",memory:".codex/AGENTS.md",settings:".codex/config.toml"}},jo=200,Cn=200,Vo=["allow","deny","ask"],zo=/(?<=^|[\s(,=:])(?:~|[A-Za-z]:)?[\\/][^\s,)]+/g,ct="<path>",Wo=new RegExp(`${ct}(?:\\s+[A-Za-z.][^\\s,)]*[\\\\/][^\\s,)]*)+`,"g");function Jo(e){let t=e.replace(zo,ct).replace(Wo,ct);return t.length>Cn?`${t.slice(0,Cn)}...`:t}function Tn(e){let t=W(e,{}),n=[];for(let r of Vo)for(let o of t.permissions?.[r]??[])typeof o=="string"&&o.length>0&&n.push({key:Jo(o),mode:r});return{model:t.model??"",permissionKeys:n}}var Yo=10,Xo=840*60*1e3,Zo="self-config-cache.json";function lt(){return E("EV_AI_HOOK_USER_SPEC")?.toLowerCase()==="off"}function Qo(e,t=Date.now()){return e===void 0||!Number.isFinite(e)?!0:t-e>=Xo}var qo={claude:["claude"],cursor:["agent","cursor-agent"],codex:["codex"]};async function es(e,t=R){let n=qo[e];if(!n||n.length===0)return null;let r=async o=>{let s=n[o];if(s===void 0)return null;let a=((await t(s,["--version"],2e3)).split(`
|
|
10
|
+
`)[0]??"").trim();return a||r(o+1)};return r(0)}function ts(e=An()){return w(e,".ev-ai","agent-hook",Zo)}function ns(e){let n=[...e].sort((r,o)=>r.name.localeCompare(o.name)).map(r=>`${r.name}:${r.size}`).join(`
|
|
11
|
+
`);return I(n)}function Ee(e,t,n=!1){let r=ns(e),o=e.length;return t===r?n?{hash:r,count:o,truncated:n}:{hash:r,count:o}:n?{hash:r,count:o,entries:e,truncated:n}:{hash:r,count:o,entries:e}}function rs(e){return $o(e)?O(Go(e,"utf8"),{}):{}}function os(e,t){try{B(e,`${JSON.stringify(t)}
|
|
12
|
+
`)}catch(n){let r=n instanceof Error?n.message:String(n);m(`WARN: self-config cache write failed open: ${r}`)}}function ss(e,t,n,r){let o={...e,send_count:n};for(let s of Object.keys(t)){let i=t[s];i.entries!==void 0&&(o[s]=i.hash)}return r&&(o.user_spec_collected_at_ms=r.collectedAtMs,r.included&&(o.user_spec=r.hash,o.user_spec_components=r.componentHashes),o.user_spec_text_hashes=r.textHashes),o}async function kn(e,t=process.cwd(),n=An(),r={}){let o=e==="claude",s=r.gitRoot??t,i=await es(e),a="",c=[];if(o){let b=Tn(w(n,".claude/settings.json")),M=Tn(w(t,".claude/settings.local.json"));a=M.model||b.model,c=[...b.permissionKeys,...M.permissionKeys].slice(0,jo)}let l=Ko[e]??{},u={present:!1,size:0},d=b=>{let M=Array.isArray(b)?b:b?[b]:[],S=[],H=!1;for(let Ae of M){let k=q(w(n,Ae));if(S=S.concat(k.entries),H=H||k.truncated,S.length>=G){S=S.slice(0,G),H=!0;break}}return{entries:S,truncated:H}},g=ts(n),f=rs(g),h=f[e]??{},x=(h.send_count??0)+1,v=x>0&&x%Yo===0,C=b=>v?void 0:h[b],U=d(l.skills),F=l.subagents?q(w(n,l.subagents)):{entries:[],truncated:!1},Te=l.commands?q(w(n,l.commands)):{entries:[],truncated:!1},yt=l.rules?q(w(n,l.rules)):{entries:[],truncated:!1},Z={skills:Ee(U.entries,C("skills"),U.truncated),subagents:Ee(F.entries,C("subagents"),F.truncated),commands:Ee(Te.entries,C("commands"),Te.truncated),rules:Ee(yt.entries,C("rules"),yt.truncated)},A={runner_platform:e,config_scope:"user",cli_version:i,claude_version:o?i:null,model:o&&a||null,permission_keys:c,user_scope:{skills:Z.skills,subagents:Z.subagents,commands:Z.commands,rules:Z.rules,memory:l.memory?ee(w(n,l.memory)):u,settings:l.settings?ee(w(n,l.settings)):u,mcp:l.mcp?ee(w(n,l.mcp)):u},local_settings:o?ee(w(t,".claude/settings.local.json")):u},It=null,Rt=()=>{},Ct=r.nowMs??Date.now();if(!lt()&&Qo(h.user_spec_collected_at_ms,Ct)){let b=h.user_spec_collected_at_ms!==void 0,M=nt(e,n),S=rt(M.components,h.user_spec_components,{forceFull:!h.user_spec_components,truncated:M.truncated}),H=new Set(h.user_spec_text_hashes??[]),Ae=ot(M.components,S.upserts,H),k=it(at([...S.upserts,...Ae],H));A.user_spec_hash=S.hash,A.user_spec_count=S.count,A.user_spec_truncated=S.truncated||k.droppedCount>0,(k.components.length>0||S.removed.length>0||S.full)&&(S.full&&(A.user_spec_full=!0),k.components.length>0&&(A.user_spec=k.components),S.removed.length>0&&!A.user_spec_truncated&&(A.user_spec_removed=S.removed),k.textDeferredCount>0&&(A.user_spec_text_deferred=k.textDeferredCount));let ke=S.full?{}:{...h.user_spec_components??{}};if(!A.user_spec_truncated)for(let z of S.removed)delete ke[P(z.path,z.name)];for(let z of k.components)ke[P(z.path,z.name)]=z.content_hash;It={hash:S.hash,componentHashes:ke,textHashes:st(H,k.textHashesSent,M.components),included:k.components.length>0||S.removed.length>0&&!A.user_spec_truncated||S.full,collectedAtMs:Ct};let Oe=await ge({gitRoot:s,installationStorePath:r.installationStorePath,forceResend:b});Oe.operator&&(A.operator=Oe.operator),Rt=Oe.commit}let ur=ss(h,Z,x,It);return{config:A,commit:()=>{f[e]=ur,os(g,f),Rt()}}}function Y(e,t,n){let r={installation_id:n.installationId};return n.platformAgentId&&(r.platform_agent_id=n.platformAgentId),n.sessionId&&(r.session_id=n.sessionId),n.turnId&&(r.turn_id=n.turnId),{schema_version:2,event:e,timestamp:de(),session_id:n.sessionId||null,turn_id:n.turnId||null,installation_id:n.installationId,platform:n.runnerPlatform,platform_agent_id:n.platformAgentId||null,runner_event:n.runnerEvent||null,agent_hook_version:be,host_arch:process.arch,node_version:process.version,correlation:r,payload:t}}import{existsSync as zn}from"node:fs";import{spawn as Wn}from"node:child_process";import{basename as Ns}from"node:path";import{fileURLToPath as vs}from"node:url";var is=new Set(["localhost","127.0.0.1","[::1]","::1"]),On=/^[A-Za-z0-9._~-]+$/;function xn(e){for(let t=0;t<e.length;t++){let n=e.charCodeAt(t);if(n<=32||n===127||n===39)return!0}return!1}function Se(e){try{let t=new URL(e);return t.protocol==="https:"?!0:t.protocol==="http:"?is.has(t.hostname):!1}catch{return!1}}function Un(e){let t;try{t=new URL(e)}catch{return`invalid URL (got: ${e})`}if(!Se(e))return`must be https (or http on localhost / 127.0.0.1 / ::1) (got: ${e})`;let n=as(e);if(!n)return`must end with /{orgToken}/hook (got: ${e})`;if(!On.test(n))return`org token must match ${On.source} (got: ${n})`;if(xn(e))return`must not contain whitespace, control characters, or single quotes (got: ${e})`;if(xn(t.pathname))return`pathname must not contain whitespace, control characters, or single quotes (got: ${e})`}function bn(e){return new URL(e).toString()}function as(e){try{let n=new URL(e).pathname.split("/").filter(r=>r.length>0);if(n.length>=2&&n[n.length-1]==="hook"){let r=n[n.length-2];return r.length>0?r:void 0}return}catch{return}}function dt(e){try{let t=new URL(e),n=t.pathname.split("/").filter(r=>r.length>0);return n.length>=2&&n[n.length-1]==="hook"&&(n[n.length-2]="***",t.pathname=`/${n.join("/")}`),t.toString()}catch{return"<invalid-url>"}}function wn(e){if(e.collector_url)return e.collector_url;let t=e.repo_ingest_token?.trim();return t?le(t):""}var Nn=/(?:^|\/|[\s"'=(])(?:\.cursor\/|\.claude\/|\.agents\/)skills(?:-cursor)?\/([^/]+)\/SKILL\.md/i,vn=/(?:^|\/|[\s"'=(])\.codex\/commands\/([^/]+)\.md\b/i,cs=/(?:^|\s)\/([a-z][a-z0-9-]{1,63})\b/gi,ls=new Set(["applications","app","bin","boot","data","dev","etc","home","lib","media","mnt","node_modules","opt","pkg","private","proc","projects","repos","run","sbin","src","srv","sys","tmp","usr","users","var","volumes","workspace","workspaces"]),us=new Set(["read","read_file","view"]),ds=new Set(["bash","shell","zsh"]);function ps(e){let t=e.replace(/\\/g,"/");return Nn.exec(t)?.[1]??null}function fs(e){let t=e.replace(/\\/g,"/"),r=vn.exec(t)?.[1];return r?r.toLowerCase():null}function ms(e){return ps(e)??fs(e)}function gs(e){for(let t of["path","file_path","target_file"]){let n=e[t];if(typeof n=="string"&&n.length>0)return n}return null}function Mn(e){if(typeof e=="string")try{let t=JSON.parse(e);return Mn(t)}catch{return null}return!e||typeof e!="object"?null:gs(e)}function _s(e){if(!e||typeof e!="object")return null;let t=e.command;return typeof t=="string"&&t.length>0?t:null}function hs(e){let t=e.replace(/\\/g,"/"),n=Nn.exec(t);if(n?.[1])return n[1];let o=vn.exec(t)?.[1];return o?o.toLowerCase():null}function Es(e){return typeof e.tool_name=="string"?e.tool_name:typeof e.tool=="string"?e.tool:""}function Ln(e){let t=Es(e).toLowerCase();if(us.has(t)){let n=Mn(e.tool_input);return n?ms(n):null}if(ds.has(t)){let n=_s(e.tool_input);return n?hs(n):null}return null}function Ss(e){let t=new Set,n=[];for(let r of e.matchAll(cs)){let o=r[1]?.toLowerCase();!o||t.has(o)||ls.has(o)||(t.add(o),n.push(o))}return n}function ys(e){return Q(e.prompt)}function Pn(e){let t=p(e,"command_name");if(t){let r=p(e,"expansion_type");if(r&&r!=="slash_command")return[];let o=t.replace(/^\//,"").toLowerCase();return o?[o]:[]}let n=ys(e);return n?Ss(n):[]}function pt(e){return e!==void 0&&bt.includes(e)}function ye(e,t){let n=e[t+1];return n&&!n.startsWith("--")?{value:n,next:t+1}:{next:t}}function Ie(e){let t,n,r,o,s;for(let i=0;i<e.length;i++){let a=e[i];if(a!==void 0){if(a==="--runner"){let c=ye(e,i);t=c.value,i=c.next;continue}if(a.startsWith("--runner=")){t=a.slice(9);continue}if(a==="--url"){let c=ye(e,i);c.value&&(r=c.value),i=c.next;continue}if(a.startsWith("--url=")){r=a.slice(6);continue}if(a==="--token"){let c=ye(e,i);c.value&&(o=c.value),i=c.next;continue}if(a.startsWith("--token=")){o=a.slice(8);continue}if(a==="--base-url"){let c=ye(e,i);c.value&&(s=c.value),i=c.next;continue}if(a.startsWith("--base-url=")){s=a.slice(11);continue}!a.startsWith("-")&&n===void 0&&(n=a)}}return{runner:pt(t)?t:void 0,event:n,collectorUrl:r,orgToken:o,baseUrl:s}}function ft(e){let t=e.collectorUrl?.trim(),n;if(t)n=t;else{let o=e.orgToken?.trim();o&&(n=le(o,e.baseUrl?.trim()??void 0))}if(!n)return;let r=Un(n);if(r){m(`WARN: ignoring --url/--token collector override: ${r}`);return}return bn(n)}function Dn(e,t){if(p(e,"conversation_id"))return!0;if(t==="")return!1;let n=t[0];return n?.toLowerCase()===n}function Is(){return!!(E("CURSOR_VERSION")??E("CURSOR_PROJECT_DIR"))}function mt(e,t,n){return e!=="claude"&&e!=="codex"?!1:Dn(t,n)?!0:Is()}function gt(e,t,n,r){if(Dn(e,t))return"cursor";if(pt(r))return r;let o=p(e,"conversation_id"),s=p(e,"turn_id"),i=p(e,"session_id"),a=t.toLowerCase(),c="unknown";return o||t===a&&t!==""?c="cursor":s?c="codex":(i||a==="sessionstart"||a==="sessionend"||a==="stop"||a==="stopfailure"||a==="pretooluse"||a==="posttooluse"||a==="posttoolusefailure"||a==="permissiondenied"||a==="subagentstart"||a==="subagentstop"||a==="userpromptexpansion")&&(c="claude"),pt(n)&&(c=n),c}function Re(e,t){let n=e.toLowerCase();return n==="sessionend"||n==="stopfailure"||n==="subagentstop"?!0:n==="stop"&&t==="codex"}function Rs(e){switch(e){case"sessionstart":return"session_start";case"stop":case"sessionend":case"stopfailure":return"session_end";case"pretooluse":case"posttooluse":case"posttoolusefailure":case"permissiondenied":case"beforemcpexecution":case"beforeshellexecution":case"afterfileedit":case"subagentstart":case"subagentstop":return"tool_invoked";case"beforesubmitprompt":case"userpromptexpansion":case"userpromptsubmit":return"skill_invoked";default:return""}}function Hn(e){let t=e.toLowerCase();return t==="posttooluse"?!0:t==="posttoolusefailure"||t==="permissiondenied"?!1:null}function Fn(e,t,n){let r=p(e,"session_id")||p(e,"conversation_id"),o=p(e,"prompt.id")||p(e,"prompt_id")||p(e,"generation_id")||p(e,"turn_id"),s=p(e,"hook_event_name")||p(e,"event"),i=p(e,"source"),a=gt(e,s,t,n);return{sessionId:r,turnId:o,runnerEvent:s,hookSource:i,runnerPlatform:a}}var Cs=["session_start","session_end","tool_invoked","skill_invoked"];function Ts(e){return Cs.includes(e)}function Bn(e,t){return e&&Ts(e)?e:Rs(t.toLowerCase())}function $n(e){let t=p(e,"tool_name")||p(e,"tool")||null,n=e.tool_input,o=(n&&typeof n=="object"?Q(n.skill)||Q(n.skill_name):"")||p(e,"skill_name")||null;return o??=Ln(e),{toolName:t,skillName:o}}var As=/^[A-Za-z][A-Za-z0-9_.:-]{0,63}$/;function Gn(e){for(let t of["subagent_type","agent_type"]){let n=p(e,t);if(n&&As.test(n))return n}return null}function Kn(e){let t=$(e,"duration_ms");if(typeof t=="number")return t;let n=$(e,"duration");return typeof n=="number"?n:null}var ks="error",Os="interrupted",xs="permission_denied",Us=/^[A-Za-z][A-Za-z0-9_.-]{0,63}$/;function _t(e){return Us.test(e)?e:null}function bs(e){for(let t of["failure_type","error_type"]){let n=_t(p(e,t));if(n)return n}return null}function jn(e,t){return $(e,"is_interrupt")===!0?Os:t.toLowerCase()==="permissiondenied"?xs:bs(e)??ks}function ws(e,t){let n=null;for(let r of t)r&&(e===r||e.startsWith(`${r}_`)||e.startsWith(`${r}-`))&&(n===null||r.length>n.length)&&(n=r);return n}function Vn(e,t=[]){if(!e)return{mcpServer:null,mcpTool:null};let n=/^mcp__(.+?)__(.+)$/i.exec(e);if(n?.[1]&&n[2])return{mcpServer:n[1],mcpTool:n[2]};if(/^MCP:/i.test(e)){let r=e.slice(4);if(!r)return{mcpServer:null,mcpTool:null};let o=r.indexOf(":");return o>0?{mcpServer:r.slice(0,o),mcpTool:r.slice(o+1)||null}:{mcpServer:ws(r,t),mcpTool:r}}return{mcpServer:null,mcpTool:null}}var ht="__post",Ce="__work";function Ms(e,t){let n=e.payload,r=n&&typeof n=="object"&&!Array.isArray(n)?Object.keys(n):[],o=e.correlation&&typeof e.correlation=="object"?Object.keys(e.correlation):[];return JSON.stringify({event:e.event,schema_version:e.schema_version,agent_hook_version:e.agent_hook_version,host_arch:e.host_arch,node_version:e.node_version,build_ms:e.build_ms,body_bytes:t,correlation_keys:o,payload_keys:r})}function Jn(e){switch(e){case"session_start":return At;case"session_end":return kt;case"tool_invoked":case"skill_invoked":return xe;default:return xe}}function Ls(e,t,n){return`${JSON.stringify({url:e,timeoutMs:t})}
|
|
13
|
+
${n}`}function Yn(e,t=[],n=process.execPath,r=import.meta.url,o=zn){if(Ns(n)===ue)return{command:n,args:[e,...t]};let s=vs(r);return o(s)?{command:n,args:[s,e,...t]}:{command:n,args:[e,...t]}}function Ps(e=process.execPath,t=import.meta.url,n=zn){return Yn(ht,[],e,t,n)}function Ds(e){let t=e.indexOf(`
|
|
14
|
+
`);if(t<0)return null;let n;try{n=JSON.parse(e.slice(0,t))}catch{return null}return{meta:n,body:e.slice(t+1)}}async function Xn(e,t=fetch){let n=await e(),r=Ds(n);if(!r)return;let{meta:o,body:s}=r,i={"Content-Type":"application/json"};try{await t(o.url,{method:"POST",headers:i,body:s,signal:AbortSignal.timeout(Number(o.timeoutMs))})}catch{}}async function Hs(e,t,n){let r=Jn(e);m(`POST event=${e} url=${dt(n)} size=${t.length} platform=${process.platform}`);let o={"Content-Type":"application/json"},s=Date.now();try{let i=await fetch(n,{method:"POST",headers:o,body:t,signal:AbortSignal.timeout(r)}),a=Date.now()-s;if(i.ok)return m(`POST outcome=ok elapsed_ms=${a} http=${i.status}`),!0;let c=(await i.text()).slice(0,200).replace(/[\n\r]/g,"");return m(`POST outcome=fail elapsed_ms=${a} http=${i.status} body=${c}`),!1}catch(i){let a=Date.now()-s,c=i instanceof Error?i.message:String(i);return m(`POST outcome=fail elapsed_ms=${a} http=000 body=${c}`),!1}}async function Zn(e,t,n,r,o){try{let s=r(e,t,{detached:!0,stdio:["pipe","ignore","ignore"],windowsHide:!0});s.on("error",()=>{}),s.stdin.on("error",()=>{});let i=!1;return await new Promise(a=>{let c=setTimeout(()=>{if(!i){m(`WARN: ${o} stdin handoff timed out \u2014 continuing fail-open`);try{s.stdin.destroy()}catch{}}a()},Ot),l=()=>{i=!0,clearTimeout(c),a()};s.stdin.end(n,()=>l()),s.stdin.once("error",()=>l())}),s.unref(),s}catch(s){let i=s instanceof Error?s.message:String(s);return m(`WARN: ${o} spawn failed open: ${i}`),null}}async function Fs(e,t,n,r=Wn,o=Ps){let s=Jn(e),i=Ls(n,s,t),{command:a,args:c}=o();return Zn(a,c,i,r,"detached post")}async function Qn(e,t,n=Wn,r=Yn){let{command:o,args:s}=r(Ce,t);return Zn(o,s,e,n,"detached work")}async function X(e,t,n,r,o,s){if(!o)return m("WARN: collector URL missing \u2014 pass --url on the hook command or set collector_url in manifest"),!1;if(!Se(o))return m(`WARN: collector URL blocked (https required): ${dt(o)}`),!1;let i=r(e,t,n);s!==void 0&&(i.build_ms=Math.max(0,Date.now()-s));let a=`${JSON.stringify(i)}
|
|
15
|
+
`,c=E("EV_AI_HOOK_DEBUG");c==="full"?m(`DEBUG envelope=${JSON.stringify(i)}`):c==="1"&&m(`DEBUG summary=${Ms(i,Buffer.byteLength(a,"utf8"))}`);let l=process.argv.includes(Ce),u=E("EV_AI_HOOK_SYNC")==="1";return Re(n.runnerEvent,n.runnerPlatform)||l||u?Hs(e,a,o):(await Fs(e,a,o),!1)}import{relative as Bs,resolve as Et,sep as qn}from"node:path";var $s=["session_id","conversation_id","turn_id","generation_id","prompt.id","prompt_id","hook_event_name","event","source","status","stop_reason","reason","tool_name","tool","tool_use_id","skill_name","command_name","expansion_type","command_source","permission_mode","model","model_id","agent_id","agent_type","subagent_id","subagent_type","subagent_model","is_parallel_worker","effort","effort.level","duration_ms","duration","failure_type","is_interrupt"];function Gs(e){return e.capture_hook_input==="full"?!0:e.capture_hook_input==="allowlist"?!1:E("EV_AI_HOOK_CAPTURE_FULL_INPUT")==="1"}function Ks(e){let t={};for(let n of $s){let r=$(e,n);r!==void 0&&(t[n]=r)}return t}function js(e,t){if(typeof e!="string"||e.length===0||!t)return null;let n=Et(e),r=Et(t),o=Bs(r,n);return!o||o==="."?".":o.startsWith(`..${qn}`)||o===".."||Et(r,o)!==n?null:o.split(qn).join("/")}function er(e,t){let n=JSON.stringify(e),r=Buffer.byteLength(n,"utf8");if(r<=t)return e;let o=Object.entries(e).filter(([i,a])=>!i.startsWith("_")&&(typeof a=="string"||typeof a=="number"||typeof a=="boolean")).sort((i,a)=>Buffer.byteLength(JSON.stringify(i[1]),"utf8")-Buffer.byteLength(JSON.stringify(a[1]),"utf8")),s={_truncated:!0,_original_bytes:r};for(let[i,a]of o){let c={...s,[i]:a};if(Buffer.byteLength(JSON.stringify(c),"utf8")>t)break;s[i]=a}return s}function se(e,t,n={}){let r=n.gitRoot!==void 0?js(e.cwd,n.gitRoot):null;if(Gs(t)){let s={...e};return delete s.cwd,delete s.transcript_path,r!==null&&(s.cwd_relative=r),er(s,Ut)}let o=Ks(e);return r!==null&&(o.cwd_relative=r),er(o,xt)}import{createReadStream as Vs}from"node:fs";import{stat as zs}from"node:fs/promises";import{basename as Ws,resolve as Js}from"node:path";import{createInterface as Ys}from"node:readline";var Xs=1024*1024;function Zs(e){let t=e.replace(/\\/g,"/");return t.includes("/.claude/projects/")&&Ws(t).endsWith(".jsonl")}async function tr(e){if(!e||!Zs(e))return null;try{let t=Js(e),n=await zs(t);if(!n.isFile())return null;let r=Math.max(0,n.size-Xs),o=[],s=Ys({input:Vs(t,{encoding:"utf8",start:r}),crlfDelay:1/0});for await(let i of s)i.length!==0&&o.push(i);r>0&&o.length>0&&o.shift();for(let i=o.length-1;i>=0;i--){let a=o[i];if(a)try{let c=JSON.parse(a);if(c.type!=="assistant")continue;let l=c.message;if(!l||typeof l!="object")continue;let u=l.model;if(typeof u=="string"&&u.length>0)return u}catch{continue}}return null}catch{return null}}function ae(e){return{sessionId:e.sessionId,turnId:e.turnId,installationId:e.manifest.installationId,runnerPlatform:e.runnerPlatform,platformAgentId:e.platformAgentId,runnerEvent:e.runnerEvent}}function Qs(...e){for(let t of e)if(t)return t;return null}function N(e,t,n){if(e.status==="fulfilled")return e.value;let r=e.reason instanceof Error?e.reason.message:String(e.reason);return m(`WARN: ${n} failed open: ${r}`),t}function qs(e){let t={present:!1,size:0},n={hash:"",count:0};return{config:{runner_platform:e,config_scope:"user",cli_version:null,claude_version:null,model:null,permission_keys:[],user_scope:{skills:n,subagents:n,commands:n,rules:n,memory:t,settings:t,mcp:t},local_settings:t},commit:()=>{}}}function ei(e,t){return{runner_platform:e,config_scope:"user",...t?{operator:t}:{}}}var V=new Set,ie=null;async function nr(e){if(lt())return;let t=e.manifest.installationId,n=e.manifest.installationStorePath;if(V.has(t))return;if(!Xe(n)){V.add(t);return}let r=Fe();if(cn(r)){if(ie){await ie;return}ie=(async()=>{if(V.has(t)||!Xe(n)){V.add(t);return}if(!Zt(n)){V.add(t);return}let o=!1;try{let s=Date.now(),{gitRoot:i}=e.manifest,a=String(e.runnerPlatform),[c,l,u,d,g]=await Promise.allSettled([ne(i),Be(),Ke(r),$e(),ge({gitRoot:i,installationStorePath:n,forceResend:!1})]),f=N(c,null,"gitSnapshot"),h=N(l,"","detectVirt"),x=N(u,null,"probeCloud"),v=N(d,{},"hostEnv"),C=N(g,{commit:()=>{}},"resolveOperatorForSend");await ce(e,i,f);let U={identity:{host:Ge(),context:r,virt:h||null,cloud:x,git:f},host_env:v,env_vars:We(),self_config:ei(a,C.operator),run_meta:{trigger:"cloud_identity_bootstrap"}};o=!!await X("session_start",U,ae(e),Y,e.manifest.collectorUrl,s),o&&(C.commit(),V.add(t))}finally{Qt(n)}})().finally(()=>{ie=null}),await ie}}async function ce(e,t,n){try{let r=n===void 0?await ne(t):n;e.platformAgentId=await rn(e.manifest.manifest,e.platformAgentId,String(e.runnerPlatform),t,r,e.manifest.installationStorePath,e.manifest.repoKey)}catch(r){let o=r instanceof Error?r.message:String(r);m(`WARN: derivePlatformAgentId failed open: ${o}`)}}async function ti(e){let t=Date.now(),{gitRoot:n}=e.manifest,r=Fe(),o=String(e.runnerPlatform),[s,i,a,c,l,u]=await Promise.allSettled([ne(n),Be(),Ke(r),$e(),ze(e.manifest.manifest,n,o),kn(o,n,void 0,{installationStorePath:e.manifest.installationStorePath,gitRoot:n})]),d=N(s,null,"gitSnapshot"),g=N(i,"","detectVirt"),f=N(a,null,"probeCloud"),h=N(c,{},"hostEnv"),x=N(l,[],"mcpDeclared"),v=N(u,qs(o),"selfConfig"),C=v.config;await ce(e,n,d);let U=p(e.hookInput,"model");U&&(C.model=U);let F={identity:{host:Ge(),context:r,virt:g||null,cloud:f,git:d},host_env:h,env_vars:We(),mcp:{declared:x},self_config:C,run_meta:{trigger:e.hookSource||"startup"},hook_input:se(e.hookInput,e.manifest.manifest,{gitRoot:n})};await X("session_start",F,ae(e),Y,e.manifest.collectorUrl,t)&&(v.commit(),V.add(e.manifest.installationId))}async function ni(e){let t=Date.now(),{gitRoot:n}=e.manifest;await ce(e,n);let r=Qs(p(e.hookInput,"status"),p(e.hookInput,"stop_reason"),p(e.hookInput,"reason"),_t(p(e.hookInput,"error"))),o=e.runnerPlatform==="claude"?await tr(p(e.hookInput,"transcript_path")):null,s=se(e.hookInput,e.manifest.manifest,{gitRoot:n});o&&(s.model=o),await X("session_end",{status:r,...o?{model:o}:{},hook_input:s},ae(e),Y,e.manifest.collectorUrl,t)}async function ri(e){let t=Date.now(),n=Pn(e.hookInput);if(n.length===0)return;await nr(e);let{gitRoot:r}=e.manifest;await ce(e,r);let o=se(e.hookInput,e.manifest.manifest,{gitRoot:r}),s=ae(e);await Promise.all(n.map(i=>X("tool_invoked",{tool_name:"Skill",skill_name:i,success:null,duration_ms:null,hook_input:o},s,Y,e.manifest.collectorUrl,t)))}async function oi(e){let t=Date.now();await nr(e);let{gitRoot:n}=e.manifest;await ce(e,n);let{toolName:r,skillName:o}=$n(e.hookInput),s=Kn(e.hookInput),i=Hn(e.runnerEvent),a=i===!1?jn(e.hookInput,e.runnerEvent):null,c=await ze(e.manifest.manifest,e.manifest.gitRoot,String(e.runnerPlatform)).catch(()=>[]),{mcpServer:l,mcpTool:u}=Vn(r,c.map(g=>g.name)),d=Gn(e.hookInput);await X("tool_invoked",{tool_name:r,skill_name:o,success:i,duration_ms:s,...a?{failure_reason:a}:{},...l?{mcp_server:l}:{},...u?{mcp_tool:u}:{},...d?{subagent_type:d}:{},hook_input:se(e.hookInput,e.manifest.manifest,{gitRoot:n})},ae(e),Y,e.manifest.collectorUrl,t)}async function rr(e){switch(e.internalEvent){case"session_start":await ti(e);return;case"session_end":await ni(e);return;case"skill_invoked":await ri(e);return;case"tool_invoked":await oi(e);return;default:return}}function or(e){return e!=="session_start"&&e!=="session_end"&&e!=="tool_invoked"&&e!=="skill_invoked"&&e!==""}import{existsSync as St,readFileSync as si}from"node:fs";import{dirname as ii,join as sr,relative as ai}from"node:path";var ir=[Tt,".cursor/ev-ai-runtime-report.json",".codex/ev-ai-runtime-report.json"];async function ci(e=process.cwd(),t){let n=E("EV_AI_HOOK_MANIFEST");if(n&&St(n))return n;let r=t??await pe(e);for(let o of ir){let s=sr(r,o);if(St(s))return s}for(let o of ir){let s=sr(e,o);if(St(s))return s}}async function li(e,t){let n=t??await pe(ii(e)),r=ai(n,e),o=await L("git",["ls-files","--error-unmatch",r],2e3,{cwd:n});return o.ok?!0:o.code===1?!1:(m(`WARN: git ls-files failed for manifest ${e} (code=${String(o.code)}); treating as tracked`),!0)}function ui(e){let t=si(e,"utf8");return O(t,{})}function di(){return{schema_version:2,mcp_servers:[]}}async function ar(e=process.cwd()){let t=await pe(e),n=await ci(e,t),r=n?ui(n):di();delete r.installation_id;let o=n?await li(n,t):!1;r.capture_hook_input==="full"&&n&&o&&(m(`WARN: ignoring capture_hook_input=full in git-tracked manifest ${n}; use EV_AI_HOOK_CAPTURE_FULL_INPUT=1 or an untracked operator manifest`),delete r.capture_hook_input);let{installationId:s,storePath:i,repoKey:a}=await nn(t);return{manifestPath:n??i,manifest:r,installationId:s,installationStorePath:i,repoKey:a,collectorUrl:wn(r),platformAgentId:r.platform_agent_id??"",gitRoot:t}}async function cr(e,t,n,r){let o=t??await ve(Ue),s=O(o,{}),i=await ar();if(!i)return;r&&(i.collectorUrl=r);let a=Fn(s,i.manifest.platform,n),c=Bn(e,a.runnerEvent);if(!c){m(`WARN: unknown hook event '${a.runnerEvent}'; skipping telemetry`);return}let l={hookInput:s,sessionId:a.sessionId,turnId:a.turnId,runnerEvent:a.runnerEvent,runnerPlatform:a.runnerPlatform,hookSource:a.hookSource,internalEvent:c,manifest:i,platformAgentId:i.platformAgentId};if(or(c)){m(`WARN: unsupported internal event '${c}'`);return}await rr(l)}function pi(e,t){if(E("EV_AI_HOOK_SYNC")==="1")return!0;let n=Ie(e),r=O(t,{}),o=n.event??(p(r,"hook_event_name")||p(r,"event")),s=gt(r,o,void 0,n.runner);return Re(o,s)}async function lr(e=process.argv.slice(2)){if(e[0]===ht){try{await Xn(Ne)}catch{}return 0}if(e[0]===Ce){try{let t=Ie(e.slice(1)),n=await Ne(),r=O(n,{}),o=t.event??(p(r,"hook_event_name")||p(r,"event"));if(mt(t.runner,r,o))return 0;await cr(t.event,n,t.runner,ft(t))}catch(t){let n=t instanceof Error?t.message:String(t);m(`WARN: detached work failed open: ${n}`)}return 0}try{let t=await ve(Ue),n=Ie(e),r=ft(n),o=O(t,{}),s=n.event??(p(o,"hook_event_name")||p(o,"event"));if(mt(n.runner,o,s))return 0;pi(e,t)?await cr(n.event,t,n.runner,r):await Qn(t,e)}catch(t){let n=t instanceof Error?t.message:String(t);m(`WARN: hook failed open: ${n}`)}finally{Dt()}return 0}lr().then(e=>{process.exit(e)}).catch(e=>{let t=e instanceof Error?e.message:String(e);process.stderr.write(`[ev-ai-agent-hook] ${t}
|
|
12
16
|
`),process.exit(1)});
|
package/dist/plugin-hooks.mjs
CHANGED
|
@@ -3,15 +3,15 @@ import { mkdirSync, writeFileSync } from "node:fs";
|
|
|
3
3
|
import { dirname, join } from "node:path";
|
|
4
4
|
|
|
5
5
|
// src/constants.ts
|
|
6
|
-
var HOOK_BINARY_NAME = "
|
|
6
|
+
var HOOK_BINARY_NAME = "ev-ai-agent-hook";
|
|
7
7
|
var GLOBAL_HOOK_BINARY_RELATIVE = `current/${HOOK_BINARY_NAME}`;
|
|
8
|
-
var PROJECT_HOOK_BINARY_RELATIVE = `.
|
|
8
|
+
var PROJECT_HOOK_BINARY_RELATIVE = `.ev-ai/agent-hook/${HOOK_BINARY_NAME}`;
|
|
9
9
|
var HOOK_INPUT_ALLOWLIST_MAX_BYTES = 4 * 1024;
|
|
10
10
|
var HOOK_INPUT_FULL_MAX_BYTES = 32 * 1024;
|
|
11
11
|
var HOOK_INPUT_MCP_MAX_BYTES = 4 * 1024;
|
|
12
|
-
var PACKAGE_VERSION = "1.0.
|
|
13
|
-
var NPX_PACKAGE_SPEC = `@
|
|
14
|
-
var
|
|
12
|
+
var PACKAGE_VERSION = "1.0.7";
|
|
13
|
+
var NPX_PACKAGE_SPEC = `@ev-ai/agent-hook@${PACKAGE_VERSION}`;
|
|
14
|
+
var HOOK_STATUS_MESSAGE = "ev-ai runtime report";
|
|
15
15
|
|
|
16
16
|
// src/install.ts
|
|
17
17
|
function npxHookCommand(packageSpec = NPX_PACKAGE_SPEC) {
|
|
@@ -47,7 +47,7 @@ function desiredCodexHookGroups(command) {
|
|
|
47
47
|
const entry = {
|
|
48
48
|
type: "command",
|
|
49
49
|
command,
|
|
50
|
-
statusMessage:
|
|
50
|
+
statusMessage: HOOK_STATUS_MESSAGE
|
|
51
51
|
};
|
|
52
52
|
const commandHook = () => ({ hooks: [entry] });
|
|
53
53
|
return {
|
package/package.json
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ev-ai/agent-hook",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.7",
|
|
4
4
|
"description": "Cross-runner runtime telemetry hook for Claude Code, Cursor, and Codex",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
7
|
-
"
|
|
7
|
+
"ev-ai-agent-hook": "dist/cli.mjs"
|
|
8
8
|
},
|
|
9
9
|
"files": [
|
|
10
10
|
"dist",
|
|
@@ -12,32 +12,10 @@
|
|
|
12
12
|
"COLLECTED-DATA.md"
|
|
13
13
|
],
|
|
14
14
|
"publishConfig": {
|
|
15
|
-
"registry": "https://
|
|
16
|
-
|
|
17
|
-
"scripts": {
|
|
18
|
-
"build": "node scripts/build.mjs",
|
|
19
|
-
"build:hook-binary": "node scripts/compile-hook.mjs",
|
|
20
|
-
"build:hook-binary:host": "node scripts/compile-hook.mjs --host",
|
|
21
|
-
"ensure:project-binary": "sh -c 'test -x \"$(git rev-parse --show-toplevel)/.evalon/agent-hook/evalon-agent-hook\" || (yarn build && yarn build:hook-binary:host && node dist/cli.mjs update)'",
|
|
22
|
-
"update:local": "yarn build && yarn build:hook-binary:host && node dist/cli.mjs update",
|
|
23
|
-
"clean": "rm -rf dist compile-out",
|
|
24
|
-
"lint": "eslint src",
|
|
25
|
-
"lint:fix": "eslint --fix src",
|
|
26
|
-
"test": "vitest run --config vitest.config.unit.ts",
|
|
27
|
-
"sync:hooks": "node scripts/sync-hook-events.mjs",
|
|
28
|
-
"pin:hooks": "node scripts/pin-version.mjs",
|
|
29
|
-
"pin:local": "node scripts/pin-version.mjs --local",
|
|
30
|
-
"publish:gh": "node scripts/publish-gh.mjs"
|
|
15
|
+
"registry": "https://registry.npmjs.org",
|
|
16
|
+
"access": "public"
|
|
31
17
|
},
|
|
32
18
|
"engines": {
|
|
33
19
|
"node": ">=18"
|
|
34
|
-
},
|
|
35
|
-
"devDependencies": {
|
|
36
|
-
"@types/node": "~24.10.13",
|
|
37
|
-
"esbuild": "~0.27.3",
|
|
38
|
-
"eslint": "~9.39.1",
|
|
39
|
-
"eslint-config-prettier": "~10.1.0",
|
|
40
|
-
"typescript": "~5.9.3",
|
|
41
|
-
"vitest": "~4.1.0"
|
|
42
20
|
}
|
|
43
21
|
}
|