@agent-beam/beam 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +661 -0
- package/README.md +188 -0
- package/dist/agents.d.ts +26 -0
- package/dist/agents.js +96 -0
- package/dist/agents.js.map +1 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +234 -0
- package/dist/cli.js.map +1 -0
- package/dist/client.d.ts +28 -0
- package/dist/client.js +176 -0
- package/dist/client.js.map +1 -0
- package/dist/config.d.ts +5 -0
- package/dist/config.js +23 -0
- package/dist/config.js.map +1 -0
- package/dist/core.d.ts +64 -0
- package/dist/core.js +176 -0
- package/dist/core.js.map +1 -0
- package/dist/custom-rules.d.ts +7 -0
- package/dist/custom-rules.js +80 -0
- package/dist/custom-rules.js.map +1 -0
- package/dist/enroll.d.ts +16 -0
- package/dist/enroll.js +68 -0
- package/dist/enroll.js.map +1 -0
- package/dist/extract.d.ts +6 -0
- package/dist/extract.js +148 -0
- package/dist/extract.js.map +1 -0
- package/dist/forward.d.ts +8 -0
- package/dist/forward.js +53 -0
- package/dist/forward.js.map +1 -0
- package/dist/hook-adapters.d.ts +2 -0
- package/dist/hook-adapters.js +36 -0
- package/dist/hook-adapters.js.map +1 -0
- package/dist/install.d.ts +15 -0
- package/dist/install.js +68 -0
- package/dist/install.js.map +1 -0
- package/dist/inventory.d.ts +12 -0
- package/dist/inventory.js +23 -0
- package/dist/inventory.js.map +1 -0
- package/dist/open-browser.d.ts +1 -0
- package/dist/open-browser.js +8 -0
- package/dist/open-browser.js.map +1 -0
- package/dist/os-monitor.d.ts +5 -0
- package/dist/os-monitor.js +26 -0
- package/dist/os-monitor.js.map +1 -0
- package/dist/policy.d.ts +27 -0
- package/dist/policy.js +59 -0
- package/dist/policy.js.map +1 -0
- package/dist/sequences.d.ts +13 -0
- package/dist/sequences.js +58 -0
- package/dist/sequences.js.map +1 -0
- package/dist/serve.d.ts +27 -0
- package/dist/serve.js +113 -0
- package/dist/serve.js.map +1 -0
- package/dist/server.d.ts +10 -0
- package/dist/server.js +101 -0
- package/dist/server.js.map +1 -0
- package/dist/service.d.ts +27 -0
- package/dist/service.js +169 -0
- package/dist/service.js.map +1 -0
- package/dist/store.d.ts +19 -0
- package/dist/store.js +114 -0
- package/dist/store.js.map +1 -0
- package/dist/studio.d.ts +1 -0
- package/dist/studio.js +337 -0
- package/dist/studio.js.map +1 -0
- package/package.json +43 -0
package/README.md
ADDED
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
# Beam
|
|
2
|
+
|
|
3
|
+
Local observation and heuristic risk scanning for AI agent activity. Beam runs entirely on your machine: a loopback-only HTTP collector stores normalized events and scan reports in NDJSON files under `~/.beam`, and the `beam` CLI talks to it (or scans files completely offline).
|
|
4
|
+
|
|
5
|
+
Beam does not execute, block, or approve anything an agent does. It observes, redacts secrets before persisting, and flags risky patterns for human review.
|
|
6
|
+
|
|
7
|
+
## Install
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
npm run setup:global
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
This installs dependencies, builds, `npm link`s the `beam` binary globally, and starts a background watcher so the global command always reflects the current source — no manual rebuild needed after edits.
|
|
14
|
+
|
|
15
|
+
## Commands
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
beam start # start the local collector (binds 127.0.0.1:4319)
|
|
19
|
+
beam start --port 4400 # use a different port
|
|
20
|
+
|
|
21
|
+
beam studio # open the activity dashboard in your browser
|
|
22
|
+
|
|
23
|
+
beam token # print the collector's pairing token
|
|
24
|
+
|
|
25
|
+
beam import events.ndjson # send normalized events to /ingest
|
|
26
|
+
beam scan SKILL.md # scan offline for risky instructions
|
|
27
|
+
beam scan mcp.json --mcp # scan an MCP config (checks version pinning)
|
|
28
|
+
beam scan SKILL.md --save # also persist the report to the collector
|
|
29
|
+
|
|
30
|
+
beam hook claude-code < payload.json # forward a hook payload for the given agent (stdin)
|
|
31
|
+
|
|
32
|
+
beam agent list # supported agents and payload verification status
|
|
33
|
+
beam agent install cursor # wire beam's hook into that agent's own config, non-destructively
|
|
34
|
+
beam agent install-all # detect every agent actually installed on this machine and wire them all
|
|
35
|
+
|
|
36
|
+
beam rule list # the active rule catalog (built-in + custom + sequence), grouped by category
|
|
37
|
+
beam rule reload # apply edits to ~/.beam/rules.json into the running collector, no restart
|
|
38
|
+
|
|
39
|
+
beam service install # run the collector as a background service (starts on login)
|
|
40
|
+
beam service status # is it installed / running
|
|
41
|
+
beam service stop # stop it
|
|
42
|
+
beam service start # start it again
|
|
43
|
+
beam service uninstall # remove it
|
|
44
|
+
beam service logs # where its log files are (or the command to follow them)
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
`scan` runs entirely offline unless `--save` is passed — no collector required. `hook` never throws or blocks the calling agent; capture failures are logged to stderr only. This mirrors Beam's core rule: **observation must never become enforcement.**
|
|
48
|
+
|
|
49
|
+
## Studio (activity dashboard)
|
|
50
|
+
|
|
51
|
+
`beam start` or `beam service install` also serves a dashboard at `GET /` and `GET /studio` on the collector itself — no separate app, no build step, no dependency added to the package (plain HTML/CSS/JS, no fonts or CDNs). `beam studio` opens it in your default browser for you.
|
|
52
|
+
|
|
53
|
+
- **Activity** — every captured event, searchable and filterable by agent/risk, with a detail drawer per action.
|
|
54
|
+
- **Findings** — the subset with heuristic matches, with a per-event "mark reviewed" (a record of your assessment, never an approval or block).
|
|
55
|
+
- **Skill & MCP scan** — paste or check a file's content and see findings live, same engine as `beam scan`.
|
|
56
|
+
|
|
57
|
+
The page itself carries no secret and needs no auth to load — only the API calls it makes do. `beam studio` reads the pairing token from disk and passes it once via a URL that's immediately scrubbed from the address bar (`history.replaceState`) after the page reads it. From there it's saved in that browser's `localStorage` (scoped to the collector's own origin, `127.0.0.1:4319` — no other site or app can read it), so reloading the tab or closing and reopening the browser stays connected without re-pairing. If the collector ever rejects the stored token (e.g. `beam service uninstall && beam service install` generates a new one), the page detects that and clears it automatically rather than looping silently. Use the **Disconnect** button to clear it yourself.
|
|
58
|
+
|
|
59
|
+
Sessions and Usage views from the original Sentinel console aren't ported yet — Activity/Findings/Scan cover the core loop first.
|
|
60
|
+
|
|
61
|
+
## Multi-agent coverage
|
|
62
|
+
|
|
63
|
+
Different agents send different JSON shapes to their hooks. `beam hook <agent>` picks the right adapter for the agent id you pass, and `beam agent install <agent>` writes beam's hook into that agent's real config file in its own native format, merging with (never overwriting) whatever hooks are already there.
|
|
64
|
+
|
|
65
|
+
`npm run setup:global` runs `beam agent install-all` automatically at the end, so every agent it can detect on your machine gets wired without you having to know which ones you have installed. Detection uses each agent's own real, pre-existing files (e.g. `~/.codex/config.toml`, `~/.copilot/config.json`) — never a file beam itself writes — so an agent that was never actually installed won't get a hook, and one that's already wired won't get a duplicate entry on a second run.
|
|
66
|
+
|
|
67
|
+
| Agent id | Config file `agent install` writes | Payload |
|
|
68
|
+
|---|---|---|
|
|
69
|
+
| `claude-code` | `~/.claude/settings.json` (`hooks.PreToolUse`) | Verified against Claude Code's docs |
|
|
70
|
+
| `codex` | `~/.codex/hooks.json` (`hooks.PreToolUse`) | Same shape as Claude Code; verified |
|
|
71
|
+
| `cursor` | `~/.cursor/hooks.json` (`hooks.preToolUse`) | Verified against Cursor's docs |
|
|
72
|
+
| `copilot-cli` | `~/.copilot/hooks/beam.json` (`hooks.preToolUse`) | Verified (camelCase — translated internally) |
|
|
73
|
+
| `gemini` | `~/.gemini/settings.json` (`hooks.BeforeTool`) | **Not verified** — Gemini CLI's stdin schema isn't published; capture uses a generic best-effort field adapter |
|
|
74
|
+
| `opencode` | not built yet | discovery (config/artifact presence) only — OpenCode uses a generated TS plugin, not a JSON hook file |
|
|
75
|
+
|
|
76
|
+
Run `beam agent list` for the current status of each. Adding a new agent means one entry in `src/agents.ts` (config path + how to merge the hook block) and, if its stdin payload uses different field names than `tool_name`/`tool_input`/`session_id`/`cwd`/`hook_event_name`, one adapter function in `src/hook-adapters.ts`.
|
|
77
|
+
|
|
78
|
+
This is an intentionally small first slice of what a full multi-agent observer could cover. Wider agent coverage, enforcement/blocking, and portable case bundles aren't built yet — tracked as future slices, not silently unsupported.
|
|
79
|
+
|
|
80
|
+
## Forensic extraction (no hook required)
|
|
81
|
+
|
|
82
|
+
`beam agent extract <agent>` reads an agent's own existing session/transcript files directly — no hook needed, and it works for history from *before* Beam was ever installed:
|
|
83
|
+
|
|
84
|
+
```bash
|
|
85
|
+
beam agent extract claude-code # preview: normalizes locally, prints JSON, nothing sent anywhere
|
|
86
|
+
beam agent extract claude-code --limit 20 # cap how many events the preview prints (default 200)
|
|
87
|
+
beam agent extract claude-code --save # import into the running collector (dedupes by event_id)
|
|
88
|
+
beam agent extract codex --save
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
Supported today: **`claude-code`** (`~/.claude/projects/**/*.jsonl` — reads `tool_use` blocks out of assistant turns) and **`codex`** (`~/.codex/{sessions,archived_sessions}/**/*.jsonl` — reads `function_call` and `custom_tool_call` response items). Every extracted event gets `source: "extract"` and `phase: "observed"` so it's visibly distinct from a live hook capture (which is `"proposed"`/`"completed hook"`). Preview mode normalizes (and therefore redacts) locally without ever contacting the collector; `--save` sends the raw records through the same `/ingest` pipeline a live hook uses, batched under the collector's 2,000-record-per-request cap. Bounded like everything else in Beam: 50 MB max per transcript file, 20,000 parsed lines per file, 2,000 files walked per run.
|
|
92
|
+
|
|
93
|
+
Other agents aren't wired yet — `beam agent extract <agent>` fails clearly rather than silently returning nothing for one that isn't supported.
|
|
94
|
+
|
|
95
|
+
## Rule engine
|
|
96
|
+
|
|
97
|
+
Detection has three layers now, all active in both `beam scan` (offline) and the running collector:
|
|
98
|
+
|
|
99
|
+
- **Categorized built-in rules** — every rule has a `category` (`exec`, `exfil`, `impact`, `integrity`, `persistence`, `privilege`, `recon`, `secrets`, `source_control`), not just a flat id. `beam rule list` shows the full catalog grouped by category.
|
|
100
|
+
- **Custom rules from `~/.beam/rules.json`** — extend detection without touching Beam's source. A JSON array of `{ id, pattern, severity, title?, explanation?, category? }`; `pattern` is a regex (case-insensitive). Loaded once at collector startup; a malformed entry is skipped and reported (`beam rule list` / `beam start`'s output shows why), never crashes the rest of detection.
|
|
101
|
+
|
|
102
|
+
```json
|
|
103
|
+
[
|
|
104
|
+
{ "id": "internal_host", "pattern": "wiki\\.internal\\.corp", "severity": "high", "category": "exfil", "title": "Internal wiki referenced" }
|
|
105
|
+
]
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
`beam rule reload` applies edits to the running collector immediately, no restart needed.
|
|
109
|
+
- **Cross-event sequence rules** — some risk only shows up as a *pattern of actions*, not one action in isolation: a credential read followed by network activity later in the same session, or a network scan followed by remote code execution, even across separate, unrelated-looking tool calls that a single-event regex could never connect. Beam re-evaluates a session's recent events (last 50) whenever new events land, and attaches one composite finding to the event that completes the pattern — idempotently, so re-ingesting the same history never duplicates it.
|
|
110
|
+
|
|
111
|
+
All three feed the same `Finding[]` shape everywhere — Studio, `/export`, `/state` — so there's nothing separate to look at.
|
|
112
|
+
|
|
113
|
+
## Running as a background service
|
|
114
|
+
|
|
115
|
+
`beam start` in a terminal works, but closing that terminal stops the collector. `beam service install` instead registers it as a real background service:
|
|
116
|
+
|
|
117
|
+
- **macOS**: a `launchd` user agent at `~/Library/LaunchAgents/ai.beam.collector.plist` (`RunAtLoad` + `KeepAlive`, so it starts on login and restarts if it crashes).
|
|
118
|
+
- **Linux**: a `systemd --user` unit at `~/.config/systemd/user/beam.service` (`enable --now`, `Restart=always`).
|
|
119
|
+
|
|
120
|
+
Both embed the resolved `BEAM_DATA_DIR` directly into the service definition (launchd/systemd don't inherit your shell's environment), so `BEAM_DATA_DIR=/custom/path beam service install` keeps using that path even after a reboot. Logs go to `$BEAM_DATA_DIR/logs/`.
|
|
121
|
+
|
|
122
|
+
This is a userspace HTTP server, same as running `beam start` yourself — not kernel-level capture. Beam has nothing to observe at the kernel level: the actual signal comes from agents calling `beam hook <agent>` at the moment they're about to act, the same way whether run in a terminal or as a background service.
|
|
123
|
+
|
|
124
|
+
Windows isn't supported yet (`beam service *` will say so and tell you to run `beam start` directly).
|
|
125
|
+
|
|
126
|
+
## Configuration
|
|
127
|
+
|
|
128
|
+
- `BEAM_HOME` — root config directory (default `~/.beam`).
|
|
129
|
+
- `BEAM_DATA_DIR` — where events/scans/token are stored (default `$BEAM_HOME/data`).
|
|
130
|
+
- `BEAM_TOKEN` — pairing token (skips reading the token file).
|
|
131
|
+
- `BEAM_COLLECTOR_URL` — collector origin the CLI talks to (default `http://127.0.0.1:4319`); must stay on HTTP loopback.
|
|
132
|
+
- `BEAM_PORT` — port `beam start` binds to (default `4319`).
|
|
133
|
+
- `BEAM_ALLOWED_ORIGINS` — comma-separated browser origins allowed to call the collector (for a future local UI).
|
|
134
|
+
|
|
135
|
+
## Connect a Claude Code hook
|
|
136
|
+
|
|
137
|
+
```json
|
|
138
|
+
{
|
|
139
|
+
"hooks": {
|
|
140
|
+
"PreToolUse": [{
|
|
141
|
+
"matcher": "",
|
|
142
|
+
"hooks": [{
|
|
143
|
+
"type": "command",
|
|
144
|
+
"command": "beam hook claude-code"
|
|
145
|
+
}]
|
|
146
|
+
}]
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
Choose `PreToolUse` to observe proposed actions before they run. `beam` must be on the agent's PATH (or use its absolute path).
|
|
152
|
+
|
|
153
|
+
## API
|
|
154
|
+
|
|
155
|
+
All routes require `Authorization: Bearer <token>` and are bound to loopback only.
|
|
156
|
+
|
|
157
|
+
- `GET /health` — collector version and retention.
|
|
158
|
+
- `GET /state` — retained events, scans, reviews, rule catalog.
|
|
159
|
+
- `GET /agents` — existence checks on common agent config/artifact locations, hook-install/payload-verification status; no contents are read.
|
|
160
|
+
- `POST /ingest` — one normalized JSON object, JSON array, or NDJSON (up to 2 MB / 2,000 records; 100 KB per record).
|
|
161
|
+
- `POST /v1/logs` — OTLP/HTTP **JSON** (not protobuf).
|
|
162
|
+
- `POST /scan` — `{ "name": "SKILL.md", "kind": "skill", "content": "..." }` (or `kind: "mcp"`; max 500 KB).
|
|
163
|
+
- `POST /review` — `{ "id": "...", "reviewed": true }`.
|
|
164
|
+
- `POST /rules/reload` — reload `~/.beam/rules.json` into this running process; returns `{ path, loaded, errors }`.
|
|
165
|
+
- `GET /export` — redacted event NDJSON.
|
|
166
|
+
|
|
167
|
+
## Limits and guarantees
|
|
168
|
+
|
|
169
|
+
- Retention: latest 10,000 events and 500 scan reports. Each accepted batch atomically replaces the bounded event file.
|
|
170
|
+
- Known credential formats, assignments, auth headers, URL query strings, and private keys are redacted before persistence. Other sensitive text may remain; inspect exports before sharing.
|
|
171
|
+
- Data directory mode `0700`, files `0600`. Token is generated once per data directory and reused across restarts.
|
|
172
|
+
- The heuristic scanner is pattern matching, not semantic malware analysis or a safety guarantee. Findings require human review.
|
|
173
|
+
|
|
174
|
+
## Development
|
|
175
|
+
|
|
176
|
+
```bash
|
|
177
|
+
npm test
|
|
178
|
+
npm run typecheck
|
|
179
|
+
npm run build
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
## Related
|
|
183
|
+
|
|
184
|
+
- [beam-mcp](https://github.com/whyashthakker/beam-mcp) — an MCP server exposing this CLI's scanning to MCP-compatible hosts. Open source.
|
|
185
|
+
|
|
186
|
+
## License
|
|
187
|
+
|
|
188
|
+
AGPL-3.0-only — see [LICENSE](./LICENSE).
|
package/dist/agents.d.ts
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
export type Obj = Record<string, unknown>;
|
|
2
|
+
export interface AgentDefinition {
|
|
3
|
+
id: string;
|
|
4
|
+
name: string;
|
|
5
|
+
/** Paths (relative to home) checked for config presence during discovery. */
|
|
6
|
+
configs: string[];
|
|
7
|
+
/** Paths (relative to home) checked for session/transcript artifacts during discovery. */
|
|
8
|
+
artifacts: string[];
|
|
9
|
+
/** Path (relative to home) beam writes the hook configuration into. */
|
|
10
|
+
hookConfigPath: string | null;
|
|
11
|
+
/** Event name this agent's hook contract uses for a pre-action gate (documented casing). */
|
|
12
|
+
hookEventName: string | null;
|
|
13
|
+
/**
|
|
14
|
+
* Merge beam's hook entry into this agent's existing hook config (parsed JSON, or {} if the
|
|
15
|
+
* file didn't exist yet). Must be idempotent — safe to call repeatedly without duplicating.
|
|
16
|
+
*/
|
|
17
|
+
mergeHookConfig: ((existing: Obj, command: string) => Obj) | null;
|
|
18
|
+
/** Payload adapter id used by src/hook-adapters.ts to normalize this agent's stdin JSON. */
|
|
19
|
+
adapter: "passthrough" | "copilot-camel" | "generic";
|
|
20
|
+
/** Whether the adapter above was verified against vendor documentation (vs. best-effort). */
|
|
21
|
+
verifiedPayload: boolean;
|
|
22
|
+
notes: string;
|
|
23
|
+
}
|
|
24
|
+
export declare const AGENTS: AgentDefinition[];
|
|
25
|
+
export declare function findAgent(id: string): AgentDefinition | undefined;
|
|
26
|
+
export declare function hookConfigFullPath(agent: AgentDefinition, home: string): string;
|
package/dist/agents.js
ADDED
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import { join } from "node:path";
|
|
2
|
+
function obj(v) { return v && typeof v === "object" && !Array.isArray(v) ? v : {}; }
|
|
3
|
+
function arr(v) { return Array.isArray(v) ? v : []; }
|
|
4
|
+
// Claude Code, Codex, and Cursor all install into a `hooks.<Event>` array of
|
|
5
|
+
// `{ matcher, hooks: [{ type: "command", command }] }` entries (Claude Code's own shape).
|
|
6
|
+
function mergeClaudeStyleHooks(event) {
|
|
7
|
+
return (existing, command) => {
|
|
8
|
+
const hooks = obj(existing.hooks);
|
|
9
|
+
const list = arr(hooks[event]).map(obj);
|
|
10
|
+
const alreadyInstalled = list.some(entry => arr(entry.hooks).map(obj).some(h => h.command === command));
|
|
11
|
+
if (!alreadyInstalled)
|
|
12
|
+
list.push({ matcher: "", hooks: [{ type: "command", command }] });
|
|
13
|
+
return { ...existing, hooks: { ...hooks, [event]: list } };
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
// Cursor's own hooks.json instead nests `{ command, matcher }` directly under the event array.
|
|
17
|
+
function mergeCursorHooks(event) {
|
|
18
|
+
return (existing, command) => {
|
|
19
|
+
const hooks = obj(existing.hooks);
|
|
20
|
+
const list = arr(hooks[event]).map(obj);
|
|
21
|
+
if (!list.some(entry => entry.command === command))
|
|
22
|
+
list.push({ command, matcher: ".*" });
|
|
23
|
+
return { version: existing.version ?? 1, ...existing, hooks: { ...hooks, [event]: list } };
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
// Copilot CLI's dedicated hook file uses `{ type: "command", bash, timeoutSec }` entries.
|
|
27
|
+
function mergeCopilotHooks(event) {
|
|
28
|
+
return (existing, command) => {
|
|
29
|
+
const hooks = obj(existing.hooks);
|
|
30
|
+
const list = arr(hooks[event]).map(obj);
|
|
31
|
+
if (!list.some(entry => entry.bash === command))
|
|
32
|
+
list.push({ type: "command", bash: command, timeoutSec: 30 });
|
|
33
|
+
return { version: existing.version ?? 1, ...existing, hooks: { ...hooks, [event]: list } };
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
export const AGENTS = [
|
|
37
|
+
{
|
|
38
|
+
id: "claude-code", name: "Claude Code",
|
|
39
|
+
configs: [".claude/settings.json"], artifacts: [".claude/projects"],
|
|
40
|
+
hookConfigPath: ".claude/settings.json", hookEventName: "PreToolUse",
|
|
41
|
+
mergeHookConfig: mergeClaudeStyleHooks("PreToolUse"), adapter: "passthrough", verifiedPayload: true,
|
|
42
|
+
notes: "Payload verified against code.claude.com/docs/en/hooks."
|
|
43
|
+
},
|
|
44
|
+
{
|
|
45
|
+
id: "codex", name: "Codex",
|
|
46
|
+
configs: [".codex/config.toml"], artifacts: [".codex/sessions", ".codex/archived_sessions"],
|
|
47
|
+
hookConfigPath: ".codex/hooks.json", hookEventName: "PreToolUse",
|
|
48
|
+
mergeHookConfig: mergeClaudeStyleHooks("PreToolUse"), adapter: "passthrough", verifiedPayload: true,
|
|
49
|
+
notes: "Same hooks.json shape and stdin payload fields as Claude Code (session_id, cwd, hook_event_name, tool_name, tool_input, tool_use_id)."
|
|
50
|
+
},
|
|
51
|
+
{
|
|
52
|
+
id: "cursor", name: "Cursor",
|
|
53
|
+
// ".cursor/hooks.json" is the file beam itself writes on install, so it can never be used to
|
|
54
|
+
// detect a pre-existing Cursor install (circular). The bare ".cursor" directory is what
|
|
55
|
+
// Cursor itself creates just from being used, so it's a real presence signal.
|
|
56
|
+
configs: [".cursor"], artifacts: [".cursor/projects"],
|
|
57
|
+
hookConfigPath: ".cursor/hooks.json", hookEventName: "preToolUse",
|
|
58
|
+
mergeHookConfig: mergeCursorHooks("preToolUse"), adapter: "passthrough", verifiedPayload: true,
|
|
59
|
+
notes: "Payload verified against cursor.com/docs/hooks; extra fields (model, conversation_id, ...) are ignored, not misread."
|
|
60
|
+
},
|
|
61
|
+
{
|
|
62
|
+
id: "copilot-cli", name: "GitHub Copilot CLI",
|
|
63
|
+
// Same circularity as Cursor above: ".copilot/hooks/beam.json" is our own output.
|
|
64
|
+
// ".copilot/config.json" is what the real Copilot CLI writes on its own first run.
|
|
65
|
+
configs: [".copilot/config.json"], artifacts: [".copilot/session-state"],
|
|
66
|
+
hookConfigPath: ".copilot/hooks/beam.json", hookEventName: "preToolUse",
|
|
67
|
+
mergeHookConfig: mergeCopilotHooks("preToolUse"), adapter: "copilot-camel", verifiedPayload: true,
|
|
68
|
+
notes: "Payload verified against docs.github.com Copilot hooks reference (camelCase: sessionId, cwd, toolName, toolArgs)."
|
|
69
|
+
},
|
|
70
|
+
{
|
|
71
|
+
id: "gemini", name: "Gemini CLI",
|
|
72
|
+
// settings.json only exists once hooks/other settings are configured; the bare ".gemini"
|
|
73
|
+
// directory (created by any use of the Gemini CLI, e.g. mcp_config.json, projects/) is the
|
|
74
|
+
// reliable presence signal.
|
|
75
|
+
configs: [".gemini", ".gemini/settings.json"], artifacts: [".gemini/tmp"],
|
|
76
|
+
hookConfigPath: ".gemini/settings.json", hookEventName: "BeforeTool",
|
|
77
|
+
mergeHookConfig: mergeClaudeStyleHooks("BeforeTool"), adapter: "generic", verifiedPayload: false,
|
|
78
|
+
notes: "Config wiring only. Gemini CLI's BeforeTool stdin schema is not published; capture uses a best-effort generic field adapter and may miss fields."
|
|
79
|
+
},
|
|
80
|
+
{
|
|
81
|
+
id: "opencode", name: "OpenCode",
|
|
82
|
+
configs: [".config/opencode/opencode.json", ".config/opencode/opencode.jsonc"], artifacts: [".local/share/opencode"],
|
|
83
|
+
hookConfigPath: null, hookEventName: null,
|
|
84
|
+
mergeHookConfig: null, adapter: "generic", verifiedPayload: false,
|
|
85
|
+
notes: "OpenCode uses a generated TypeScript plugin, not a JSON hook file; beam does not generate plugin code yet. Discovery only."
|
|
86
|
+
},
|
|
87
|
+
];
|
|
88
|
+
export function findAgent(id) {
|
|
89
|
+
return AGENTS.find(a => a.id === id);
|
|
90
|
+
}
|
|
91
|
+
export function hookConfigFullPath(agent, home) {
|
|
92
|
+
if (!agent.hookConfigPath)
|
|
93
|
+
throw new Error(`${agent.name} has no supported hook config file yet.`);
|
|
94
|
+
return join(home, agent.hookConfigPath);
|
|
95
|
+
}
|
|
96
|
+
//# sourceMappingURL=agents.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"agents.js","sourceRoot":"","sources":["../src/agents.ts"],"names":[],"mappings":"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"}
|
package/dist/cli.d.ts
ADDED
package/dist/cli.js
ADDED
|
@@ -0,0 +1,234 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import fs from "node:fs";
|
|
3
|
+
import { Command } from "commander";
|
|
4
|
+
import { startServer } from "./serve.js";
|
|
5
|
+
import { captureHook, extractPreview, extractSave, importEvents, readToken, reloadRemoteRules, scanFile } from "./client.js";
|
|
6
|
+
import { supportsExtraction } from "./extract.js";
|
|
7
|
+
import { AGENTS } from "./agents.js";
|
|
8
|
+
import { installAllDetectedHooks, installHook } from "./install.js";
|
|
9
|
+
import { installService, serviceLogPaths, serviceStatus, startService, stopService, uninstallService } from "./service.js";
|
|
10
|
+
import { getCollectorUrl, getIdentityPath } from "./config.js";
|
|
11
|
+
import { enrollDevice, readIdentity } from "./enroll.js";
|
|
12
|
+
import { syncPolicy } from "./forward.js";
|
|
13
|
+
import { openBrowser } from "./open-browser.js";
|
|
14
|
+
import { ruleCatalog } from "./core.js";
|
|
15
|
+
import { loadCustomRules } from "./custom-rules.js";
|
|
16
|
+
import { sequenceRuleCatalog } from "./sequences.js";
|
|
17
|
+
const packageJson = JSON.parse(fs.readFileSync(new URL("../package.json", import.meta.url), "utf8"));
|
|
18
|
+
const program = new Command()
|
|
19
|
+
.name("beam")
|
|
20
|
+
.description("Local observation and heuristic risk scanning for AI agent activity")
|
|
21
|
+
.version(packageJson.version);
|
|
22
|
+
program.command("start")
|
|
23
|
+
.description("Start the local Beam collector (binds to 127.0.0.1)")
|
|
24
|
+
.option("-p, --port <port>", "port to listen on")
|
|
25
|
+
.action(async (options) => {
|
|
26
|
+
const result = await startServer({ port: options.port ? Number(options.port) : undefined });
|
|
27
|
+
const rulesNote = result.customRules.loaded ? `\nCustom rules loaded: ${result.customRules.loaded} from ${result.customRules.path}` : "";
|
|
28
|
+
for (const message of result.customRules.errors)
|
|
29
|
+
console.error(`✖ ${message}`);
|
|
30
|
+
const policyNote = result.policySync ? "\nPolicy sync: on (every 60s)" : "\nPolicy sync: off (device not enrolled — run 'beam enroll')";
|
|
31
|
+
const newlyInstalled = result.agentInstalls.filter(r => r.status === "installed");
|
|
32
|
+
const installNote = newlyInstalled.length
|
|
33
|
+
? `\nAgent hooks installed: ${newlyInstalled.map(r => r.name).join(", ")}`
|
|
34
|
+
: "";
|
|
35
|
+
for (const r of result.agentInstalls) {
|
|
36
|
+
if (r.status === "error")
|
|
37
|
+
console.error(`✖ Could not wire beam's hook into ${r.name}: ${r.error}`);
|
|
38
|
+
}
|
|
39
|
+
console.log(`Beam collector running.\nMode: observe only\nLocal storage: ${result.directory}${rulesNote}${policyNote}${installNote}\nRun 'beam agent list' to see every detected agent's capture status.\nRun 'beam token' for the pairing token.`);
|
|
40
|
+
});
|
|
41
|
+
const service = program.command("service").description("Run the collector as a background service (launchd on macOS, systemd --user on Linux)");
|
|
42
|
+
service.command("install")
|
|
43
|
+
.description("Install and start the collector as a background service that survives reboots")
|
|
44
|
+
.option("-p, --port <port>", "port to listen on")
|
|
45
|
+
.action(async (options) => {
|
|
46
|
+
const result = await installService({ port: options.port ? Number(options.port) : undefined });
|
|
47
|
+
console.log(`✔ Installed and started the beam service (${result.platform})\n config: ${result.configPath}`);
|
|
48
|
+
});
|
|
49
|
+
service.command("uninstall")
|
|
50
|
+
.description("Stop and remove the background service")
|
|
51
|
+
.action(async () => { await uninstallService(); console.log("✔ Removed the beam service."); });
|
|
52
|
+
service.command("start").description("Start the installed background service").action(async () => { await startService(); console.log("✔ Started."); });
|
|
53
|
+
service.command("stop").description("Stop the installed background service").action(async () => { await stopService(); console.log("✔ Stopped."); });
|
|
54
|
+
service.command("status")
|
|
55
|
+
.description("Show whether the background service is installed and running")
|
|
56
|
+
.action(async () => {
|
|
57
|
+
const result = await serviceStatus();
|
|
58
|
+
console.log(`platform: ${result.platform}\ninstalled: ${result.managed}\nrunning: ${result.running ?? "unknown"}\nconfig: ${result.configPath}`);
|
|
59
|
+
});
|
|
60
|
+
service.command("logs")
|
|
61
|
+
.description("Print the background service's log file paths (or the command to follow them)")
|
|
62
|
+
.action(async () => {
|
|
63
|
+
const paths = await serviceLogPaths();
|
|
64
|
+
console.log(paths.err ? `stdout: ${paths.out}\nstderr: ${paths.err}` : paths.out);
|
|
65
|
+
});
|
|
66
|
+
program.command("studio")
|
|
67
|
+
.description("Open the local activity dashboard in your browser")
|
|
68
|
+
.action(async () => {
|
|
69
|
+
const origin = getCollectorUrl().origin;
|
|
70
|
+
let token;
|
|
71
|
+
try {
|
|
72
|
+
token = await readToken();
|
|
73
|
+
}
|
|
74
|
+
catch (e) {
|
|
75
|
+
throw new Error(`${e.message} 'beam studio' needs the collector running first.`);
|
|
76
|
+
}
|
|
77
|
+
try {
|
|
78
|
+
await fetch(`${origin}/health`, { signal: AbortSignal.timeout(2000) });
|
|
79
|
+
}
|
|
80
|
+
catch {
|
|
81
|
+
throw new Error("Cannot reach the collector. Run 'beam start' or 'beam service install' first.");
|
|
82
|
+
}
|
|
83
|
+
openBrowser(`${origin}/?token=${encodeURIComponent(token)}`);
|
|
84
|
+
console.log("Opening beam studio in your browser…");
|
|
85
|
+
});
|
|
86
|
+
program.command("enroll")
|
|
87
|
+
.description("Enroll this device with your Beam workspace using a code from your manager")
|
|
88
|
+
.requiredOption("--code <code>", "enrollment code, e.g. BEAM-XXXX-XXXX-XXXX")
|
|
89
|
+
.option("--url <url>", "Beam API base URL (default $BEAM_API_URL or http://127.0.0.1:3200)")
|
|
90
|
+
.action(async (options) => {
|
|
91
|
+
const existing = await readIdentity();
|
|
92
|
+
if (existing)
|
|
93
|
+
console.error(`Replacing the existing enrollment (device ${existing.deviceId}).`);
|
|
94
|
+
const identity = await enrollDevice(options);
|
|
95
|
+
console.log(`✔ Enrolled device ${identity.deviceId}\n` +
|
|
96
|
+
` org: ${identity.orgId}\n` +
|
|
97
|
+
` api: ${identity.apiBase}\n` +
|
|
98
|
+
` identity: ${getIdentityPath()} (0600)\n\n` +
|
|
99
|
+
`Next: beam agent install-all && beam start`);
|
|
100
|
+
});
|
|
101
|
+
program.command("whoami")
|
|
102
|
+
.description("Show this device's enrollment, if any")
|
|
103
|
+
.action(async () => {
|
|
104
|
+
const identity = await readIdentity();
|
|
105
|
+
if (!identity)
|
|
106
|
+
throw new Error("This device is not enrolled. Run 'beam enroll --code <code>'.");
|
|
107
|
+
console.log(`device: ${identity.deviceId}\norg: ${identity.orgId}\napi: ${identity.apiBase}\nhost: ${identity.hostname} (${identity.os})\nsince: ${identity.enrolledAt}`);
|
|
108
|
+
});
|
|
109
|
+
program.command("sync")
|
|
110
|
+
.description("Pull the latest policy from your Beam workspace into ~/.beam/data/policy.json")
|
|
111
|
+
.action(async () => {
|
|
112
|
+
const result = await syncPolicy();
|
|
113
|
+
if (result.status === "not-enrolled")
|
|
114
|
+
throw new Error("This device is not enrolled. Run 'beam enroll --code <code>'.");
|
|
115
|
+
if (result.status === "unreachable")
|
|
116
|
+
throw new Error("Could not reach the Beam workspace. Check the network or 'beam whoami'.");
|
|
117
|
+
console.log(result.status === "updated" ? `✔ Policy v${result.version} synced → ${result.path}` : "✔ Policy already up to date.");
|
|
118
|
+
});
|
|
119
|
+
program.command("token")
|
|
120
|
+
.description("Print the Beam collector pairing token")
|
|
121
|
+
.action(async () => console.log(await readToken()));
|
|
122
|
+
program.command("import")
|
|
123
|
+
.description("Send a normalized events file (JSON/NDJSON) to the collector")
|
|
124
|
+
.argument("<file>", "path to events.ndjson or a JSON array/object")
|
|
125
|
+
.action(async (file) => console.log(JSON.stringify(await importEvents(file), null, 2)));
|
|
126
|
+
program.command("scan")
|
|
127
|
+
.description("Scan a SKILL.md or MCP config for risky instructions")
|
|
128
|
+
.argument("<file>", "path to SKILL.md or an MCP configuration file")
|
|
129
|
+
.option("--mcp", "treat the file as an MCP configuration instead of a skill")
|
|
130
|
+
.option("--save", "also save the report to the running collector")
|
|
131
|
+
.action(async (file, options) => console.log(JSON.stringify(await scanFile(file, options), null, 2)));
|
|
132
|
+
program.command("hook")
|
|
133
|
+
.description("Forward a hook payload from stdin for the given agent (observation only, never blocks the agent). Payload field names are adapted per agent; see 'beam agent list'.")
|
|
134
|
+
.argument("[source-agent]", "reporting agent id, e.g. claude-code, codex, cursor, copilot-cli", "claude-code")
|
|
135
|
+
.action(captureHook);
|
|
136
|
+
const agent = program.command("agent").description("Discover and configure supported AI agents");
|
|
137
|
+
agent.command("list")
|
|
138
|
+
.alias("ls")
|
|
139
|
+
.description("List supported agents and their hook payload verification status")
|
|
140
|
+
.action(() => {
|
|
141
|
+
for (const a of AGENTS) {
|
|
142
|
+
const install = a.hookConfigPath ? "installable" : "config wiring not built yet";
|
|
143
|
+
const payload = a.verifiedPayload ? "payload verified" : "payload best-effort";
|
|
144
|
+
console.log(`${a.id}\t${a.name}\t${install}\t${payload}`);
|
|
145
|
+
}
|
|
146
|
+
});
|
|
147
|
+
agent.command("install")
|
|
148
|
+
.description("Wire beam's hook into an agent's own hook config file, without disturbing existing hooks")
|
|
149
|
+
.argument("<agent>", "agent id, e.g. claude-code, codex, cursor, copilot-cli")
|
|
150
|
+
.action(async (agentId) => {
|
|
151
|
+
const result = await installHook(agentId);
|
|
152
|
+
console.log(result.alreadyInstalled ? `✔ Already installed for ${result.agent}\n → ${result.path}` : `✔ Installed beam hook for ${result.agent}\n → ${result.path}`);
|
|
153
|
+
});
|
|
154
|
+
agent.command("extract")
|
|
155
|
+
.description("Forensic extraction: read an agent's existing session/transcript files directly, no hook or live capture required")
|
|
156
|
+
.argument("<agent>", `agent id (currently: claude-code, codex)`)
|
|
157
|
+
.option("--save", "import extracted records into the running collector instead of just previewing them")
|
|
158
|
+
.option("--limit <n>", "cap how many events the offline preview prints", "200")
|
|
159
|
+
.action(async (agentId, options) => {
|
|
160
|
+
if (!supportsExtraction(agentId))
|
|
161
|
+
throw new Error(`Forensic extraction isn't built for '${agentId}' yet. Supported: claude-code, codex.`);
|
|
162
|
+
if (options.save) {
|
|
163
|
+
const result = await extractSave(agentId);
|
|
164
|
+
console.log(`Found ${result.found} historical action${result.found === 1 ? "" : "s"} in ${agentId}'s session files.\n✔ Imported: ${result.accepted}\n— Already had: ${result.duplicates}\n— Skipped (unsupported record type): ${result.skipped}`);
|
|
165
|
+
}
|
|
166
|
+
else {
|
|
167
|
+
const result = await extractPreview(agentId, Number(options.limit) || 200);
|
|
168
|
+
console.log(JSON.stringify(result.events, null, 2));
|
|
169
|
+
console.log(`\n${result.found} historical action${result.found === 1 ? "" : "s"} found (showing ${result.previewed}). This was NOT sent to the collector -- rerun with --save to import.`);
|
|
170
|
+
}
|
|
171
|
+
});
|
|
172
|
+
agent.command("install-all")
|
|
173
|
+
.description("Detect which agents are actually installed on this machine and wire beam's hook into all of them")
|
|
174
|
+
.action(async () => {
|
|
175
|
+
const results = await installAllDetectedHooks();
|
|
176
|
+
for (const r of results) {
|
|
177
|
+
if (r.status === "installed")
|
|
178
|
+
console.log(`✔ Installed for ${r.name}\n → ${r.path}`);
|
|
179
|
+
else if (r.status === "already-installed")
|
|
180
|
+
console.log(`✔ Already installed for ${r.name}`);
|
|
181
|
+
else if (r.status === "not-supported")
|
|
182
|
+
console.log(`— ${r.name} detected, but hook install isn't built for it yet`);
|
|
183
|
+
else if (r.status === "error")
|
|
184
|
+
console.log(`✖ ${r.name}: ${r.error}`);
|
|
185
|
+
// "not-detected" agents are omitted entirely to keep this output about what's actually on this machine.
|
|
186
|
+
}
|
|
187
|
+
const acted = results.filter(r => r.status === "installed" || r.status === "already-installed");
|
|
188
|
+
if (!acted.length)
|
|
189
|
+
console.log("No supported agents detected on this machine. Run 'beam agent list' to see what's supported.");
|
|
190
|
+
});
|
|
191
|
+
const rule = program.command("rule").description("Inspect the active detection rule catalog");
|
|
192
|
+
rule.command("list")
|
|
193
|
+
.alias("ls")
|
|
194
|
+
.description("List every active rule (built-in, custom, and cross-event sequence rules) grouped by category")
|
|
195
|
+
.action(async () => {
|
|
196
|
+
const customResult = await loadCustomRules();
|
|
197
|
+
const catalog = ruleCatalog();
|
|
198
|
+
const byCategory = new Map();
|
|
199
|
+
for (const r of catalog) {
|
|
200
|
+
const list = byCategory.get(r.category);
|
|
201
|
+
if (list)
|
|
202
|
+
list.push(r);
|
|
203
|
+
else
|
|
204
|
+
byCategory.set(r.category, [r]);
|
|
205
|
+
}
|
|
206
|
+
for (const [category, entries] of [...byCategory.entries()].sort(([a], [b]) => a.localeCompare(b))) {
|
|
207
|
+
console.log(`\n${category}`);
|
|
208
|
+
for (const r of entries)
|
|
209
|
+
console.log(` ${r.id}\t${r.severity}\t${r.title}`);
|
|
210
|
+
}
|
|
211
|
+
console.log(`\nsequence (cross-event, evaluated per session)`);
|
|
212
|
+
for (const r of sequenceRuleCatalog)
|
|
213
|
+
console.log(` ${r.id}\t${r.severity}\t${r.title} (${r.steps.length} steps)`);
|
|
214
|
+
const customCount = catalog.filter(r => r.category === "custom").length;
|
|
215
|
+
console.log(`\n${catalog.length} single-event rule${catalog.length === 1 ? "" : "s"} (${customCount} custom), ${sequenceRuleCatalog.length} sequence rule${sequenceRuleCatalog.length === 1 ? "" : "s"}.`);
|
|
216
|
+
if (customResult.errors.length) {
|
|
217
|
+
console.log(`\nCustom rule file issues (${customResult.path}):`);
|
|
218
|
+
for (const e of customResult.errors)
|
|
219
|
+
console.log(` ✖ ${e}`);
|
|
220
|
+
}
|
|
221
|
+
});
|
|
222
|
+
rule.command("reload")
|
|
223
|
+
.description("Reload ~/.beam/rules.json into the running collector, without restarting it")
|
|
224
|
+
.action(async () => {
|
|
225
|
+
const result = await reloadRemoteRules();
|
|
226
|
+
console.log(`Loaded ${result.loaded} custom rule${result.loaded === 1 ? "" : "s"} from ${result.path}.`);
|
|
227
|
+
for (const e of result.errors)
|
|
228
|
+
console.log(`✖ ${e}`);
|
|
229
|
+
});
|
|
230
|
+
program.parseAsync().catch((error) => {
|
|
231
|
+
console.error(`\n✖ ${error instanceof Error ? error.message : String(error)}`);
|
|
232
|
+
process.exitCode = 1;
|
|
233
|
+
});
|
|
234
|
+
//# sourceMappingURL=cli.js.map
|
package/dist/cli.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
|
package/dist/client.d.ts
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { type Event, type Scan } from "./core.js";
|
|
2
|
+
export declare function readToken(): Promise<string>;
|
|
3
|
+
export declare function importEvents(filePath: string): Promise<unknown>;
|
|
4
|
+
export interface RuleReloadResult {
|
|
5
|
+
path: string;
|
|
6
|
+
loaded: number;
|
|
7
|
+
errors: string[];
|
|
8
|
+
}
|
|
9
|
+
export declare function reloadRemoteRules(): Promise<RuleReloadResult>;
|
|
10
|
+
export interface ScanOptions {
|
|
11
|
+
mcp?: boolean;
|
|
12
|
+
save?: boolean;
|
|
13
|
+
}
|
|
14
|
+
export declare function scanFile(filePath: string, options?: ScanOptions, beamHome?: string): Promise<Scan | unknown>;
|
|
15
|
+
export interface ExtractPreviewResult {
|
|
16
|
+
found: number;
|
|
17
|
+
previewed: number;
|
|
18
|
+
events: Event[];
|
|
19
|
+
}
|
|
20
|
+
export interface ExtractSaveResult {
|
|
21
|
+
found: number;
|
|
22
|
+
accepted: number;
|
|
23
|
+
duplicates: number;
|
|
24
|
+
skipped: number;
|
|
25
|
+
}
|
|
26
|
+
export declare function extractPreview(agentId: string, limit?: number, home?: string, beamHome?: string): Promise<ExtractPreviewResult>;
|
|
27
|
+
export declare function extractSave(agentId: string, home?: string): Promise<ExtractSaveResult>;
|
|
28
|
+
export declare function captureHook(sourceAgent?: string): Promise<void>;
|