Remove the logging daemon and launchd agent

ober

a120a3c8b46658066641be494192824b69b62b82

diff --git a/Makefile b/Makefile
index ac5ec0a..99960b7 100644
--- a/Makefile
+++ b/Makefile
@@ -21,10 +21,8 @@ endif
 TUI_SHIM := $(TUI_SHIM_DIR)/signal_tui_shim.$(TUI_SHIM_EXT)
 LOG_SHIM := signal_log_shim.$(TUI_SHIM_EXT)
 SQLCIPHER_PREFIX := $(shell brew --prefix sqlcipher 2>/dev/null)
-LAUNCHD_LABEL := org.linbsd.jerboa-signal.log
-LAUNCHD_PLIST := $(HOME)/Library/LaunchAgents/$(LAUNCHD_LABEL).plist
 
-.PHONY: all build binary run run-tui test install clean help vendor-deps tui-shim log-shim launchd-install launchd-uninstall
+.PHONY: all build binary run run-tui test install clean help vendor-deps tui-shim log-shim
 .DEFAULT_GOAL := help
 
 all: binary
@@ -84,34 +82,6 @@ log-shim:
 	    -o $(LOG_SHIM) signal/log_shim.c && echo "Built $(LOG_SHIM)"; \
 	fi
 
-# Install the always-on logger as a launchd LaunchAgent: auto-start at login,
-# restart on crash. The passphrase is read from the macOS Keychain by the
-# wrapper, never stored in the plist.
-launchd-install:
-	$(MAKE) log-shim
-	$(MAKE) install
-	install -m 0755 dist/jerboa-signal-logd.sh $(BIN_DIR)/jerboa-signal-logd
-	mkdir -p $(HOME)/Library/LaunchAgents $(HOME)/Library/Logs
-	sed 's|__HOME__|$(HOME)|g' dist/$(LAUNCHD_LABEL).plist.in > $(LAUNCHD_PLIST)
-	@echo ""
-	@echo "Installed LaunchAgent + wrapper. Two manual steps remain:"
-	@echo "  1) Store the DB passphrase in your Keychain (prompts; nothing on disk):"
-	@echo "       security add-generic-password -a \"$$USER\" -s jerboa-signal-db -w"
-	@echo "  2) Load the agent (starts now and at every login):"
-	@echo "       launchctl load -w $(LAUNCHD_PLIST)"
-	@echo ""
-	@echo "  Logs:  $(HOME)/Library/Logs/jerboa-signal-log.{out,err}.log"
-	@echo "  Stop:  make launchd-uninstall   (or: launchctl unload -w the plist)"
-	@echo "  NOTE:  stop the daemon before using the TUI -- signal-cli allows only"
-	@echo "         one connection per account."
-
-launchd-uninstall:
-	-launchctl unload -w $(LAUNCHD_PLIST) 2>/dev/null || true
-	rm -f $(LAUNCHD_PLIST) $(BIN_DIR)/jerboa-signal-logd
-	@echo "Removed LaunchAgent and wrapper."
-	@echo "Keychain item kept; remove it with:"
-	@echo "  security delete-generic-password -a \"$$USER\" -s jerboa-signal-db"
-
 help:
 	@echo "jerboa-signal -- Signal client over signal-cli"
 	@echo ""
@@ -123,8 +93,6 @@ help:
 	@echo "  install             Install ./jerboa-signal to ~/.local/bin"
 	@echo "  tui-shim            Build the termbox2 TUI shim"
 	@echo "  log-shim            Build the SQLCipher encrypted-logging shim"
-	@echo "  launchd-install     Install the always-on logger as a login agent (macOS)"
-	@echo "  launchd-uninstall   Remove the launchd agent and wrapper"
 	@echo "  clean               Remove build artifacts"
 	@echo ""
 	@echo "Prerequisite: signal-cli must be linked to your Signal account."
diff --git a/README.md b/README.md
index 1757c01..85f97b7 100644
--- a/README.md
+++ b/README.md
@@ -13,7 +13,6 @@ Bidirectional bridge between Signal and your shell:
 jerboa-signal send [-a +PHONE] RECIPIENT MESSAGE   # send one message, exit
 jerboa-signal listen [-a +PHONE]                   # stream inbound as NDJSON
 jerboa-signal tui [-a +PHONE]                      # terminal UI shell
