From d538c5e694f7bd1b47f74dba3d5ac4d557b43f99 Mon Sep 17 00:00:00 2001 From: Daniel Abeles Date: Tue, 17 Feb 2026 13:21:55 +0200 Subject: [PATCH 1/2] updated spoon to use api --- .../Spoons/ClaudeRewriter.spoon/init.lua | 52 +++++++++++-------- hammerspoon/init.lua | 8 ++- zsh/.zshrc | 2 +- 3 files changed, 39 insertions(+), 23 deletions(-) diff --git a/hammerspoon/Spoons/ClaudeRewriter.spoon/init.lua b/hammerspoon/Spoons/ClaudeRewriter.spoon/init.lua index a28182f..6efe96b 100644 --- a/hammerspoon/Spoons/ClaudeRewriter.spoon/init.lua +++ b/hammerspoon/Spoons/ClaudeRewriter.spoon/init.lua @@ -7,12 +7,14 @@ obj.author = "Daniel Abeles" obj.homepage = "https://github.com/Den1al/dotfiles" obj.license = "MIT - https://opensource.org/licenses/MIT" -obj.claudePath = os.getenv("HOME") .. "/.local/bin/claude" -obj.model = "sonnet" +obj.apiKey = nil +obj.model = "claude-sonnet-4-5" obj.systemPrompt = - "Rewrite the following text for clarity and correct grammar. Preserve the original tone, intent, and meaning. Return ONLY the rewritten text with no preamble or explanation. Don't use emdashes." + "Rewrite the following text for clarity and correct grammar. Preserve the original tone, intent, and meaning. Return ONLY the rewritten text with no preamble or explanation. DONT use emdashes." obj.alertDuration = 1.5 +local API_URL = "https://api.anthropic.com/v1/messages" + local hotkeys = {} local rewriting = false @@ -66,8 +68,8 @@ function obj:rewrite(pasteInPlace) return end - if not hs.fs.attributes(self.claudePath) then - hs.alert.show("Claude CLI not found", self.alertDuration) + if not self.apiKey or self.apiKey == "" then + hs.alert.show("API key not set", self.alertDuration) return end @@ -75,27 +77,37 @@ function obj:rewrite(pasteInPlace) local savedClipboard = hs.pasteboard.readAllData() local progressAlert = hs.alert.show("Rewriting...", 30) - local args = { - "-p", - selected, - "--model", - self.model, - "--output-format", - "text", - "--system-prompt", - self.systemPrompt, + local headers = { + ["x-api-key"] = self.apiKey, + ["anthropic-version"] = "2023-06-01", + ["content-type"] = "application/json", } - local task = hs.task.new(self.claudePath, function(exitCode, stdout, stderr) + local body = hs.json.encode({ + model = self.model, + max_tokens = 4096, + system = self.systemPrompt, + messages = { + { role = "user", content = selected }, + }, + }) + + hs.http.asyncPost(API_URL, body, headers, function(status, responseBody) hs.alert.closeSpecific(progressAlert) rewriting = false - if exitCode ~= 0 then - hs.alert.show("Rewrite failed", self.alertDuration) + if status ~= 200 then + hs.alert.show("Rewrite failed (HTTP " .. tostring(status) .. ")", self.alertDuration) + return + end + + local ok, response = pcall(hs.json.decode, responseBody) + if not ok or not response or not response.content or #response.content == 0 then + hs.alert.show("Failed to parse response", self.alertDuration) return end - local result = stdout and stdout:gsub("^%s+", ""):gsub("%s+$", "") or "" + local result = (response.content[1].text or ""):gsub("^%s+", ""):gsub("%s+$", "") if result == "" then hs.alert.show("Empty response", self.alertDuration) return @@ -112,9 +124,7 @@ function obj:rewrite(pasteInPlace) else hs.alert.show("Copied to clipboard", self.alertDuration) end - end, args) - - task:start() + end) end return obj diff --git a/hammerspoon/init.lua b/hammerspoon/init.lua index 30666e6..0668768 100644 --- a/hammerspoon/init.lua +++ b/hammerspoon/init.lua @@ -27,7 +27,13 @@ hs.hotkey.bind({ "alt" }, "R", function() end) hs.loadSpoon("ClaudeRewriter") -spoon.ClaudeRewriter.model = "sonnet" + +local f = io.open(os.getenv("HOME") .. "/.config/gitlab-duo/a-key", "r") +if f then + spoon.ClaudeRewriter.apiKey = f:read("*l") + f:close() +end + spoon.ClaudeRewriter:bindHotkeys({ rewrite = { { "alt" }, "c" }, clipboard = { { "alt", "shift" }, "c" }, diff --git a/zsh/.zshrc b/zsh/.zshrc index 65eaa30..e4e1d48 100644 --- a/zsh/.zshrc +++ b/zsh/.zshrc @@ -74,7 +74,7 @@ tmuxifier() { # Gitlab Duo (use zsh native file reading, avoid cat subshells) [[ -r "$HOME/.config/gitlab-duo/key" ]] && export GITLAB_TOKEN=$(<"$HOME/.config/gitlab-duo/key") -[[ -r "$HOME/.config/gitlab-duo/a-key" ]] && export ANTHROPIC_TOKEN=$(<"$HOME/.config/gitlab-duo/a-key") ANTHROPIC_API_KEY=$(<"$HOME/.config/gitlab-duo/a-key") +[[ -r "$HOME/.config/gitlab-duo/a-key" ]] && export ANTHROPIC_TOKEN=$(<"$HOME/.config/gitlab-duo/a-key") && export ANTHROPIC_API_KEY=$(<"$HOME/.config/gitlab-duo/a-key") # FZF From 231f965cf786b419143502948a7d20a3212675e6 Mon Sep 17 00:00:00 2001 From: Daniel Abeles Date: Tue, 17 Feb 2026 13:25:03 +0200 Subject: [PATCH 2/2] add docs for launchctl --- hammerspoon/Spoons/ClaudeRewriter.spoon/init.lua | 3 +++ hammerspoon/init.lua | 6 +----- zsh/.zshrc | 2 ++ 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/hammerspoon/Spoons/ClaudeRewriter.spoon/init.lua b/hammerspoon/Spoons/ClaudeRewriter.spoon/init.lua index 6efe96b..e7def6f 100644 --- a/hammerspoon/Spoons/ClaudeRewriter.spoon/init.lua +++ b/hammerspoon/Spoons/ClaudeRewriter.spoon/init.lua @@ -7,6 +7,9 @@ obj.author = "Daniel Abeles" obj.homepage = "https://github.com/Den1al/dotfiles" obj.license = "MIT - https://opensource.org/licenses/MIT" +-- Note: Hammerspoon is a GUI app and won't see shell env vars by default. +-- Use `launchctl setenv ANTHROPIC_API_KEY ` in your shell config +-- to propagate it to launchd so os.getenv() works here. obj.apiKey = nil obj.model = "claude-sonnet-4-5" obj.systemPrompt = diff --git a/hammerspoon/init.lua b/hammerspoon/init.lua index 0668768..d514d20 100644 --- a/hammerspoon/init.lua +++ b/hammerspoon/init.lua @@ -28,11 +28,7 @@ end) hs.loadSpoon("ClaudeRewriter") -local f = io.open(os.getenv("HOME") .. "/.config/gitlab-duo/a-key", "r") -if f then - spoon.ClaudeRewriter.apiKey = f:read("*l") - f:close() -end +spoon.ClaudeRewriter.apiKey = os.getenv("ANTHROPIC_API_KEY") spoon.ClaudeRewriter:bindHotkeys({ rewrite = { { "alt" }, "c" }, diff --git a/zsh/.zshrc b/zsh/.zshrc index e4e1d48..6f400a0 100644 --- a/zsh/.zshrc +++ b/zsh/.zshrc @@ -75,6 +75,8 @@ tmuxifier() { # Gitlab Duo (use zsh native file reading, avoid cat subshells) [[ -r "$HOME/.config/gitlab-duo/key" ]] && export GITLAB_TOKEN=$(<"$HOME/.config/gitlab-duo/key") [[ -r "$HOME/.config/gitlab-duo/a-key" ]] && export ANTHROPIC_TOKEN=$(<"$HOME/.config/gitlab-duo/a-key") && export ANTHROPIC_API_KEY=$(<"$HOME/.config/gitlab-duo/a-key") +# Propagate to launchd so GUI apps (e.g. Hammerspoon) can access it via os.getenv +[[ -n "$ANTHROPIC_API_KEY" ]] && launchctl setenv ANTHROPIC_API_KEY "$ANTHROPIC_API_KEY" # FZF