diff --git a/.gitattributes b/.gitattributes
index 01edfd4..e5e1d5b 100644
--- a/.gitattributes
+++ b/.gitattributes
@@ -1,3 +1,5 @@
# 批处理脚本必须用 CRLF,否则 cmd 解析会出错
*.bat text eol=crlf
*.cmd text eol=crlf
+# shell 脚本必须用 LF
+*.sh text eol=lf
diff --git a/.gitignore b/.gitignore
index 154e127..271a104 100644
--- a/.gitignore
+++ b/.gitignore
@@ -475,3 +475,9 @@ $RECYCLE.BIN/
# Windows shortcuts
*.lnk
+
+# 引导脚本要进库(notify.exe 等仍被上面的 [Bb]in/ 忽略)
+!/bin/
+/bin/*
+!/bin/notify.cmd
+!/bin/notify.sh
diff --git a/Notify/Notify.csproj b/Notify/Notify.csproj
index ad7a96f..4bf256f 100644
--- a/Notify/Notify.csproj
+++ b/Notify/Notify.csproj
@@ -44,4 +44,38 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ <_AotJunk Include="$(PublishDir)*.dll" />
+ <_AotJunk Include="$(PublishDir)*.lib" />
+ <_AotJunk Include="$(PublishDir)*.pdb" />
+
+
+
+
diff --git a/bin/notify.cmd b/bin/notify.cmd
new file mode 100644
index 0000000..7bfbcc8
--- /dev/null
+++ b/bin/notify.cmd
@@ -0,0 +1,43 @@
+@echo off
+rem ============================================================
+rem Download URL (notify.exe is fetched from here on first run) -- edit as needed
+set "DOWNLOAD_URL=https://github.com/OWNER/REPO/releases/latest/download/notify.exe"
+rem ============================================================
+setlocal
+set "EXE=%~dp0notify.exe"
+set "LOCK=%~dp0notify.download.lock"
+
+rem only bootstrap on first run; the common path runs the exe directly (keeps piped stdin intact)
+if not exist "%EXE%" call :bootstrap
+
+if exist "%EXE%" "%EXE%" %*
+endlocal
+exit /b
+
+:bootstrap
+set "TMP=%~dp0notify.exe.%RANDOM%.tmp"
+rem mkdir is atomic; success = this process downloads, failure = someone else is downloading
+mkdir "%LOCK%" 2>nul
+if errorlevel 1 goto :waitdl
+rem double-check in case it just finished
+if exist "%EXE%" ( rmdir "%LOCK%" 2>nul & exit /b )
+rem download to temp then atomic rename, so no half-written exe is ever seen
+curl -fsSL "%DOWNLOAD_URL%" -o "%TMP%"
+if errorlevel 1 ( del "%TMP%" 2>nul & rmdir "%LOCK%" 2>nul & exit /b )
+move /y "%TMP%" "%EXE%" >nul
+rmdir "%LOCK%" 2>nul
+exit /b
+
+:waitdl
+rem did not get the lock; wait for the exe to appear (up to ~60s)
+set /a _w=0
+:waitloop
+if exist "%EXE%" exit /b
+if %_w% geq 120 (
+ rem timed out; a killed download may have left a stale lock, clear it for next time
+ rmdir "%LOCK%" 2>nul
+ exit /b
+)
+ping -n 2 127.0.0.1 >nul
+set /a _w+=1
+goto :waitloop
diff --git a/bin/notify.sh b/bin/notify.sh
new file mode 100644
index 0000000..b52bb32
--- /dev/null
+++ b/bin/notify.sh
@@ -0,0 +1,38 @@
+#!/bin/sh
+# ============================================================
+# 下载地址(首次运行从这里拉取 notify.exe)—— 按需修改
+DOWNLOAD_URL="https://github.com/OWNER/REPO/releases/latest/download/notify.exe"
+# ============================================================
+
+DIR="$(cd "$(dirname "$0")" && pwd)"
+EXE="$DIR/notify.exe"
+LOCK="$DIR/notify.download.lock"
+
+if [ ! -f "$EXE" ]; then
+ # mkdir 是原子操作,用作锁:成功=本进程负责下载,失败=已有进程在下
+ if mkdir "$LOCK" 2>/dev/null; then
+ # 双重检查,避免刚好别人下完
+ if [ ! -f "$EXE" ]; then
+ TMP="$DIR/notify.exe.$$.tmp"
+ if curl -fsSL "$DOWNLOAD_URL" -o "$TMP"; then
+ mv -f "$TMP" "$EXE" # 原子改名,避免半截 exe
+ chmod +x "$EXE" 2>/dev/null
+ else
+ rm -f "$TMP"
+ fi
+ fi
+ rmdir "$LOCK" 2>/dev/null
+ else
+ # 没抢到锁:等 exe 出现(最多约 60 秒)
+ i=0
+ while [ ! -f "$EXE" ] && [ "$i" -lt 120 ]; do
+ sleep 0.5
+ i=$((i + 1))
+ done
+ # 超时仍没下好:可能上次下载被杀留下陈旧锁,清掉让下次重下
+ [ ! -f "$EXE" ] && rmdir "$LOCK" 2>/dev/null
+ fi
+fi
+
+# 转发全部参数与 stdin 给真正的 exe
+[ -f "$EXE" ] && exec "$EXE" "$@"
diff --git a/hooks/hooks.json b/hooks/hooks.json
index 7e97fb9..44d2f26 100644
--- a/hooks/hooks.json
+++ b/hooks/hooks.json
@@ -6,8 +6,8 @@
"hooks": [
{
"type": "command",
- "command": "${CLAUDE_PLUGIN_ROOT}/bin/notify.exe save",
- "timeout": 5
+ "command": "${CLAUDE_PLUGIN_ROOT}/bin/notify.cmd save",
+ "timeout": 30
}
]
}
@@ -18,8 +18,8 @@
"hooks": [
{
"type": "command",
- "command": "${CLAUDE_PLUGIN_ROOT}/bin/notify.exe input",
- "timeout": 10
+ "command": "${CLAUDE_PLUGIN_ROOT}/bin/notify.cmd input",
+ "timeout": 30
}
]
}
@@ -30,8 +30,8 @@
"hooks": [
{
"type": "command",
- "command": "${CLAUDE_PLUGIN_ROOT}/bin/notify.exe input",
- "timeout": 10
+ "command": "${CLAUDE_PLUGIN_ROOT}/bin/notify.cmd input",
+ "timeout": 30
}
]
}
@@ -42,8 +42,8 @@
"hooks": [
{
"type": "command",
- "command": "${CLAUDE_PLUGIN_ROOT}/bin/notify.exe notify",
- "timeout": 10
+ "command": "${CLAUDE_PLUGIN_ROOT}/bin/notify.cmd notify",
+ "timeout": 30
}
]
}
@@ -54,8 +54,8 @@
"hooks": [
{
"type": "command",
- "command": "${CLAUDE_PLUGIN_ROOT}/bin/notify.exe cleanup",
- "timeout": 5
+ "command": "${CLAUDE_PLUGIN_ROOT}/bin/notify.cmd cleanup",
+ "timeout": 10
}
]
}