nicejade / nicejade/agent.jeffjade.com

Claude Code 如何在完成任务后通知给主人?

Open
#4 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
CSS
Stars
7
Forks
0
PR merge metrics
No merged PRs in 30d

Description

  • ~/.claude/settings.json
{
  "env": {
    "ANTHROPIC_BASE_URL": "https://api.deepseek.com/anthropic",
    "ANTHROPIC_API_KEY": "sk-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
    "API_TIMEOUT_MS": "3000000",
    "BASH_DEFAULT_TIMEOUT_MS": "300000",
    "CLAUDE_AUTOCOMPACT_PCT_OVERRIDE": "80",
    "CLAUDE_CODE_ATTRIBUTION_HEADER": "0",
    "CLAUDE_CODE_AUTO_COMPACT_WINDOW": "120000",
    "CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC": "1",
    "CLAUDE_CODE_NO_FLICKER": "true",
    "DISABLE_ERROR_REPORTING": "1",
    "DISABLE_TELEMETRY": "1",
    "ENABLE_PROMPT_CACHING_1H": "1",
     "ANTHROPIC_DEFAULT_HAIKU_MODEL": "deepseek-v4-flash",
    "ANTHROPIC_DEFAULT_SONNET_MODEL": "deepseek-v4-pro",
    "ANTHROPIC_DEFAULT_OPUS_MODEL": "deepseek-v4-pro[1m]",
    "skipDangerousModePermissionPrompt": "true"
  },
  "model": "opus",
  "hooks": {
    "Notification": [
      {
        "matcher": "",
        "hooks": [
          {
            "type": "command",
            "command": "~/.claude/notify.sh '⏳ 需要你的输入' && afplay /System/Library/Sounds/Hero.aiff"
          }
        ]
      }
    ],
    "Stop": [
      {
        "hooks": [
          {
            "type": "command",
            "command": "~/.claude/notify.sh '✅ 任务完成' && afplay /System/Library/Sounds/Glass.aiff"
          }
        ]
      }
    ]
  },
  "skipDangerousModePermissionPrompt": true
}
  • ~/.claude/notify.sh
#!/bin/bash
# ~/.claude/notify.sh
# 用法: notify.sh <消息> <事件类型: stop|waiting>
 
message="$1"
event_type="${2:-stop}"

activate_app() {
    local app_name="$1"

    if [ -n "$app_name" ]; then
        osascript -e "tell application \"$app_name\" to activate" >/dev/null 2>&1
    fi
}

focus_apple_terminal_tty() {
    local target_tty="${TTY:-$(tty 2>/dev/null)}"

    [ -n "$target_tty" ] || return 1

    TARGET_TTY="$target_tty" osascript >/dev/null 2>&1 <<'APPLESCRIPT'
set targetTty to system attribute "TARGET_TTY"

tell application "Terminal"
    repeat with terminalWindow in windows
        repeat with terminalTab in tabs of terminalWindow
            if tty of terminalTab is targetTty then
                set selected tab of terminalWindow to terminalTab
                set index of terminalWindow to 1
                activate
                return
            end if
        end repeat
    end repeat
end tell

error "No matching Terminal tab"
APPLESCRIPT
}

focus_iterm_tty() {
    local target_tty="${TTY:-$(tty 2>/dev/null)}"

    [ -n "$target_tty" ] || return 1

    TARGET_TTY="$target_tty" osascript >/dev/null 2>&1 <<'APPLESCRIPT'
set targetTty to system attribute "TARGET_TTY"

tell application "iTerm2"
    repeat with terminalWindow in windows
        repeat with terminalTab in tabs of terminalWindow
            repeat with terminalSession in sessions of terminalTab
                if tty of terminalSession is targetTty then
                    select terminalSession
                    select terminalTab
                    set index of terminalWindow to 1
                    activate
                    return
                end if
            end repeat
        end repeat
    end repeat
end tell

error "No matching iTerm session"
APPLESCRIPT
}

return_to_origin_app() {
    # Claude Code hooks inherit the terminal environment, so TERM_PROGRAM is the
    # best lightweight signal for returning to the app that started the task.
    case "$TERM_PROGRAM" in
        Apple_Terminal)
            focus_apple_terminal_tty && return
            activate_app "Terminal" && return
            ;;
        iTerm.app)
            focus_iterm_tty && return
            activate_app "iTerm" && return
            activate_app "iTerm2" && return
            ;;
        WezTerm)
            activate_app "WezTerm" && return
            ;;
        vscode)
            activate_app "Cursor" && return
            activate_app "Visual Studio Code" && return
            ;;
    esac

    # Fallback for Cursor-launched tasks or any environment where TERM_PROGRAM
    # is missing/ambiguous.
    activate_app "Cursor" || activate_app "Terminal"
}
 
# 获取项目名
if git rev-parse --is-inside-work-tree &>/dev/null; then
    repo_name=$(basename "$(git rev-parse --show-toplevel 2>/dev/null)")
else
    repo_name=$(basename "$(pwd)")
fi
 
# 后台发送通知,避免 Claude Code hook/手动命令被 afplay 或 say 阻塞。
(
    # ① 任务完成时直接回到发起任务的应用;识别不到时回到 Cursor。
    return_to_origin_app

    # ② 声音提示
    if [ "$event_type" = "stop" ]; then
        afplay /System/Library/Sounds/Hero.aiff
    else
        afplay /System/Library/Sounds/Glass.aiff
    fi

    # ③ 语音播报(修正:Tingting 无连字符)
    # 可替换为 Meijia(台湾)或 Sinji(粤语)
    if [ "$event_type" = "stop" ]; then
        say -v Tingting "Claude 任务完成,请查看 $repo_name"
    else
        say -v Tingting "Claude 需要你的输入"
    fi
) >/dev/null 2>&1 &

exit 0

Contributor guide

No contributing guide indexed for this repository

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

The issue only provides example contents for ~/.claude/settings.json and ~/.claude/notify.sh; no repository file or documentation location is named. First clarify whether this is intended as a tutorial addition or a correction, then verify the Claude Code hooks and macOS notification behavior before defining completion.

Written by the indexing model from the issue text.

Assessment

Tech stack
bash, macos
Domain
documentation
Issue type
Documentation
Difficulty
2/5
Estimated time
1-3 hours
Activity status
Quiet
Clarity
Needs clarification
Newbie friendliness
45/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.