@agent-beam/beam 0.2.20 → 0.2.22

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (67) hide show
  1. package/README.md +19 -0
  2. package/dist/account.js +1 -1
  3. package/dist/account.js.map +1 -1
  4. package/dist/agents.d.ts +8 -2
  5. package/dist/agents.js +7 -7
  6. package/dist/agents.js.map +1 -1
  7. package/dist/cli.js +289 -41
  8. package/dist/cli.js.map +1 -1
  9. package/dist/client.js +23 -6
  10. package/dist/client.js.map +1 -1
  11. package/dist/connect.js +1 -1
  12. package/dist/connect.js.map +1 -1
  13. package/dist/enroll.d.ts +0 -4
  14. package/dist/enroll.js +2 -60
  15. package/dist/enroll.js.map +1 -1
  16. package/dist/forward.d.ts +2 -0
  17. package/dist/forward.js +19 -0
  18. package/dist/forward.js.map +1 -1
  19. package/dist/hook-adapters.js +14 -1
  20. package/dist/hook-adapters.js.map +1 -1
  21. package/dist/install.d.ts +2 -0
  22. package/dist/install.js +58 -6
  23. package/dist/install.js.map +1 -1
  24. package/dist/policy.d.ts +1 -0
  25. package/dist/policy.js +11 -3
  26. package/dist/policy.js.map +1 -1
  27. package/dist/serve.d.ts +2 -0
  28. package/dist/serve.js +47 -2
  29. package/dist/serve.js.map +1 -1
  30. package/dist/setup.js +33 -2
  31. package/dist/setup.js.map +1 -1
  32. package/dist/skill-context.d.ts +11 -0
  33. package/dist/skill-context.js +78 -0
  34. package/dist/skill-context.js.map +1 -0
  35. package/dist/skill-gate.d.ts +21 -0
  36. package/dist/skill-gate.js +180 -0
  37. package/dist/skill-gate.js.map +1 -0
  38. package/dist/skill-inventory.d.ts +81 -0
  39. package/dist/skill-inventory.js +167 -0
  40. package/dist/skill-inventory.js.map +1 -0
  41. package/dist/skill-risk-rules.d.ts +17 -0
  42. package/dist/skill-risk-rules.js +61 -0
  43. package/dist/skill-risk-rules.js.map +1 -0
  44. package/dist/skill-scan.d.ts +27 -0
  45. package/dist/skill-scan.js +157 -0
  46. package/dist/skill-scan.js.map +1 -0
  47. package/dist/skill-setup.d.ts +11 -0
  48. package/dist/skill-setup.js +26 -0
  49. package/dist/skill-setup.js.map +1 -0
  50. package/dist/skill-sync.d.ts +40 -0
  51. package/dist/skill-sync.js +79 -0
  52. package/dist/skill-sync.js.map +1 -0
  53. package/dist/skill-watch.d.ts +16 -0
  54. package/dist/skill-watch.js +41 -0
  55. package/dist/skill-watch.js.map +1 -0
  56. package/dist/skills.d.ts +33 -0
  57. package/dist/skills.js +139 -0
  58. package/dist/skills.js.map +1 -0
  59. package/dist/tamper.d.ts +9 -0
  60. package/dist/tamper.js +116 -0
  61. package/dist/tamper.js.map +1 -0
  62. package/dist/trusted-skills.d.ts +9 -0
  63. package/dist/trusted-skills.js +31 -0
  64. package/dist/trusted-skills.js.map +1 -0
  65. package/dist/tty-prompt.js +3 -1
  66. package/dist/tty-prompt.js.map +1 -1
  67. package/package.json +2 -2
package/README.md CHANGED
@@ -2,6 +2,25 @@
2
2
 
3
3
  AgentBeam is a local security layer for AI agents. `beam` is the AgentBeam CLI. It installs hooks for the agents detected on your machine, captures agent and MCP activity, applies your AgentBeam policy locally, and sends approved telemetry to the AgentBeam dashboard.
4
4
 
