add feature toggles

This commit is contained in:
Adam Jeniski 2026-01-08 02:47:01 -05:00
parent 34ab774759
commit f9ec72d808
2 changed files with 167 additions and 27 deletions

View File

@ -16,12 +16,14 @@ The tool integrates with Claude Code's hook system to send real-time notificatio
The entire implementation is a single Babashka script (`iamwaiting`) with these key functions:
- `load-config` - Loads webhook URL from config file or environment variable
- `load-config` - Loads webhook URL and toggles from config file or environment variable
- `send-discord-webhook` - Makes HTTP POST request to Discord webhook API
- `format-waiting-message` - Formats the notification message with project context
- `setup-config` - Interactive setup wizard for webhook configuration
- `test-webhook` - Sends a test message to verify configuration
- `send-waiting-notification` - Main function that sends the notification
- `send-waiting-notification` - Main function that sends the notification (respects toggles)
- `toggle-feature` - Toggle notification features on or off via CLI
- `show-toggle-status` - Display current toggle status
- `-main` - CLI argument parsing and entry point
### Configuration
@ -30,13 +32,46 @@ Configuration is stored in `~/.iamwaiting/config.edn` with the following structu
```clojure
{:webhook-url "https://discord.com/api/webhooks/..."
:user-id "123456789012345678"} ; Optional: Discord user ID for @mentions
:user-id "123456789012345678" ; Optional: Discord user ID for @mentions
:toggles {:idle-prompt true ; Enable idle prompt notifications
:permission-prompt true}} ; Enable permission prompt notifications
```
Alternatively, configuration can be set via environment variables:
- `IAMWAITING_WEBHOOK_URL` - Discord webhook URL (required)
- `IAMWAITING_USER_ID` - Discord user ID for @mentions (optional)
### Notification Toggles
Control which types of notifications are sent using the `:toggles` configuration key. If toggles are not specified, both notification types are enabled by default (backwards compatible).
**Managing toggles via CLI:**
```bash
# Show current toggle status
iamwaiting toggle status
# Disable idle prompt notifications
iamwaiting toggle idle-prompt off
# Enable permission prompt notifications
iamwaiting toggle permission-prompt on
```
**Manually editing config file:**
```clojure
;; Only get notified for permission prompts
{:webhook-url "https://discord.com/api/webhooks/..."
:toggles {:idle-prompt false
:permission-prompt true}}
;; Disable all notifications
{:webhook-url "https://discord.com/api/webhooks/..."
:toggles {:idle-prompt false
:permission-prompt false}}
```
**Default behavior:** If toggles are not specified in the config file, both notification types are enabled.
## Installation
Install via bbin (recommended):
@ -71,6 +106,25 @@ iamwaiting
iamwaiting '{"cwd": "/path/to/project"}'
```
### Toggle Management
```bash
# Show current toggle status
iamwaiting toggle status
# Disable idle prompt notifications
iamwaiting toggle idle-prompt off
# Enable permission prompt notifications
iamwaiting toggle permission-prompt on
# Enable idle prompt notifications
iamwaiting toggle idle-prompt on
# Disable permission prompt notifications
iamwaiting toggle permission-prompt off
```
### Running via Babashka Tasks
```bash

View File

