5 Commits

  • feat(hooks): add WSL desktop notification support via PowerShell + BurntToast (#1019)
    * fix(hooks): add WSL desktop notification support via PowerShell + BurntToast
    
    Adds WSL (Windows Subsystem for Linux) desktop notification support to the
    existing desktop-notify hook. The hook now detects WSL, finds available
    PowerShell (7 or Windows PowerShell), checks for BurntToast module, and
    sends Windows toast notifications.
    
    New functions:
    - isWSL(): detects WSL environment
    - findPowerShell(): finds PowerShell 7 or Windows PowerShell on WSL
    - isBurntToastAvailable(): checks if BurntToast module is installed
    - notifyWindows(): sends Windows toast notification via BurntToast
    
    If BurntToast is not installed, logs helpful tip for installation.
    Falls back silently on non-WSL/non-macOS platforms.
    
    * docs(hooks): update desktop-notify description to include WSL
    
    Updates the hook description in hooks.json to reflect the newly
    added WSL notification support alongside macOS.
    
    * fix(hooks): capture stderr properly in notifyWindows
    
    Change stdio to ['ignore', 'pipe', 'pipe'] so stderr is captured
    and can be logged on errors. Without this, result.stderr is null
    and error logs show 'undefined' instead of the actual error.
    
    * fix(hooks): quote PowerShell path in install tip for shell safety
    
    The PowerShell path contains spaces and needs to be quoted
    when displayed as a copy-pasteable command.
    
    * fix(hooks): remove external repo URL from tip message
    
    BurntToast module is a well-known Microsoft module but per project
    policy avoiding unvetted external links in user-facing output.
    
    * fix(hooks): probe WSL interop PATH before hardcoded paths
    
    Adds 'pwsh.exe' and 'powershell.exe' as candidates to leverage
    WSL's Windows interop PATH resolution, making the hook work with
    non-default WSL mount prefixes or Windows drives.
    
    * perf(hooks): memoize isWSL detection at module load
    
    Avoids reading /proc/version twice (once in run(), once in findPowerShell())
    by computing the result once when the module loads.
    
    * perf(hooks): reduce PowerShell spawns from 3 to 1 per notification
    
    Merge findPowerShell version check and isBurntToastAvailable check
    into a single notifyWindows call. Now just tries to send directly;
    if it fails, tries next PowerShell path. Version field was unused.
    
    Net effect: up to 3 spawns reduced to 1 in the happy path.
    
    * fix(hooks): remove duplicate notifyWindows declaration
    
    There were two notifyWindows function declarations due to incomplete
    refactoring. Keeps only the version that returns true/false for the
    call site. Node.js would throw SyntaxError with 'use strict'.
    
    * fix(hooks): improve error handling and detection robustness
    
    - Increase PowerShell detection timeout from 1s to 3s to avoid false
      negatives on slower/cold WSL interop startup
    - Return error reason from notifyWindows to distinguish BurntToast
      module not found vs other PowerShell errors
    - Log actionable error details instead of always showing install tip
    
    ---------
    
    Co-authored-by: boss <boss@example.com>
  • fix: add spawnSync error logging and restore 5s timeout
    - Check spawnSync result and log warning on failure via stderr
    - Restore osascript timeout to 5000ms, increase hook deadline to 10s
      for sufficient headroom
  • fix: use AppleScript-safe escaping and reduce spawnSync timeout
    - Replace JSON.stringify with curly quote substitution for AppleScript
      compatibility (AppleScript does not support \" backslash escapes)
    - Reduce spawnSync timeout from 5000ms to 3000ms to leave headroom
      within the 5s hook deadline
  • feat: add macOS desktop notification Stop hook
    Add a new Stop hook that sends a native macOS notification with the
    task summary (first line of last_assistant_message) when Claude finishes
    responding. Uses osascript via spawnSync for shell injection safety.
    Supports run-with-flags fast require() path. Only active on standard
    and strict profiles; silently skips on non-macOS platforms.