@agent-beam/beam 0.2.3 → 0.2.5

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 (97) hide show
  1. package/README.md +6 -0
  2. package/Skills/README.md +64 -0
  3. package/Skills/agent-cost-abuse-review/SKILL.md +63 -0
  4. package/Skills/agent-incident-response/SKILL.md +109 -0
  5. package/Skills/agent-monitoring-review/SKILL.md +104 -0
  6. package/Skills/agent-network-segmentation/SKILL.md +70 -0
  7. package/Skills/agent-permissions-review/SKILL.md +107 -0
  8. package/Skills/agent-plugin-marketplace-review/SKILL.md +68 -0
  9. package/Skills/agent-transport-security/SKILL.md +108 -0
  10. package/Skills/agent-web-security/SKILL.md +103 -0
  11. package/Skills/agents/README.md +43 -0
  12. package/Skills/agents/claude/beam-ai-auditor.md +25 -0
  13. package/Skills/agents/claude/beam-appsec-auditor.md +25 -0
  14. package/Skills/agents/claude/beam-findings-reviewer.md +25 -0
  15. package/Skills/agents/claude/beam-incident-analyst.md +25 -0
  16. package/Skills/agents/claude/beam-infrastructure-auditor.md +25 -0
  17. package/Skills/agents/claude/beam-mcp-auditor.md +25 -0
  18. package/Skills/agents/claude/beam-skill-auditor.md +25 -0
  19. package/Skills/agents/codex/beam-ai-auditor.toml +23 -0
  20. package/Skills/agents/codex/beam-appsec-auditor.toml +23 -0
  21. package/Skills/agents/codex/beam-findings-reviewer.toml +23 -0
  22. package/Skills/agents/codex/beam-incident-analyst.toml +23 -0
  23. package/Skills/agents/codex/beam-infrastructure-auditor.toml +23 -0
  24. package/Skills/agents/codex/beam-mcp-auditor.toml +23 -0
  25. package/Skills/agents/codex/beam-skill-auditor.toml +23 -0
  26. package/Skills/ai-asset-scanner/SKILL.md +69 -0
  27. package/Skills/ai-security/SKILL.md +59 -0
  28. package/Skills/api-auth-security/SKILL.md +106 -0
  29. package/Skills/browser-agent-security/SKILL.md +77 -0
  30. package/Skills/cicd-agent-security/SKILL.md +108 -0
  31. package/Skills/cloud-agent-security/SKILL.md +101 -0
  32. package/Skills/container-sandbox-security/SKILL.md +101 -0
  33. package/Skills/data-retention-privacy-review/SKILL.md +69 -0
  34. package/Skills/dependency-supply-chain/SKILL.md +106 -0
  35. package/Skills/llm-output-handling/SKILL.md +66 -0
  36. package/Skills/manifest.json +147 -0
  37. package/Skills/mcp-scanner/SKILL.md +64 -0
  38. package/Skills/model-artifact-scanner/SKILL.md +108 -0
  39. package/Skills/multi-agent-trust-review/SKILL.md +71 -0
  40. package/Skills/prompt-injection-review/SKILL.md +102 -0
  41. package/Skills/rag-memory-security/SKILL.md +105 -0
  42. package/Skills/scripts/validate-skills.mjs +113 -0
  43. package/Skills/secrets-egress-review/SKILL.md +105 -0
  44. package/Skills/security-assessment/SKILL.md +73 -0
  45. package/Skills/security-reporting/SKILL.md +73 -0
  46. package/Skills/skill-scanner/SKILL.md +68 -0
  47. package/Skills/tool-schema-review/SKILL.md +66 -0
  48. package/Skills/training-data-security/SKILL.md +70 -0
  49. package/Skills/webhook-callback-security/SKILL.md +71 -0
  50. package/dist/agents.d.ts +2 -1
  51. package/dist/agents.js +24 -8
  52. package/dist/agents.js.map +1 -1
  53. package/dist/approvals.d.ts +65 -0
  54. package/dist/approvals.js +86 -0
  55. package/dist/approvals.js.map +1 -0
  56. package/dist/banner.js +7 -2
  57. package/dist/banner.js.map +1 -1
  58. package/dist/cli.js +71 -15
  59. package/dist/cli.js.map +1 -1
  60. package/dist/client.js +107 -3
  61. package/dist/client.js.map +1 -1
  62. package/dist/color.d.ts +5 -0
  63. package/dist/color.js +15 -0
  64. package/dist/color.js.map +1 -0
  65. package/dist/data-detectors.d.ts +18 -0
  66. package/dist/data-detectors.js +33 -0
  67. package/dist/data-detectors.js.map +1 -0
  68. package/dist/forward.js +7 -2
  69. package/dist/forward.js.map +1 -1
  70. package/dist/hook-adapters.js +13 -2
  71. package/dist/hook-adapters.js.map +1 -1
  72. package/dist/install.js +63 -8
  73. package/dist/install.js.map +1 -1
  74. package/dist/owl.d.ts +6 -0
  75. package/dist/owl.js +50 -0
  76. package/dist/owl.js.map +1 -0
  77. package/dist/policy.d.ts +66 -6
  78. package/dist/policy.js +132 -40
  79. package/dist/policy.js.map +1 -1
  80. package/dist/prompts.d.ts +1 -0
  81. package/dist/prompts.js +22 -6
  82. package/dist/prompts.js.map +1 -1
  83. package/dist/run.d.ts +1 -0
  84. package/dist/run.js +48 -0
  85. package/dist/run.js.map +1 -0
  86. package/dist/sandbox.d.ts +13 -0
  87. package/dist/sandbox.js +116 -0
  88. package/dist/sandbox.js.map +1 -0
  89. package/dist/setup.js +45 -5
  90. package/dist/setup.js.map +1 -1
  91. package/dist/shims.d.ts +13 -0
  92. package/dist/shims.js +85 -0
  93. package/dist/shims.js.map +1 -0
  94. package/dist/store.d.ts +16 -0
  95. package/dist/store.js +19 -2
  96. package/dist/store.js.map +1 -1
  97. package/package.json +35 -6
