Skip to content

fix: quota keychain prompts, permission reset, banner quality, multi-window activation#63

Merged
hiskudin merged 7 commits into
mainfrom
fix/keychain-permissions-banner-quality
May 27, 2026
Merged

fix: quota keychain prompts, permission reset, banner quality, multi-window activation#63
hiskudin merged 7 commits into
mainfrom
fix/keychain-permissions-banner-quality

Conversation

@hiskudin

Copy link
Copy Markdown
Collaborator

Seven targeted fixes off the back of user testing. Each is its own commit so the diff is easy to review.

Quota / keychain

fix(quota): prefer ~/.claude/.credentials.json over keychain when present (32df863)

Claude Code rotates its keychain item every ~8h and the rewrite wipes the trusted-app ACL, re-firing the password prompt despite "Always Allow." Upstream (anthropics/claude-code#22144) closed the fix as not planned. The credentials file path is the documented escape hatch: users who write ~/.claude/.credentials.json (mode 0600) get zero prompts because Claude itself reads the file first and we now do the same.

Permissions

fix(permissions): use real AppleEvent to trigger Automation prompt (33914d8)

AEDeterminePermissionToAutomateTarget(...askUserIfNeeded: true) often returns the cached decision without dispatching the TCC dialog, so "Reset & prompt" on Automation → System Events appeared to do nothing. Send a real AppleScript command to System Events instead; macOS reliably fires the prompt on the first AppleEvent after a tccutil reset. Also surface tccutil non-zero exits via stderr.

Banner & panel quality

fix(events): dedupe hooks fired twice within 2s (9a3d846)

Claude Code occasionally fires the same Stop hook twice in rapid succession. Drop the duplicate (same agent / kind / message / claudeSessionID) within a 2s window.

fix(panel): banner title includes session name; approve keeps panel open when more events remain (fcb763f)

  • Banner title now appends the custom/claudeName label, mirroring Sessions tab and context banners — lets users tell which session fired when several are active.
  • Approving no longer always closes the panel — only closes when the queue is empty (matches the dismiss flow). Approving the last event still hides so the keystroke lands in the target app.

Click-to-focus on the right window

fix(activator): route Cursor/VSCode CLI through captured IPC socket (688641a)

cursor/code --reuse-window picks the most-recently-focused matching window, which is wrong when multiple editor windows are open for the same project. notify.sh already captures the per-window VSCODE_IPC_HOOK_CLI as event.ipcHook — the activator never used it. Prefix the shell invocation with the captured socket path so the CLI talks to that specific window's IPC server.

fix(activator): route iTerm2 click-to-focus via ITERM_SESSION_ID (ad34ae4)

For iTerm2 with multiple tabs in the same project folder, the AX title-fragment walk picked an arbitrary matching tab. Use iTerm2's AppleScript dictionary to walk windows → tabs → sessions and select the exact session whose id matches event.sessionID. Falls through to the AX path if scripting errors.

fix(activator): correct iTerm2 session-id match + AX-raise specific Cursor window (d1e5226)

  • iTerm: ITERM_SESSION_ID is w0t0p0:UUID but iTerm's AppleScript id of session returns just the UUID. Strip the prefix before comparing.
  • Cursor/VSCode: even with the IPC fix, --reuse-window routes the open request correctly but doesn't raise the targeted window. Added an AX-raise step matching the captured windowTitle (which has the open filename and is window-specific).

Known limitation: Zed multi-window

Investigated and confirmed unfixable from our side. Zed is single-process Rust/GPUI with no per-window env var (ZED_TERM, TERM_PROGRAM are static), no AppleScript dictionary, no IPC socket, no URL-scheme window targeting, and no CLI flag to target a specific window. All Zed windows share PID, so process-tree walking doesn't help either. No third-party tool has solved this. Filing upstream as a follow-up.

Test plan

  • Quota: with ~/.claude/.credentials.json present, no keychain prompts on quota polls.
  • Permissions: "Reset & prompt" on Automation → System Events dispatches the macOS dialog reliably.
  • Banner: custom session names appear in the title (e.g. "Claude Code — my-named-session").
  • Dedup: duplicate Stop hooks within 2s produce one event, one banner.
  • Approve: with multiple events queued, approving advances to the next without closing the panel.
  • iTerm2: with two tabs in the same project, click on the banner activates the agent's specific tab.
  • Cursor: with two windows on the same project, click on the banner raises the agent's specific window.
  • Zed: documented as known limitation pending upstream ZED_WINDOW_ID.

🤖 Generated with Claude Code

hiskudin and others added 7 commits May 27, 2026 10:42
…sent

Claude Code rotates its keychain item every ~8h and the rewrite wipes
the trusted-app ACL, re-firing the password prompt despite "Always
Allow." Upstream (anthropics/claude-code#22144) closed the fix as not
planned. The credentials file path is the documented escape hatch:
users who write ~/.claude/.credentials.json (mode 0600) get zero
prompts because Claude itself reads the file first and we now do the
same.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
AEDeterminePermissionToAutomateTarget(...askUserIfNeeded: true) often
returns the cached decision without dispatching the TCC dialog, so
"Reset & prompt" on Automation -> System Events appeared to do
nothing. Send a real harmless AppleScript command to System Events
instead; macOS reliably fires the prompt on the first AppleEvent send
after a tccutil reset clears the decision.

Also surface tccutil non-zero exits via stderr so silent failures
become visible during dev.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Claude Code occasionally fires the same Stop hook twice in rapid
succession, producing two identical banners + two list entries. Drop
the second event when an identical one (same agent/kind/message/
claudeSessionID) landed within a 2s window.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
…pen when more events remain

- Banner title now appends the custom/claudeName label (mirroring
  Sessions tab and context banners) so users can tell which session
  fired when multiple sessions are active.
- Approve no longer closes the panel unconditionally — only closes
  when the queue is empty, matching the dismiss flow. Approving the
  last event still hides so the keystroke lands in the target app.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
cursor/code --reuse-window picks the most-recently-focused window
matching the path, which is wrong when multiple editor windows are
open for the same project. notify.sh already captures the per-window
VSCODE_IPC_HOOK_CLI as event.ipcHook but the activator never used it.

Prefix the shell invocation with the captured socket path so the CLI
talks to that specific window's IPC server — pinning activation to
the window the agent actually ran in.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
For iTerm2 with multiple tabs in the same project folder, the AX
title-fragment walk picks an arbitrary matching tab — wrong when
the agent runs in a specific pane. notify.sh already captures
ITERM_SESSION_ID as event.sessionID; use iTerm2's AppleScript
dictionary to walk windows -> tabs -> sessions and select the exact
session whose id matches. Falls through to the AX path if scripting
errors or the session has since been closed.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
…ursor window

iTerm2: ITERM_SESSION_ID is 'w0t0p0:UUID' (window-tab-pane prefix +
UUID) but iTerm2's AppleScript 'id of session' returns just the UUID.
The previous match compared the prefixed form against the bare UUID
and always missed. Strip the prefix before comparing.

Cursor/VSCode: --reuse-window routes the open request to the correct
window via the IPC hook, but the CLI doesn't raise that window — the
most-recently-focused window pops to front instead. Add an AX raise
step that matches the captured windowTitle (which includes the open
filename and is window-specific), pinning activation to the agent's
window.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
@hiskudin hiskudin merged commit e335ee6 into main May 27, 2026
4 checks passed
@hiskudin hiskudin deleted the fix/keychain-permissions-banner-quality branch May 27, 2026 16:16
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant