e7c1a04 · Reload the map on SIGHUP · 5 days ago

typescript79 lines · 2.1 KB
1#!/usr/bin/env npx tsx
2/** Axiom scoped relay — TypeScript runtime. Same contract as the Python agent. */
3
4import { parseArgs } from "node:util";
5import { loadMappingFrom } from "./mapping.ts";
6import { formatReport } from "./report.ts";
7import { ScopeGuard } from "./scope.ts";
8import { SlackAdapter } from "./slack.ts";
9import { DiscordAdapter } from "./discord.ts";
10
11const adapters = { slack: SlackAdapter, discord: DiscordAdapter } as const;
12
13class Runtime {
14 mapping!: Awaited<ReturnType<typeof loadMappingFrom>>;
15 guard!: ScopeGuard;
16 adapter!: SlackAdapter | DiscordAdapter;
17 platform!: keyof typeof adapters;
18
19 constructor(
20 private source: string,
21 private platformOverride?: string,
22 ) {}
23
24 async reload(): Promise<void> {
25 const mapping = await loadMappingFrom(this.source);
26 const platform = (this.platformOverride ?? mapping.platform) as keyof typeof adapters;
27 const Adapter = adapters[platform];
28 if (!Adapter) {
29 console.error(`unknown platform: ${platform}`);
30 process.exit(2);
31 }
32 this.mapping = mapping;
33 this.platform = platform;
34 this.guard = new ScopeGuard(mapping);
35 this.adapter = new Adapter(mapping, this.guard);
36 }
37}
38
39const { values } = parseArgs({
40 options: {
41 mapping: { type: "string" },
42 platform: { type: "string" },
43 "dry-run": { type: "boolean", default: false },
44 "collect-seconds": { type: "string" },
45 },
46});
47
48if (!values.mapping) {
49 console.error("usage: axiom-relay --mapping [--platform slack|discord] [--dry-run]");
50 process.exit(2);
51}
52
53const runtime = new Runtime(values.mapping, values.platform);
54await runtime.reload();
55
56const collect = Number(values["collect-seconds"] ?? runtime.mapping.collectSeconds);
57
58if (values["dry-run"]) {
59 runtime.adapter.describe();
60 process.stdout.write(
61 formatReport({
62 mapping: runtime.mapping,
63 guard: runtime.guard,
64 broadcastId: runtime.mapping.channels.find((c) => c.role === "management")!.id,
65 replyCount: 0,
66 collectSeconds: collect,
67 }),
68 );
69 process.exit(0);
70}
71
72if (process.platform !== "win32") {
73 process.on("SIGHUP", () => {
74 void runtime.reload();
75 });
76}
77
78runtime.adapter.run(collect);
79