-jerboa-signal log [-a +PHONE]                      # headless: capture all to an encrypted DB
 ```
 
 `-a` is required only if multiple Signal accounts are linked to signal-cli.
@@ -122,50 +121,8 @@ sqlcipher ~/.local/share/jerboa-signal/messages-+15551234567.db \
   "PRAGMA key='your passphrase'; SELECT timestamp,direction,sender,kind,body FROM messages;"
 ```
 
-### Always-on logging daemon
-
-The TUI only logs while it is open. To capture messages around the clock, run
-the headless logger, which connects to signal-cli in receive mode and appends
-every event to the same encrypted database until stopped:
-
-```sh
-export JERBOA_SIGNAL_DB_KEY='your passphrase'   # required when headless
-jerboa-signal log                               # prints a line per captured event
-```
-
-Run it under launchd/`nohup`/tmux for 24/7 capture. It reads the passphrase from
-`JERBOA_SIGNAL_DB_KEY`, or prompts if started attached to a terminal. Each event
-is committed immediately, so killing the daemon never loses logged messages.
-
-Note: signal-cli allows only one connection per account, so the daemon and the
-TUI cannot run at the same time for the same account — use the daemon for
-unattended capture and the TUI for reading/replying.
-
-### Auto-start at login (launchd, macOS)
-
-To run the logger as a LaunchAgent that starts at login and restarts on crash:
-
-```sh
-make launchd-install
-```
-
-This builds and installs the binary, the SQLCipher shim, and a wrapper, then
-writes `~/Library/LaunchAgents/org.linbsd.jerboa-signal.log.plist`. The wrapper
-reads the passphrase from the **macOS Keychain**, so it is never stored in the
-plist (which would otherwise sit in plaintext next to the encrypted database).
-Finish with the two steps it prints:
-
-```sh
-# store the passphrase once (prompts; nothing written to disk or shell history)
-security add-generic-password -a "$USER" -s jerboa-signal-db -w
-# load the agent (starts now and at every login)
-launchctl load -w ~/Library/LaunchAgents/org.linbsd.jerboa-signal.log.plist
-```
-
-Output goes to `~/Library/Logs/jerboa-signal-log.{out,err}.log`. Remove
-everything with `make launchd-uninstall`. Because the daemon holds the single
-signal-cli connection, unload it (`make launchd-uninstall`, or `launchctl
-unload -w` the plist) before using the TUI.
+Logging happens only while the TUI is open — messages that arrive while it is
+closed are not captured.
 
 ## Architecture
 
@@ -186,9 +143,8 @@ Modules:
 - `signal/cmd-send.ss` — `send` subcommand
 - `signal/cmd-listen.ss` — `listen` subcommand
 - `signal/cmd-tui.ss` — TUI command entry point; see `docs/TUI_PLAN.md`
-- `signal/cmd-log.ss` — always-on headless logging daemon (`log` subcommand)
 - `signal/store.ss` — persistent local state (deleted-conversation list)
-- `signal/capture.ss` — notification → encrypted log row (shared by TUI + daemon)
+- `signal/capture.ss` — normalizes a notification into an encrypted log row
 - `signal/logdb.ss` + `signal/log_shim.c` — FFI to the SQLCipher encrypted log
 - `signal/tui/` — termbox2 FFI and the first terminal shell
 
