Commit Diff


commit - 2da793de0cd4883ac80a6ddb70d38e5392c2bda3
commit + 31da3d0eb44fdab82e620d1cbdd35f31e8f1ee7f
blob - 7cc2a636f4b5d7ffb0f386885857845f94ef092a
blob + 90746acf5ebc4767db1eb0802376063676ab79d4
--- hosts/bbox/overlays/config/magdalena/config.json.nix
+++ hosts/bbox/overlays/config/magdalena/config.json.nix
@@ -19,16 +19,6 @@
   		".qwen",
   		"saturn"
   	],
-  	"fzf_opts": [
-  		"--highlight-line",
-  		"--ansi",
-  		"--layout=reverse",
-  		"--border=rounded",
-  		"--color=bg+:#2a1f2e,bg:-1,spinner:#c084b8,hl:#e08060",
-  		"--color=fg:#c8b8bf,header:#c4607a,info:#7a6e7a,pointer:#c084b8",
-  		"--color=marker:#e06fad,fg+:#f0dfe5,prompt:#7a9fd4,hl+:#f0a070",
-  		"--color=border:#3d2a42"
-  	],
   	"favorites": [
   		"${homeDir}/src",
   		"${homeDir}/src/nix",
blob - 15a61f61e7aab80997730b2704c127fe08cd7620
blob + 8b2cb2bdfe4df1507f10c19ef239df7fed214a43
--- hosts/impish/default.nix
+++ hosts/impish/default.nix
@@ -169,11 +169,8 @@
         skopeo
         podman
         sccache
-        podlet
         buildah
         meson
-        butane
-        redo-sh
         knit
         go-task
         goreleaser
@@ -221,15 +218,15 @@
         xorriso
         jsonnet-bundler
         minisign
+        zf
+        gitleaks
       ];
 
       lsp = [
         gopls
         nixd
         zls
-        clojure-lsp
         ols
-        npins
         jsonnet-language-server
       ];
 
@@ -239,18 +236,9 @@
         golangci-lint
       ];
 
-      clojure = [
-        babashka
-        clojure
-        clj-kondo
-        cljstyle
-        leiningen
-      ];
-
       lisp = [
         haunt
         gnu-shepherd
-        gerbil
         chez
         ecl
         janet
@@ -262,14 +250,6 @@
         [fnlfmt]
       ];
 
-      llm = [
-        rtk
-        snip
-        gitingest
-        pi-coding-agent
-        ollama
-      ];
-
       gui = [
         picard
         xnviewmp
@@ -284,6 +264,9 @@
         emscripten
         astroterm
         odin
+        npins
+        snip
+        pi-coding-agent
       ];
     }));
   };
blob - 07ee7dd6e21834358ba81debb480c57da009916f
blob + 2bca5dbc27fdb99394b361fece0f0ee2b124c29b
Binary files hosts/void/overlays/config/magdalena/config.json.nix and hosts/void/overlays/config/magdalena/config.json.nix differ
blob - 50a5ff03186b05831c1fcde13ea4b77f3a76c903
blob + 09e3303f75f18379849625ab4451acad2d24d43a
Binary files hosts/work/overlays/config/magdalena/config.json.nix and hosts/work/overlays/config/magdalena/config.json.nix differ
blob - 7e34237f3d17734f4f705bfe127f10277491cc9b (mode 644)
blob + 1798d1212ece7f107439e6fbc2ff249861524b15 (mode 755)
--- modules/mixins/dotfiles/bin/khal_notifier
+++ modules/mixins/dotfiles/bin/khal_notifier
@@ -1,204 +1,226 @@
-#!/usr/bin/env bb
-;; vim: ft=clojure
+#!/usr/bin/env janet
 
-(ns khal-notifier
-  (:require [clojure.edn :as edn]
-            [clojure.string :as str]
-            [babashka.process :refer [shell]]
-            [babashka.fs :as fs]))
+(defn blank? [s]
+  (or (nil? s) (= "" s)))
 
-(defn all-day? [event]
-  (and (str/blank? (:start-time event))
-       (str/blank? (:end-time event))))
+(defn path-join [parts]
+  (string/join parts "/"))
 
-(defn state-file []
-  (or (System/getenv "KHAL_NOTIFIER_STATE_FILE")
-      (str (fs/path (or (System/getenv "XDG_CACHE_HOME")
-                        (fs/path (System/getProperty "user.home") ".cache"))
-                    "khal_notifier" "notified-all-day.edn"))))
+(defn dir-of [path]
+  (let [parts (string/split "/" path)]
+    (if (<= (length parts) 1)
+      "."
+      (path-join (slice parts 0 -2)))))
 
-(defn read-notified-all-day []
-  (try
-    (let [state (edn/read-string (slurp (state-file)))]
-      (if (set? state) state #{}))
-    (catch Exception _ #{})))
-
-(defn write-notified-all-day [events]
-  (let [path (state-file)]
+(defn mkdir-p [path]
+  (when (and (not (blank? path)) (nil? (os/stat path)))
+    (let [parent (dir-of path)]
+      (when (and (not (= parent path)) (not (= parent ".")) (not (blank? parent)))
+        (mkdir-p parent)))
     (try
-      (fs/create-dirs (fs/parent path))
-      (spit path (pr-str events))
-      true
-      (catch Exception e
-        (println (format "[WARN] Could not save all-day notification state: %s"
-                         (ex-message e)))
-        false))))
+      (do (os/mkdir path) true)
+      ([e] false))))
 
+(defn state-file []
+  (or (os/getenv "KHAL_NOTIFIER_STATE_FILE")
+      (path-join [(or (os/getenv "XDG_CACHE_HOME")
+                      (path-join [(or (os/getenv "HOME") "/tmp") ".cache"]))
+                  "khal_notifier"
+                  "notified-all-day.txt"])))
+
+(defn read-notified []
+  (try
+    (do
+      (def table @{})
+      (each line (string/split "\n" (slurp (state-file)))
+        (when (not (blank? line))
+          (put table line true)))
+      table)
+    ([e] @{})))
+
+(defn write-notified [table]
+  (try
+    (do
+      (mkdir-p (dir-of (state-file)))
+      (spit (state-file) (string/join (keys table) "\n"))
+      true)
+    ([e]
+      (printf "WARN: Could not save all-day notification state: %s" e)
+      false)))
+
 (defn event-key [event]
-  [(:start-date event)
-   (if (str/blank? (:uid event))
-     [(:title event) (:organizer event)]
-     (:uid event))])
+  (string/join
+    [(or (event :start-date) "")
+     (let [uid (or (event :uid) "")]
+       (if (blank? uid)
+         (string/join [(or (event :title) "") (or (event :organizer) "")] "::")
+         uid))]
+    "|"))
 
-(defn run-cmd [cmd args & {:keys [timeout] :or {timeout 30000}}]
+(defn run-cmd [cmd & args]
   (try
-    (if-not (fs/which cmd)
-      {:status :error :reason :enoent}
-      (let [result (apply shell {:out :string :err :string :timeout timeout} cmd args)]
-        {:status :ok :out (:out result) :code (:exit result)}))
-    (catch java.util.concurrent.TimeoutException _
-      {:status :error :reason :timeout})
-    (catch Exception e
-      {:status :error :reason e})))
+    (do
+      (file/flush stdout)
+      (def proc (os/spawn [cmd ;args] :p {:out :pipe :err :out}))
+      (def out (or (ev/read (proc :out) :all) ""))
+      (def code (os/proc-wait proc))
+      (os/proc-close proc)
+      {:status :ok :out (string out) :code code})
+    ([e] {:status :error :reason e})))
 
+(defn cmd-ok? [result]
+  (and (= (result :status) :ok) (zero? (result :code))))
+
 (defn sync-pimsync []
-  (println "[INFO] Syncing calendars with pimsync")
-  (let [result (run-cmd "pimsync" ["sync"] :timeout 60000)]
-    (cond
-      (and (= :ok (:status result)) (zero? (:code result)))
-      (do (println "[INFO] pimsync sync complete") true)
+  (print "INFO: Syncing calendars with pimsync")
+  (def result (run-cmd "pimsync" "sync"))
+  (cond
+    (cmd-ok? result)
+    (do (print "INFO: pimsync sync complete") true)
 
-      (= :ok (:status result))
-      (do (println (format "[WARN] pimsync exited with code %d: %s"
-                           (:code result) (str/trim (or (:out result) ""))))
-          false)
+    (= (result :status) :ok)
+    (do
+      (printf "WARN: pimsync exited with code %d: %s"
+              (result :code) (string/trim (or (result :out) "")))
+      false)
 
-      (= :enoent (:reason result)) (do (println "[ERROR] pimsync not found") false)
-      (= :timeout (:reason result)) (do (println "[ERROR] pimsync timed out") false)
-      :else (do (println (format "[ERROR] pimsync failed: %s" (ex-message (:reason result))))
-                false))))
+    (do
+      (printf "ERROR: pimsync failed: %s" (result :reason))
+      false)))
 
 (defn parse-event-line [line]
-  (let [parts (str/split line #"\|" 6)
-        cnt (count parts)]
+  (let [parts (string/split "|" line)
+        cnt (length parts)
+        at (fn [i] (or (get parts i) ""))]
     (case cnt
-      6 {:start-date (nth parts 0) :start-time (nth parts 1)
-         :end-time (nth parts 2) :uid (nth parts 3)
-         :title (nth parts 4) :organizer (nth parts 5)}
-      4 {:start-time (nth parts 0) :end-time (nth parts 1)
-         :title (nth parts 2) :organizer (nth parts 3)}
-      3 {:start-time (nth parts 0) :end-time (nth parts 1)
-         :title (nth parts 2) :organizer ""}
-      2 {:start-time (nth parts 0) :end-time ""
-         :title (nth parts 1) :organizer ""}
-      {:start-time "" :end-time "" :title (nth parts 0) :organizer ""})))
+      6 {:start-date (at 0) :start-time (at 1) :end-time (at 2)
+         :uid (at 3) :title (at 4) :organizer (at 5)}
+      4 {:start-date "" :start-time (at 0) :end-time (at 1)
+         :uid "" :title (at 2) :organizer (at 3)}
+      3 {:start-date "" :start-time (at 0) :end-time (at 1)
+         :uid "" :title (at 2) :organizer ""}
+      2 {:start-date "" :start-time (at 0) :end-time ""
+         :uid "" :title (at 1) :organizer ""}
+      {:start-date "" :start-time "" :end-time ""
+       :uid "" :title (or (get parts 0) "") :organizer ""})))
 
 (defn get-upcoming-events [lookahead]
-  (println (format "[INFO] Checking khal for events in the next %s" lookahead))
-  (let [result (run-cmd "khal" ["list" "now" lookahead "--format"
-                                (str "{start-date}|{start-time}|{end-time}|"
-                                     "{uid}|{title}|{organizer}")])]
-    (cond
-      (and (= :ok (:status result)) (zero? (:code result)))
-      (let [events (->> (:out result)
-                        str/split-lines
-                        (map str/trim)
-                        (remove str/blank?)
-                        (filter #(str/includes? % "|"))
-                        (map parse-event-line)
-                        (remove #(str/blank? (:title %)))
-                        vec)]
-        (println (format "[INFO] Found %d upcoming event(s)" (count events)))
-        events)
+  (printf "INFO: Checking khal for events in the next %s" lookahead)
+  (def format-str "{start-date}|{start-time}|{end-time}|{uid}|{title}|{organizer}")
+  (def result (run-cmd "khal" "list" "now" lookahead "--format" format-str))
+  (cond
+    (cmd-ok? result)
+    (do
+      (def lines (string/split "\n" (or (result :out) "")))
+      (def events
+        (filter
+          (fn [e] (not (blank? (e :title))))
+          (map parse-event-line
+               (filter
+                 (fn [l] (and (not (blank? (string/trim l))) (string/find "|" l)))
+                 lines))))
+      (printf "INFO: Found %d upcoming event(s)" (length events))
+      events)
 
-      (= :ok (:status result))
-      (do (println (format "[WARN] khal exited with code %d: %s"
-                           (:code result) (str/trim (or (:out result) ""))))
-          [])
+    (= (result :status) :ok)
+    (do
+      (printf "WARN: khal exited with code %d: %s"
+              (result :code) (string/trim (or (result :out) "")))
+      [])
 
-      (= :enoent (:reason result)) (do (println "[ERROR] khal not found") [])
-      (= :timeout (:reason result)) (do (println "[ERROR] khal timed out") [])
-      :else (do (println "[ERROR] khal execution failed") []))))
+    (do (print "ERROR: khal execution failed") [])))
 
-(defn now-time []
-  (-> (shell {:out :string} "date" "+%H:%M") :out str/trim))
+(defn now-hhmm []
+  (let [d (os/date nil true)]
+    (string/format "%02d:%02d" (d :hours) (d :minutes))))
 
 (defn event-started? [start end now]
   (cond
-    (str/blank? start) false
-    (str/blank? end) (<= (compare start now) 0)
+    (blank? start) false
+    (blank? end) (<= (compare start now) 0)
     (<= (compare start end) 0) (<= (compare start now) 0)
-    :else (or (<= (compare start now) 0) (<= (compare now end) 0))))
+    (or (<= (compare start now) 0) (<= (compare now end) 0))))
 
-(defn filter-events [events]
-  (let [now (now-time)]
-    (remove #(event-started? (:start-time %) (:end-time %) now) events)))
+(defn all-day? [event]
+  (and (blank? (event :start-time)) (blank? (event :end-time))))
 
 (defn format-event [event]
-  (let [time-str (cond
+  (let [start (or (event :start-time) "")
+        end (or (event :end-time) "")
+        org (or (event :organizer) "")
+        time-str (cond
                    (all-day? event) "All day"
-                   (str/blank? (:end-time event)) (:start-time event)
-                   :else (str (:start-time event) " - " (:end-time event)))]
-    (if (str/blank? (:organizer event))
+                   (blank? end) start
+                   (string start " - " end))]
+    (if (blank? org)
       time-str
-      (str time-str "\nOrganizer: " (:organizer event)))))
+      (string time-str "\nOrganizer: " org))))
 
 (defn send-notification [summary body]
-  (println (format "[INFO] Notifying: %s — %s" summary body))
-  (let [result (run-cmd "notify-send"
-                        ["--app-name" "khal_notifier"
-                         "--urgency" "critical"
-                         summary body])]
-    (cond
-      (and (= :ok (:status result)) (zero? (:code result))) true
-      (= :ok (:status result))
-      (do (println (format "[ERROR] notify-send failed (code %d): %s"
-                           (:code result) (str/trim (or (:out result) ""))))
-          false)
-      (= :enoent (:reason result)) (do (println "[ERROR] notify-send not found") false)
-      :else (do (println "[ERROR] notify-send failed") false))))
+  (printf "INFO: Notifying: %s - %s" summary body)
+  (def result (run-cmd "notify-send" "--app-name" "khal_notifier"
+                       "--urgency" "critical" summary body))
+  (if (cmd-ok? result)
+    true
+    (do
+      (if (= (result :status) :ok)
+        (printf "ERROR: notify-send failed (code %d): %s"
+                (result :code) (string/trim (or (result :out) "")))
+        (print "ERROR: notify-send failed"))
+      false)))
 
 (defn notify-events [events]
-  (loop [remaining events
-         notified (read-notified-all-day)]
-    (when-let [event (first remaining)]
-      (let [key (event-key event)]
-        (if (and (all-day? event) (contains? notified key))
-          (do
-            (println (format "[INFO] Already notified: %s — All day" (:title event)))
-            (recur (rest remaining) notified))
-          (let [sent? (send-notification (:title event) (format-event event))
-                newly-notified (if (and sent? (all-day? event))
-                                 (conj notified key)
-                                 notified)]
-            (when (not= notified newly-notified)
-              (write-notified-all-day newly-notified))
-            (recur (rest remaining) newly-notified)))))))
+  (var notified (read-notified))
+  (var dirty false)
+  (each event events
+    (let [key (event-key event)
+          seen (not (nil? (get notified key)))]
+      (if (and (all-day? event) seen)
+        (printf "INFO: Already notified: %s - All day" (event :title))
+        (when (send-notification (event :title) (format-event event))
+          (when (all-day? event)
+            (put notified key true)
+            (set dirty true))))))
+  (when dirty
+    (write-notified notified)))
 
 (defn run-once [lookahead skip-sync]
-  (when-not skip-sync
-    (when-not (sync-pimsync)
-      (println "[WARN] Sync failed — continuing with local calendar data")))
-  (let [events (get-upcoming-events lookahead)
-        filtered (filter-events events)]
+  (unless skip-sync
+    (unless (sync-pimsync)
+      (print "WARN: Sync failed - continuing with local calendar data")))
+  (let [filtered (filter
+                   (fn [e] (not (event-started? (e :start-time) (e :end-time) (now-hhmm))))
+                   (get-upcoming-events lookahead))]
     (if (empty? filtered)
-      (println "[INFO] No upcoming events")
+      (print "INFO: No upcoming events")
       (notify-events filtered))))
 
 (defn parse-opts [args]
-  (loop [remaining args
-         opts {:lookahead "60m" :skip-sync false :help false}]
-    (if (empty? remaining)
-      opts
-      (let [arg (first remaining)]
-        (cond
-          (= arg "--help")      (recur (rest remaining) (assoc opts :help true))
-          (= arg "--skip-sync") (recur (rest remaining) (assoc opts :skip-sync true))
-          (= arg "--lookahead") (recur (drop 2 remaining) (assoc opts :lookahead (second remaining)))
-          :else                (recur (rest remaining) opts))))))
+  (var lookahead "60m")
+  (var skip-sync false)
+  (var help false)
+  (var i 0)
+  (while (< i (length args))
+    (let [arg (get args i)]
+      (cond
+        (= arg "--help") (set help true)
+        (= arg "--skip-sync") (set skip-sync true)
+        (= arg "--lookahead")
+        (do
+          (def val (get args (+ i 1)))
+          (if (nil? val)
+            (do (print "ERROR: --lookahead needs a value") (os/exit 2))
+            (set lookahead val))
+          (++ i))))
+    (++ i))
+  {:lookahead lookahead :skip-sync skip-sync :help help})
 
 (defn print-usage []
-  (println "Usage: khal_notifier [options]")
-  (println)
-  (println "Options:")
-  (println "  --lookahead TIME  How far ahead to check (default: 60m)")
-  (println "  --skip-sync       Skip pimsync sync")
-  (println "  --help            Show this help"))
+  (print "Usage: khal_notifier [options]\n\nOptions:\n  --lookahead TIME  How far ahead to check (default: 60m)\n  --skip-sync       Skip pimsync sync\n  --help            Show this help"))
 