@ -15,9 +15,13 @@
webhook-url (or (:webhook-url config)
(System/getenv "IAMWAITING_WEBHOOK_URL"))
user-id (or (:user-id config)
(System/getenv "IAMWAITING_USER_ID"))]
(System/getenv "IAMWAITING_USER_ID"))
toggles (or (:toggles config)
{:idle-prompt true
:permission-prompt true})]
{:webhook-url webhook-url
:user-id user-id}))
:user-id user-id
:toggles toggles}))
(defn send-discord-webhook [webhook-url message]
"Send a message to Discord via webhook"
@ -81,20 +85,37 @@
(print "> ")
(flush)
(let [user-id-input (str/trim (read-line))
user-id (when-not (str/blank? user-id-input) user-id-input)
config (if user-id
{:webhook-url webhook-url :user-id user-id}
{:webhook-url webhook-url})]
user-id (when-not (str/blank? user-id-input) user-id-input)]
;; Create config directory
(fs/create-dirs (fs/parent config-file))
;; NEW: Toggle prompts
(println "\n📬 Notification Preferences")
(print "Enable notifications for idle prompts? (y/n, default: y): ")
(flush)
(let [idle-response (str/lower-case (str/trim (read-line)))
idle-enabled? (not= idle-response "n")]
;; Write config
(spit config-file (pr-str config))
(println "\n✓ Configuration saved to" config-file)
(when user-id
(println "✓ User ID configured - you will be @mentioned on permission prompts"))
(println "\nTest the webhook with: ./iamwaiting test"))))
(print "Enable notifications for permission prompts? (y/n, default: y): ")
(flush)
(let [perm-response (str/lower-case (str/trim (read-line)))
perm-enabled? (not= perm-response "n")
;; Build config with toggles
config (cond-> {:webhook-url webhook-url
:toggles {:idle-prompt idle-enabled?
:permission-prompt perm-enabled?}}
user-id (assoc :user-id user-id))]
;; Create config directory
(fs/create-dirs (fs/parent config-file))
;; Write config
(spit config-file (pr-str config))
(println "\n✓ Configuration saved to" config-file)
(when user-id
(println "✓ User ID configured - you will be @mentioned on permission prompts"))
(println (str "✓ Idle prompts: " (if idle-enabled? "enabled" "disabled")))
(println (str "✓ Permission prompts: " (if perm-enabled? "enabled" "disabled")))
(println "\nTest the webhook with: ./iamwaiting test"))))))
(defn test-webhook []
"Test the webhook configuration"
@ -141,21 +162,78 @@
(json/parse-string (first event-data-args) true)
(catch Exception _ {})))
{})
message (format-waiting-message event-data (:user-id config))
result (send-discord-webhook (:webhook-url config) message)]
(if (:success result)
(println "✓ Notification sent")
(do
(println "✗ Failed to send notification:" (:error result))
(System/exit 1)))))))
;; Determine notification type
notification-type (:notification_type event-data)
permission-mode (:permission_mode event-data)
is-permission-prompt? (or (= notification-type "permission_prompt")
(some? permission-mode))
;; Determine which toggle to check
toggle-key (if is-permission-prompt? :permission-prompt :idle-prompt)
enabled? (get-in config [:toggles toggle-key] true)]
;; Exit early if notification type is disabled
(if-not enabled?
(when (System/getenv "DEBUG")
(println (str "Notification disabled for " toggle-key)))
;; Original notification logic
(let [message (format-waiting-message event-data (:user-id config))
result (send-discord-webhook (:webhook-url config) message)]
(if (:success result)
(println "✓ Notification sent")
(do
(println "✗ Failed to send notification:" (:error result))
(System/exit 1)))))))))
(defn toggle-feature [feature action]
"Toggle a notification feature on or off"
(let [config (load-config)
feature-key (case feature
"idle-prompt" :idle-prompt
"permission-prompt" :permission-prompt
nil)
action-bool (case action
"on" true
"off" false
nil)]
(cond
(nil? feature-key)
(do
(println "❌ Invalid feature. Use: idle-prompt | permission-prompt")
(System/exit 1))
(nil? action-bool)
(do
(println "❌ Invalid action. Use: on | off")
(System/exit 1))
:else
(let [updated-config (assoc-in config [:toggles feature-key] action-bool)]
(fs/create-dirs (fs/parent config-file))
(spit config-file (pr-str updated-config))
(println (str "✅ " feature " notifications: " action))))))
(defn show-toggle-status []
"Display current toggle status"
(let [config (load-config)
toggles (or (:toggles config)
{:idle-prompt true
:permission-prompt true})]
(println "📊 Current Toggle Status\n")
(println (str "Idle prompts: " (if (:idle-prompt toggles) "✅ enabled" "❌ disabled")))
(println (str "Permission prompts: " (if (:permission-prompt toggles) "✅ enabled" "❌ disabled")))))
(defn show-help []
(println "iamwaiting - Send Discord notifications when Claude is waiting")
(println "")
(println "Usage:")
(println " iamwaiting setup Set up Discord webhook configuration")
(println " iamwaiting test Test webhook configuration")
(println " iamwaiting [event-data-json] Send waiting notification")
(println " iamwaiting setup Set up Discord webhook configuration")
(println " iamwaiting test Test webhook configuration")
(println " iamwaiting toggle status Show current toggle status")
(println " iamwaiting toggle idle-prompt <on|off> Toggle idle prompt notifications")
(println " iamwaiting toggle permission-prompt <on|off> Toggle permission prompt notifications")
(println " iamwaiting [event-data-json] Send waiting notification")
(println "")
(println "Configuration:")
(println " Config file: ~/.iamwaiting/config.edn")
@ -175,6 +253,14 @@
(case command
"setup" (setup-config)
"test" (test-webhook)
"toggle" (let [subcommand (second args)]
(case subcommand
"status" (show-toggle-status)
"idle-prompt" (toggle-feature "idle-prompt" (nth args 2 nil))
"permission-prompt" (toggle-feature "permission-prompt" (nth args 2 nil))
(do
(println "Usage: iamwaiting toggle <status|idle-prompt|permission-prompt> [on|off]")
(System/exit 1))))
"help" (show-help)
"--help" (show-help)
"-h" (show-help)