diff --git a/dist/jerboa-signal-logd.sh b/dist/jerboa-signal-logd.sh
deleted file mode 100755
index 76e8164..0000000
--- a/dist/jerboa-signal-logd.sh
+++ /dev/null
@@ -1,25 +0,0 @@
-#!/bin/sh
-# jerboa-signal-logd -- launchd wrapper for the always-on encrypted logger.
-#
-# Fetches the SQLCipher passphrase from the macOS Keychain so the key never sits
-# in the LaunchAgent plist (which lives in ~/Library/LaunchAgents, right next to
-# the encrypted database), then execs `jerboa-signal log`.
-#
-# One-time Keychain setup (prompts for the passphrase; it is not stored in shell
-# history or any plaintext file):
-#   security add-generic-password -a "$USER" -s jerboa-signal-db -w
-set -eu
-
-USER="${USER:-$(id -un)}"
-BIN="${JERBOA_SIGNAL_BIN:-$HOME/.local/bin/jerboa-signal}"
-
-if ! KEY="$(security find-generic-password -a "$USER" -s jerboa-signal-db -w 2>/dev/null)"; then
-  echo "jerboa-signal-logd: missing Keychain item 'jerboa-signal-db'." >&2
-  echo "  create it with:" >&2
-  echo "    security add-generic-password -a \"\$USER\" -s jerboa-signal-db -w" >&2
-  exit 1
-fi
-
-JERBOA_SIGNAL_DB_KEY="$KEY"
-export JERBOA_SIGNAL_DB_KEY
-exec "$BIN" log
diff --git a/dist/org.linbsd.jerboa-signal.log.plist.in b/dist/org.linbsd.jerboa-signal.log.plist.in
deleted file mode 100644
index a7e2efc..0000000
--- a/dist/org.linbsd.jerboa-signal.log.plist.in
+++ /dev/null
@@ -1,47 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN"
-  "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
-<!-- LaunchAgent for the jerboa-signal always-on encrypted logger.
-     __HOME__ is substituted by `make launchd-install`; do not edit the
-     installed copy in ~/Library/LaunchAgents by hand. -->
-<plist version="1.0">
-<dict>
-  <key>Label</key>
-  <string>org.linbsd.jerboa-signal.log</string>
-
-  <key>ProgramArguments</key>
-  <array>
-    <string>__HOME__/.local/bin/jerboa-signal-logd</string>
-  </array>
-
-  <!-- launchd agents get a minimal PATH; signal-cli (Homebrew) and security
-       must be reachable. -->
-  <key>EnvironmentVariables</key>
-  <dict>
-    <key>PATH</key>
-    <string>/opt/homebrew/bin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin</string>
-  </dict>
-
-  <key>RunAtLoad</key>
-  <true/>
-
-  <!-- Keep it running: if signal-cli hiccups the daemon exits and launchd
-       restarts it (reconnecting), throttled so a persistent failure does not
-       spin. -->
-  <key>KeepAlive</key>
-  <true/>
-  <key>ThrottleInterval</key>
-  <integer>30</integer>
-
-  <key>WorkingDirectory</key>
-  <string>__HOME__</string>
-
-  <key>StandardOutPath</key>
-  <string>__HOME__/Library/Logs/jerboa-signal-log.out.log</string>
-  <key>StandardErrorPath</key>
-  <string>__HOME__/Library/Logs/jerboa-signal-log.err.log</string>
-
-  <key>ProcessType</key>
-  <string>Background</string>
-</dict>
-</plist>
diff --git a/signal/cmd-log.ss b/signal/cmd-log.ss
deleted file mode 100644
index 67752fc..0000000
--- a/signal/cmd-log.ss
+++ /dev/null
@@ -1,145 +0,0 @@
-#!chezscheme
-;;; signal/cmd-log -- always-on headless message logger.
-;;;
-;;; Connects to signal-cli in receive mode and appends every event to the
-;;; encrypted SQLCipher log, so messages are kept even if the sender later
-;;; deletes them ("delete for everyone"). Runs until the stream closes or it is
-;;; interrupted. Each insert is its own committed transaction, so an abrupt kill
-;;; never loses already-logged messages.
-;;;
-;;; Passphrase: JERBOA_SIGNAL_DB_KEY if set (for unattended/launchd use),
-;;; otherwise prompt when attached to a terminal.
-
-(library (signal cmd-log)
-  (export cmd-log)
-
-  (import (except (chezscheme)
-                  make-hash-table hash-table?
-                  sort sort!
-                  printf fprintf
-                  path-extension path-absolute?
-                  with-input-from-string with-output-to-string
-                  iota 1+ 1-
-                  partition
-                  make-date make-time)
-          (except (jerboa prelude) meta atom?)
-          (std misc process)
-          (signal rpc-actor)
-          (signal store)
-          (signal logdb)
-          (signal capture))
-
-  (def (cmd-log account)
-    (let* ([acct (or account "default")]
-           [logdb (open-log-or-exit acct)]
-           [actor (start-signal-actor account "on-connection")])
-      (dynamic-wind
-        (lambda () (void))
-        (lambda ()
-          (announce acct)
-          (confirm-backend actor)
-          (log-loop logdb acct actor 0))
-        (lambda ()
-          (stop-signal-actor actor)
-          (logdb-close logdb)
-          (display "jerboa-signal log: stopped.\n")))))
-
-  (def (open-log-or-exit acct)
-    (unless (logdb-available?)
-      (die "encrypted logging unavailable; build it with: brew install sqlcipher && make log-shim"))
-    (let ([key (resolve-key)])
-      (unless (and key (not (string=? key "")))
-        (die "no passphrase; set JERBOA_SIGNAL_DB_KEY or run attached to a terminal"))
-      (ensure-store-dir!)
-      (let ([db (logdb-open (messages-store-path acct) key)])
-        (unless db
-          (die "could not open encrypted log (wrong passphrase, or corrupt file)"))
-        db)))
-
-  (def (resolve-key)
-    (let ([env (getenv "JERBOA_SIGNAL_DB_KEY")])
-      (cond
-        [(and env (not (string=? env ""))) env]
-        [(tty? (current-input-port))
-         (logdb-prompt-passphrase
-           "jerboa-signal log: passphrase for encrypted message log: ")]
-        [else #f])))
-
-  (def (announce acct)
-    (display "jerboa-signal log: capturing to ")
-    (display (messages-store-path acct))
-    (newline)
-    (display "  receive mode on-connection; press Ctrl-C to stop.\n")
-    (flush-output-port (current-output-port)))
-
-  (def (confirm-backend actor)
-    (guard (e [#t (void)])
-      (let ([v (actor-call actor "version" #f)])
-        (when (hashtable? v)
-          (display "  signal-cli ")
-          (display (hashtable-ref v "version" "unknown"))
-          (newline)
-          (flush-output-port (current-output-port))))))
-
-  ;; Poll the actor's event stream, log every notification, and keep a running
-  ;; total. Exits when signal-cli closes the stream.
-  (def (log-loop logdb acct actor total)
-    (cond
-      [(signal-actor-closed? actor)
-       (display "jerboa-signal log: signal-cli stream closed.\n")
-       total]
-      [else
-       (let ([n (handle-events! logdb acct (actor-drain-events actor) total)])
-         (sleep-ms 150)
-         (log-loop logdb acct actor n))]))
-
-  (def (handle-events! logdb acct events total)
-    (let loop ([evs events] [count total])
-      (cond
-        [(null? evs) count]
-        [else
-         (let ([ev (car evs)]
-               [rest (cdr evs)])
-           (cond
-             [(notification-event? ev)
-              (let ([summary (capture-notification! logdb acct (cadr ev))]
-                    [n (+ count 1)])
-                (report n summary)
-                (loop rest n))]
-             [(tagged? ev 'error)
-              (display "jerboa-signal log: signal-cli error: ")
-              (display (event-detail ev))
-              (newline)
-              (flush-output-port (current-output-port))
-              (loop rest count)]
-             [else (loop rest count)]))])))
-
-  (def (notification-event? ev)
-    (and (tagged? ev 'notification) (pair? (cdr ev))))
-
-  (def (tagged? ev tag)
-    (and (pair? ev) (eq? (car ev) tag)))
-
-  (def (report n summary)
-    (display "[")
-    (display n)
-    (display "] ")
-    (display (if (string? summary) summary "event"))
-    (newline)
-    (flush-output-port (current-output-port)))
-
-  (def (event-detail ev)
-    (if (pair? (cdr ev))
-      (let ([d (cadr ev)]) (if (string? d) d (object->string d)))
-      "?"))
-
-  (def (object->string x)
-    (let ([p (open-output-string)]) (display x p) (get-output-string p)))
-
-  (def (die msg)
-    (display "jerboa-signal log: " (current-error-port))
-    (display msg (current-error-port))
-    (newline (current-error-port))
-    (exit 1))
-
-  ) ;; end library
diff --git a/signal/main.ss b/signal/main.ss
index 75631fb..4585eac 100644
--- a/signal/main.ss
+++ b/signal/main.ss
@@ -35,8 +35,7 @@
 (import (except (jerboa prelude) meta atom?)
         (signal cmd-send)
         (signal cmd-listen)
-        (signal cmd-tui)
-        (signal cmd-log))
+        (signal cmd-tui))
 
 (def *version* "0.1.0")
 
@@ -48,7 +47,6 @@ Subcommands:
   send [-a +PHONE] RECIPIENT MESSAGE   Send a Signal message
   listen [-a +PHONE]                   Stream inbound envelopes as NDJSON
   tui [-a +PHONE]                      Start the terminal UI
-  log [-a +PHONE]                      Capture all messages to an encrypted log
   version                              Print version
   help                                 Print this help
 
@@ -103,15 +101,6 @@ linking once before using this tool:
                (exit 2)]
               [else
                (cmd-tui account)]))]
-         [(string=? sub "log")
-          (let-values ([(account args) (parse-account-flag rest)])
-            (cond
-              [(not (null? args))
-               (display "jerboa-signal: log takes no positional arguments\n"
-                        (current-error-port))
-               (exit 2)]
-              [else
-               (cmd-log account)]))]
          [else
           (display "jerboa-signal: unknown subcommand: " (current-error-port))
           (display sub (current-error-port))