-(defn -main [& args]
-  (let [{:keys [lookahead skip-sync help]} (parse-opts args)]
+(defn main [& raw-args]
+  (let [{:lookahead lookahead :skip-sync skip-sync :help help}
+        (parse-opts (slice raw-args 1))]
     (if help
-      (do (print-usage) (System/exit 0))
+      (do (print-usage) (os/exit 0))
       (run-once lookahead skip-sync))))
-
-(apply -main *command-line-args*)
blob - f7e89e6ed912be88257ad76d868a013c8adad5f3
blob + 42f6412011bd44cbec1df9bd99ac1c525abbbf04
--- modules/mixins/dotfiles/bin/plsmenu
+++ modules/mixins/dotfiles/bin/plsmenu
@@ -32,9 +32,9 @@ else
 fi
 
 if eval "$("$HOME/bin/amen")" && zsh -c "mpd_add_to_playlist '$playlist'"; then
-	notify-send -u normal "mpd" "saved a track to $playlist"
+	notify-send -u normal "mpd" "saved to $playlist"
 	exit 0
 else
-	notify-send -u critical "mpd" "could not save a track"
+	notify-send -u critical "mpd" "could not save to $playlist"
 	exit 1
 fi
blob - c1c7580dd8ed8400cef4b0c20b0c254efd88a086
blob + 21edcbdf3e421e6a2c8e818a3b971b6366373d31
--- modules/mixins/dotfiles/config/magdalena/config.json.nix
+++ modules/mixins/dotfiles/config/magdalena/config.json.nix
@@ -16,16 +16,6 @@
   		".nix-data",
   		"saturn"
   	],
-  	"fzf_opts": [
-  		"--highlight-line",
-  		"--ansi",
-  		"--layout=reverse",
-  		"--border=rounded",
-    "--color=bg+:#222222,bg:#101010,spinner:#8a8a8a,hl:#d2d2d2",
-    "--color=fg:#999999,header:#a2a2a2,info:#5e5e5e,pointer:#999999",
-    "--color=marker:#999999,fg+:#999999,prompt:#999999,hl+:#999999",
-    "--color=border:#353535"
-  	],
   	"fav_dirs": [
   		"${homeDir}/src",
   		"${homeDir}/src/misc",