My agentic slop goes here. Not intended for anyone else!

more

Changed files
+83 -33
stack
bushel
eiocmd
keyeio
river
+14 -7
stack/bushel/bin/bushel_main.ml
···
(* Import actual command implementations from submodules *)
-
(* Obsidian command *)
+
(* Obsidian command - no API keys needed *)
let obsidian_cmd =
let doc = "Convert Bushel entries to Obsidian format" in
Eiocmd.run
+
~use_keyeio:false
~info:(Cmd.info "obsidian" ~version ~doc)
~app_name:"bushel"
~service:"bushel"
···
(* Paper tex command *)
let paper_tex_cmd = Bushel_paper_tex.cmd
-
(* Thumbs command *)
+
(* Thumbs command - no API keys needed *)
let thumbs_cmd =
let doc = "Generate thumbnails from paper PDFs" in
Eiocmd.run
+
~use_keyeio:false
~info:(Cmd.info "thumbs" ~version ~doc)
~app_name:"bushel"
~service:"bushel"
Bushel_thumbs.term
-
(* Query command *)
+
(* Query command - needs Typesense API key *)
let query_cmd =
let doc = "Query Bushel collections using multisearch" in
Eiocmd.run
+
~use_keyeio:true
~info:(Cmd.info "query" ~version ~doc)
~app_name:"bushel"
~service:"bushel"
Bushel_search.term
-
(* Bibtex command *)
+
(* Bibtex command - no API keys needed *)
let bibtex_cmd =
let doc = "Export bibtex for all papers" in
Eiocmd.run
+
~use_keyeio:false
~info:(Cmd.info "bibtex" ~version ~doc)
~app_name:"bushel"
~service:"bushel"
···
(* Ideas command *)
let ideas_cmd = Bushel_ideas.cmd
-
(* Info command *)
+
(* Info command - no API keys needed *)
let info_cmd =
let doc = "Display all information for a given slug" in
Eiocmd.run
+
~use_keyeio:false
~info:(Cmd.info "info" ~version ~doc)
~app_name:"bushel"
~service:"bushel"
Bushel_info.term
-
(* Missing command *)
+
(* Missing command - no API keys needed *)
let missing_cmd =
let doc = "Check for missing metadata in entries" in
Eiocmd.run
+
~use_keyeio:false
~info:(Cmd.info "missing" ~version ~doc)
~app_name:"bushel"
~service:"bushel"
Bushel_missing.term
-
(* Note DOI command *)
+
(* Note DOI command - no API keys needed *)
let note_doi_cmd =
let doc = "Assign DOIs to notes with perma:true" in
Eiocmd.run
+
~use_keyeio:false
~info:(Cmd.info "note-doi" ~version ~doc)
~app_name:"bushel"
~service:"bushel"
+36 -24
stack/eiocmd/lib/eiocmd.ml
···
(** {1 Running Applications} *)
-
(* Batteries-included run with XDG and keyeio *)
-
let run ~info ~app_name ~service main_term =
+
(* Batteries-included run with XDG and optional keyeio *)
+
let run ?(use_keyeio=true) ~info ~app_name ~service main_term =
let open Cmdliner in
let run_main main profile_name_opt key_file_opt =
···
(* Create xdg context *)
let xdg = Xdge.create env#fs app_name in
-
(* Load keyeio profile *)
-
let keyeio_ctx = Keyeio.create xdg in
-
let profile_name = Option.value profile_name_opt ~default:"default" in
+
(* Load keyeio profile if requested *)
+
let profile =
+
if not use_keyeio then
+
(* Create empty profile when keyeio is not needed *)
+
Keyeio.Profile.empty
+
else
+
(* Load from keyeio *)
+
let keyeio_ctx = Keyeio.create xdg in
+
let profile_name = Option.value profile_name_opt ~default:"default" in
-
let profile = match key_file_opt with
-
| Some _path ->
-
(* TODO: Load from specified file *)
-
failwith "Direct file loading not yet supported in eiocmd (use --profile instead)"
-
| None ->
-
(* Load from XDG directory *)
-
match Keyeio.load_service keyeio_ctx ~service with
-
| Ok svc ->
-
(match Keyeio.Service.get_profile svc profile_name with
-
| Some prof -> prof
-
| None ->
-
failwith (Printf.sprintf "Profile '%s' not found in service '%s'"
-
profile_name service))
-
| Error (`Msg msg) -> failwith msg
+
match key_file_opt with
+
| Some _path ->
+
(* TODO: Load from specified file *)
+
failwith "Direct file loading not yet supported in eiocmd (use --profile instead)"
+
| None ->
+
(* Load from XDG directory *)
+
match Keyeio.load_service keyeio_ctx ~service with
+
| Ok svc ->
+
(match Keyeio.Service.get_profile svc profile_name with
+
| Some prof -> prof
+
| None ->
+
failwith (Printf.sprintf "Profile '%s' not found in service '%s'"
+
profile_name service))
+
| Error (`Msg msg) -> failwith msg
in
main env xdg profile
in
-
(* Add profile and key-file flags *)
+
(* Add profile and key-file flags only if using keyeio *)
let profile_flag =
-
let doc = Printf.sprintf "Profile name to use for %s service" service in
-
Arg.(value & opt (some string) None & info [ "profile" ] ~docv:"NAME" ~doc)
+
if use_keyeio then
+
let doc = Printf.sprintf "Profile name to use for %s service" service in
+
Arg.(value & opt (some string) None & info [ "profile" ] ~docv:"NAME" ~doc)
+
else
+
Term.const None
in
let key_file_flag =
-
let doc = Printf.sprintf "Override with direct path to %s key file" service in
-
Arg.(value & opt (some file) None & info [ "key-file" ] ~docv:"FILE" ~doc)
+
if use_keyeio then
+
let doc = Printf.sprintf "Override with direct path to %s key file" service in
+
Arg.(value & opt (some file) None & info [ "key-file" ] ~docv:"FILE" ~doc)
+
else
+
Term.const None
in
(* Compose with main term and add logging setup *)
+15 -2
stack/eiocmd/lib/eiocmd.mli
···
- Logging (via Logs_cli with standard flags)
- Cmdliner argument parsing
- XDG directory structure (all directories created)
-
- API key management via keyeio
+
- API key management via keyeio (optional)
+
+
@param use_keyeio
+
Controls whether to initialize keyeio for API key management.
+
- [true] (default): Load keyeio service and profile, add --profile and --key-file flags
+
- [false]: Skip keyeio, provide empty profile, no keyeio-related flags
+
+
Use [~use_keyeio:false] for commands that don't need API keys to avoid
+
creating unnecessary config directories and service files.
+
+
@param info Command info for Cmdliner
+
@param app_name Application name for XDG directories
+
@param service Service name for keyeio profile lookup (ignored if use_keyeio=false)
+
@param main_term The main command term that receives (env, xdg, profile) parameters
]} *)
val run :
+
?use_keyeio:bool ->
info:Cmdliner.Cmd.info ->
app_name:string ->
service:string ->
(Eio_unix.Stdenv.base -> Xdge.t -> Keyeio.Profile.t -> int) Cmdliner.Term.t ->
Cmdliner.Cmd.Exit.code Cmdliner.Cmd.t
-
+2
stack/keyeio/lib/keyeio.ml
···
let keys t = List.map fst t.data
+
let empty = { service = ""; name = ""; data = [] }
+
let to_toml t =
let table = Toml.Types.Table.empty in
List.fold_left
+8
stack/keyeio/lib/keyeio.mli
···
]} *)
val keys : t -> string list
+
(** [empty] creates an empty profile with no data.
+
+
This is useful when a command doesn't need API keys but must
+
conform to an interface that expects a profile parameter.
+
+
@return An empty profile with empty service name, empty profile name, and no data *)
+
val empty : t
+
(** [to_toml t] converts the profile to a TOML table representation.
Returns a TOML table containing all key-value pairs in the profile.
+8
stack/river/bin/river_cli.ml
···
let user_add_cmd =
let doc = "Add a new user" in
Eiocmd.run
+
~use_keyeio:false
~info:(Cmd.info "add" ~doc)
~app_name:"river"
~service:"river"
···
let user_remove_cmd =
let doc = "Remove a user" in
Eiocmd.run
+
~use_keyeio:false
~info:(Cmd.info "remove" ~doc)
~app_name:"river"
~service:"river"
···
let user_list_cmd =
let doc = "List all users" in
Eiocmd.run
+
~use_keyeio:false
~info:(Cmd.info "list" ~doc)
~app_name:"river"
~service:"river"
···
let user_show_cmd =
let doc = "Show user details" in
Eiocmd.run
+
~use_keyeio:false
~info:(Cmd.info "show" ~doc)
~app_name:"river"
~service:"river"
···
let user_add_feed_cmd =
let doc = "Add a feed to a user" in
Eiocmd.run
+
~use_keyeio:false
~info:(Cmd.info "add-feed" ~doc)
~app_name:"river"
~service:"river"
···
let user_remove_feed_cmd =
let doc = "Remove a feed from a user" in
Eiocmd.run
+
~use_keyeio:false
~info:(Cmd.info "remove-feed" ~doc)
~app_name:"river"
~service:"river"
···
Arg.(value & pos 0 (some string) None & info [] ~docv:"USERNAME" ~doc)
in
Eiocmd.run
+
~use_keyeio:false
~info:(Cmd.info "sync" ~doc)
~app_name:"river"
~service:"river"
···
Arg.(value & opt (some int) None & info ["limit"; "n"] ~doc)
in
Eiocmd.run
+
~use_keyeio:false
~info:(Cmd.info "list" ~doc)
~app_name:"river"
~service:"river"