5
+ ## WipeBench: coding agent safety benchmark
6
+
7
+ [WipeBench](https://github.com/whyashthakker/WipeBench) gives coding agents an
8
+ objective, captures the commands they choose, and evaluates task completion and
9
+ harmful effects in Docker. A benchmark by [AgentBeam](https://agentbeam.com), in
10
+ collaboration with [ExplainX.ai](https://explainx.ai).
11
+
12
+ The [local snapshot](safety-bench/README.md) includes 112 scored scenarios across
13
+ 12 categories and a no-key smoke test:
14
+
15
+ ```sh
16
+ python3 safety-bench/bench.py selftest --scenarios smoke-hello
17
+ ```
18
+
19
+ Requires Python 3.11+ and a running Docker daemon. Scripted self-tests validate
20
+ the harness; they are not model rankings. The benchmark snapshot uses its own
21
+ [Apache-2.0 license](safety-bench/LICENSE). See the
22
+ [benchmark page](https://agentbeam.com/benchmarks/wipebench) for scope and usage.
23
+
5
24
  ## Install and setup
6
25
 
7
26
  ```bash
package/dist/account.js CHANGED
@@ -21,7 +21,7 @@ export async function fetchAccount(identity) {
21
21
  }
22
22
  catch { /* keep the status-only message */ }
23
23
  if (response.status === 401)
24
- message = "This device's credentials were revoked. Run 'beam enroll' or 'beam connect' again.";
24
+ message = "This device's credentials were revoked. Run 'beam setup' again.";
25
25
  throw new Error(message);
26
26
  }
27
27
  return (await response.json());
@@ -1 +1 @@
1
- {"version":3,"file":"account.js","sourceRoot":"","sources":["../src/account.ts"],"names":[],"mappings":"AAQA,+FAA+F;AAC/F,4FAA4F;AAC5F,yDAAyD;AACzD,MAAM,CAAC,KAAK,UAAU,YAAY,CAAC,QAAkB;IACnD,IAAI,QAAkB,CAAC;IACvB,IAAI,CAAC;QACH,QAAQ,GAAG,MAAM,KAAK,CAAC,GAAG,QAAQ,CAAC,OAAO,aAAa,EAAE;YACvD,OAAO,EAAE,EAAE,aAAa,EAAE,UAAU,QAAQ,CAAC,YAAY,EAAE,EAAE;YAC7D,MAAM,EAAE,WAAW,CAAC,OAAO,CAAC,MAAM,CAAC;SACpC,CAAC,CAAC;IACL,CAAC;IAAC,MAAM,CAAC;QACP,MAAM,IAAI,KAAK,CAAC,mBAAmB,QAAQ,CAAC,OAAO,GAAG,CAAC,CAAC;IAC1D,CAAC;IAED,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;QACjB,IAAI,OAAO,GAAG,oCAAoC,QAAQ,CAAC,MAAM,IAAI,CAAC;QACtE,IAAI,CAAC;YACH,MAAM,IAAI,GAAG,CAAC,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAuB,CAAC;YAC3D,IAAI,IAAI,CAAC,KAAK;gBAAE,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC;QACvC,CAAC;QAAC,MAAM,CAAC,CAAC,kCAAkC,CAAC,CAAC;QAC9C,IAAI,QAAQ,CAAC,MAAM,KAAK,GAAG;YAAE,OAAO,GAAG,oFAAoF,CAAC;QAC5H,MAAM,IAAI,KAAK,CAAC,OAAO,CAAC,CAAC;IAC3B,CAAC;IAED,OAAO,CAAC,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAY,CAAC;AAC5C,CAAC;AAED,+FAA+F;AAC/F,gGAAgG;AAChG,gGAAgG;AAChG,uEAAuE;AACvE,MAAM,CAAC,KAAK,UAAU,YAAY,CAAC,QAAkB;IACnD,IAAI,QAAkB,CAAC;IACvB,IAAI,CAAC;QACH,QAAQ,GAAG,MAAM,KAAK,CAAC,GAAG,QAAQ,CAAC,OAAO,YAAY,EAAE;YACtD,MAAM,EAAE,MAAM;YACd,OAAO,EAAE,EAAE,aAAa,EAAE,UAAU,QAAQ,CAAC,YAAY,EAAE,EAAE;YAC7D,MAAM,EAAE,WAAW,CAAC,OAAO,CAAC,MAAM,CAAC;SACpC,CAAC,CAAC;IACL,CAAC;IAAC,MAAM,CAAC;QACP,MAAM,IAAI,KAAK,CAAC,mBAAmB,QAAQ,CAAC,OAAO,GAAG,CAAC,CAAC;IAC1D,CAAC;IAED,6EAA6E;IAC7E,IAAI,QAAQ,CAAC,MAAM,KAAK,GAAG;QAAE,OAAO;IAEpC,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;QACjB,IAAI,OAAO,GAAG,iCAAiC,QAAQ,CAAC,MAAM,IAAI,CAAC;QACnE,IAAI,CAAC;YACH,MAAM,IAAI,GAAG,CAAC,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAuB,CAAC;YAC3D,IAAI,IAAI,CAAC,KAAK;gBAAE,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC;QACvC,CAAC;QAAC,MAAM,CAAC,CAAC,kCAAkC,CAAC,CAAC;QAC9C,MAAM,IAAI,KAAK,CAAC,OAAO,CAAC,CAAC;IAC3B,CAAC;AACH,CAAC"}
1
+ {"version":3,"file":"account.js","sourceRoot":"","sources":["../src/account.ts"],"names":[],"mappings":"AAQA,+FAA+F;AAC/F,4FAA4F;AAC5F,yDAAyD;AACzD,MAAM,CAAC,KAAK,UAAU,YAAY,CAAC,QAAkB;IACnD,IAAI,QAAkB,CAAC;IACvB,IAAI,CAAC;QACH,QAAQ,GAAG,MAAM,KAAK,CAAC,GAAG,QAAQ,CAAC,OAAO,aAAa,EAAE;YACvD,OAAO,EAAE,EAAE,aAAa,EAAE,UAAU,QAAQ,CAAC,YAAY,EAAE,EAAE;YAC7D,MAAM,EAAE,WAAW,CAAC,OAAO,CAAC,MAAM,CAAC;SACpC,CAAC,CAAC;IACL,CAAC;IAAC,MAAM,CAAC;QACP,MAAM,IAAI,KAAK,CAAC,mBAAmB,QAAQ,CAAC,OAAO,GAAG,CAAC,CAAC;IAC1D,CAAC;IAED,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;QACjB,IAAI,OAAO,GAAG,oCAAoC,QAAQ,CAAC,MAAM,IAAI,CAAC;QACtE,IAAI,CAAC;YACH,MAAM,IAAI,GAAG,CAAC,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAuB,CAAC;YAC3D,IAAI,IAAI,CAAC,KAAK;gBAAE,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC;QACvC,CAAC;QAAC,MAAM,CAAC,CAAC,kCAAkC,CAAC,CAAC;QAC9C,IAAI,QAAQ,CAAC,MAAM,KAAK,GAAG;YAAE,OAAO,GAAG,iEAAiE,CAAC;QACzG,MAAM,IAAI,KAAK,CAAC,OAAO,CAAC,CAAC;IAC3B,CAAC;IAED,OAAO,CAAC,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAY,CAAC;AAC5C,CAAC;AAED,+FAA+F;AAC/F,gGAAgG;AAChG,gGAAgG;AAChG,uEAAuE;AACvE,MAAM,CAAC,KAAK,UAAU,YAAY,CAAC,QAAkB;IACnD,IAAI,QAAkB,CAAC;IACvB,IAAI,CAAC;QACH,QAAQ,GAAG,MAAM,KAAK,CAAC,GAAG,QAAQ,CAAC,OAAO,YAAY,EAAE;YACtD,MAAM,EAAE,MAAM;YACd,OAAO,EAAE,EAAE,aAAa,EAAE,UAAU,QAAQ,CAAC,YAAY,EAAE,EAAE;YAC7D,MAAM,EAAE,WAAW,CAAC,OAAO,CAAC,MAAM,CAAC;SACpC,CAAC,CAAC;IACL,CAAC;IAAC,MAAM,CAAC;QACP,MAAM,IAAI,KAAK,CAAC,mBAAmB,QAAQ,CAAC,OAAO,GAAG,CAAC,CAAC;IAC1D,CAAC;IAED,6EAA6E;IAC7E,IAAI,QAAQ,CAAC,MAAM,KAAK,GAAG;QAAE,OAAO;IAEpC,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;QACjB,IAAI,OAAO,GAAG,iCAAiC,QAAQ,CAAC,MAAM,IAAI,CAAC;QACnE,IAAI,CAAC;YACH,MAAM,IAAI,GAAG,CAAC,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAuB,CAAC;YAC3D,IAAI,IAAI,CAAC,KAAK;gBAAE,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC;QACvC,CAAC;QAAC,MAAM,CAAC,CAAC,kCAAkC,CAAC,CAAC;QAC9C,MAAM,IAAI,KAAK,CAAC,OAAO,CAAC,CAAC;IAC3B,CAAC;AACH,CAAC"}
package/dist/agents.d.ts CHANGED
@@ -19,9 +19,15 @@ export interface AgentDefinition {
19
19
  /**
20
20
  * Reverse of mergeHookConfig — strips beam's hook entry back out, leaving any other hooks the
21
21
  * agent or the user configured untouched. Must be idempotent — safe to call on a config that
22
- * never had beam installed (a no-op).
22
+ * never had beam installed (a no-op). Takes a predicate rather than an exact command string:
23
+ * a hook's command embeds the absolute path to whichever beam install wrote it (see
24
+ * resolveHookCommand in install.ts), which differs between a global npm install, a local dev
25
+ * checkout, or the same install after 'beam update' changes its resolved path. An uninstall
26
+ * running from a *different* beam install than the one that wrote the entry must still
27
+ * recognize and remove it -- matching only one exact string silently leaves it in place (and
28
+ * beam fully monitoring/enforcing) instead. See isOwnHookCommand in install.ts.
23
29
  */
24
- unmergeHookConfig: ((existing: Obj, command: string) => Obj) | null;
30
+ unmergeHookConfig: ((existing: Obj, isOwnCommand: (command: string) => boolean) => Obj) | null;
25
31
  /** Payload adapter id used by src/hook-adapters.ts to normalize this agent's stdin JSON. */
26
32
  adapter: "passthrough" | "copilot-camel" | "generic" | "gemini";
27
33
  /** Whether the AGENT ITSELF (not just this entry's payload verification) is unverified — the
package/dist/agents.js CHANGED
@@ -43,33 +43,33 @@ function mergeCopilotHooks(event) {
43
43
  // Reverse of mergeClaudeStyleHooks: drops beam's command out of each entry's inner hooks array
44
44
  // (rather than the whole entry), so a user-added hook sharing the same matcher is left alone.
45
45
  function unmergeClaudeStyleHooks(event) {
46
- return (existing, command) => {
46
+ return (existing, isOwnCommand) => {
47
47
  const hooks = obj(existing.hooks);
48
48
  if (!(event in hooks))
49
49
  return existing;
50
50
  const list = arr(hooks[event]).map(obj)
51
- .map(entry => ({ ...entry, hooks: arr(entry.hooks).map(obj).filter(h => h.command !== command) }))
51
+ .map(entry => ({ ...entry, hooks: arr(entry.hooks).map(obj).filter(h => !isOwnCommand(String(h.command ?? ""))) }))
52
52
  .filter(entry => arr(entry.hooks).length > 0);
53
53
  return { ...existing, hooks: { ...hooks, [event]: list } };
54
54
  };
55
55
  }
56
56
  // Reverse of mergeCursorHooks.
57
57
  function unmergeCursorHooks(event) {
58
- return (existing, command) => {
58
+ return (existing, isOwnCommand) => {
59
59
  const hooks = obj(existing.hooks);
60
60
  if (!(event in hooks))
61
61
  return existing;
62
- const list = arr(hooks[event]).map(obj).filter(entry => entry.command !== command);
62
+ const list = arr(hooks[event]).map(obj).filter(entry => !isOwnCommand(String(entry.command ?? "")));
63
63
  return { ...existing, hooks: { ...hooks, [event]: list } };
64
64
  };
65
65
  }
66
66
  // Reverse of mergeCopilotHooks.
67
67
  function unmergeCopilotHooks(event) {
68
- return (existing, command) => {
68
+ return (existing, isOwnCommand) => {
69
69
  const hooks = obj(existing.hooks);
70
70
  if (!(event in hooks))
71
71
  return existing;
72
- const list = arr(hooks[event]).map(obj).filter(entry => entry.bash !== command);
72
+ const list = arr(hooks[event]).map(obj).filter(entry => !isOwnCommand(String(entry.bash ?? "")));
73
73
  return { ...existing, hooks: { ...hooks, [event]: list } };
74
74
  };
75
75
  }
@@ -83,7 +83,7 @@ function mergeAll(mergers) {
83
83
  return (existing, command) => mergers.reduce((acc, merge) => merge(acc, command), existing);
84
84
  }
85
85
  function unmergeAll(unmergers) {
86
- return (existing, command) => unmergers.reduce((acc, unmerge) => unmerge(acc, command), existing);
86
+ return (existing, isOwnCommand) => unmergers.reduce((acc, unmerge) => unmerge(acc, isOwnCommand), existing);
87
87
  }
88
88
  export const AGENTS = [
89
89
  {
@@ -1 +1 @@
1
- {"version":3,"file":"agents.js","sourceRoot":"","sources":["../src/agents.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"agents.js","sourceRoot":"","sources":["../src/agents.ts"],"names":[],"mappings":"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"}
package/dist/cli.js CHANGED
@@ -6,11 +6,11 @@ import { startServer } from "./serve.js";
6
6
  import { captureHook, extractPreview, extractSave, importEvents, readToken, reloadRemoteRules, scanFile } from "./client.js";
7
7
  import { supportsExtraction } from "./extract.js";
8
8
  import { AGENTS } from "./agents.js";
9
- import { installAllDetectedHooks, installHook, uninstallAllHooks } from "./install.js";
9
+ import { installAllDetectedHooks, installHook, uninstallAllHooks, uninstallHook } from "./install.js";
10
10
  import { configuredPort, installService, serviceLogPaths, serviceStatus, startService, stopService, uninstallService } from "./service.js";
11
11
  import { waitForCollectorUp } from "./collector-health.js";
12
12
  import { getBeamHome, getCollectorUrl, getDataDirectory, getIdentityPath } from "./config.js";
13
- import { clearIdentity, enrollDevice, readIdentity } from "./enroll.js";
13
+ import { clearIdentity, readIdentity } from "./enroll.js";
14
14
  import { startConnect } from "./connect.js";
15
15
  import { runSetup, promptYesNo } from "./setup.js";
16
16
  import { installEnterprisePackage } from "./enterprise-install.js";
@@ -22,8 +22,13 @@ import { loadCustomRules } from "./custom-rules.js";
22
22
  import { sequenceRuleCatalog } from "./sequences.js";
23
23
  import { printBanner } from "./banner.js";
24
24
  import { runWithSudoFallback } from "./elevate.js";
25
- import { renderColumns, withSpinner } from "./prompts.js";
26
- import { cyan, green } from "./color.js";
25
+ import { confirm, renderColumns, withSpinner } from "./prompts.js";
26
+ import { cyan, dim, green, red } from "./color.js";
27
+ import { ALL_SKILL_AGENTS, addSkill, isBlocked, scanInstalledSkills } from "./skills.js";
28
+ import { scanSkillDir } from "./skill-scan.js";
29
+ import { syncSkillInventory } from "./skill-sync.js";
30
+ import { agentSkillRoots, deviceSkillsScore, indexSkills, inventoryFile, readInventory, trustedHashes } from "./skill-inventory.js";
31
+ import { readTrustedSkills, trustSkill, untrustSkill } from "./trusted-skills.js";
27
32
  import { runAgent } from "./run.js";
28
33
  import { AGENT_BINARIES, installShims, listShims, pathExportLine, shimDir, uninstallShims } from "./shims.js";
29
34
  import { runMcpProxy } from "./mcp-proxy.js";
@@ -31,6 +36,7 @@ import { registerJevCommands } from "./jev-cli.js";
31
36
  import { addTrustedPath, readTrustedPaths, removeTrustedPath, trustedPathsFile } from "./trusted-paths.js";
32
37
  import { blockedTargetsFile, readBlockedTargets, removeBlockedTarget } from "./blocked-targets.js";
33
38
  import { checkForUpdate, installUpdate } from "./update.js";
39
+ import { recordExpectedHooks, reportControlEvent } from "./tamper.js";
34
40
  // Lets 'BEAM_API_URL=... beam connect' style overrides live in a .env file instead of the
35
41
  // shell profile. Checked in cwd first (handy when developing from the repo), then in
36
42
  // ~/.beam so overrides still apply when 'beam' is run globally from any directory.
@@ -74,7 +80,7 @@ program.command("start")
74
80
  const rulesNote = result.customRules.loaded ? `\nCustom rules loaded: ${result.customRules.loaded} from ${result.customRules.path}` : "";
75
81
  for (const message of result.customRules.errors)
76
82
  console.error(`✖ ${message}`);
77
- const policyNote = result.policySync ? "\nPolicy sync: on (every 60s)" : "\nPolicy sync: off (device not enrolled — run 'beam enroll')";
83
+ const policyNote = result.policySync ? "\nPolicy sync: on (every 60s)" : "\nPolicy sync: off (device not enrolled — run 'beam setup')";
78
84
  const newlyInstalled = result.agentInstalls.filter(r => r.status === "installed");
79
85
  const installNote = newlyInstalled.length
80
86
  ? `\nAgent hooks installed: ${newlyInstalled.map(r => r.name).join(", ")}`
@@ -85,6 +91,22 @@ program.command("start")
85
91
  }
86
92
  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.`);
87
93
  });
94
+ // Shared gate for every command that reduces or removes beam's visibility on this device
95
+ // (stopping/uninstalling the service, detaching an agent's hook, or logging out entirely). On an
96
+ // enrolled device these are exactly the actions an employee could otherwise use to go dark to
97
+ // their org's dashboard without anyone knowing -- see tamper.ts. So each one prints what will
98
+ // actually happen and, when enrolled, that the org admin will be notified this device did it,
99
+ // then requires an explicit "Yes" (or --yes, for scripted/CI use) before doing anything. There is
100
+ // no path to run the underlying action without either declining here or accepting the notice: the
101
+ // action and the report are the same decision, not two.
102
+ async function confirmControlAction(message, identity, yes) {
103
+ console.log(identity
104
+ ? `${message}\nYour organization admin will be notified that this device (${identity.hostname}) did this.`
105
+ : message);
106
+ if (yes)
107
+ return true;
108
+ return promptYesNo("\nProceed?", false);
109
+ }
88
110
  const service = program.command("service").description("Run the collector as a background service (launchd on macOS, systemd --user on Linux)");
89
111
  service.command("install")
90
112
  .description("Install and start the collector as a background service that survives reboots")
@@ -102,7 +124,19 @@ service.command("install")
102
124
  });
103
125
  service.command("uninstall")
104
126
  .description("Stop and remove the background service")
105
- .action(async () => { await uninstallService(); console.log("✔ Removed the beam service."); });
127
+ .option("--yes", "skip the confirmation prompt")
128
+ .action(async (options) => {
129
+ const identity = await readIdentity();
130
+ const proceed = await confirmControlAction("This will stop and remove beam's background service. It will no longer observe or policy-enforce AI agent activity on this device.", identity, options.yes);
131
+ if (!proceed) {
132
+ console.log("Cancelled.");
133
+ return;
134
+ }
135
+ if (identity)
136
+ await reportControlEvent("service-uninstall", `Beam service removed on ${identity.hostname}`, "This device ran 'beam service uninstall'. Beam's background collector will no longer start automatically -- it is not observing or policy-enforcing until 'beam service install' runs again.");
137
+ await uninstallService();
138
+ console.log("✔ Removed the beam service.");
139
+ });
106
140
  service.command("start")
107
141
  .description("Start the installed background service")
108
142
  .action(async () => {
@@ -116,7 +150,21 @@ service.command("start")
116
150
  process.exitCode = 1;
117
151
  }
118
152
  });
119
- service.command("stop").description("Stop the installed background service").action(async () => { await stopService(); console.log("✔ Stopped."); });
153
+ service.command("stop")
154
+ .description("Stop the installed background service")
155
+ .option("--yes", "skip the confirmation prompt")
156
+ .action(async (options) => {
157
+ const identity = await readIdentity();
158
+ const proceed = await confirmControlAction("This will stop beam's background service. It will not observe or policy-enforce AI agent activity on this device until it's started again.", identity, options.yes);
159
+ if (!proceed) {
160
+ console.log("Cancelled.");
161
+ return;
162
+ }
163
+ if (identity)
164
+ await reportControlEvent("service-stop", `Beam service stopped on ${identity.hostname}`, "This device ran 'beam service stop'. Beam's background collector is not running -- it is not observing or policy-enforcing until it's started again.");
165
+ await stopService();
166
+ console.log("✔ Stopped.");
167
+ });
120
168
  service.command("status")