@@ -0,0 +1,33 @@
1
+ const detectors = [
2
+ { kind: "PRIVATE_KEY", pattern: /-----BEGIN [^-]*PRIVATE KEY-----[\s\S]*?(?:-----END [^-]*PRIVATE KEY-----|$)/g, replacement: "[PRIVATE_KEY_REDACTED]" },
3
+ { kind: "API_KEY", pattern: /\b(?:sk-(?:proj-|ant-)?[A-Za-z0-9_-]{12,}|gh[pousr]_[A-Za-z0-9_]{16,}|github_pat_[A-Za-z0-9_]{16,}|AKIA[A-Z0-9]{16}|xox[baprs]-[\w-]{10,})\b/g, replacement: "[API_KEY_REDACTED]" },
4
+ { kind: "SECRET", pattern: /((?:api[_-]?key|access[_-]?token|token|secret|authorization)\s*[:=]\s*["']?)([^\s,"';&}\]]+)/gi, replacement: "$1[SECRET_REDACTED]" },
5
+ { kind: "PASSWORD", pattern: /((?:password|passwd|pwd)\s*[:=]\s*["']?)([^\s,"';&}\]]+)/gi, replacement: "$1[PASSWORD_REDACTED]" },
6
+ { kind: "EMAIL", pattern: /\b[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}\b/gi, replacement: "[EMAIL_REDACTED]" },
7
+ { kind: "PHONE", pattern: /(?<!\w)(?:\+\d{1,3}[\s.-]?)?(?:\d[\s.-]?){8,14}\d(?!\w)/g, replacement: "[PHONE_REDACTED]" },
8
+ ];
9
+ export function detectSensitive(text, custom = []) {
10
+ const findings = [];
11
+ for (const detector of detectors) {
12
+ detector.pattern.lastIndex = 0;
13
+ for (const match of text.matchAll(detector.pattern))
14
+ findings.push({ kind: detector.kind, confidence: 0.9, start: match.index ?? 0, end: (match.index ?? 0) + match[0].length, replacement: detector.replacement });
15
+ }
16
+ for (const customDetector of custom) {
17
+ try {
18
+ const pattern = new RegExp(customDetector.pattern, "g");
19
+ for (const match of text.matchAll(pattern))
20
+ findings.push({ kind: "CUSTOM", confidence: 0.8, start: match.index ?? 0, end: (match.index ?? 0) + match[0].length, replacement: customDetector.replacement });
21
+ }
22
+ catch { /* policy validation reports malformed custom detectors */ }
23
+ }
24
+ return findings.sort((a, b) => b.start - a.start);
25
+ }
26
+ export function redactSensitive(text, custom = []) {
27
+ const findings = detectSensitive(text, custom);
28
+ let result = text;
29
+ for (const finding of findings)
30
+ result = result.slice(0, finding.start) + finding.replacement + result.slice(finding.end);
31
+ return { text: result, findings };
32
+ }
33
+ //# sourceMappingURL=data-detectors.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"data-detectors.js","sourceRoot":"","sources":["../src/data-detectors.ts"],"names":[],"mappings":"AAGA,MAAM,SAAS,GAAwE;IACrF,EAAE,IAAI,EAAE,aAAa,EAAE,OAAO,EAAE,+EAA+E,EAAE,WAAW,EAAE,wBAAwB,EAAE;IACxJ,EAAE,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,+IAA+I,EAAE,WAAW,EAAE,oBAAoB,EAAE;IAChN,EAAE,IAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,gGAAgG,EAAE,WAAW,EAAE,qBAAqB,EAAE;IACjK,EAAE,IAAI,EAAE,UAAU,EAAE,OAAO,EAAE,4DAA4D,EAAE,WAAW,EAAE,uBAAuB,EAAE;IACjI,EAAE,IAAI,EAAE,OAAO,EAAE,OAAO,EAAE,6CAA6C,EAAE,WAAW,EAAE,kBAAkB,EAAE;IAC1G,EAAE,IAAI,EAAE,OAAO,EAAE,OAAO,EAAE,0DAA0D,EAAE,WAAW,EAAE,kBAAkB,EAAE;CACxH,CAAC;AAGF,MAAM,UAAU,eAAe,CAAC,IAAY,EAAE,SAA2B,EAAE;IACzE,MAAM,QAAQ,GAAkB,EAAE,CAAC;IACnC,KAAK,MAAM,QAAQ,IAAI,SAAS,EAAE,CAAC;QACjC,QAAQ,CAAC,OAAO,CAAC,SAAS,GAAG,CAAC,CAAC;QAC/B,KAAK,MAAM,KAAK,IAAI,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,OAAO,CAAC;YAAE,QAAQ,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,QAAQ,CAAC,IAAI,EAAE,UAAU,EAAE,GAAG,EAAE,KAAK,EAAE,KAAK,CAAC,KAAK,IAAI,CAAC,EAAE,GAAG,EAAE,CAAC,KAAK,CAAC,KAAK,IAAI,CAAC,CAAC,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,EAAE,WAAW,EAAE,QAAQ,CAAC,WAAW,EAAE,CAAC,CAAC;IACtN,CAAC;IACD,KAAK,MAAM,cAAc,IAAI,MAAM,EAAE,CAAC;QACpC,IAAI,CAAC;YACH,MAAM,OAAO,GAAG,IAAI,MAAM,CAAC,cAAc,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC;YACxD,KAAK,MAAM,KAAK,IAAI,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC;gBAAE,QAAQ,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,UAAU,EAAE,GAAG,EAAE,KAAK,EAAE,KAAK,CAAC,KAAK,IAAI,CAAC,EAAE,GAAG,EAAE,CAAC,KAAK,CAAC,KAAK,IAAI,CAAC,CAAC,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,EAAE,WAAW,EAAE,cAAc,CAAC,WAAW,EAAE,CAAC,CAAC;QAC9M,CAAC;QAAC,MAAM,CAAC,CAAC,0DAA0D,CAAC,CAAC;IACxE,CAAC;IACD,OAAO,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC;AACpD,CAAC;AAED,MAAM,UAAU,eAAe,CAAC,IAAY,EAAE,SAA2B,EAAE;IACzE,MAAM,QAAQ,GAAG,eAAe,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;IAAC,IAAI,MAAM,GAAG,IAAI,CAAC;IAClE,KAAK,MAAM,OAAO,IAAI,QAAQ;QAAE,MAAM,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC,EAAE,OAAO,CAAC,KAAK,CAAC,GAAG,OAAO,CAAC,WAAW,GAAG,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;IAC1H,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC;AACpC,CAAC"}
package/dist/forward.js CHANGED
@@ -1,6 +1,7 @@
1
- import { mkdir, writeFile } from "node:fs/promises";
1
+ import { mkdir, rename, writeFile } from "node:fs/promises";
2
2
  import { dirname, join } from "node:path";
3
3
  import { getDataDirectory, getTelemetryUrl } from "./config.js";
4
+ import { lastGoodPolicyPath } from "./policy.js";
4
5
  import { readIdentity } from "./enroll.js";
5
6
  function policyPath() {
6
7
  return join(getDataDirectory(), "policy.json");
@@ -134,7 +135,11 @@ export async function syncPolicy() {
134
135
  const bundle = await response.json();
135
136
  const path = policyPath();
136
137
  await mkdir(dirname(path), { recursive: true, mode: 0o700 });
137
- await writeFile(path, `${JSON.stringify(bundle, null, 2)}\n`, { mode: 0o600 });
138
+ const contents = `${JSON.stringify(bundle, null, 2)}\n`;
139
+ const temp = `${path}.tmp`;
140
+ await writeFile(temp, contents, { mode: 0o600 });
141
+ await rename(temp, path);
142
+ await writeFile(lastGoodPolicyPath(), contents, { mode: 0o600 });
138
143
  return { status: "updated", version: bundle.version, path };
139
144
  }
140
145
  //# sourceMappingURL=forward.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"forward.js","sourceRoot":"","sources":["../src/forward.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"forward.js","sourceRoot":"","sources":["../src/forward.ts"],"names":[],"mappings":"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"}
@@ -23,11 +23,22 @@ function generic(raw) {
23
23
  session_id: raw.session_id ?? raw.sessionId ?? raw.session,
24
24
  cwd: raw.cwd ?? raw.project_path ?? raw.workingDirectory ?? raw.working_directory,
25
25
  tool_name: raw.tool_name ?? raw.toolName ?? raw.tool,
26
- tool_input: raw.tool_input ?? raw.toolArgs ?? raw.toolInput ?? raw.input,
26
+ tool_input: raw.tool_input ?? raw.toolArgs ?? raw.toolInput ?? raw.input ?? raw.args,
27
27
  hook_event_name: raw.hook_event_name ?? raw.hookEventName ?? raw.event,
28
28
  };
29
29
  }
30
- const adapters = { passthrough, "copilot-camel": copilotCamel, generic };
30
+ // Gemini's documented pre_tool_execution contract nests the call under tool_call.
31
+ function gemini(raw) {
32
+ const call = raw.tool_call && typeof raw.tool_call === "object" ? raw.tool_call : {};
33
+ return {
34
+ ...raw,
35
+ session_id: raw.session_id ?? raw.sessionId ?? raw.environment_id,
36
+ tool_name: raw.tool_name ?? raw.toolName ?? call.name,
37
+ tool_input: raw.tool_input ?? raw.toolArgs ?? call.args,
38
+ hook_event_name: raw.hook_event_name ?? "pre_tool_execution",
39
+ };
40
+ }
41
+ const adapters = { passthrough, "copilot-camel": copilotCamel, generic, gemini };
31
42
  export function adaptHookPayload(sourceAgent, raw) {
32
43
  const agent = findAgent(sourceAgent);
33
44
  const adapter = adapters[agent?.adapter ?? "generic"];
@@ -1 +1 @@
1
- {"version":3,"file":"hook-adapters.js","sourceRoot":"","sources":["../src/hook-adapters.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAY,MAAM,aAAa,CAAC;AAElD,8FAA8F;AAC9F,+FAA+F;AAC/F,SAAS,WAAW,CAAC,GAAQ;IAC3B,OAAO,GAAG,CAAC;AACb,CAAC;AAED,0FAA0F;AAC1F,0EAA0E;AAC1E,SAAS,YAAY,CAAC,GAAQ;IAC5B,OAAO;QACL,GAAG,GAAG;QACN,UAAU,EAAE,GAAG,CAAC,SAAS,IAAI,GAAG,CAAC,UAAU;QAC3C,GAAG,EAAE,GAAG,CAAC,GAAG;QACZ,SAAS,EAAE,GAAG,CAAC,QAAQ,IAAI,GAAG,CAAC,SAAS;QACxC,UAAU,EAAE,GAAG,CAAC,QAAQ,IAAI,GAAG,CAAC,UAAU;QAC1C,eAAe,EAAE,GAAG,CAAC,eAAe,IAAI,YAAY;KACrD,CAAC;AACJ,CAAC;AAED,gGAAgG;AAChG,SAAS,OAAO,CAAC,GAAQ;IACvB,OAAO;QACL,GAAG,GAAG;QACN,UAAU,EAAE,GAAG,CAAC,UAAU,IAAI,GAAG,CAAC,SAAS,IAAI,GAAG,CAAC,OAAO;QAC1D,GAAG,EAAE,GAAG,CAAC,GAAG,IAAI,GAAG,CAAC,YAAY,IAAI,GAAG,CAAC,gBAAgB,IAAI,GAAG,CAAC,iBAAiB;QACjF,SAAS,EAAE,GAAG,CAAC,SAAS,IAAI,GAAG,CAAC,QAAQ,IAAI,GAAG,CAAC,IAAI;QACpD,UAAU,EAAE,GAAG,CAAC,UAAU,IAAI,GAAG,CAAC,QAAQ,IAAI,GAAG,CAAC,SAAS,IAAI,GAAG,CAAC,KAAK;QACxE,eAAe,EAAE,GAAG,CAAC,eAAe,IAAI,GAAG,CAAC,aAAa,IAAI,GAAG,CAAC,KAAK;KACvE,CAAC;AACJ,CAAC;AAED,MAAM,QAAQ,GAAG,EAAE,WAAW,EAAE,eAAe,EAAE,YAAY,EAAE,OAAO,EAAE,CAAC;AAEzE,MAAM,UAAU,gBAAgB,CAAC,WAAmB,EAAE,GAAQ;IAC5D,MAAM,KAAK,GAAG,SAAS,CAAC,WAAW,CAAC,CAAC;IACrC,MAAM,OAAO,GAAG,QAAQ,CAAC,KAAK,EAAE,OAAO,IAAI,SAAS,CAAC,CAAC;IACtD,OAAO,OAAO,CAAC,GAAG,CAAC,CAAC;AACtB,CAAC"}
1
+ {"version":3,"file":"hook-adapters.js","sourceRoot":"","sources":["../src/hook-adapters.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAY,MAAM,aAAa,CAAC;AAElD,8FAA8F;AAC9F,+FAA+F;AAC/F,SAAS,WAAW,CAAC,GAAQ;IAC3B,OAAO,GAAG,CAAC;AACb,CAAC;AAED,0FAA0F;AAC1F,0EAA0E;AAC1E,SAAS,YAAY,CAAC,GAAQ;IAC5B,OAAO;QACL,GAAG,GAAG;QACN,UAAU,EAAE,GAAG,CAAC,SAAS,IAAI,GAAG,CAAC,UAAU;QAC3C,GAAG,EAAE,GAAG,CAAC,GAAG;QACZ,SAAS,EAAE,GAAG,CAAC,QAAQ,IAAI,GAAG,CAAC,SAAS;QACxC,UAAU,EAAE,GAAG,CAAC,QAAQ,IAAI,GAAG,CAAC,UAAU;QAC1C,eAAe,EAAE,GAAG,CAAC,eAAe,IAAI,YAAY;KACrD,CAAC;AACJ,CAAC;AAED,gGAAgG;AAChG,SAAS,OAAO,CAAC,GAAQ;IACvB,OAAO;QACL,GAAG,GAAG;QACN,UAAU,EAAE,GAAG,CAAC,UAAU,IAAI,GAAG,CAAC,SAAS,IAAI,GAAG,CAAC,OAAO;QAC1D,GAAG,EAAE,GAAG,CAAC,GAAG,IAAI,GAAG,CAAC,YAAY,IAAI,GAAG,CAAC,gBAAgB,IAAI,GAAG,CAAC,iBAAiB;QACjF,SAAS,EAAE,GAAG,CAAC,SAAS,IAAI,GAAG,CAAC,QAAQ,IAAI,GAAG,CAAC,IAAI;QACpD,UAAU,EAAE,GAAG,CAAC,UAAU,IAAI,GAAG,CAAC,QAAQ,IAAI,GAAG,CAAC,SAAS,IAAI,GAAG,CAAC,KAAK,IAAI,GAAG,CAAC,IAAI;QACpF,eAAe,EAAE,GAAG,CAAC,eAAe,IAAI,GAAG,CAAC,aAAa,IAAI,GAAG,CAAC,KAAK;KACvE,CAAC;AACJ,CAAC;AAED,kFAAkF;AAClF,SAAS,MAAM,CAAC,GAAQ;IACtB,MAAM,IAAI,GAAG,GAAG,CAAC,SAAS,IAAI,OAAO,GAAG,CAAC,SAAS,KAAK,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,SAAgB,CAAC,CAAC,CAAC,EAAE,CAAC;IAC5F,OAAO;QACL,GAAG,GAAG;QACN,UAAU,EAAE,GAAG,CAAC,UAAU,IAAI,GAAG,CAAC,SAAS,IAAI,GAAG,CAAC,cAAc;QACjE,SAAS,EAAE,GAAG,CAAC,SAAS,IAAI,GAAG,CAAC,QAAQ,IAAI,IAAI,CAAC,IAAI;QACrD,UAAU,EAAE,GAAG,CAAC,UAAU,IAAI,GAAG,CAAC,QAAQ,IAAI,IAAI,CAAC,IAAI;QACvD,eAAe,EAAE,GAAG,CAAC,eAAe,IAAI,oBAAoB;KAC7D,CAAC;AACJ,CAAC;AAED,MAAM,QAAQ,GAAG,EAAE,WAAW,EAAE,eAAe,EAAE,YAAY,EAAE,OAAO,EAAE,MAAM,EAAE,CAAC;AAEjF,MAAM,UAAU,gBAAgB,CAAC,WAAmB,EAAE,GAAQ;IAC5D,MAAM,KAAK,GAAG,SAAS,CAAC,WAAW,CAAC,CAAC;IACrC,MAAM,OAAO,GAAG,QAAQ,CAAC,KAAK,EAAE,OAAO,IAAI,SAAS,CAAC,CAAC;IACtD,OAAO,OAAO,CAAC,GAAG,CAAC,CAAC;AACtB,CAAC"}
package/dist/install.js CHANGED
@@ -1,15 +1,56 @@
1
1
  import { access, mkdir, readFile, writeFile } from "node:fs/promises";
2
2
  import { homedir } from "node:os";
3
3
  import { dirname, join } from "node:path";
4
+ import { fileURLToPath } from "node:url";
4
5
  import { AGENTS, findAgent, hookConfigFullPath } from "./agents.js";
6
+ const OPEN_CODE_PLUGIN = `import { spawnSync } from "node:child_process";
7
+
8
+ export const BeamPlugin = async () => ({
9
+ "tool.execute.before": async (input: any, output: any) => {
10
+ const payload = { tool_name: input?.tool, tool_input: output?.args ?? {}, session_id: input?.sessionID, cwd: input?.directory ?? input?.worktree, source_agent: "opencode", source_type: "hook" };
11
+ const result = spawnSync("beam", ["hook", "opencode"], { input: JSON.stringify(payload), encoding: "utf8", timeout: 5000 });
12
+ let response: any = {};
13
+ try { response = JSON.parse(result.stdout || "{}"); } catch { /* fail closed below */ }
14
+ if (result.error || result.status !== 0 || response.decision === "deny") throw new Error(response.reason || "Beam denied this tool execution.");
15
+ },
16
+ });
17
+ `;
18
+ // A bare "beam" command relies on beam's global bin symlink being resolvable on PATH -- but the
19
+ // shell that runs an agent's hooks (e.g. Claude Code's own PreToolUse child process) doesn't
20
+ // always source the same profile a user's interactive shell does, so "beam" can 404 silently
21
+ // there even though it works fine when the user types it themselves. Embedding the absolute path
22
+ // to this running install (both the node binary and dist/cli.js, resolved via import.meta.url
23
+ // rather than argv[1] so it's correct however beam itself was invoked) sidesteps PATH entirely.
24
+ function resolveHookCommand(agentId) {
25
+ const cliPath = fileURLToPath(new URL("./cli.js", import.meta.url));
26
+ return `${quoteForShell(process.execPath)} ${quoteForShell(cliPath)} hook ${agentId}`;
27
+ }
28
+ function quoteForShell(value) {
29
+ return `"${value.replace(/(["\\$`])/g, "\\$1")}"`;
30
+ }
31
+ // Pre-fix installs wrote a bare "beam hook <agent>" command that depends on PATH; recognizing it
32
+ // here lets installHook migrate an existing entry to the absolute-path form instead of leaving a
33
+ // dead duplicate behind, and lets uninstallHook still find and remove it.
34
+ function legacyHookCommand(agentId) {
35
+ return `beam hook ${agentId}`;
36
+ }
5
37
  export async function installHook(agentId, home = homedir()) {
6
38
  const agent = findAgent(agentId);
7
39
  if (!agent)
8
40
  throw new Error(`Unknown agent '${agentId}'. Run 'beam agent list' to see supported agents.`);
9
- if (!agent.hookConfigPath || !agent.mergeHookConfig)
41
+ if (agent.id === "opencode" && agent.pluginPath) {
42
+ const path = join(home, agent.pluginPath);
43
+ const existing = await readFile(path, "utf8").catch(() => "");
44
+ if (!existing) {
45
+ await mkdir(dirname(path), { recursive: true });
46
+ await writeFile(path, OPEN_CODE_PLUGIN, { mode: 0o600 });
47
+ }
48
+ return { agent: agent.id, path, alreadyInstalled: Boolean(existing) };
49
+ }
50
+ if (!agent.hookConfigPath || !agent.mergeHookConfig || !agent.unmergeHookConfig)
10
51
  throw new Error(`${agent.name} has no supported hook install path yet; see 'beam agent list' for its status.`);
11
52
  const path = hookConfigFullPath(agent, home);
12
- const command = `beam hook ${agent.id}`;
53
+ const command = resolveHookCommand(agent.id);
13
54
  let existing = {};
14
55
  let raw = "";
15
56
  try {
@@ -23,7 +64,9 @@ export async function installHook(agentId, home = homedir()) {
23
64
  throw e;
24
65
  }
25
66
  }
26
- const merged = agent.mergeHookConfig(existing, command);
67
+ // Strip any pre-fix legacy entry first so re-installing migrates it rather than duplicating.
68
+ const base = agent.unmergeHookConfig(existing, legacyHookCommand(agent.id));
69
+ const merged = agent.mergeHookConfig(base, command);
27
70
  const alreadyInstalled = JSON.stringify(merged) === JSON.stringify(existing) && raw.trim() !== "";
28
71
  if (!alreadyInstalled) {
29
72
  await mkdir(dirname(path), { recursive: true });
@@ -39,10 +82,19 @@ export async function uninstallHook(agentId, home = homedir()) {
39
82
  const agent = findAgent(agentId);
40
83
  if (!agent)
41
84
  throw new Error(`Unknown agent '${agentId}'. Run 'beam agent list' to see supported agents.`);
85
+ if (agent.id === "opencode" && agent.pluginPath) {
86
+ const path = join(home, agent.pluginPath);
87
+ const existing = await readFile(path, "utf8").catch(() => "");
88
+ if (existing === OPEN_CODE_PLUGIN) {
89
+ const { rm } = await import("node:fs/promises");
90
+ await rm(path, { force: true });
91
+ return { agent: agent.id, path, removed: true };
92
+ }
93
+ return { agent: agent.id, path, removed: false };
94
+ }
42
95
  if (!agent.hookConfigPath || !agent.unmergeHookConfig)
43
- throw new Error(`${agent.name} has no supported hook install path yet; see 'beam agent list' for its status.`);
96
+ throw new Error(`${agent.name} has no supported hook path yet; see 'beam agent list' for its status.`);
44
97
  const path = hookConfigFullPath(agent, home);
45
- const command = `beam hook ${agent.id}`;
46
98
  let existing = {};
47
99
  let raw = "";
48
100
  try {
@@ -56,7 +108,10 @@ export async function uninstallHook(agentId, home = homedir()) {
56
108
  throw new Error(`${path} contains invalid JSON; fix or remove it manually.`);
57
109
  throw e;
58
110
  }
59
- const updated = agent.unmergeHookConfig(existing, command);
111
+ // Remove both the current absolute-path command and any pre-fix legacy "beam hook <agent>"
112
+ // entry, so uninstall cleans up a machine regardless of which form was installed.
113
+ const withoutCurrent = agent.unmergeHookConfig(existing, resolveHookCommand(agent.id));
114
+ const updated = agent.unmergeHookConfig(withoutCurrent, legacyHookCommand(agent.id));
60
115
  const removed = JSON.stringify(updated) !== JSON.stringify(existing);
61
116
  if (removed)
62
117
  await writeFile(path, `${JSON.stringify(updated, null, 2)}\n`);
@@ -69,7 +124,7 @@ export async function uninstallHook(agentId, home = homedir()) {
69
124
  export async function uninstallAllHooks(home = homedir()) {
70
125
  const results = [];
71
126
  for (const agent of AGENTS) {
72
- if (!agent.hookConfigPath || !agent.unmergeHookConfig)
127
+ if (agent.id !== "opencode" && (!agent.hookConfigPath || !agent.unmergeHookConfig))
73
128
  continue;
74
129
  results.push(await uninstallHook(agent.id, home));
75
130
  }
@@ -105,7 +160,7 @@ export async function installAllDetectedHooks(home = homedir()) {
105
160
  results.push({ agent: agent.id, name: agent.name, status: "not-detected" });
106
161
  continue;
107
162
  }
108
- if (!agent.hookConfigPath || !agent.mergeHookConfig) {
163
+ if (agent.id !== "opencode" && (!agent.hookConfigPath || !agent.mergeHookConfig)) {
109
164
  results.push({ agent: agent.id, name: agent.name, status: "not-supported" });
110
165
  continue;
111
166
  }
@@ -1 +1 @@
1
- {"version":3,"file":"install.js","sourceRoot":"","sources":["../src/install.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"install.js","sourceRoot":"","sources":["../src/install.ts"],"names":[],"mappings":"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"}
package/dist/owl.d.ts ADDED
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Print the owl and a short hello the first time `beam setup` runs on a
3
+ * machine, then record that it happened. Any later setup runs stay quiet.
4
+ * Never throws — a greeting is never worth failing onboarding over.
5
+ */
6
+ export declare function showFirstRunWelcome(): Promise<void>;
package/dist/owl.js ADDED
@@ -0,0 +1,50 @@
1
+ import { mkdir, writeFile, access } from "node:fs/promises";
2
+ import path from "node:path";
3
+ import { getBeamHome } from "./config.js";
4
+ // Beam the owl, in 2-bit block art — the same little mascot that watches over
5
+ // your agents on agentbeam.com, drawn for a monospace terminal.
6
+ const OWL = String.raw `
7
+ ▟▀▙ ▟▀▙
8
+ █◉█ █◉█
9
+ ▜▄▛▲▜▄▛
10
+ ▔`;
11
+ const WELCOME = [
12
+ "",
13
+ " Hi, I'm Beam. I'll keep an eye on what your AI agents do —",
14
+ " locally, on this machine. No agent activity leaves without you.",
15
+ "",
16
+ ];
17
+ // A once-ever marker in ~/.beam. Its presence means this machine has already
18
+ // been greeted, so the welcome only ever shows on the very first setup.
19
+ function welcomeMarkerPath() {
20
+ return path.join(getBeamHome(), ".welcomed");
21
+ }
22
+ async function hasBeenWelcomed() {
23
+ try {
24
+ await access(welcomeMarkerPath());
25
+ return true;
26
+ }
27
+ catch {
28
+ return false;
29
+ }
30
+ }
31
+ /**
32
+ * Print the owl and a short hello the first time `beam setup` runs on a
33
+ * machine, then record that it happened. Any later setup runs stay quiet.
34
+ * Never throws — a greeting is never worth failing onboarding over.
35
+ */
36
+ export async function showFirstRunWelcome() {
37
+ try {
38
+ if (await hasBeenWelcomed())
39
+ return;
40
+ console.log(OWL);
41
+ for (const line of WELCOME)
42
+ console.log(line);
43
+ await mkdir(getBeamHome(), { recursive: true });
44
+ await writeFile(welcomeMarkerPath(), `${new Date().toISOString()}\n`, "utf8");
45
+ }
46
+ catch {
47
+ // Ignore — if we can't write the marker, worst case the owl greets twice.
48
+ }
49
+ }
50
+ //# sourceMappingURL=owl.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"owl.js","sourceRoot":"","sources":["../src/owl.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAC;AAC5D,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAE1C,8EAA8E;AAC9E,gEAAgE;AAChE,MAAM,GAAG,GAAG,MAAM,CAAC,GAAG,CAAA;;;;SAIb,CAAC;AAEV,MAAM,OAAO,GAAG;IACd,EAAE;IACF,8DAA8D;IAC9D,mEAAmE;IACnE,EAAE;CACH,CAAC;AAEF,6EAA6E;AAC7E,wEAAwE;AACxE,SAAS,iBAAiB;IACxB,OAAO,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,EAAE,WAAW,CAAC,CAAC;AAC/C,CAAC;AAED,KAAK,UAAU,eAAe;IAC5B,IAAI,CAAC;QACH,MAAM,MAAM,CAAC,iBAAiB,EAAE,CAAC,CAAC;QAClC,OAAO,IAAI,CAAC;IACd,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC;AAED;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,mBAAmB;IACvC,IAAI,CAAC;QACH,IAAI,MAAM,eAAe,EAAE;YAAE,OAAO;QACpC,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QACjB,KAAK,MAAM,IAAI,IAAI,OAAO;YAAE,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QAC9C,MAAM,KAAK,CAAC,WAAW,EAAE,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QAChD,MAAM,SAAS,CAAC,iBAAiB,EAAE,EAAE,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,IAAI,EAAE,MAAM,CAAC,CAAC;IAChF,CAAC;IAAC,MAAM,CAAC;QACP,0EAA0E;IAC5E,CAAC;AACH,CAAC"}
package/dist/policy.d.ts CHANGED
@@ -1,27 +1,87 @@
1
+ import type { CustomDetector } from "./data-detectors.js";
2
+ import type { ApprovalPolicy } from "./approvals.js";
1
3
  export type PolicyMode = "observe" | "advisory" | "enforce";
4
+ export type PolicyAction = "ALLOW" | "ASK" | "BLOCK" | "REDACT" | "AUDIT";
5
+ export interface PolicyRule {
6
+ id: string;
7
+ title?: string;
8
+ action: PolicyAction;
9
+ risk?: number;
10
+ tool?: string;
11
+ command?: string;
12
+ args?: string[];
13
+ path?: string;
14
+ url?: string;
15
+ role?: string;
16
+ user?: string;
17
+ agent?: string;
18
+ cwd?: string;
19
+ repository?: string;
20
+ branch?: string;
21
+ environment?: string;
22
+ time?: {
23
+ after?: string;
24
+ before?: string;
25
+ };
26
+ reason?: string;
27
+ approval?: ApprovalPolicy;
28
+ }
2
29
  export interface PolicyRules {
3
30
  mode: PolicyMode;
4
31
  blockedTools: string[];
5
32
  blockedCommandPatterns: string[];
6
33
  disabledAgents: string[];
34
+ rules?: PolicyRule[];
35
+ risk?: {
36
+ askAt?: number;
37
+ blockAt?: number;
38
+ };
39
+ customDetectors?: CustomDetector[];
7
40
  }
8
41
  export interface PolicyBundle {
9
42
  version: number;
10
43
  rules: PolicyRules;
11
44
  notAfter: string | null;
45
+ errors?: string[];
12
46
  }
13
47
  export declare function policyPath(): string;
48
+ export declare function lastGoodPolicyPath(): string;
14
49
  export declare function readPolicy(): Promise<PolicyBundle | null>;
15
- export type DecisionAction = "allow" | "warn" | "deny";
50
+ export type DecisionAction = "allow" | "ask" | "block" | "redact" | "audit" | "warn" | "deny";
51
+ export interface ActionContext {
52
+ agent: string;
53
+ tool: string;
54
+ command: string;
55
+ args?: string[];
56
+ path?: string;
57
+ url?: string;
58
+ role?: string;
59
+ user?: string;
60
+ cwd?: string;
61
+ repository?: string;
62
+ branch?: string;
63
+ environment?: string;
64
+ time?: string;
65
+ }
16
66
  export interface Decision {
17
67
  action: DecisionAction;
18
68
  reason?: string;
19
69
  mode: PolicyMode;
20
70
  policyVersion: number;
21
- }
22
- export interface ActionContext {
23
- agent: string;
24
- tool: string;
25
- command: string;
71
+ policy?: string;
72
+ rule?: string;
73
+ approval?: ApprovalPolicy;
74
+ actor?: string;
75
+ role?: string;
76
+ agent?: string;
77
+ tool?: string;
78
+ command?: string;
79
+ args?: string[];
80
+ resource?: string;
81
+ riskScore: number;
82
+ riskLevel: "LOW" | "MEDIUM" | "HIGH" | "CRITICAL";
83
+ riskFactors: string[];
84
+ customDetectors?: CustomDetector[];
85
+ errors?: string[];
26
86
  }
27
87
  export declare function evaluate(bundle: PolicyBundle | null, ctx: ActionContext): Decision;
package/dist/policy.js CHANGED
@@ -1,59 +1,151 @@
1
1
  import { readFile } from "node:fs/promises";
2
2
  import { join } from "node:path";
3
3
  import { getDataDirectory } from "./config.js";
4
- const EMPTY = { mode: "observe", blockedTools: [], blockedCommandPatterns: [], disabledAgents: [] };
5
- export function policyPath() {
6
- return join(getDataDirectory(), "policy.json");
4
+ const EMPTY = { mode: "observe", blockedTools: [], blockedCommandPatterns: [], disabledAgents: [], rules: [], customDetectors: [] };
5
+ export function policyPath() { return join(getDataDirectory(), "policy.json"); }
6
+ export function lastGoodPolicyPath() { return join(getDataDirectory(), "policy.last-good.json"); }
7
+ function validAction(v) { return ["ALLOW", "ASK", "BLOCK", "REDACT", "AUDIT"].includes(String(v).toUpperCase()); }
8
+ function validRule(v, index, errors) {
9
+ if (!v || typeof v !== "object" || Array.isArray(v)) {
10
+ errors.push(`rules[${index}] must be an object`);
11
+ return undefined;
12
+ }
13
+ const r = v;
14
+ if (typeof r.id !== "string" || !r.id.trim()) {
15
+ errors.push(`rules[${index}].id is required`);
16
+ return undefined;
17
+ }
18
+ if (!validAction(r.action)) {
19
+ errors.push(`rules[${index}] (${r.id}) has an invalid action`);
20
+ return undefined;
21
+ }
22
+ if (r.args !== undefined && (!Array.isArray(r.args) || r.args.some(a => typeof a !== "string"))) {
23
+ errors.push(`rules[${index}] (${r.id}).args must be strings`);
24
+ return undefined;
25
+ }
26
+ if (r.risk !== undefined && (typeof r.risk !== "number" || r.risk < 0 || r.risk > 100)) {
27
+ errors.push(`rules[${index}] (${r.id}).risk must be 0-100`);
28
+ return undefined;
29
+ }
30
+ return { ...r, action: String(r.action).toUpperCase() };
7
31
  }
8
32
  export async function readPolicy() {
33
+ const read = async (path) => {
34
+ const parsed = JSON.parse(await readFile(path, "utf8"));
35
+ if (!parsed.rules || typeof parsed.rules !== "object")
36
+ throw new Error("missing rules");
37
+ const errors = [];
38
+ const source = parsed.rules;
39
+ if (source.customDetectors !== undefined && (!Array.isArray(source.customDetectors) || source.customDetectors.some(d => !d || typeof d.name !== "string" || typeof d.pattern !== "string" || typeof d.replacement !== "string")))
40
+ errors.push("customDetectors must contain name, pattern, and replacement strings");
41
+ for (const detector of Array.isArray(source.customDetectors) ? source.customDetectors : []) {
42
+ try {
43
+ new RegExp(detector.pattern);
44
+ }
45
+ catch {
46
+ errors.push(`Invalid custom detector pattern: ${detector.name}`);
47
+ }
48
+ }
49
+ const rules = Array.isArray(source.rules) ? source.rules.map((r, i) => validRule(r, i, errors)).filter((r) => Boolean(r)) : [];
50
+ if (source.rules !== undefined && !Array.isArray(source.rules))
51
+ errors.push("rules must be an array");
52
+ return { version: typeof parsed.version === "number" ? parsed.version : 0, notAfter: typeof parsed.notAfter === "string" ? parsed.notAfter : null, rules: { ...EMPTY, ...source, rules }, errors };
53
+ };
9
54
  try {
10
- const parsed = JSON.parse(await readFile(policyPath(), "utf8"));
11
- if (!parsed.rules)
55
+ return await read(policyPath());
56
+ }
57
+ catch (error) {
58
+ if (error.code === "ENOENT")
12
59
  return null;
13
- return {
14
- version: typeof parsed.version === "number" ? parsed.version : 0,
15
- notAfter: parsed.notAfter ?? null,
16
- rules: { ...EMPTY, ...parsed.rules },
17
- };
60
+ try {
61
+ return await read(lastGoodPolicyPath());
62
+ }
63
+ catch {
64
+ // A present but malformed policy with no last-known-good copy fails closed.
65
+ return { version: 0, notAfter: null, errors: ["Policy file is malformed or unreadable; no last-known-good policy is available."], rules: { ...EMPTY, mode: "enforce" } };
66
+ }
18
67
  }
19
- catch {
20
- return null;
68
+ }
69
+ const safety = { ALLOW: 0, AUDIT: 1, REDACT: 2, ASK: 3, BLOCK: 4 };
70
+ function glob(pattern, value) { const e = pattern.replace(/[.+^${}()|[\]\\]/g, "\\$&").replace(/\*\*/g, "§§").replace(/\*/g, "[^/]*").replace(/§§/g, ".*").replace(/\?/g, "."); return new RegExp(`^${e}$`, "i").test(value); }
71
+ function same(a, b) { return !a || (b ?? "").toLowerCase() === a.toLowerCase(); }
72
+ function riskInfo(c) { const s = `${c.command} ${c.path ?? ""} ${c.url ?? ""}`; const factors = []; let n = 0; if (/\brm\s+.*-rf\s+\//i.test(s)) {
73
+ n += 98;
74
+ factors.push("destructive operation");
75
+ }
76
+ else if (/\brm\b/i.test(s)) {
77
+ n += 45;
78
+ factors.push("filesystem operation");
79
+ } if (/\bsudo\b/i.test(s)) {
80
+ n += 35;
81
+ factors.push("privileged operation");
82
+ } if (/\b(curl|wget)\b|https?:\/\//i.test(s)) {
83
+ n += 25;
84
+ factors.push("external destination");
85
+ } if (/\.env|\.ssh|\.aws|private.?key|api.?key|token|secret/i.test(s)) {
86
+ n += 35;
87
+ factors.push("sensitive data or file");
88
+ } const score = Math.min(100, n); return { score, level: score >= 90 ? "CRITICAL" : score >= 70 ? "HIGH" : score >= 30 ? "MEDIUM" : "LOW", factors }; }
89
+ function matches(r, c) {
90
+ if (!same(r.tool, c.tool) || !same(r.role, c.role) || !same(r.user, c.user) || !same(r.agent, c.agent) || !same(r.repository, c.repository) || !same(r.branch, c.branch) || !same(r.environment, c.environment))
91
+ return false;
92
+ if (r.cwd && !glob(r.cwd, c.cwd ?? ""))
93
+ return false;
94
+ if (r.command && !glob(r.command, c.command.split(/\s+/)[0] ?? ""))
95
+ return false;
96
+ if (r.path && !glob(r.path, c.path ?? ""))
97
+ return false;
98
+ if (r.url && !glob(r.url, c.url ?? ""))
99
+ return false;
100
+ if (r.args && r.args.some((a, i) => !glob(a, c.args?.[i] ?? "")))
101
+ return false;
102
+ if (r.risk !== undefined && c.riskScore < r.risk)
103
+ return false;
104
+ if (r.time && c.time) {
105
+ const t = c.time.slice(11, 16);
106
+ if (r.time.after && t < r.time.after || r.time.before && t > r.time.before)
107
+ return false;
21
108
  }
109
+ return true;
22
110
  }
23
- // Evaluate a proposed action. No policy, observe mode, or an expired bundle => allow.
111
+ function specificity(r) { return [r.tool, r.command, r.args?.length, r.path, r.url, r.role, r.user, r.agent, r.cwd, r.repository, r.branch, r.environment, r.time].filter(Boolean).length; }
24
112
  export function evaluate(bundle, ctx) {
113
+ const info = riskInfo(ctx);
114
+ const score = info.score;
115
+ const base = { mode: bundle?.rules.mode ?? "observe", policyVersion: bundle?.version ?? 0, riskScore: score, riskLevel: info.level, riskFactors: info.factors, customDetectors: bundle?.rules.customDetectors ?? [], actor: ctx.user, role: ctx.role, agent: ctx.agent, tool: ctx.tool, command: ctx.command, args: ctx.args, resource: ctx.path ?? ctx.url, errors: bundle?.errors };
25
116
  if (!bundle)
26
- return { action: "allow", mode: "observe", policyVersion: 0 };
27
- const { rules, version } = bundle;
28
- const base = { mode: rules.mode, policyVersion: version };
29
- if (rules.mode === "observe")
30
117
  return { action: "allow", ...base };
31
- // Stale cached policy: fail open rather than trap the user offline.
32
- if (bundle.notAfter && Date.parse(bundle.notAfter) < Date.now())
118
+ if (bundle.errors?.length)
119
+ return { action: "deny", ...base, reason: `Security policy rejected: ${bundle.errors.join("; ")}`, rule: "policy.invalid" };
120
+ if (bundle.rules.mode === "observe" || (bundle.notAfter && Date.parse(bundle.notAfter) < Date.now()))
33
121
  return { action: "allow", ...base };
34
- const hit = (reason) => ({
35
- action: rules.mode === "enforce" ? "deny" : "warn",
36
- reason,
37
- ...base,
38
- });
39
- if (rules.disabledAgents.some((a) => a.toLowerCase() === ctx.agent.toLowerCase())) {
40
- return hit(`${ctx.agent} is disabled for your account by workspace policy.`);
41
- }
42
- if (ctx.tool && rules.blockedTools.some((t) => t.toLowerCase() === ctx.tool.toLowerCase())) {
43
- return hit(`The ${ctx.tool} tool is blocked by workspace policy.`);
44
- }
45
- for (const pattern of rules.blockedCommandPatterns) {
46
- if (!ctx.command)
47
- break;
122
+ const candidates = [];
123
+ for (const r of bundle.rules.rules ?? [])
124
+ if (matches(r, { ...ctx, riskScore: score }))
125
+ candidates.push({ r, rank: specificity(r) });
126
+ for (const tool of bundle.rules.blockedTools) {
127
+ const r = { id: `legacy.tool.${tool}`, tool, action: "BLOCK", reason: `The ${tool} tool is blocked by workspace policy.` };
128
+ if (matches(r, { ...ctx, riskScore: score }))
129
+ candidates.push({ r, rank: 1 });
130
+ }
131
+ if (bundle.rules.disabledAgents.some(a => a.toLowerCase() === ctx.agent.toLowerCase()))
132
+ candidates.push({ r: { id: "legacy.disabled-agent", agent: ctx.agent, action: "BLOCK", reason: `${ctx.agent} is disabled by workspace policy.` }, rank: 1 });
133
+ for (const pattern of bundle.rules.blockedCommandPatterns) {
48
134
  try {
49
- if (new RegExp(pattern, "i").test(ctx.command)) {
50
- return hit(`This command matches a blocked pattern: /${pattern}/`);
51
- }
52
- }
53
- catch {
54
- /* ignore an unparseable pattern */
135
+ if (new RegExp(pattern, "i").test(ctx.command))
136
+ candidates.push({ r: { id: `legacy.command.${pattern}`, action: "BLOCK", reason: `Command matches blocked pattern: /${pattern}/` }, rank: 1 });
55
137
  }
138
+ catch { /* preserve legacy fail-open behavior; structured rules are validated and reported */ }
56
139
  }
57
- return { action: "allow", ...base };
140
+ const selected = candidates.sort((a, b) => b.rank - a.rank || safety[b.r.action] - safety[a.r.action])[0]?.r;
141
+ const thresholds = bundle.rules.risk ?? { askAt: 30, blockAt: 70 };
142
+ let action = selected?.action ?? "ALLOW";
143
+ if (!selected && score >= (thresholds.blockAt ?? 70))
144
+ action = "BLOCK";
145
+ else if (!selected && score >= (thresholds.askAt ?? 30))
146
+ action = "ASK";
147
+ const reason = selected?.reason ?? (action === "BLOCK" ? `Risk score ${score} exceeds the block threshold.` : action === "ASK" ? `Risk score ${score} requires approval.` : action === "REDACT" ? "Sensitive data must be transformed before this action." : undefined);
148
+ const mapped = action === "BLOCK" ? (bundle.rules.mode === "enforce" ? "deny" : "warn") : action === "ASK" && bundle.rules.mode === "advisory" ? "warn" : action.toLowerCase();
149
+ return { ...base, action: mapped, reason, policy: "local policy", rule: selected?.id, approval: selected?.approval };
58
150
  }
59
151
  //# sourceMappingURL=policy.js.map