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

more

Changed files
+90 -80
stack
+6 -5
stack/bushel/bin/bushel_links.ml
···
let filter_tags = if tag = "" then [] else [tag] in
(* Fetch bookmarks from Karakeep *)
-
let bookmarks = Karakeepe.fetch_all_bookmarks ~sw ~env ~api_key ~filter_tags base_url in
+
let client = Karakeepe.create ~sw ~env ~api_key ~base_url in
+
let bookmarks = Karakeepe.fetch_all_bookmarks client ~filter_tags () in
print_endline (Fmt.str "Retrieved %d bookmarks from Karakeep" (List.length bookmarks));
···
(* Download the asset *)
print_endline (Fmt.str "Downloading %s asset %s..." asset_type asset_id);
-
let data = Karakeepe.fetch_asset ~sw ~env ~api_key base_url asset_id in
+
let data = Karakeepe.fetch_asset client asset_id in
(* Guess content type based on first bytes *)
let content_type =
···
(* Create the bookmark with tags *)
try
+
let client = Karakeepe.create ~sw ~env ~api_key ~base_url in
let bookmark = Karakeepe.create_bookmark
-
~sw ~env
-
~api_key
+
client
~url
?title
~tags
-
base_url
+
()
in
(* Create updated link with karakeep data *)
+12 -8
stack/karakeepe/bin/karakeepe_cli.ml
···
in
try
+
let client = Karakeepe.create ~sw ~env ~api_key ~base_url in
let bookmarks = Karakeepe.fetch_all_bookmarks
-
~sw ~env ~api_key
+
client
~max_bookmarks:limit
~include_content:true
?filter_tags:(if tags = [] then None else Some tags)
-
base_url
+
()
in
(* Filter by archived/favourited if requested *)
···
in
try
-
let bookmark = Karakeepe.fetch_bookmark_details ~sw ~env ~api_key base_url bookmark_id in
+
let client = Karakeepe.create ~sw ~env ~api_key ~base_url in
+
let bookmark = Karakeepe.fetch_bookmark_details client bookmark_id in
Printf.printf "Bookmark: %s\n" bookmark.url;
Printf.printf "ID: %s\n" bookmark.id;
···
Printf.printf "\nAssets:\n";
List.iter (fun (id, asset_type) ->
Printf.printf " %s (%s)\n" id asset_type;
-
Printf.printf " URL: %s\n" (Karakeepe.get_asset_url base_url id)
+
Printf.printf " URL: %s\n" (Karakeepe.get_asset_url client id)
) bookmark.assets
end;
···
let tags_opt = if tags = [] then None else Some tags in
+
let client = Karakeepe.create ~sw ~env ~api_key ~base_url in
let bookmark = Karakeepe.create_bookmark
-
~sw ~env ~api_key
+
client
~url
?title
?note
?tags:tags_opt
~archived
~favourited
-
base_url
+
()
in
Printf.printf "✓ Bookmark created successfully!\n";
···
1
end else begin
try
+
let client = Karakeepe.create ~sw ~env ~api_key ~base_url in
let bookmarks = Karakeepe.fetch_all_bookmarks
-
~sw ~env ~api_key
+
client
~max_bookmarks:limit
~filter_tags:tags
~include_content:true
-
base_url
+
()
in
Printf.printf "Found %d bookmark%s\n\n" (List.length bookmarks)
+38 -24
stack/karakeepe/karakeepe.ml
···
let src = Logs.Src.create "karakeepe" ~doc:"Karakeepe API client"
module Log = (val Logs.src_log src : Logs.LOG)
+
(** Type representing a Karakeepe client session *)
+
type 'net t_internal = {
+
api_key: string;
+
base_url: string;
+
http_client: (float Eio.Time.clock_ty Eio.Resource.t, 'net Eio.Net.ty Eio.Resource.t) Requests.t;
+
}
+
+
type t = [`Generic | `Unix] t_internal
+
+
(** Create a new Karakeepe client *)
+
let create ~sw ~env ~api_key ~base_url : t =
+
let http_client = Requests.create ~sw env in
+
{ api_key; base_url; http_client }
+
(** Type representing a Karakeep bookmark *)
type bookmark = {
id: string;
···
)
(** Fetch bookmarks from a Karakeep instance with pagination support *)
-
let fetch_bookmarks ~sw ~env ~api_key ?(limit=50) ?(offset=0) ?cursor ?(include_content=false) ?filter_tags base_url =
+
let fetch_bookmarks client ?(limit=50) ?(offset=0) ?cursor ?(include_content=false) ?filter_tags () =
let url_base = Fmt.str "%s/api/v1/bookmarks?limit=%d&includeContent=%b"
-
base_url limit include_content in
+
client.base_url limit include_content in
let url =
match cursor with
···
in
let headers = Requests.Headers.empty
-
|> Requests.Headers.set "Authorization" ("Bearer " ^ api_key) in
+
|> Requests.Headers.set "Authorization" ("Bearer " ^ client.api_key) in
Log.debug (fun m -> m "Fetching bookmarks from: %s" url);
try
-
let response = Requests.One.get ~sw ~clock:env#clock ~net:env#net ~headers url in
+
let response = Requests.get client.http_client ~headers url in
let status_code = Requests.Response.status_code response in
if status_code = 200 then begin
let body_str = Requests.Response.body response |> Eio.Flow.read_all in
···
raise e
(** Fetch all bookmarks from a Karakeep instance using pagination *)
-
let fetch_all_bookmarks ~sw ~env ~api_key ?(page_size=50) ?max_pages ?max_bookmarks ?filter_tags ?(include_content=false) base_url =
+
let fetch_all_bookmarks client ?(page_size=50) ?max_pages ?max_bookmarks ?filter_tags ?(include_content=false) () =
let rec fetch_pages page_num cursor acc =
(* Check if we've reached the max_bookmarks limit *)
let reached_limit = match max_bookmarks with
···
Log.debug (fun m -> m "Fetching page %d" page_num);
let response =
match cursor with
-
| Some cursor_str -> fetch_bookmarks ~sw ~env ~api_key ~limit:page_size ~cursor:cursor_str ~include_content ?filter_tags base_url
-
| None -> fetch_bookmarks ~sw ~env ~api_key ~limit:page_size ~offset:(page_num * page_size) ~include_content ?filter_tags base_url
+
| Some cursor_str -> fetch_bookmarks client ~limit:page_size ~cursor:cursor_str ~include_content ?filter_tags ()
+
| None -> fetch_bookmarks client ~limit:page_size ~offset:(page_num * page_size) ~include_content ?filter_tags ()
in
let all_bookmarks = acc @ response.data in
···
fetch_pages 0 None []
(** Fetch detailed information for a single bookmark by ID *)
-
let fetch_bookmark_details ~sw ~env ~api_key base_url bookmark_id =
-
let url = Fmt.str "%s/api/v1/bookmarks/%s" base_url bookmark_id in
+
let fetch_bookmark_details client bookmark_id =
+
let url = Fmt.str "%s/api/v1/bookmarks/%s" client.base_url bookmark_id in
let headers = Requests.Headers.empty
-
|> Requests.Headers.set "Authorization" ("Bearer " ^ api_key) in
+
|> Requests.Headers.set "Authorization" ("Bearer " ^ client.api_key) in
-
let response = Requests.One.get ~sw ~clock:env#clock ~net:env#net ~headers url in
+
let response = Requests.get client.http_client ~headers url in
let status_code = Requests.Response.status_code response in
if status_code = 200 then begin
let body_str = Requests.Response.body response |> Eio.Flow.read_all in
···
failwith (Fmt.str "HTTP error: %d" status_code)
(** Get the asset URL for a given asset ID *)
-
let get_asset_url base_url asset_id =
-
Fmt.str "%s/api/assets/%s" base_url asset_id
+
let get_asset_url client asset_id =
+
Fmt.str "%s/api/assets/%s" client.base_url asset_id
(** Fetch an asset from the Karakeep server as a binary string *)
-
let fetch_asset ~sw ~env ~api_key base_url asset_id =
-
let url = get_asset_url base_url asset_id in
+
let fetch_asset client asset_id =
+
let url = Fmt.str "%s/api/assets/%s" client.base_url asset_id in
let headers = Requests.Headers.empty
-
|> Requests.Headers.set "Authorization" ("Bearer " ^ api_key) in
+
|> Requests.Headers.set "Authorization" ("Bearer " ^ client.api_key) in
-
let response = Requests.One.get ~sw ~clock:env#clock ~net:env#net ~headers url in
+
let response = Requests.get client.http_client ~headers url in
let status_code = Requests.Response.status_code response in
if status_code = 200 then
Requests.Response.body response |> Eio.Flow.read_all
···
failwith (Fmt.str "Asset fetch error: %d" status_code)
(** Create a new bookmark in Karakeep with optional tags *)
-
let create_bookmark ~sw ~env ~api_key ~url ?title ?note ?tags ?(favourited=false) ?(archived=false) base_url =
+
let create_bookmark client ~url ?title ?note ?tags ?(favourited=false) ?(archived=false) () =
let body_obj = [
("type", `String "link");
("url", `String url);
···
let body_str = J.to_string body_json in
let headers = Requests.Headers.empty
-
|> Requests.Headers.set "Authorization" ("Bearer " ^ api_key)
+
|> Requests.Headers.set "Authorization" ("Bearer " ^ client.api_key)
|> Requests.Headers.set "Content-Type" "application/json"
in
-
let url_endpoint = Fmt.str "%s/api/v1/bookmarks" base_url in
+
let url_endpoint = Fmt.str "%s/api/v1/bookmarks" client.base_url in
let body = Requests.Body.of_string Requests.Mime.json body_str in
-
let response = Requests.One.post ~sw ~clock:env#clock ~net:env#net ~headers ~body url_endpoint in
+
let response = Requests.post client.http_client ~headers ~body url_endpoint in
let status_code = Requests.Response.status_code response in
if status_code = 201 || status_code = 200 then begin
···
let tags_body = `O [("tags", `A tag_objects)] in
let tags_body_str = J.to_string tags_body in
-
let tags_url = Fmt.str "%s/api/v1/bookmarks/%s/tags" base_url bookmark.id in
+
let tags_url = Fmt.str "%s/api/v1/bookmarks/%s/tags" client.base_url bookmark.id in
let tags_body = Requests.Body.of_string Requests.Mime.json tags_body_str in
-
let tags_response = Requests.One.post ~sw ~clock:env#clock ~net:env#net ~headers ~body:tags_body tags_url in
+
let tags_response = Requests.post client.http_client ~headers ~body:tags_body tags_url in
let tags_status = Requests.Response.status_code tags_response in
if tags_status = 200 then
-
fetch_bookmark_details ~sw ~env ~api_key base_url bookmark.id
+
fetch_bookmark_details client bookmark.id
else
bookmark
| _ -> bookmark
+34 -43
stack/karakeepe/karakeepe.mli
···
(** Karakeepe API client interface (Eio version) *)
+
(** Type representing a Karakeepe client session *)
+
type t
+
+
(** Create a new Karakeepe client
+
@param sw Eio switch for resource management
+
@param env Eio environment (provides clock and network)
+
@param api_key API key for authentication
+
@param base_url Base URL of the Karakeep instance
+
@return A client instance *)
+
val create :
+
sw:Eio.Switch.t ->
+
env:< clock: float Eio.Time.clock_ty Eio.Resource.t;
+
net: [`Generic | `Unix] Eio.Net.ty Eio.Resource.t;
+
fs: Eio.Fs.dir_ty Eio.Path.t; .. > ->
+
api_key:string ->
+
base_url:string ->
+
t
+
(** Type representing a Karakeep bookmark *)
type bookmark = {
id: string;
···
val parse_bookmark_response : Ezjsonm.value -> bookmark_response
(** Fetch bookmarks from a Karakeep instance with pagination support
-
@param sw Eio switch for resource management
-
@param env Eio environment (provides clock and network)
-
@param api_key API key for authentication
+
@param client Karakeepe client instance
@param limit Number of bookmarks to fetch per page (default: 50)
@param offset Starting index for pagination (0-based) (default: 0)
@param cursor Optional pagination cursor for cursor-based pagination (overrides offset when provided)
@param include_content Whether to include full content (default: false)
@param filter_tags Optional list of tags to filter by
-
@param base_url Base URL of the Karakeep instance
@return The bookmark response *)
val fetch_bookmarks :
-
sw:Eio.Switch.t ->
-
env:< clock: [> float Eio.Time.clock_ty ] Eio.Resource.t; net: [> [> `Generic] Eio.Net.ty ] Eio.Resource.t; .. > ->
-
api_key:string ->
+
t ->
?limit:int ->
?offset:int ->
?cursor:string ->
?include_content:bool ->
?filter_tags:string list ->
-
string ->
+
unit ->
bookmark_response
(** Fetch all bookmarks from a Karakeep instance using pagination
-
@param sw Eio switch for resource management
-
@param env Eio environment (provides clock and network)
-
@param api_key API key for authentication
+
@param client Karakeepe client instance
@param page_size Number of bookmarks to fetch per page (default: 50)
@param max_pages Maximum number of pages to fetch (None for all pages)
@param max_bookmarks Maximum total number of bookmarks to return (None for all)
@param filter_tags Optional list of tags to filter by
@param include_content Whether to include full content (default: false)
-
@param base_url Base URL of the Karakeep instance
@return All bookmarks combined *)
val fetch_all_bookmarks :
-
sw:Eio.Switch.t ->
-
env:< clock: [> float Eio.Time.clock_ty ] Eio.Resource.t; net: [> [> `Generic] Eio.Net.ty ] Eio.Resource.t; .. > ->
-
api_key:string ->
+
t ->
?page_size:int ->
?max_pages:int ->
?max_bookmarks:int ->
?filter_tags:string list ->
?include_content:bool ->
-
string ->
+
unit ->
bookmark list
(** Fetch detailed information for a single bookmark by ID
-
@param sw Eio switch for resource management
-
@param env Eio environment (provides clock and network)
-
@param api_key API key for authentication
-
@param base_url Base URL of the Karakeep instance
+
@param client Karakeepe client instance
@param bookmark_id ID of the bookmark to fetch
@return The complete bookmark details *)
val fetch_bookmark_details :
-
sw:Eio.Switch.t ->
-
env:< clock: [> float Eio.Time.clock_ty ] Eio.Resource.t; net: [> [> `Generic] Eio.Net.ty ] Eio.Resource.t; .. > ->
-
api_key:string ->
-
string ->
+
t ->
string ->
bookmark
···
val to_bushel_link : ?base_url:string -> bookmark -> Bushel.Link.t
(** Fetch an asset from the Karakeep server as a binary string
-
@param sw Eio switch for resource management
-
@param env Eio environment (provides clock and network)
-
@param api_key API key for authentication
-
@param base_url Base URL of the Karakeep instance
+
@param client Karakeepe client instance
@param asset_id ID of the asset to fetch
@return The binary asset data *)
val fetch_asset :
-
sw:Eio.Switch.t ->
-
env:< clock: [> float Eio.Time.clock_ty ] Eio.Resource.t; net: [> [> `Generic] Eio.Net.ty ] Eio.Resource.t; .. > ->
-
api_key:string ->
-
string ->
+
t ->
string ->
string
-
(** Get the asset URL for a given asset ID
-
@param base_url Base URL of the Karakeep instance
+
(** Get the asset URL for a given client and asset ID
+
@param client Karakeepe client instance
@param asset_id ID of the asset
@return The full URL to the asset *)
val get_asset_url :
-
string ->
+
t ->
string ->
string
(** Create a new bookmark in Karakeep with optional tags
-
@param sw Eio switch for resource management
-
@param env Eio environment (provides clock and network)
-
@param api_key API key for authentication
+
@param client Karakeepe client instance
@param url The URL to bookmark
@param title Optional title for the bookmark
@param note Optional note to add to the bookmark
@param tags Optional list of tag names to add to the bookmark
@param favourited Whether the bookmark should be marked as favourite (default: false)
@param archived Whether the bookmark should be archived (default: false)
-
@param base_url Base URL of the Karakeep instance
@return The created bookmark *)
val create_bookmark :
-
sw:Eio.Switch.t ->
-
env:< clock: [> float Eio.Time.clock_ty ] Eio.Resource.t; net: [> [> `Generic] Eio.Net.ty ] Eio.Resource.t; .. > ->
-
api_key:string ->
+
t ->
url:string ->
?title:string ->
?note:string ->
?tags:string list ->
?favourited:bool ->
?archived:bool ->
-
string ->
+
unit ->
bookmark