121
169
  .description("Show whether the background service is installed and running")
122
170
  .action(async () => {
@@ -149,27 +197,12 @@ program.command("studio")
149
197
  openBrowser(`${origin}/?token=${encodeURIComponent(token)}`);
150
198
  console.log("Opening beam studio in your browser…");
151
199
  });
152
- program.command("enroll")
153
- .description("Enroll this device with your Beam workspace using a code from your manager")
154
- .requiredOption("--code <code>", "enrollment code, e.g. BEAM-XXXX-XXXX-XXXX")
155
- .option("--url <url>", "Beam API base URL (default $BEAM_API_URL or https://collector.agentbeam.com)")
156
- .action(async (options) => {
157
- const existing = await readIdentity();
158
- if (existing)
159
- console.error(`Replacing the existing enrollment (device ${existing.deviceId}).`);
160
- const identity = await enrollDevice(options);
161
- console.log(`${green("✔")} Enrolled device ${identity.deviceId}\n` +
162
- ` org: ${identity.orgId}\n` +
163
- ` api: ${identity.apiBase}\n` +
164
- ` identity: ${getIdentityPath()} (0600)\n\n` +
165
- cyan(`Next: beam agent install-all && beam start`));
166
- });
167
200
  program.command("whoami")
168
201
  .description("Show this device's enrollment, if any")
