Skip to content

feat: add macOS click-through commands for notifications#42

Merged
mylee04 merged 4 commits intomylee04:mainfrom
jw-12138:ux/click-through
Mar 30, 2026
Merged

feat: add macOS click-through commands for notifications#42
mylee04 merged 4 commits intomylee04:mainfrom
jw-12138:ux/click-through

Conversation

@jw-12138
Copy link
Copy Markdown
Contributor

Summary

Add click-through commands on macOS so users can control which app is activated when they click a Code-Notify system notification.

What Changed

  • add a new click-through command group for macOS
  • support:
    • cn click-through
    • cn click-through add [name]
    • cn click-through remove
    • cn click-through reset
    • cn click-through help
  • store TERM_PROGRAM -> bundle ID mappings in ~/.code-notify/click-through.conf
  • update macOS notification activation to read user-defined mappings before falling back to built-in defaults
  • expand built-in bundle ID coverage for apps such as Ghostty, Cursor, and Zed
  • show click-through help only on macOS
  • add test coverage for:
    • adding a mapping
    • re-running auto-detected add when the current app is already mapped
    • interactive remove
    • quit without changing mappings
    • notifier activation using the configured bundle ID

Why

On macOS, clicking a notification should bring the user back to the app they actually work in.

Default terminal detection works for common cases, but it breaks down once users switch terminals, use editors as terminals, or want a different app to be activated than the built-in fallback.

This adds an explicit configuration path instead of hard-coding one behavior for everyone.

Platform Scope

This PR intentionally limits the feature to macOS because notification click activation is implemented through terminal-notifier bundle activation.

I did not try to generalize this to Linux or Windows here. That likely needs guidance from the maintainer, both for platform-appropriate behavior and for keeping the interface aligned with the rest of the project.

If there is a better cross-platform abstraction or a more idiomatic way to fit this into Code-Notify, I’d be happy to adjust the implementation.

Behavior

  • macOS only
  • hidden from non-macOS help output
  • non-macOS users do not get the click-through command
  • if cn click-through add auto-detects the current app and the mapping already exists, it exits early and points the user to cn click-through remove

Validation

  • ./scripts/run_tests.sh

Copy link
Copy Markdown
Owner

@mylee04 mylee04 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for putting this together. The direction makes sense, but I don’t think this is ready to merge yet because the two main IDE / embedded-terminal cases still break in practice.

  1. Custom click-through mappings are ignored when TERM_PROGRAM is empty.

In get_terminal_bundle_id(), the new config file is only consulted behind [[ -n "$term_prog" ]]. If TERM_PROGRAM is unset or empty, notifier skips the user mapping entirely and falls back to the built-in default (Terminal.app). That means the new feature still does not help one of the main classes of terminals this PR is trying to support.

I reproduced this locally by writing a mapping like:

jb_jediterm=com.jetbrains.PhpStorm

and then invoking the notifier with TERM_PROGRAM=''. It still emitted:

-activate com.apple.Terminal

instead of the configured PhpStorm bundle ID.

  1. click-through add can save a guessed key instead of the real TERM_PROGRAM.

In the add flow, the current shell TERM_PROGRAM is only used when the query is already a full .app path. If the user follows the issue-thread flow and runs something like:

cn click-through add PhpStorm

from inside an IDE terminal, the code falls back to click_through_guess_term_program(...). So pressing Enter can save a guessed key based on the app name instead of the actual runtime key that notifier will later look up.

I reproduced this with TERM_PROGRAM=JetBrains-JediTerm, where running:

cn click-through add FakeCodex

saved:

fakecodex=com.example.fakecodex

instead of using the live JetBrains-JediTerm value.

Because of those two cases, I don’t think we can say this fully resolves the open PhpStorm / embedded-terminal gap from #19 yet. I’d like to see the lookup and add flow tightened so the stored key and runtime lookup are aligned for real IDE terminal environments before merging.

@jw-12138
Copy link
Copy Markdown
Contributor Author

Thanks for the review. I tightened the TERM_PROGRAM handling and also cleaned up the click-through implementation so the resolution path is now explicit.

Behavior changes:

  • runtime activation now checks user mappings before built-in fallbacks, even when TERM_PROGRAM is empty
  • click-through add now prefers the live runtime TERM_PROGRAM instead of guessing from the selected app name

I verified this locally with a real PyCharm install:

  • cn click-through add PyCharm saved JetBrains-JediTerm=com.jetbrains.pycharm
  • TERM_PROGRAM="" code-notify test still activated PyCharm on notification click instead of Terminal.app

I do not have PhpStorm installed locally, so I used PyCharm for the real manual check. Since JetBrains IDEs use the same embedded terminal key (JetBrains-JediTerm), PhpStorm should follow the same path with a mapping like JetBrains-JediTerm=com.jetbrains.PhpStorm.

I also expanded test coverage in two layers:

  • tests/test-click-through.sh covers the end-to-end command flow and the two review reproductions
  • tests/test-click-through-resolver.sh covers the resolution order directly so the mapping / fallback rules stay stable

I ran ./scripts/run_tests.sh and everything passes.

Copy link
Copy Markdown
Owner

@mylee04 mylee04 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the follow-up here. I rechecked the two cases from my earlier review, and this update addresses them: the notifier now honors configured mappings even when TERM_PROGRAM is empty, and click-through add now prefers the live runtime terminal key instead of saving a guessed app name. The added regression coverage for both cases also helps.

@mylee04 mylee04 merged commit 83fcf2a into mylee04:main Mar 30, 2026
2 checks passed
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.

2 participants