@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.
Files changed (66) hide show
  1. package/LICENSE +661 -0
  2. package/README.md +188 -0
  3. package/dist/agents.d.ts +26 -0
  4. package/dist/agents.js +96 -0
  5. package/dist/agents.js.map +1 -0
  6. package/dist/cli.d.ts +2 -0
  7. package/dist/cli.js +234 -0
  8. package/dist/cli.js.map +1 -0
  9. package/dist/client.d.ts +28 -0
  10. package/dist/client.js +176 -0
  11. package/dist/client.js.map +1 -0
  12. package/dist/config.d.ts +5 -0
  13. package/dist/config.js +23 -0
  14. package/dist/config.js.map +1 -0
  15. package/dist/core.d.ts +64 -0
  16. package/dist/core.js +176 -0
  17. package/dist/core.js.map +1 -0
  18. package/dist/custom-rules.d.ts +7 -0
  19. package/dist/custom-rules.js +80 -0
  20. package/dist/custom-rules.js.map +1 -0
  21. package/dist/enroll.d.ts +16 -0
  22. package/dist/enroll.js +68 -0
  23. package/dist/enroll.js.map +1 -0
  24. package/dist/extract.d.ts +6 -0
  25. package/dist/extract.js +148 -0
  26. package/dist/extract.js.map +1 -0
  27. package/dist/forward.d.ts +8 -0
  28. package/dist/forward.js +53 -0
  29. package/dist/forward.js.map +1 -0
  30. package/dist/hook-adapters.d.ts +2 -0
  31. package/dist/hook-adapters.js +36 -0
  32. package/dist/hook-adapters.js.map +1 -0
  33. package/dist/install.d.ts +15 -0
  34. package/dist/install.js +68 -0
  35. package/dist/install.js.map +1 -0
  36. package/dist/inventory.d.ts +12 -0
  37. package/dist/inventory.js +23 -0
  38. package/dist/inventory.js.map +1 -0
  39. package/dist/open-browser.d.ts +1 -0
  40. package/dist/open-browser.js +8 -0
  41. package/dist/open-browser.js.map +1 -0
  42. package/dist/os-monitor.d.ts +5 -0
  43. package/dist/os-monitor.js +26 -0
  44. package/dist/os-monitor.js.map +1 -0
  45. package/dist/policy.d.ts +27 -0
  46. package/dist/policy.js +59 -0
  47. package/dist/policy.js.map +1 -0
  48. package/dist/sequences.d.ts +13 -0
  49. package/dist/sequences.js +58 -0
  50. package/dist/sequences.js.map +1 -0
  51. package/dist/serve.d.ts +27 -0
  52. package/dist/serve.js +113 -0
  53. package/dist/serve.js.map +1 -0
  54. package/dist/server.d.ts +10 -0
  55. package/dist/server.js +101 -0
  56. package/dist/server.js.map +1 -0
  57. package/dist/service.d.ts +27 -0
  58. package/dist/service.js +169 -0
  59. package/dist/service.js.map +1 -0
  60. package/dist/store.d.ts +19 -0
  61. package/dist/store.js +114 -0
  62. package/dist/store.js.map +1 -0
  63. package/dist/studio.d.ts +1 -0
  64. package/dist/studio.js +337 -0
  65. package/dist/studio.js.map +1 -0
  66. package/package.json +43 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"policy.js","sourceRoot":"","sources":["../src/policy.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,13 @@
1
+ import type { Event, Finding, RuleCategory, Severity } from "./core.js";
2
+ export interface SequenceRule {
3
+ id: string;
4
+ title: string;
5
+ severity: Severity;
6
+ category: RuleCategory;
7
+ explanation: string;
8
+ /** Ordered step predicates; a match requires each to be satisfied by a later-or-equal event
9
+ * than the previous step, not necessarily consecutively. */
10
+ steps: ((e: Event) => boolean)[];
11
+ }
12
+ export declare const sequenceRuleCatalog: SequenceRule[];
13
+ export declare function detectSequenceFindings(sessionEvents: Event[]): Map<string, Finding[]>;
@@ -0,0 +1,58 @@
1
+ // A single risky-looking action can be routine. Two specific actions in the same session, in
2
+ // order, are what actually matters -- neither built-in single-event rule nor a 3-line text
3
+ // window can see across separate tool calls the way this can.
4
+ export const sequenceRuleCatalog = [
5
+ {
6
+ id: "chain.secret_then_egress",
7
+ title: "Credential read followed by network activity",
8
+ severity: "critical",
9
+ category: "exfil",
10
+ explanation: "A credential or secret was read in one action, and network activity followed later in the same session. Neither step alone is unusual; review what the second action actually sent.",
11
+ steps: [
12
+ e => e.findings.some(f => f.id === "credentials.access"),
13
+ e => /https?:\/\/|\bcurl\b|\bwget\b|\bupload\b|\bwebhook\b/i.test(e.summary) || e.type === "browser.navigate",
14
+ ],
15
+ },
16
+ {
17
+ id: "chain.recon_then_exec",
18
+ title: "Network reconnaissance followed by remote execution",
19
+ severity: "critical",
20
+ category: "exec",
21
+ explanation: "A network or host scan was followed by code fetched and run from a remote source in the same session.",
22
+ steps: [
23
+ e => e.findings.some(f => f.id === "recon.network_sweep"),
24
+ e => e.findings.some(f => f.id === "execution.remote"),
25
+ ],
26
+ },
27
+ ];
28
+ const WINDOW = 50; // only the most recent N events per session are considered
29
+ // Scans one session's events (any order) for completed step sequences and returns the finding
30
+ // each completed match should attach to its final (most recent) matching event. Idempotent: the
31
+ // caller should skip attaching a finding an event already has -- re-running over the same
32
+ // history must never duplicate a chain finding.
33
+ export function detectSequenceFindings(sessionEvents) {
34
+ const ordered = [...sessionEvents].sort((a, b) => Date.parse(a.timestamp) - Date.parse(b.timestamp)).slice(-WINDOW);
35
+ const attach = new Map();
36
+ for (const rule of sequenceRuleCatalog) {
37
+ let stepIndex = 0;
38
+ for (const event of ordered) {
39
+ if (!rule.steps[stepIndex](event))
40
+ continue;
41
+ stepIndex++;
42
+ if (stepIndex < rule.steps.length)
43
+ continue;
44
+ if (!event.findings.some(f => f.id === rule.id)) {
45
+ const finding = {
46
+ id: rule.id, title: rule.title, severity: rule.severity, explanation: rule.explanation,
47
+ evidence: `Matched a ${rule.steps.length}-step sequence across events in session "${event.session}".`,
48
+ };
49
+ const list = attach.get(event.id) ?? [];
50
+ list.push(finding);
51
+ attach.set(event.id, list);
52
+ }
53
+ stepIndex = 0; // allow another, later match of the same rule in the same session
54
+ }
55
+ }
56
+ return attach;
57
+ }
58
+ //# sourceMappingURL=sequences.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sequences.js","sourceRoot":"","sources":["../src/sequences.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,27 @@
1
+ import { type InstallAllResult } from "./install.js";
2
+ export interface StartServerOptions {
3
+ directory?: string;
4
+ token?: string;
5
+ port?: number;
6
+ hostname?: string;
7
+ origins?: string[];
8
+ /** Root to load ~/.beam/rules.json from; defaults to the real BEAM_HOME. Tests override this. */
9
+ rulesHome?: string;
10
+ /** Home directory to scan/write agent hook configs into; defaults to the real home. Tests override this. */
11
+ agentHome?: string;
12
+ /** Whether to run OS-level process/network monitoring (see os-monitor.ts). Defaults to on; tests disable it. */
13
+ osMonitor?: boolean;
14
+ }
15
+ export declare function startServer(options?: StartServerOptions): Promise<{
16
+ url: string;
17
+ token: string;
18
+ directory: string;
19
+ customRules: {
20
+ path: string;
21
+ loaded: number;
22
+ errors: string[];
23
+ };
24
+ policySync: boolean;
25
+ agentInstalls: InstallAllResult[];
26
+ close: () => void;
27
+ }>;
package/dist/serve.js ADDED
@@ -0,0 +1,113 @@
1
+ import { chmod, mkdir, readFile, writeFile } from "node:fs/promises";
2
+ import { homedir } from "node:os";
3
+ import { join } from "node:path";
4
+ import { randomBytes } from "node:crypto";
5
+ import { createServer } from "node:http";
6
+ import { createCollector } from "./server.js";
7
+ import { getDataDirectory } from "./config.js";
8
+ import { loadCustomRules } from "./custom-rules.js";
9
+ import { readIdentity } from "./enroll.js";
10
+ import { syncPolicy } from "./forward.js";
11
+ import { installAllDetectedHooks } from "./install.js";
12
+ import { startOsMonitor } from "./os-monitor.js";
13
+ function toWebRequest(req) {
14
+ return new Promise((resolvePromise, reject) => {
15
+ const chunks = [];
16
+ req.on("data", (chunk) => chunks.push(chunk));
17
+ req.on("end", () => {
18
+ try {
19
+ const hasBody = !["GET", "HEAD"].includes(req.method ?? "GET");
20
+ const headers = new Headers();
21
+ for (const [key, value] of Object.entries(req.headers)) {
22
+ if (Array.isArray(value))
23
+ for (const v of value)
24
+ headers.append(key, v);
25
+ else if (value !== undefined)
26
+ headers.set(key, value);
27
+ }
28
+ const url = `http://${req.headers.host ?? "127.0.0.1"}${req.url ?? "/"}`;
29
+ resolvePromise(new Request(url, { method: req.method, headers, body: hasBody ? Buffer.concat(chunks) : undefined }));
30
+ }
31
+ catch (error) {
32
+ reject(error);
33
+ }
34
+ });
35
+ req.on("error", reject);
36
+ });
37
+ }
38
+ async function writeWebResponse(response, res) {
39
+ res.statusCode = response.status;
40
+ response.headers.forEach((value, key) => res.setHeader(key, value));
41
+ const body = response.body ? Buffer.from(await response.arrayBuffer()) : Buffer.alloc(0);
42
+ res.end(body);
43
+ }
44
+ export async function startServer(options = {}) {
45
+ const directory = options.directory ?? getDataDirectory();
46
+ await mkdir(directory, { recursive: true, mode: 0o700 });
47
+ // Wire beam's hook into every detected-but-not-yet-wired agent on every start, so a newly
48
+ // installed agent (or one that showed up after the last `beam start`) starts getting captured
49
+ // without a separate manual `beam agent install-all` step. Never blocks or fails startup --
50
+ // a single agent's config being unwritable shouldn't stop the collector from serving.
51
+ const agentInstalls = await installAllDetectedHooks(options.agentHome ?? homedir()).catch(() => []);
52
+ // Loaded once per process into core.ts's shared rule set; a file edit needs a restart to apply.
53
+ // Errors are returned, not logged here -- the caller (cli.ts) owns all console output, since
54
+ // this same function also runs unattended inside the background service process.
55
+ const customRules = await loadCustomRules(options.rulesHome);
56
+ let token = options.token ?? process.env.BEAM_TOKEN;
57
+ if (!token) {
58
+ const tokenPath = join(directory, "token");
59
+ try {
60
+ token = (await readFile(tokenPath, "utf8")).trim();
61
+ await chmod(tokenPath, 0o600);
62
+ }
63
+ catch (e) {
64
+ if (e.code !== "ENOENT")
65
+ throw e;
66
+ token = randomBytes(32).toString("hex");
67
+ await writeFile(tokenPath, token, { mode: 0o600, flag: "wx" });
68
+ }
69
+ }
70
+ if (token.length < 32)
71
+ throw new Error("BEAM_TOKEN must contain at least 32 characters.");
72
+ const app = await createCollector({ directory, token, origins: options.origins ?? process.env.BEAM_ALLOWED_ORIGINS?.split(",").map(s => s.trim()), rulesHome: options.rulesHome });
73
+ const port = options.port ?? Number(process.env.BEAM_PORT || 4319);
74
+ const hostname = options.hostname ?? "127.0.0.1";
75
+ const server = createServer((req, res) => {
76
+ toWebRequest(req)
77
+ .then(webRequest => app.fetch(webRequest))
78
+ .then(webResponse => writeWebResponse(webResponse, res))
79
+ .catch(error => {
80
+ console.error("Beam server error:", error instanceof Error ? error.message : error);
81
+ if (!res.headersSent)
82
+ res.statusCode = 500;
83
+ res.end();
84
+ });
85
+ });
86
+ const boundPort = await new Promise((resolvePromise, reject) => {
87
+ server.once("error", reject);
88
+ server.listen(port, hostname, () => {
89
+ const address = server.address();
90
+ resolvePromise(typeof address === "object" && address ? address.port : port);
91
+ });
92
+ });
93
+ // Keep the cached policy fresh so `beam hook` can enforce it without a network call.
94
+ let policyTimer;
95
+ const identity = await readIdentity();
96
+ if (identity) {
97
+ const poll = () => { void syncPolicy().catch(() => { }); };
98
+ poll();
99
+ policyTimer = setInterval(poll, 60_000);
100
+ policyTimer.unref?.();
101
+ }
102
+ // Observes AI agent activity directly (process start/exit, network connections) so agents that
103
+ // don't cooperate with any hook -- or that run through a GUI/IDE surface with no hook path at
104
+ // all -- still get captured. See os-monitor.ts. macOS only; a no-op elsewhere.
105
+ const osMonitor = options.osMonitor === false ? { stop: () => { } } : await startOsMonitor(async (events) => { await app.store.addEvents(events); });
106
+ return {
107
+ url: `http://${hostname}:${boundPort}`, token, directory, customRules, agentInstalls,
108
+ policySync: Boolean(identity),
109
+ close: () => { if (policyTimer)
110
+ clearInterval(policyTimer); osMonitor.stop(); server.close(); },
111
+ };
112
+ }
113
+ //# sourceMappingURL=serve.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"serve.js","sourceRoot":"","sources":["../src/serve.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,10 @@
1
+ import { Store } from "./store.js";
2
+ export declare function createCollector(options: {
3
+ directory: string;
4
+ token: string;
5
+ origins?: string[];
6
+ rulesHome?: string;
7
+ }): Promise<{
8
+ store: Store;
9
+ fetch(req: Request): Promise<Response>;
10
+ }>;
package/dist/server.js ADDED
@@ -0,0 +1,101 @@
1
+ import { timingSafeEqual } from "node:crypto";
2
+ import { normalize, parseInput, ruleCatalog, scanText } from "./core.js";
3
+ import { Store } from "./store.js";
4
+ import { inventory } from "./inventory.js";
5
+ import { studioPage } from "./studio.js";
6
+ import { loadCustomRules } from "./custom-rules.js";
7
+ export async function createCollector(options) {
8
+ const store = new Store(options.directory);
9
+ await store.init();
10
+ const origins = new Set(options.origins ?? ["http://localhost:3200", "http://127.0.0.1:3200"]);
11
+ const secret = Buffer.from(`Bearer ${options.token}`);
12
+ return { store, async fetch(req) {
13
+ const origin = req.headers.get("origin");
14
+ const url = new URL(req.url);
15
+ const headers = { "Cache-Control": "no-store", "X-Content-Type-Options": "nosniff", "Vary": "Origin" };
16
+ const json = (data, status = 200) => Response.json(data, { status, headers });
17
+ if (!["127.0.0.1", "localhost", "[::1]"].includes(url.hostname))
18
+ return json({ error: "Loopback host required." }, 403);
19
+ // Studio is served by this same collector, so its own fetch() calls are same-origin --
20
+ // browsers still attach an Origin header to same-origin POSTs, so that must be allowed
21
+ // unconditionally rather than only checked against the cross-origin management-app allowlist.
22
+ if (origin && origin !== url.origin && !origins.has(origin))
23
+ return json({ error: "Origin not permitted." }, 403);
24
+ if (origin) {
25
+ headers["Access-Control-Allow-Origin"] = origin;
26
+ headers["Access-Control-Allow-Methods"] = "GET, POST, OPTIONS";
27
+ headers["Access-Control-Allow-Headers"] = "Authorization, Content-Type";
28
+ headers["Access-Control-Allow-Private-Network"] = "true";
29
+ }
30
+ if (req.method === "OPTIONS")
31
+ return new Response(null, { status: 204, headers });
32
+ // The studio shell carries no secret (a static page); it pairs with its own token in-browser.
33
+ if (req.method === "GET" && (url.pathname === "/" || url.pathname === "/studio")) {
34
+ return new Response(studioPage(), { headers: { ...headers, "Content-Type": "text/html; charset=utf-8" } });
35
+ }
36
+ const provided = Buffer.from(req.headers.get("authorization") ?? "");
37
+ if (provided.length !== secret.length || !timingSafeEqual(provided, secret))
38
+ return json({ error: "Pairing token is missing or incorrect." }, 401);
39
+ if (req.headers.get("content-encoding"))
40
+ return json({ error: "Compressed requests are not supported; disable gzip in the exporter." }, 415);
41
+ try {
42
+ if (req.method === "GET" && url.pathname === "/agents")
43
+ return json(await inventory(store.events));
44
+ if (req.method === "GET" && url.pathname === "/health")
45
+ return json({ name: "Beam", version: "0.1.0", mode: "observe", events: store.events.length, retention: store.maxEvents });
46
+ if (req.method === "GET" && url.pathname === "/state")
47
+ return json({ events: store.events, scans: store.scans, reviews: store.reviews, rules: ruleCatalog(), retention: store.maxEvents });
48
+ if (req.method === "GET" && url.pathname === "/export")
49
+ return new Response(store.events.map(e => JSON.stringify(e)).join("\n"), { headers: { ...headers, "Content-Type": "application/x-ndjson", "Content-Disposition": 'attachment; filename="beam-events.ndjson"' } });
50
+ // Reloads ~/.beam/rules.json into this running process without a restart.
51
+ if (req.method === "POST" && url.pathname === "/rules/reload")
52
+ return json(await loadCustomRules(options.rulesHome));
53
+ if (req.method !== "POST" || !["/ingest", "/v1/logs", "/scan", "/review"].includes(url.pathname))
54
+ return json({ error: "Route not found." }, 404);
55
+ // Bound streamed bodies too; Content-Length alone cannot protect chunked requests.
56
+ const reader = req.body?.getReader();
57
+ let size = 0;
58
+ const chunks = [];
59
+ if (reader)
60
+ while (true) {
61
+ const { done, value } = await reader.read();
62
+ if (done)
63
+ break;
64
+ size += value.byteLength;
65
+ if (size > 2_000_000) {
66
+ await reader.cancel();
67
+ return json({ error: "Request exceeds 2 MB." }, 413);
68
+ }
69
+ chunks.push(value);
70
+ }
71
+ const body = Buffer.concat(chunks).toString("utf8");
72
+ if (url.pathname === "/ingest" || url.pathname === "/v1/logs") {
73
+ const records = parseInput(body, url.pathname === "/v1/logs");
74
+ if (records.length > 2000)
75
+ throw new Error("Batch exceeds 2,000 records.");
76
+ // Some exporters also emit indicator, summary and enforcement records; those are not action events.
77
+ const supported = records.filter(r => !r.record_type || ["event", "finding"].includes(String(r.record_type)));
78
+ const result = await store.addEvents(supported.map(normalize));
79
+ return json(url.pathname === "/v1/logs" ? {} : { ...result, skipped: records.length - supported.length });
80
+ }
81
+ const data = JSON.parse(body);
82
+ if (url.pathname === "/scan") {
83
+ if (typeof data.content !== "string" || typeof data.name !== "string" || !["skill", "mcp"].includes(data.kind))
84
+ throw new Error("Expected name, content and kind (skill or mcp).");
85
+ return json(await store.addScan(scanText(data.name, data.content, data.kind)));
86
+ }
87
+ if (typeof data.id !== "string" || typeof data.reviewed !== "boolean")
88
+ throw new Error("Expected event id and reviewed boolean.");
89
+ await store.review(data.id, data.reviewed);
90
+ return json({ ok: true });
91
+ }
92
+ catch (e) {
93
+ if (e.code) {
94
+ console.error("Beam storage error:", e.code);
95
+ return json({ error: "Local storage failed. Check collector permissions and disk space; retry the request." }, 500);
96
+ }
97
+ return json({ error: e instanceof Error ? e.message : "Invalid request." }, 400);
98
+ }
99
+ } };
100
+ }
101
+ //# sourceMappingURL=server.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAC9C,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,WAAW,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAC;AACzE,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AACnC,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAC3C,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAEpD,MAAM,CAAC,KAAK,UAAU,eAAe,CAAC,OAAqF;IACzH,MAAM,KAAK,GAAG,IAAI,KAAK,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;IAAC,MAAM,KAAK,CAAC,IAAI,EAAE,CAAC;IAC/D,MAAM,OAAO,GAAG,IAAI,GAAG,CAAC,OAAO,CAAC,OAAO,IAAI,CAAC,uBAAuB,EAAE,uBAAuB,CAAC,CAAC,CAAC;IAC/F,MAAM,MAAM,GAAG,MAAM,CAAC,IAAI,CAAC,UAAU,OAAO,CAAC,KAAK,EAAE,CAAC,CAAC;IACtD,OAAO,EAAE,KAAK,EAAE,KAAK,CAAC,KAAK,CAAC,GAAY;YACtC,MAAM,MAAM,GAAG,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;YACzC,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;YAC7B,MAAM,OAAO,GAA2B,EAAE,eAAe,EAAE,UAAU,EAAE,wBAAwB,EAAE,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC;YAC/H,MAAM,IAAI,GAAG,CAAC,IAAa,EAAE,MAAM,GAAG,GAAG,EAAE,EAAE,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,EAAE,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC,CAAC;YACvF,IAAI,CAAC,CAAC,WAAW,EAAE,WAAW,EAAE,OAAO,CAAC,CAAC,QAAQ,CAAC,GAAG,CAAC,QAAQ,CAAC;gBAAE,OAAO,IAAI,CAAC,EAAE,KAAK,EAAE,yBAAyB,EAAE,EAAE,GAAG,CAAC,CAAC;YACxH,uFAAuF;YACvF,uFAAuF;YACvF,8FAA8F;YAC9F,IAAI,MAAM,IAAI,MAAM,KAAK,GAAG,CAAC,MAAM,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC;gBAAE,OAAO,IAAI,CAAC,EAAE,KAAK,EAAE,uBAAuB,EAAE,EAAE,GAAG,CAAC,CAAC;YAClH,IAAI,MAAM,EAAE,CAAC;gBACX,OAAO,CAAC,6BAA6B,CAAC,GAAG,MAAM,CAAC;gBAChD,OAAO,CAAC,8BAA8B,CAAC,GAAG,oBAAoB,CAAC;gBAC/D,OAAO,CAAC,8BAA8B,CAAC,GAAG,6BAA6B,CAAC;gBACxE,OAAO,CAAC,sCAAsC,CAAC,GAAG,MAAM,CAAC;YAC3D,CAAC;YACD,IAAI,GAAG,CAAC,MAAM,KAAK,SAAS;gBAAE,OAAO,IAAI,QAAQ,CAAC,IAAI,EAAE,EAAE,MAAM,EAAE,GAAG,EAAE,OAAO,EAAE,CAAC,CAAC;YAClF,8FAA8F;YAC9F,IAAI,GAAG,CAAC,MAAM,KAAK,KAAK,IAAI,CAAC,GAAG,CAAC,QAAQ,KAAK,GAAG,IAAI,GAAG,CAAC,QAAQ,KAAK,SAAS,CAAC,EAAE,CAAC;gBACjF,OAAO,IAAI,QAAQ,CAAC,UAAU,EAAE,EAAE,EAAE,OAAO,EAAE,EAAE,GAAG,OAAO,EAAE,cAAc,EAAE,0BAA0B,EAAE,EAAE,CAAC,CAAC;YAC7G,CAAC;YACD,MAAM,QAAQ,GAAG,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,eAAe,CAAC,IAAI,EAAE,CAAC,CAAC;YACrE,IAAI,QAAQ,CAAC,MAAM,KAAK,MAAM,CAAC,MAAM,IAAI,CAAC,eAAe,CAAC,QAAQ,EAAE,MAAM,CAAC;gBAAE,OAAO,IAAI,CAAC,EAAE,KAAK,EAAE,wCAAwC,EAAE,EAAE,GAAG,CAAC,CAAC;YACnJ,IAAI,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,kBAAkB,CAAC;gBAAE,OAAO,IAAI,CAAC,EAAE,KAAK,EAAE,sEAAsE,EAAE,EAAE,GAAG,CAAC,CAAC;YAC7I,IAAI,CAAC;gBACH,IAAI,GAAG,CAAC,MAAM,KAAK,KAAK,IAAI,GAAG,CAAC,QAAQ,KAAK,SAAS;oBAAE,OAAO,IAAI,CAAC,MAAM,SAAS,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC;gBACnG,IAAI,GAAG,CAAC,MAAM,KAAK,KAAK,IAAI,GAAG,CAAC,QAAQ,KAAK,SAAS;oBAAE,OAAO,IAAI,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,MAAM,EAAE,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE,SAAS,EAAE,KAAK,CAAC,SAAS,EAAE,CAAC,CAAC;gBAClL,IAAI,GAAG,CAAC,MAAM,KAAK,KAAK,IAAI,GAAG,CAAC,QAAQ,KAAK,QAAQ;oBAAE,OAAO,IAAI,CAAC,EAAE,MAAM,EAAE,KAAK,CAAC,MAAM,EAAE,KAAK,EAAE,KAAK,CAAC,KAAK,EAAE,OAAO,EAAE,KAAK,CAAC,OAAO,EAAE,KAAK,EAAE,WAAW,EAAE,EAAE,SAAS,EAAE,KAAK,CAAC,SAAS,EAAE,CAAC,CAAC;gBAC3L,IAAI,GAAG,CAAC,MAAM,KAAK,KAAK,IAAI,GAAG,CAAC,QAAQ,KAAK,SAAS;oBAAE,OAAO,IAAI,QAAQ,CAAC,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,EAAE,OAAO,EAAE,EAAE,GAAG,OAAO,EAAE,cAAc,EAAE,sBAAsB,EAAE,qBAAqB,EAAE,2CAA2C,EAAE,EAAE,CAAC,CAAC;gBAC1Q,0EAA0E;gBAC1E,IAAI,GAAG,CAAC,MAAM,KAAK,MAAM,IAAI,GAAG,CAAC,QAAQ,KAAK,eAAe;oBAAE,OAAO,IAAI,CAAC,MAAM,eAAe,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC,CAAC;gBACrH,IAAI,GAAG,CAAC,MAAM,KAAK,MAAM,IAAI,CAAC,CAAC,SAAS,EAAE,UAAU,EAAE,OAAO,EAAE,SAAS,CAAC,CAAC,QAAQ,CAAC,GAAG,CAAC,QAAQ,CAAC;oBAAE,OAAO,IAAI,CAAC,EAAE,KAAK,EAAE,kBAAkB,EAAE,EAAE,GAAG,CAAC,CAAC;gBAClJ,mFAAmF;gBACnF,MAAM,MAAM,GAAG,GAAG,CAAC,IAAI,EAAE,SAAS,EAAE,CAAC;gBAAC,IAAI,IAAI,GAAG,CAAC,CAAC;gBAAC,MAAM,MAAM,GAAiB,EAAE,CAAC;gBACpF,IAAI,MAAM;oBAAE,OAAO,IAAI,EAAE,CAAC;wBAAC,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,GAAG,MAAM,MAAM,CAAC,IAAI,EAAE,CAAC;wBAAC,IAAI,IAAI;4BAAE,MAAM;wBAAC,IAAI,IAAI,KAAK,CAAC,UAAU,CAAC;wBAAC,IAAI,IAAI,GAAG,SAAS,EAAE,CAAC;4BAAC,MAAM,MAAM,CAAC,MAAM,EAAE,CAAC;4BAAC,OAAO,IAAI,CAAC,EAAE,KAAK,EAAE,uBAAuB,EAAE,EAAE,GAAG,CAAC,CAAC;wBAAC,CAAC;wBAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;oBAAC,CAAC;gBAC/O,MAAM,IAAI,GAAG,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;gBACpD,IAAI,GAAG,CAAC,QAAQ,KAAK,SAAS,IAAI,GAAG,CAAC,QAAQ,KAAK,UAAU,EAAE,CAAC;oBAC9D,MAAM,OAAO,GAAG,UAAU,CAAC,IAAI,EAAE,GAAG,CAAC,QAAQ,KAAK,UAAU,CAAC,CAAC;oBAC9D,IAAI,OAAO,CAAC,MAAM,GAAG,IAAI;wBAAE,MAAM,IAAI,KAAK,CAAC,8BAA8B,CAAC,CAAC;oBAC3E,oGAAoG;oBACpG,MAAM,SAAS,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,WAAW,IAAI,CAAC,OAAO,EAAE,SAAS,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC;oBAC9G,MAAM,MAAM,GAAG,MAAM,KAAK,CAAC,SAAS,CAAC,SAAS,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC;oBAC/D,OAAO,IAAI,CAAC,GAAG,CAAC,QAAQ,KAAK,UAAU,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,GAAG,MAAM,EAAE,OAAO,EAAE,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,MAAM,EAAE,CAAC,CAAC;gBAC5G,CAAC;gBACD,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;gBAC9B,IAAI,GAAG,CAAC,QAAQ,KAAK,OAAO,EAAE,CAAC;oBAC7B,IAAI,OAAO,IAAI,CAAC,OAAO,KAAK,QAAQ,IAAI,OAAO,IAAI,CAAC,IAAI,KAAK,QAAQ,IAAI,CAAC,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC;wBAAE,MAAM,IAAI,KAAK,CAAC,iDAAiD,CAAC,CAAC;oBACnL,OAAO,IAAI,CAAC,MAAM,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,OAAO,EAAE,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;gBACjF,CAAC;gBACD,IAAI,OAAO,IAAI,CAAC,EAAE,KAAK,QAAQ,IAAI,OAAO,IAAI,CAAC,QAAQ,KAAK,SAAS;oBAAE,MAAM,IAAI,KAAK,CAAC,yCAAyC,CAAC,CAAC;gBAClI,MAAM,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,EAAE,IAAI,CAAC,QAAQ,CAAC,CAAC;gBAAC,OAAO,IAAI,CAAC,EAAE,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC;YACxE,CAAC;YAAC,OAAO,CAAC,EAAE,CAAC;gBACX,IAAK,CAA2B,CAAC,IAAI,EAAE,CAAC;oBAAC,OAAO,CAAC,KAAK,CAAC,qBAAqB,EAAG,CAA2B,CAAC,IAAI,CAAC,CAAC;oBAAC,OAAO,IAAI,CAAC,EAAE,KAAK,EAAE,sFAAsF,EAAE,EAAE,GAAG,CAAC,CAAC;gBAAC,CAAC;gBACxO,OAAO,IAAI,CAAC,EAAE,KAAK,EAAE,CAAC,YAAY,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,kBAAkB,EAAE,EAAE,GAAG,CAAC,CAAC;YACnF,CAAC;QACH,CAAC,EAAE,CAAC;AACN,CAAC"}
@@ -0,0 +1,27 @@
1
+ import { execFile } from "node:child_process";
2
+ export declare const run: typeof execFile.__promisify__;
3
+ export interface ServiceOptions {
4
+ port?: number;
5
+ home?: string;
6
+ }
7
+ export interface ServiceInfo {
8
+ platform: string;
9
+ managed: boolean;
10
+ configPath: string;
11
+ running?: boolean;
12
+ raw?: string;
13
+ }
14
+ export declare function macPlistPath(home?: string): string;
15
+ export declare function macPlist(port: number, dataDir: string): string;
16
+ export declare function systemdUnitPath(home?: string): string;
17
+ export declare function systemdUnit(port: number, dataDir: string): string;
18
+ export declare function installService(options?: ServiceOptions): Promise<ServiceInfo>;
19
+ export declare function uninstallService(home?: string): Promise<void>;
20
+ export declare function startService(home?: string): Promise<void>;
21
+ export declare function stopService(home?: string): Promise<void>;
22
+ export declare function serviceStatus(home?: string): Promise<ServiceInfo>;
23
+ export declare function serviceLogPaths(): Promise<{
24
+ out: string;
25
+ err?: string;
26
+ }>;
27
+ export declare function readServiceConfig(home?: string): Promise<string | null>;
@@ -0,0 +1,169 @@
1
+ import { execFile } from "node:child_process";
2
+ import { promisify } from "node:util";
3
+ import { homedir } from "node:os";
4
+ import { join, dirname } from "node:path";
5
+ import { fileURLToPath } from "node:url";
6
+ import { mkdir, readFile, rm, writeFile } from "node:fs/promises";
7
+ import { getDataDirectory } from "./config.js";
8
+ export const run = promisify(execFile);
9
+ const LABEL = "ai.beam.collector";
10
+ // os.platform() does not track process.platform overrides in tests; process.platform does.
11
+ function osPlatform() { return process.platform; }
12
+ function cliEntryPath() {
13
+ // dist/service.js sits next to dist/cli.js after build.
14
+ return join(dirname(fileURLToPath(import.meta.url)), "cli.js");
15
+ }
16
+ function logDirectory() {
17
+ return join(getDataDirectory(), "logs");
18
+ }
19
+ // --- macOS: launchd user agent ---
20
+ export function macPlistPath(home = homedir()) {
21
+ return join(home, "Library", "LaunchAgents", `${LABEL}.plist`);
22
+ }
23
+ export function macPlist(port, dataDir) {
24
+ const exec = process.execPath;
25
+ const cli = cliEntryPath();
26
+ const escape = (s) => s.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
27
+ return `<?xml version="1.0" encoding="UTF-8"?>
28
+ <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
29
+ <plist version="1.0">
30
+ <dict>
31
+ <key>Label</key><string>${LABEL}</string>
32
+ <key>ProgramArguments</key>
33
+ <array>
34
+ <string>${escape(exec)}</string>
35
+ <string>${escape(cli)}</string>
36
+ <string>start</string>
37
+ <string>--port</string>
38
+ <string>${port}</string>
39
+ </array>
40
+ <key>EnvironmentVariables</key>
41
+ <dict>
42
+ <key>BEAM_DATA_DIR</key><string>${escape(dataDir)}</string>
43
+ </dict>
44
+ <key>RunAtLoad</key><true/>
45
+ <key>KeepAlive</key><true/>
46
+ <key>ProcessType</key><string>Background</string>
47
+ <key>StandardOutPath</key><string>${escape(join(dataDir, "logs", "collector.log"))}</string>
48
+ <key>StandardErrorPath</key><string>${escape(join(dataDir, "logs", "collector.err.log"))}</string>
49
+ </dict>
50
+ </plist>
51
+ `;
52
+ }
53
+ async function macInstall(options) {
54
+ const path = macPlistPath(options.home);
55
+ const dataDir = getDataDirectory();
56
+ await mkdir(join(dataDir, "logs"), { recursive: true });
57
+ await mkdir(dirname(path), { recursive: true });
58
+ await writeFile(path, macPlist(options.port ?? 4319, dataDir));
59
+ await run("launchctl", ["load", "-w", path]).catch(() => { });
60
+ return { platform: "darwin", managed: true, configPath: path };
61
+ }
62
+ async function macUninstall(home) {
63
+ const path = macPlistPath(home);
64
+ await run("launchctl", ["unload", "-w", path]).catch(() => { });
65
+ await rm(path, { force: true });
66
+ }
67
+ async function macStart(home) { await run("launchctl", ["load", "-w", macPlistPath(home)]); }
68
+ async function macStop(home) { await run("launchctl", ["unload", "-w", macPlistPath(home)]); }
69
+ async function macStatus(home) {
70
+ const { stdout } = await run("launchctl", ["list"]).catch(() => ({ stdout: "" }));
71
+ const line = stdout.split("\n").find(l => l.includes(LABEL));
72
+ return { platform: "darwin", managed: Boolean(line), configPath: macPlistPath(home), running: Boolean(line), raw: line };
73
+ }
74
+ // --- Linux: systemd user service ---
75
+ export function systemdUnitPath(home = homedir()) {
76
+ return join(home, ".config", "systemd", "user", "beam.service");
77
+ }
78
+ export function systemdUnit(port, dataDir) {
79
+ const exec = process.execPath;
80
+ const cli = cliEntryPath();
81
+ return `[Unit]
82
+ Description=Beam collector
83
+
84
+ [Service]
85
+ ExecStart=${exec} ${cli} start --port ${port}
86
+ Environment=BEAM_DATA_DIR=${dataDir}
87
+ Restart=always
88
+ RestartSec=2
89
+
90
+ [Install]
91
+ WantedBy=default.target
92
+ `;
93
+ }
94
+ async function systemdInstall(options) {
95
+ const path = systemdUnitPath(options.home);
96
+ const dataDir = getDataDirectory();
97
+ await mkdir(dirname(path), { recursive: true });
98
+ await writeFile(path, systemdUnit(options.port ?? 4319, dataDir));
99
+ await run("systemctl", ["--user", "daemon-reload"]);
100
+ await run("systemctl", ["--user", "enable", "--now", "beam.service"]);
101
+ return { platform: "linux", managed: true, configPath: path };
102
+ }
103
+ async function systemdUninstall(home) {
104
+ await run("systemctl", ["--user", "disable", "--now", "beam.service"]).catch(() => { });
105
+ await rm(systemdUnitPath(home), { force: true });
106
+ await run("systemctl", ["--user", "daemon-reload"]).catch(() => { });
107
+ }
108
+ async function systemdStart() { await run("systemctl", ["--user", "start", "beam.service"]); }
109
+ async function systemdStop() { await run("systemctl", ["--user", "stop", "beam.service"]); }
110
+ async function systemdStatus(home) {
111
+ const { stdout } = await run("systemctl", ["--user", "is-active", "beam.service"]).catch(e => ({ stdout: e.stdout ?? "inactive" }));
112
+ const running = stdout.trim() === "active";
113
+ return { platform: "linux", managed: running, configPath: systemdUnitPath(home), running, raw: stdout.trim() };
114
+ }
115
+ // --- dispatch ---
116
+ function unsupported() {
117
+ throw new Error(`'beam service' is not supported on ${osPlatform()} yet. Run 'beam start' directly instead.`);
118
+ }
119
+ export async function installService(options = {}) {
120
+ if (osPlatform() === "darwin")
121
+ return macInstall(options);
122
+ if (osPlatform() === "linux")
123
+ return systemdInstall(options);
124
+ return unsupported();
125
+ }
126
+ export async function uninstallService(home) {
127
+ if (osPlatform() === "darwin")
128
+ return macUninstall(home);
129
+ if (osPlatform() === "linux")
130
+ return systemdUninstall(home);
131
+ return unsupported();
132
+ }
133
+ export async function startService(home) {
134
+ if (osPlatform() === "darwin")
135
+ return macStart(home);
136
+ if (osPlatform() === "linux")
137
+ return systemdStart();
138
+ return unsupported();
139
+ }
140
+ export async function stopService(home) {
141
+ if (osPlatform() === "darwin")
142
+ return macStop(home);
143
+ if (osPlatform() === "linux")
144
+ return systemdStop();
145
+ return unsupported();
146
+ }
147
+ export async function serviceStatus(home) {
148
+ if (osPlatform() === "darwin")
149
+ return macStatus(home);
150
+ if (osPlatform() === "linux")
151
+ return systemdStatus(home);
152
+ return unsupported();
153
+ }
154
+ export async function serviceLogPaths() {
155
+ const dir = logDirectory();
156
+ if (osPlatform() === "darwin")
157
+ return { out: join(dir, "collector.log"), err: join(dir, "collector.err.log") };
158
+ return { out: "journalctl --user -u beam.service -f" };
159
+ }
160
+ export async function readServiceConfig(home) {
161
+ const path = osPlatform() === "darwin" ? macPlistPath(home) : systemdUnitPath(home);
162
+ try {
163
+ return await readFile(path, "utf8");
164
+ }
165
+ catch {
166
+ return null;
167
+ }
168
+ }
169
+ //# sourceMappingURL=service.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"service.js","sourceRoot":"","sources":["../src/service.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,19 @@
1
+ import type { Event, Scan } from "./core.js";
2
+ export declare class Store {
3
+ readonly directory: string;
4
+ events: Event[];
5
+ scans: Scan[];
6
+ reviews: Record<string, boolean>;
7
+ private queue;
8
+ readonly maxEvents = 10000;
9
+ constructor(directory: string);
10
+ init(): Promise<void>;
11
+ private serialized;
12
+ private replace;
13
+ addEvents(rows: Event[]): Promise<{
14
+ accepted: number;
15
+ duplicates: number;
16
+ }>;
17
+ addScan(scan: Scan): Promise<Scan>;
18
+ review(id: string, reviewed: boolean): Promise<void>;
19
+ }