A Zulip bot agent to sit in our Black Sun. Ever evolving
1(*---------------------------------------------------------------------------
2 Copyright (c) 2026 Anil Madhavapeddy <anil@recoil.org>. All rights reserved.
3 SPDX-License-Identifier: ISC
4 ---------------------------------------------------------------------------*)
5
6type t = {
7 channel : string;
8 topic : string;
9 changes_file : string;
10 monorepo_path : string;
11 admin_emails : string list;
12 changes_dir : string;
13 verse_path : string option; (* Path to verse/ directory containing user monorepos *)
14}
15
16let default = {
17 channel = "general";
18 topic = "Daily Changes";
19 changes_file = "DAILY-CHANGES.md";
20 monorepo_path = ".";
21 admin_emails = [];
22 changes_dir = ".changes";
23 verse_path = None;
24}
25
26let codec =
27 Tomlt.(
28 Table.(
29 obj (fun channel topic changes_file monorepo_path admin_emails changes_dir verse_path ->
30 { channel; topic; changes_file; monorepo_path; admin_emails; changes_dir; verse_path })
31 |> mem "channel" string ~dec_absent:default.channel
32 ~enc:(fun c -> c.channel)
33 |> mem "topic" string ~dec_absent:default.topic ~enc:(fun c -> c.topic)
34 |> mem "changes_file" string ~dec_absent:default.changes_file
35 ~enc:(fun c -> c.changes_file)
36 |> mem "monorepo_path" string ~dec_absent:default.monorepo_path
37 ~enc:(fun c -> c.monorepo_path)
38 |> mem "admin_emails" (list string) ~dec_absent:default.admin_emails
39 ~enc:(fun c -> c.admin_emails)
40 |> mem "changes_dir" string ~dec_absent:default.changes_dir
41 ~enc:(fun c -> c.changes_dir)
42 |> opt_mem "verse_path" string ~enc:(fun c -> c.verse_path)
43 |> finish))
44
45let load_from_path path =
46 let content = Eio.Path.load path in
47 match Tomlt_bytesrw.decode_string codec content with
48 | Ok config -> config
49 | Error e -> failwith (Tomlt.Error.to_string e)
50
51let load_from_path_opt path =
52 try
53 let content = Eio.Path.load path in
54 match Tomlt_bytesrw.decode_string codec content with
55 | Ok config -> Some config
56 | Error _ -> None
57 with _ -> None
58
59let xdg ~fs = Xdge.create fs "poe"
60
61let load_xdg ~fs =
62 let xdg = xdg ~fs in
63 match Xdge.find_config_file xdg "config.toml" with
64 | Some path -> load_from_path path
65 | None -> failwith "No poe configuration found in XDG config directories"
66
67let load_xdg_opt ~fs =
68 let xdg = xdg ~fs in
69 match Xdge.find_config_file xdg "config.toml" with
70 | Some path -> load_from_path_opt path
71 | None -> None
72
73let load ~fs path =
74 let open Eio.Path in
75 load_from_path (fs / path)
76
77let load_opt ~fs path =
78 let open Eio.Path in
79 load_from_path_opt (fs / path)
80
81let config_dir ~fs =
82 let xdg = xdg ~fs in
83 Xdge.config_dir xdg