169
202
  .action(async () => {
170
203
  const identity = await readIdentity();
171
204
  if (!identity)
172
- throw new Error("This device is not enrolled. Run 'beam enroll --code <code>'.");
205
+ throw new Error("This device is not enrolled. Run 'beam setup'.");
173
206
  console.log(`device: ${identity.deviceId}\norg: ${identity.orgId}\napi: ${identity.apiBase}\nhost: ${identity.hostname} (${identity.os})\nsince: ${identity.enrolledAt}`);
174
207
  });
175
208
  program.command("account")
@@ -177,7 +210,7 @@ program.command("account")
177
210
  .action(async () => {
178
211
  const identity = await readIdentity();
179
212
  if (!identity)
180
- throw new Error("This device is not enrolled. Run 'beam connect' or 'beam enroll --code <code>'.");
213
+ throw new Error("This device is not enrolled. Run 'beam setup'.");
181
214
  const account = await fetchAccount(identity);
182
215
  console.log(`user: ${account.user.email}${account.user.name ? ` (${account.user.name})` : ""}\n` +
183
216
  `org: ${account.org.name} (${account.org.slug})\n` +
@@ -186,12 +219,22 @@ program.command("account")
186
219
  });
187
220
  program.command("logout")
188
221
  .description("Disconnect this device from your Beam workspace and remove local credentials")
189
- .action(async () => {
222
+ .option("--yes", "skip the confirmation prompt")
223
+ .action(async (options) => {
190
224
  const identity = await readIdentity();
191
225
  if (!identity) {
192
226
  console.log("This device is not enrolled -- nothing to do.");
193
227
  return;
194
228
  }
229
+ const proceed = await confirmControlAction("This will disconnect this device from your Beam workspace. It will stop reporting activity until it's re-enrolled.", identity, options.yes);
230
+ if (!proceed) {
231
+ console.log("Cancelled.");
232
+ return;
233
+ }
234
+ // Sent while identity.json still exists, so it authenticates -- and before revokeDevice()
235
+ // below, so it's an authenticated "I chose to log out" record rather than something an admin
236
+ // has to infer from the device simply going quiet (see tamper.ts).
237
+ await reportControlEvent("logout", `Beam logged out on ${identity.hostname}`, `This device was logged out via 'beam logout'. It is no longer enrolled and will stop reporting until re-enrolled.`);
195
238
  try {
196
239
  await revokeDevice(identity);
197
240
  }
@@ -209,18 +252,23 @@ program.command("uninstall")
209
252
  .action(async (options) => {
210
253
  const beamHome = getBeamHome();
211
254
  const dataDir = getDataDirectory();
212
- console.log("This will remove:\n" +
255
+ const identityBeforeUninstall = await readIdentity();
256
+ const proceed = await confirmControlAction("This will remove:\n" +
213
257
  " - the beam background service (if installed)\n" +
214
258
  " - beam's hooks from every AI agent config it was wired into\n" +
215
259
  ` - ${beamHome} (identity, cached policy, event logs, custom rules)\n` +
216
260
  " - this device's registration with your Beam workspace" +
217
- (options.keepPackage ? "" : "\n - the globally installed beam (and beam-enterprise, if present) npm package"));
218
- if (!options.yes) {
219
- const proceed = await promptYesNo("\nProceed?", false);
220
- if (!proceed) {
221
- console.log("Cancelled.");
222
- return;
223
- }
261
+ (options.keepPackage ? "" : "\n - the globally installed beam (and beam-enterprise, if present) npm package"), identityBeforeUninstall, options.yes);
262
+ if (!proceed) {
263
+ console.log("Cancelled.");
264
+ return;
265
+ }
266
+ // Sent first, before anything below touches identity.json, the service, or hooks -- so the
267
+ // workspace has an authenticated "this was a deliberate 'beam uninstall'" record even if a
268
+ // later step in this command fails partway through. See tamper.ts: this is what distinguishes
269
+ // an authorized removal from the silent kind checkForTampering() is built to catch.
270
+ if (identityBeforeUninstall) {
271
+ await reportControlEvent("uninstall", `Beam uninstalled on ${identityBeforeUninstall.hostname}`, "This device ran 'beam uninstall'. Its background service, agent hooks, and local data are being removed, and its registration is being revoked.");
224
272
  }
225
273
  try {
226
274
  await uninstallService();
@@ -229,14 +277,23 @@ program.command("uninstall")
229
277
  catch (e) {
230
278
  console.log(`— Skipped background service (${e.message}).`);
231
279
  }
232
- const hookResults = await uninstallAllHooks();
233
- const removedHooks = hookResults.filter(r => r.removed);
234
- if (removedHooks.length) {
235
- for (const r of removedHooks)
236
- console.log(`✔ Removed beam's hook from ${r.agent}\n → ${r.path}`);
280
+ // Wrapped like uninstallService() above: one agent's hook config being unreadable (invalid
281
+ // JSON, a permission error) must not abort the rest of 'beam uninstall' -- in particular it
282
+ // must not skip revokeDevice() below, or the device is wiped locally but the dashboard shows
283
+ // it as connected forever with nothing left running here to ever tell it otherwise.
284
+ try {
285
+ const hookResults = await uninstallAllHooks();
286
+ const removedHooks = hookResults.filter(r => r.removed);
287
+ if (removedHooks.length) {
288
+ for (const r of removedHooks)
289
+ console.log(`✔ Removed beam's hook from ${r.agent}\n → ${r.path}`);
290
+ }
291
+ else {
292
+ console.log("— No installed agent hooks found.");
293
+ }
237
294
  }
238
- else {
239
- console.log("— No installed agent hooks found.");
295
+ catch (e) {
296
+ console.log(`— Could not remove every agent hook (${e.message}).`);
240
297
  }
241
298
  const identity = await readIdentity();
242
299
  if (identity) {
@@ -277,7 +334,7 @@ program.command("sync")
277
334
  .action(async () => {
278
335
  const result = await syncPolicy();
279
336
  if (result.status === "not-enrolled")
280
- throw new Error("This device is not enrolled. Run 'beam enroll --code <code>'.");
337
+ throw new Error("This device is not enrolled. Run 'beam setup'.");
281
338
  if (result.status === "unreachable")
282
339
  throw new Error("Could not reach the Beam workspace. Check the network or 'beam whoami'.");
283
340
  console.log(result.status === "updated" ? `✔ Policy v${result.version} synced → ${result.path}` : "✔ Policy already up to date.");
@@ -366,6 +423,178 @@ program.command("scan")
366
423
  .option("--mcp", "treat the file as an MCP configuration instead of a skill")
367
424
  .option("--save", "also save the report to the running collector")
368
425
  .action(async (file, options) => console.log(JSON.stringify(await scanFile(file, options), null, 2)));
426
+ function printSkillScan(scan) {
427
+ const badge = scan.risk === "critical" || scan.risk === "high" ? red(scan.risk.toUpperCase()) : scan.risk === "medium" ? scan.risk : green(scan.findings.length ? scan.risk : "clean");
428
+ console.log(`\n${scan.name} [${badge}] risk score ${scan.score}/100 (${scan.level}) ${scan.filesScanned} files scanned`);
429
+ for (const f of scan.findings.slice(0, 10))
430
+ console.log(` ${f.severity.padEnd(8)} ${f.title} ${dim(`${f.file}${f.line ? `:${f.line}` : ""}`)}\n ${dim(f.evidence.split("\n")[0].slice(0, 100))}`);
431
+ if (scan.findings.length > 10)
432
+ console.log(dim(` … ${scan.findings.length - 10} more (use --json for all)`));
433
+ for (const s of scan.skipped)
434
+ console.log(dim(` skipped ${s}`));
435
+ }
436
+ const add = program.command("add").description("Add reusable AI assets, scanned before they are installed");
437
+ add.command("skill")
438
+ .description("Download a skill, scan it for prompt injection and risky instructions, then install it only if it passes")
439
+ .argument("<source>", "owner/repo, a GitHub/GitLab https URL, or a local folder")
440
+ .option("--skill <name>", "pick one skill when the source contains several")
441
+ .option("--agent <agent...>", `target agent(s): ${ALL_SKILL_AGENTS.join(", ")} (default: claude-code)`)
442
+ .option("--all-agents", "install for every supported agent")
443
+ .option("-g, --global", "install for your user instead of the current project")
444
+ .option("--force", "install even when the scan finds prompt injection or critical risk")
445
+ .option("--scan-only", "scan without installing anything")
446
+ .option("--json", "print the scan result as JSON")
447
+ .action(async (source, options) => {
448
+ let result;
449
+ try {
450
+ result = await withSpinner(`Fetching and scanning ${source}`, () => addSkill(source, options));
451
+ }
452
+ catch (e) {
453
+ console.error(`✖ ${e instanceof Error ? e.message : e}`);
454
+ process.exitCode = 1;
455
+ return;
456
+ }
457
+ if (options.json) {
458
+ console.log(JSON.stringify(result, null, 2));
459
+ }
460
+ else {
461
+ result.scans.forEach(printSkillScan);
462
+ console.log("");
463
+ for (const i of result.installed)
464
+ console.log(`${green("✔")} Installed ${i.name} → ${i.path}`);
465
+ if (result.blocked.length)
466
+ console.error(`✖ Not installed (prompt injection or critical risk): ${result.blocked.join(", ")}\n Review the findings above. If you trust the source, re-run with --force.`);
467
+ if (options.scanOnly)
468
+ console.log(dim("Scan only: nothing was installed."));
469
+ }
470
+ if (result.blocked.length)
471
+ process.exitCode = 2;
472
+ });
473
+ const skills = program.command("skills").description("Inspect installed agent skills");
474
+ skills.command("scan")
475
+ .description("Scan installed skills (or one skill folder) for prompt injection and risky instructions")
476
+ .argument("[path]", "a skill folder; omit to scan every installed skill for the supported agents")
477
+ .option("--json", "print results as JSON")
478
+ .action(async (target, options) => {
479
+ const scans = target ? [await scanSkillDir(path.resolve(target), path.basename(path.resolve(target)))] : await scanInstalledSkills();
480
+ if (options.json)
481
+ console.log(JSON.stringify(scans, null, 2));
482
+ else if (!scans.length)
483
+ console.log("No installed skills found.");
484
+ else
485
+ scans.forEach(printSkillScan);
486
+ if (scans.some(isBlocked))
487
+ process.exitCode = 2;
488
+ });
489
+ skills.command("index")
490
+ .description("Find every skill on this machine (repos, nested folders, plugins), scan them, and write the inventory file")
491
+ .option("--root <dir...>", "folders to search instead of your home directory")
492
+ .option("--agents-only", "only check the agents' own skill folders (~/.claude, ~/.agents, ...), not the rest of your home directory")
493
+ .option("--depth <n>", "maximum folder depth (default 10)")
494
+ .option("--json", "print the inventory as JSON")
495
+ .action(async (options) => {
496
+ const roots = options.agentsOnly ? await agentSkillRoots() : options.root?.map(r => path.resolve(r));
497
+ if (!options.json && !roots)
498
+ console.error(dim("Searching your home folder for skills. macOS may ask you to allow access to Desktop, Documents or Downloads; use --agents-only to skip that."));
499
+ const search = () => indexSkills({ roots, maxDepth: options.depth ? Number(options.depth) : undefined });
500
+ const { inventory, changes } = options.json ? await search() : await withSpinner("Searching for skills", search);
501
+ if (options.json) {
502
+ console.log(JSON.stringify({ inventory, changes }, null, 2));
503
+ return;
504
+ }
505
+ const risky = inventory.skills.filter(s => s.level === "HIGH" || s.level === "CRITICAL").length;
506
+ console.log(`${green("✔")} ${inventory.skills.length} skills indexed (${risky} high/critical) → ${inventoryFile()}`);
507
+ if (changes.added.length || changes.modified.length || changes.removed.length)
508
+ console.log(` ${changes.added.length} new, ${changes.modified.length} modified, ${changes.removed.length} removed since last index`);
509
+ if (inventory.truncated)
510
+ console.log(dim(" Search hit its time/size budget; some folders were not visited. Narrow it with --root."));
511
+ console.log(dim("Run 'beam skills list' to view them."));
512
+ // A new or changed skill is reported to the workspace right away (enrolled devices only).
513
+ const sent = await syncSkillInventory().catch(() => null);
514
+ if (sent?.status === "sent")
515
+ console.log(dim(`Reported ${sent.skills} skills to your workspace.`));
516
+ });
517
+ skills.command("list")
518
+ .alias("ls")
519
+ .description("List every skill in the inventory with its risk score (run 'beam skills index' first)")
520
+ .option("--risk <level>", "only show LOW, MEDIUM, HIGH or CRITICAL (that level and above)")
521
+ .option("--agent <agent>", "only show one agent, e.g. claude-code, codex, universal")
522
+ .option("--json", "print as JSON")
523
+ .action(async (options) => {
524
+ let inv = await readInventory();
525
+ // Nothing has searched beyond the agents' own folders yet. Ask here, at the moment the list is
526
+ // wanted, rather than at install or startup -- this is what makes macOS ask for folder access.
527
+ if (!inv?.lastFullScanAt && process.stdin.isTTY && process.stdout.isTTY && !options.json) {
528
+ const ok = await confirm(`${inv ? "Skills inside your project folders haven't been searched." : "No skill list yet."} Search your home folder now? (macOS may ask for access to Desktop, Documents and Downloads)`, true);
529
+ if (ok) {
530
+ await withSpinner("Searching for skills", () => indexSkills());
531
+ inv = await readInventory();
532
+ }
533
+ else if (!inv) {
534
+ inv = (await indexSkills({ roots: await agentSkillRoots() })).inventory;
535
+ }
536
+ }
537
+ if (!inv) {
538
+ console.error("No inventory yet. Run: beam skills index");
539
+ process.exitCode = 1;
540
+ return;
541
+ }
542
+ const order = ["LOW", "MEDIUM", "HIGH", "CRITICAL"];
543
+ const min = options.risk ? order.indexOf(options.risk.toUpperCase()) : 0;
544
+ if (min < 0) {
545
+ console.error(`--risk must be one of ${order.join(", ")}`);
546
+ process.exitCode = 1;
547
+ return;
548
+ }
549
+ const trusted = await trustedHashes();
550
+ const rows = inv.skills.filter(s => order.indexOf(s.level) >= min && (!options.agent || s.agent === options.agent));
551
+ if (options.json) {
552
+ console.log(JSON.stringify(rows.map(s => ({ ...s, trusted: trusted.has(s.hash) })), null, 2));
553
+ return;
554
+ }
555
+ console.log(renderColumns(["skill", "agent", "scope", "risk", "trusted", "path"], rows.map(s => [s.name, s.agent, s.scope, `${s.score} ${s.level}${s.injection ? " ⚠inj" : ""}`, trusted.has(s.hash) ? "yes" : "", s.dir])));
556
+ console.log(dim(`\n${rows.length} of ${inv.skills.length} skills · indexed ${inv.generatedAt}${inv.truncated ? " (partial)" : ""} · ${inventoryFile()}`));
557
+ const device = deviceSkillsScore(inv.skills, trusted);
558
+ console.log(`Device skills score: ${device.score}/100${device.highCount ? ` (${device.highCount} untrusted high/critical skill${device.highCount > 1 ? "s" : ""})` : ""}`);
559
+ if (!inv.lastFullScanAt)
560
+ console.log(dim("Only the agents' own skill folders were checked. Run 'beam skills index' to search your project folders too."));
561
+ });
562
+ skills.command("sync")
563
+ .description("Send skill names and risk scores (never contents) to your workspace, if they changed since the last send")
564
+ .option("--force", "send even if nothing changed")
565
+ .action(async (options) => {
566
+ // Refreshes only the agents' own folders, so this never triggers a macOS folder-access prompt.
567
+ // Run 'beam skills index' first if you want project folders included.
568
+ const roots = await agentSkillRoots();
569
+ if (roots.length || !await readInventory())
570
+ await indexSkills({ roots });
571
+ const result = await syncSkillInventory({ force: options.force });
572
+ if (result.status === "sent")
573
+ console.log(`${green("✔")} Sent ${result.skills} skills to your workspace.`);
574
+ else if (result.status === "unchanged")
575
+ console.log("Nothing changed since the last send. Use --force to send anyway.");
576
+ else {
577
+ console.error(`✖ ${result.status === "not-enrolled" ? "This device isn't connected to a workspace. Run: beam setup" : result.reason ?? result.status}`);
578
+ process.exitCode = 1;
579
+ }
580
+ });
581
+ skills.command("trust")
582
+ .description("Mark a reviewed skill as trusted so the hook stops holding it for approval (pinned to its current content)")
583
+ .argument("<path>", "skill folder")
584
+ .action(async (target) => {
585
+ const dir = path.resolve(target);
586
+ const scan = await scanSkillDir(dir, path.basename(dir));
587
+ printSkillScan(scan);
588
+ await trustSkill(scan.name, scan.hash);
589
+ console.log(`\n${green("✔")} Trusted ${scan.name} (score ${scan.score}/100). Any later edit to it will be scanned again.`);
590
+ });
591
+ skills.command("untrust")
592
+ .description("Remove a skill from the trusted list")
593
+ .argument("<name-or-hash>")
594
+ .action(async (key) => console.log(`Removed ${await untrustSkill(key)} trusted skill(s).`));
595
+ skills.command("trusted")
596
+ .description("List trusted skills")
597
+ .action(async () => { const l = await readTrustedSkills(); console.log(l.length ? renderColumns(["name", "hash", "trusted"], l.map(t => [t.name, t.hash.slice(0, 12), t.trustedAt])) : "No trusted skills."); });
369
598
  const mcp = program.command("mcp").description("Run and protect local MCP integrations");
370
599
  mcp.command("proxy")
371
600
  .description("Run an MCP server through Beam response filtering")
@@ -394,8 +623,26 @@ agent.command("install")
394
623
  .argument("<agent>", "agent id, e.g. claude-code, codex, cursor, copilot-cli")
395
624
  .action(async (agentId) => {
396
625
  const result = await installHook(agentId);
626
+ await recordExpectedHooks();
397
627
  console.log(result.alreadyInstalled ? `✔ Already installed for ${result.agent}\n → ${result.path}` : `✔ Installed beam hook for ${result.agent}\n → ${result.path}`);
398
628
  });
629
+ agent.command("uninstall")
630
+ .description("Detach beam's hook from a single agent's own hook config, leaving everything else installed")
631
+ .argument("<agent>", "agent id, e.g. claude-code, codex, cursor, copilot-cli")
632
+ .option("--yes", "skip the confirmation prompt")
633
+ .action(async (agentId, options) => {
634
+ const identity = await readIdentity();
635
+ const proceed = await confirmControlAction(`This will detach beam's hook from ${agentId}. Its activity will no longer be observed or policy-enforced by beam.`, identity, options.yes);
636
+ if (!proceed) {
637
+ console.log("Cancelled.");
638
+ return;
639
+ }
640
+ if (identity)
641
+ await reportControlEvent(`agent-uninstall-${agentId}`, `Beam hook detached from ${agentId} on ${identity.hostname}`, `This device ran 'beam agent uninstall ${agentId}'. ${agentId} is no longer being observed or policy-enforced by beam.`);
642
+ const result = await uninstallHook(agentId);
643
+ await recordExpectedHooks();
644
+ console.log(result.removed ? `✔ Detached beam's hook from ${result.agent}\n → ${result.path}` : `— No beam hook found for ${result.agent}.`);
645
+ });
399
646
  agent.command("extract")
400
647
  .description("Forensic extraction: read an agent's existing session/transcript files directly, no hook or live capture required")
401
648
  .argument("<agent>", `agent id (currently: claude-code, codex)`)
@@ -418,6 +665,7 @@ agent.command("install-all")
418
665
  .description("Detect which agents are actually installed on this machine and wire beam's hook into all of them")
419
666
  .action(async () => {
420
667
  const results = await installAllDetectedHooks();
668
+ await recordExpectedHooks();
421
669
  for (const r of results) {
422
670
  if (r.status === "installed")
423
671
  console.log(`✔ Installed for ${r.name}\n → ${r.path}`);