aico-cli 0.3.20 → 0.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/chunks/simple-config.mjs +1 -1
- package/package.json +1 -1
- package/templates/agents/aico/plan/function-point-analyzer.md +219 -0
- package/templates/agents/aico/requirement/WINDOWS_USAGE.md +478 -0
- package/templates/agents/aico/requirement/crossplatform-utils.ps1 +465 -0
- package/templates/agents/aico/requirement/requirement-aligner.md +47 -0
- package/templates/agents/aico/requirement/requirement-functions-crossplatform.ps1 +458 -0
- package/templates/agents/aico/requirement/requirement-identifier.md +43 -4
- package/templates/agents/aico/requirement/requirement-launcher.ps1 +223 -0
- package/templates/agents/aico/requirement/task-executor-validator.md +42 -0
- package/templates/agents/aico/requirement/task-executor.md +44 -0
- package/templates/agents/aico/requirement/task-splitter-validator.md +44 -2
- package/templates/agents/aico/requirement/test-crossplatform.ps1 +506 -0
- package/templates/agents/aico/requirement/test-crossplatform.sh +456 -0
- package/templates/commands/base//344/273/243/347/240/201/345/256/241/346/237/245/346/231/272/350/203/275/344/275/223.md +2 -5
- package/templates/commands/base//345/212/237/350/203/275/347/202/271/346/265/213/347/256/227.md +469 -19
- package/templates/hooks/claude-code-hooks.json +69 -0
- package/templates/hooks/notify.ps1 +1 -27
- package/templates/hooks/notify.sh +0 -23
- package/templates/hooks/scripts/Notification/bash/desktop-notifier.sh +63 -0
- package/templates/hooks/scripts/Notification/powershell/desktop-notifier.ps1 +67 -0
- package/templates/hooks/scripts/PostToolUse/bash/code-formatter.sh +73 -0
- package/templates/hooks/scripts/PostToolUse/powershell/code-formatter.ps1 +90 -0
- package/templates/hooks/scripts/PreToolUse/bash/command-logger.sh +38 -0
- package/templates/hooks/scripts/PreToolUse/bash/file-protection.sh +55 -0
- package/templates/hooks/scripts/PreToolUse/powershell/command-logger.ps1 +34 -0
- package/templates/hooks/scripts/PreToolUse/powershell/file-protection.ps1 +46 -0
- package/templates/hooks/scripts/Stop/bash/session-summary.sh +83 -0
- package/templates/hooks/scripts/Stop/powershell/session-summary.ps1 +95 -0
- package/templates/hooks/scripts/UserPromptSubmit/bash/input-notifier.sh +58 -0
- package/templates/hooks/scripts/UserPromptSubmit/powershell/input-notifier.ps1 +57 -0
- package/templates/hooks/utils/crossplatform-detector.ps1 +117 -0
- package/templates/hooks/utils/crossplatform-detector.sh +111 -0
- package/templates/personality.md +3 -3
- package/templates/settings.json +4 -4
- package/templates/agents/aico/requirement/PLATFORM_COMPATIBILITY.md +0 -219
- package/templates/hooks/claude-code-hook-config.json +0 -35
- package/templates/hooks/hooks-config.json +0 -47
- package/templates/hooks/requirement/common-utils.sh +0 -186
- package/templates/hooks/requirement/hook-utils.ps1 +0 -365
- package/templates/hooks/requirement/post-requirement-aligner.sh +0 -61
- package/templates/hooks/requirement/post-requirement-identifier.sh +0 -58
- package/templates/hooks/requirement/post-task-executor-validator.sh +0 -96
- package/templates/hooks/requirement/post-task-executor.sh +0 -78
- package/templates/hooks/requirement/post-task-splitter-validator.sh +0 -73
- package/templates/hooks/requirement/pre-requirement-aligner.sh +0 -70
- package/templates/hooks/requirement/pre-requirement-identifier.sh +0 -61
- package/templates/hooks/requirement/pre-task-executor-validator.sh +0 -81
- package/templates/hooks/requirement/pre-task-executor.sh +0 -91
- package/templates/hooks/requirement/pre-task-splitter-validator.sh +0 -61
- package/templates/test-windows-compatibility.ps1 +0 -476
|
@@ -2,15 +2,9 @@
|
|
|
2
2
|
# Claude Code notification hook script
|
|
3
3
|
# Plays pleasant sounds when Claude needs input or completes tasks
|
|
4
4
|
|
|
5
|
-
# Debug logging
|
|
6
|
-
LOG_FILE="$HOME/.claude/hooks/notify.log"
|
|
7
|
-
echo "$(date): notify.sh called with args: $@" >> "$LOG_FILE"
|
|
8
|
-
|
|
9
5
|
# Get the directory where this script is located
|
|
10
6
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
11
7
|
SOUNDS_DIR="$SCRIPT_DIR/sounds"
|
|
12
|
-
echo "Script directory: $SCRIPT_DIR" >> "$LOG_FILE"
|
|
13
|
-
echo "Sounds directory: $SOUNDS_DIR" >> "$LOG_FILE"
|
|
14
8
|
|
|
15
9
|
# Function to play a sound file with cross-platform support
|
|
16
10
|
play_sound_file() {
|
|
@@ -18,20 +12,15 @@ play_sound_file() {
|
|
|
18
12
|
|
|
19
13
|
# Check if file exists
|
|
20
14
|
if [[ ! -f "$sound_file" ]]; then
|
|
21
|
-
echo "Warning: Sound file not found: $sound_file" >&2
|
|
22
|
-
echo "Warning: Sound file not found: $sound_file" >> "$LOG_FILE"
|
|
23
15
|
return 1
|
|
24
16
|
fi
|
|
25
17
|
|
|
26
|
-
echo "Playing sound: $sound_file" >> "$LOG_FILE"
|
|
27
|
-
|
|
28
18
|
# Detect OS and use appropriate command-line audio player
|
|
29
19
|
local os_type="$(uname -s)"
|
|
30
20
|
|
|
31
21
|
case "$os_type" in
|
|
32
22
|
Darwin*) # macOS
|
|
33
23
|
if command -v afplay &> /dev/null; then
|
|
34
|
-
echo "Using afplay to play: $sound_file" >> "$LOG_FILE"
|
|
35
24
|
afplay "$sound_file" 2>/dev/null &
|
|
36
25
|
return 0 # Exit immediately after starting playback
|
|
37
26
|
fi
|
|
@@ -40,28 +29,24 @@ play_sound_file() {
|
|
|
40
29
|
Linux*) # Linux
|
|
41
30
|
# Try PulseAudio first (most common on modern desktop Linux)
|
|
42
31
|
if command -v paplay &> /dev/null; then
|
|
43
|
-
echo "Using paplay to play: $sound_file" >> "$LOG_FILE"
|
|
44
32
|
paplay "$sound_file" 2>/dev/null &
|
|
45
33
|
return 0 # Exit immediately after starting playback
|
|
46
34
|
fi
|
|
47
35
|
|
|
48
36
|
# Try ALSA
|
|
49
37
|
if command -v aplay &> /dev/null; then
|
|
50
|
-
echo "Using aplay to play: $sound_file" >> "$LOG_FILE"
|
|
51
38
|
aplay -q "$sound_file" 2>/dev/null &
|
|
52
39
|
return 0 # Exit immediately after starting playback
|
|
53
40
|
fi
|
|
54
41
|
|
|
55
42
|
# Try PipeWire (newer systems)
|
|
56
43
|
if command -v pw-play &> /dev/null; then
|
|
57
|
-
echo "Using pw-play to play: $sound_file" >> "$LOG_FILE"
|
|
58
44
|
pw-play "$sound_file" 2>/dev/null &
|
|
59
45
|
return 0 # Exit immediately after starting playback
|
|
60
46
|
fi
|
|
61
47
|
|
|
62
48
|
# Try sox play command
|
|
63
49
|
if command -v play &> /dev/null; then
|
|
64
|
-
echo "Using sox play to play: $sound_file" >> "$LOG_FILE"
|
|
65
50
|
play -q "$sound_file" 2>/dev/null &
|
|
66
51
|
return 0 # Exit immediately after starting playback
|
|
67
52
|
fi
|
|
@@ -70,7 +55,6 @@ play_sound_file() {
|
|
|
70
55
|
MINGW*|CYGWIN*|MSYS*) # Windows (Git Bash, WSL, etc.)
|
|
71
56
|
# Try PowerShell
|
|
72
57
|
if command -v powershell.exe &> /dev/null; then
|
|
73
|
-
echo "Using PowerShell to play: $sound_file" >> "$LOG_FILE"
|
|
74
58
|
# Use Windows Media Player COM object for better compatibility
|
|
75
59
|
# Run in background and exit immediately
|
|
76
60
|
powershell.exe -NoProfile -Command "
|
|
@@ -89,35 +73,28 @@ play_sound_file() {
|
|
|
89
73
|
|
|
90
74
|
# If we have ffplay (cross-platform)
|
|
91
75
|
if command -v ffplay &> /dev/null; then
|
|
92
|
-
echo "Using ffplay to play: $sound_file" >> "$LOG_FILE"
|
|
93
76
|
ffplay -nodisp -autoexit -loglevel quiet "$sound_file" 2>/dev/null &
|
|
94
77
|
return 0 # Exit immediately after starting playback
|
|
95
78
|
fi
|
|
96
79
|
|
|
97
80
|
# No audio player found - fail silently
|
|
98
|
-
echo "No audio player found" >> "$LOG_FILE"
|
|
99
81
|
return 1
|
|
100
82
|
}
|
|
101
83
|
|
|
102
84
|
# Main script logic
|
|
103
85
|
case "$1" in
|
|
104
86
|
"input")
|
|
105
|
-
echo "Input needed event triggered" >> "$LOG_FILE"
|
|
106
87
|
play_sound_file "$SOUNDS_DIR/input-needed.wav"
|
|
107
88
|
;;
|
|
108
89
|
|
|
109
90
|
"complete")
|
|
110
|
-
echo "Complete event triggered" >> "$LOG_FILE"
|
|
111
91
|
play_sound_file "$SOUNDS_DIR/complete.wav"
|
|
112
92
|
;;
|
|
113
93
|
|
|
114
94
|
*)
|
|
115
95
|
echo "Usage: $0 {input|complete}" >&2
|
|
116
|
-
echo "Usage: $0 {input|complete}" >> "$LOG_FILE"
|
|
117
96
|
echo " input - Play sound when Claude needs user input" >&2
|
|
118
|
-
echo " input - Play sound when Claude needs user input" >> "$LOG_FILE"
|
|
119
97
|
echo " complete - Play sound when Claude completes tasks" >&2
|
|
120
|
-
echo " complete - Play sound when Claude completes tasks" >> "$LOG_FILE"
|
|
121
98
|
exit 1
|
|
122
99
|
;;
|
|
123
100
|
esac
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# Notification Hook - 桌面通知器
|
|
3
|
+
# 当Claude Code发送通知时在桌面显示通知
|
|
4
|
+
|
|
5
|
+
# 加载跨平台工具
|
|
6
|
+
source "$(dirname "${BASH_SOURCE[0]}")/../../../utils/crossplatform-detector.sh"
|
|
7
|
+
|
|
8
|
+
# 读取JSON输入(如果需要分析通知内容)
|
|
9
|
+
input_json=$(cat)
|
|
10
|
+
|
|
11
|
+
# 尝试从JSON中提取通知信息
|
|
12
|
+
if command_exists jq; then
|
|
13
|
+
# 尝试提取通知相关信息(如果存在)
|
|
14
|
+
message=$(echo "$input_json" | jq -r '.message // "Claude Code 发送了通知"' 2>/dev/null)
|
|
15
|
+
title=$(echo "$input_json" | jq -r '.title // "Claude Code"' 2>/dev/null)
|
|
16
|
+
else
|
|
17
|
+
message="Claude Code 发送了通知"
|
|
18
|
+
title="Claude Code"
|
|
19
|
+
fi
|
|
20
|
+
|
|
21
|
+
# 获取操作系统类型
|
|
22
|
+
os_type=$(detect_os)
|
|
23
|
+
|
|
24
|
+
# 发送桌面通知
|
|
25
|
+
send_desktop_notification() {
|
|
26
|
+
case "$os_type" in
|
|
27
|
+
"macos")
|
|
28
|
+
# macOS 使用系统通知
|
|
29
|
+
if command_exists osascript; then
|
|
30
|
+
osascript -e "display notification \"$message\" with title \"$title\""
|
|
31
|
+
fi
|
|
32
|
+
# 播放提醒声音
|
|
33
|
+
if command_exists afplay; then
|
|
34
|
+
afplay /System/Library/Sounds/Ping.aiff 2>/dev/null &
|
|
35
|
+
fi
|
|
36
|
+
;;
|
|
37
|
+
"linux")
|
|
38
|
+
# Linux 使用notify-send
|
|
39
|
+
if command_exists notify-send; then
|
|
40
|
+
notify-send "$title" "$message"
|
|
41
|
+
fi
|
|
42
|
+
# 播放提醒声音
|
|
43
|
+
if command_exists paplay; then
|
|
44
|
+
paplay /usr/share/sounds/freedesktop/stereo/complete.oga 2>/dev/null &
|
|
45
|
+
fi
|
|
46
|
+
;;
|
|
47
|
+
"windows")
|
|
48
|
+
# Windows 使用PowerShell通知
|
|
49
|
+
if command_exists powershell.exe; then
|
|
50
|
+
powershell.exe -Command "Add-Type -AssemblyName System.Windows.Forms; [System.Windows.Forms.MessageBox]::Show('$message', '$title', [System.Windows.Forms.MessageBoxButtons]::OK, [System.Windows.Forms.MessageBoxIcon]::Information)" > /dev/null 2>&1 &
|
|
51
|
+
fi
|
|
52
|
+
;;
|
|
53
|
+
esac
|
|
54
|
+
|
|
55
|
+
# 记录通知事件
|
|
56
|
+
log_message "INFO" "桌面通知: $title - $message"
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
# 发送通知
|
|
60
|
+
send_desktop_notification
|
|
61
|
+
|
|
62
|
+
# 继续执行
|
|
63
|
+
exit 0
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
# Notification Hook - 桌面通知器
|
|
2
|
+
# 当Claude Code发送通知时在桌面显示通知
|
|
3
|
+
|
|
4
|
+
# 加载跨平台工具模块
|
|
5
|
+
. "$PSScriptRoot\..\..\..\utils\crossplatform-detector.ps1"
|
|
6
|
+
|
|
7
|
+
# 读取JSON输入
|
|
8
|
+
$inputJson = $input | ConvertFrom-SafeJson
|
|
9
|
+
|
|
10
|
+
# 尝试从JSON中提取通知信息
|
|
11
|
+
if ($inputJson) {
|
|
12
|
+
$message = if ($inputJson.message) { $inputJson.message } else { "Claude Code 发送了通知" }
|
|
13
|
+
$title = if ($inputJson.title) { $inputJson.title } else { "Claude Code" }
|
|
14
|
+
} else {
|
|
15
|
+
$message = "Claude Code 发送了通知"
|
|
16
|
+
$title = "Claude Code"
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
# 获取操作系统类型
|
|
20
|
+
$osType = Get-OperatingSystem
|
|
21
|
+
|
|
22
|
+
# 发送桌面通知的函数
|
|
23
|
+
function Send-DesktopNotification {
|
|
24
|
+
param(
|
|
25
|
+
[string]$Title,
|
|
26
|
+
[string]$Message
|
|
27
|
+
)
|
|
28
|
+
|
|
29
|
+
switch ($osType) {
|
|
30
|
+
"windows" {
|
|
31
|
+
# Windows 使用系统通知
|
|
32
|
+
try {
|
|
33
|
+
Add-Type -AssemblyName System.Windows.Forms
|
|
34
|
+
$result = [System.Windows.Forms.MessageBox]::Show($Message, $Title, [System.Windows.Forms.MessageBoxButtons]::OK, [System.Windows.Forms.MessageBoxIcon]::Information)
|
|
35
|
+
|
|
36
|
+
# 播放完成声音
|
|
37
|
+
$soundFile = [System.Environment]::GetFolderPath([System.Environment+SpecialFolder]::Windows) + "\Media\tada.wav"
|
|
38
|
+
if (Test-Path $soundFile) {
|
|
39
|
+
$player = New-Object Media.SoundPlayer $soundFile
|
|
40
|
+
$player.Play()
|
|
41
|
+
}
|
|
42
|
+
} catch {
|
|
43
|
+
Write-Host "通知发送失败: $_"
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
default {
|
|
47
|
+
# Unix/Linux/macOS 系统通知
|
|
48
|
+
if (Test-CommandExists "notify-send") {
|
|
49
|
+
notify-send $Title $Message
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
# 播放完成声音
|
|
53
|
+
if (Test-CommandExists "paplay") {
|
|
54
|
+
paplay /usr/share/sounds/freedesktop/stereo/complete.oga 2>$null
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
# 记录通知事件
|
|
60
|
+
Write-HookLog "INFO" "桌面通知: $Title - $Message"
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
# 发送通知
|
|
64
|
+
Send-DesktopNotification -Title $title -Message $message
|
|
65
|
+
|
|
66
|
+
# 继续执行
|
|
67
|
+
exit 0
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# PostToolUse Hook - 代码格式化
|
|
3
|
+
# 在文件编辑后自动格式化代码
|
|
4
|
+
|
|
5
|
+
# 加载跨平台工具
|
|
6
|
+
source "$(dirname "${BASH_SOURCE[0]}")/../../../utils/crossplatform-detector.sh"
|
|
7
|
+
|
|
8
|
+
# 读取JSON输入
|
|
9
|
+
input_json=$(cat)
|
|
10
|
+
|
|
11
|
+
# 解析文件路径
|
|
12
|
+
if command_exists jq; then
|
|
13
|
+
file_path=$(echo "$input_json" | jq -r '.tool_input.file_path' 2>/dev/null)
|
|
14
|
+
else
|
|
15
|
+
file_path=$(echo "$input_json" | grep -o '"file_path":"[^"]*"' | sed 's/"file_path":"\([^"]*\)"/\1/')
|
|
16
|
+
fi
|
|
17
|
+
|
|
18
|
+
# 如果没有文件路径或文件不存在,则跳过
|
|
19
|
+
if [ -z "$file_path" ] || [ ! -f "$file_path" ]; then
|
|
20
|
+
exit 0
|
|
21
|
+
fi
|
|
22
|
+
|
|
23
|
+
# 根据文件类型选择格式化工具
|
|
24
|
+
case "$file_path" in
|
|
25
|
+
*.ts|*.tsx)
|
|
26
|
+
# TypeScript文件 - 使用prettier
|
|
27
|
+
if command_exists npx; then
|
|
28
|
+
log_message "INFO" "格式化TypeScript文件: $file_path"
|
|
29
|
+
npx prettier --write "$file_path" 2>/dev/null
|
|
30
|
+
fi
|
|
31
|
+
;;
|
|
32
|
+
*.js|*.jsx)
|
|
33
|
+
# JavaScript文件 - 使用prettier
|
|
34
|
+
if command_exists npx; then
|
|
35
|
+
log_message "INFO" "格式化JavaScript文件: $file_path"
|
|
36
|
+
npx prettier --write "$file_path" 2>/dev/null
|
|
37
|
+
fi
|
|
38
|
+
;;
|
|
39
|
+
*.py)
|
|
40
|
+
# Python文件 - 使用black
|
|
41
|
+
if command_exists black; then
|
|
42
|
+
log_message "INFO" "格式化Python文件: $file_path"
|
|
43
|
+
black "$file_path" 2>/dev/null
|
|
44
|
+
elif command_exists python3; then
|
|
45
|
+
# 尝试使用pip安装的black
|
|
46
|
+
python3 -m black "$file_path" 2>/dev/null
|
|
47
|
+
fi
|
|
48
|
+
;;
|
|
49
|
+
*.go)
|
|
50
|
+
# Go文件 - 使用gofmt
|
|
51
|
+
if command_exists gofmt; then
|
|
52
|
+
log_message "INFO" "格式化Go文件: $file_path"
|
|
53
|
+
gofmt -w "$file_path" 2>/dev/null
|
|
54
|
+
fi
|
|
55
|
+
;;
|
|
56
|
+
*.md)
|
|
57
|
+
# Markdown文件 - 使用prettier
|
|
58
|
+
if command_exists npx; then
|
|
59
|
+
log_message "INFO" "格式化Markdown文件: $file_path"
|
|
60
|
+
npx prettier --write "$file_path" 2>/dev/null
|
|
61
|
+
fi
|
|
62
|
+
;;
|
|
63
|
+
*.json)
|
|
64
|
+
# JSON文件 - 使用jq格式化
|
|
65
|
+
if command_exists jq; then
|
|
66
|
+
log_message "INFO" "格式化JSON文件: $file_path"
|
|
67
|
+
jq . "$file_path" > "$file_path.tmp" 2>/dev/null && mv "$file_path.tmp" "$file_path"
|
|
68
|
+
fi
|
|
69
|
+
;;
|
|
70
|
+
esac
|
|
71
|
+
|
|
72
|
+
# 总是继续执行
|
|
73
|
+
exit 0
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
# PostToolUse Hook - 代码格式化
|
|
2
|
+
# 在文件编辑后自动格式化代码
|
|
3
|
+
|
|
4
|
+
# 加载跨平台工具模块
|
|
5
|
+
. "$PSScriptRoot\..\..\..\utils\crossplatform-detector.ps1"
|
|
6
|
+
|
|
7
|
+
# 读取JSON输入
|
|
8
|
+
$inputJson = $input | ConvertFrom-SafeJson
|
|
9
|
+
|
|
10
|
+
if ($inputJson -and $inputJson.tool_input.file_path) {
|
|
11
|
+
$filePath = $inputJson.tool_input.file_path
|
|
12
|
+
|
|
13
|
+
# 如果文件不存在,则跳过
|
|
14
|
+
if (-not (Test-Path $filePath)) {
|
|
15
|
+
exit 0
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
# 根据文件类型选择格式化工具
|
|
19
|
+
$extension = [System.IO.Path]::GetExtension($filePath)
|
|
20
|
+
|
|
21
|
+
switch ($extension) {
|
|
22
|
+
".ts" {
|
|
23
|
+
# TypeScript文件 - 使用prettier
|
|
24
|
+
if (Test-CommandExists "npx") {
|
|
25
|
+
Write-HookLog "INFO" "格式化TypeScript文件: $filePath"
|
|
26
|
+
try {
|
|
27
|
+
npx prettier --write $filePath 2>$null
|
|
28
|
+
} catch {
|
|
29
|
+
Write-HookLog "WARN" "格式化失败: $filePath - $($_.Exception.Message)"
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
".js" {
|
|
34
|
+
# JavaScript文件 - 使用prettier
|
|
35
|
+
if (Test-CommandExists "npx") {
|
|
36
|
+
Write-HookLog "INFO" "格式化JavaScript文件: $filePath"
|
|
37
|
+
try {
|
|
38
|
+
npx prettier --write $filePath 2>$null
|
|
39
|
+
} catch {
|
|
40
|
+
Write-HookLog "WARN" "格式化失败: $filePath - $($_.Exception.Message)"
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
".py" {
|
|
45
|
+
# Python文件 - 使用black
|
|
46
|
+
if (Test-CommandExists "black") {
|
|
47
|
+
Write-HookLog "INFO" "格式化Python文件: $filePath"
|
|
48
|
+
try {
|
|
49
|
+
black $filePath 2>$null
|
|
50
|
+
} catch {
|
|
51
|
+
Write-HookLog "WARN" "格式化失败: $filePath - $($_.Exception.Message)"
|
|
52
|
+
}
|
|
53
|
+
} elseif (Test-CommandExists "python") {
|
|
54
|
+
# 尝试使用pip安装的black
|
|
55
|
+
try {
|
|
56
|
+
python -m black $filePath 2>$null
|
|
57
|
+
} catch {
|
|
58
|
+
Write-HookLog "WARN" "格式化失败: $filePath - $($_.Exception.Message)"
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
".md" {
|
|
63
|
+
# Markdown文件 - 使用prettier
|
|
64
|
+
if (Test-CommandExists "npx") {
|
|
65
|
+
Write-HookLog "INFO" "格式化Markdown文件: $filePath"
|
|
66
|
+
try {
|
|
67
|
+
npx prettier --write $filePath 2>$null
|
|
68
|
+
} catch {
|
|
69
|
+
Write-HookLog "WARN" "格式化失败: $filePath - $($_.Exception.Message)"
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
".json" {
|
|
74
|
+
# JSON文件 - 使用jq格式化
|
|
75
|
+
if (Test-CommandExists "jq") {
|
|
76
|
+
Write-HookLog "INFO" "格式化JSON文件: $filePath"
|
|
77
|
+
try {
|
|
78
|
+
$formattedContent = jq . $filePath
|
|
79
|
+
$formattedContent | Set-Content -Path "$filePath.tmp"
|
|
80
|
+
Move-Item -Force "$filePath.tmp" $filePath
|
|
81
|
+
} catch {
|
|
82
|
+
Write-HookLog "WARN" "格式化失败: $filePath - $($_.Exception.Message)"
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
# 继续执行
|
|
90
|
+
exit 0
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# PreToolUse Hook - Bash命令日志记录器
|
|
3
|
+
# 记录所有Bash命令的执行情况
|
|
4
|
+
|
|
5
|
+
# 加载跨平台工具
|
|
6
|
+
source "$(dirname "${BASH_SOURCE[0]}")/../../../utils/crossplatform-detector.sh"
|
|
7
|
+
|
|
8
|
+
# 读取JSON输入
|
|
9
|
+
input_json=$(cat)
|
|
10
|
+
|
|
11
|
+
# 使用jq解析JSON(如果可用)
|
|
12
|
+
if command_exists jq; then
|
|
13
|
+
command=$(echo "$input_json" | jq -r '.tool_input.command' 2>/dev/null)
|
|
14
|
+
description=$(echo "$input_json" | jq -r '.tool_input.description // "No description"' 2>/dev/null)
|
|
15
|
+
else
|
|
16
|
+
# 简单的文本解析(备用方案)
|
|
17
|
+
command=$(echo "$input_json" | grep -o '"command":"[^"]*"' | sed 's/"command":"\([^"]*\)"/\1/')
|
|
18
|
+
description=$(echo "$input_json" | grep -o '"description":"[^"]*"' | sed 's/"description":"\([^"]*\)"/\1/')
|
|
19
|
+
if [ -z "$description" ]; then
|
|
20
|
+
description="No description"
|
|
21
|
+
fi
|
|
22
|
+
fi
|
|
23
|
+
|
|
24
|
+
# 记录到日志文件
|
|
25
|
+
log_file="$(get_hooks_dir)/bash-command-log.txt"
|
|
26
|
+
log_dir=$(dirname "$log_file")
|
|
27
|
+
|
|
28
|
+
# 确保日志目录存在
|
|
29
|
+
mkdir -p "$log_dir"
|
|
30
|
+
|
|
31
|
+
# 记录命令执行信息
|
|
32
|
+
echo "$(date '+%Y-%m-%d %H:%M:%S'): $command - $description" >> "$log_file"
|
|
33
|
+
|
|
34
|
+
# 记录调试信息(可选)
|
|
35
|
+
log_message "INFO" "Bash命令记录: $command - $description"
|
|
36
|
+
|
|
37
|
+
# 总是允许执行(exit 0表示继续执行)
|
|
38
|
+
exit 0
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# PreToolUse Hook - 文件保护
|
|
3
|
+
# 阻止对敏感文件的修改操作
|
|
4
|
+
|
|
5
|
+
# 加载跨平台工具
|
|
6
|
+
source "$(dirname "${BASH_SOURCE[0]}")/../../../utils/crossplatform-detector.sh"
|
|
7
|
+
|
|
8
|
+
# 读取JSON输入
|
|
9
|
+
input_json=$(cat)
|
|
10
|
+
|
|
11
|
+
# 解析文件路径
|
|
12
|
+
if command_exists jq; then
|
|
13
|
+
file_path=$(echo "$input_json" | jq -r '.tool_input.file_path' 2>/dev/null)
|
|
14
|
+
else
|
|
15
|
+
file_path=$(echo "$input_json" | grep -o '"file_path":"[^"]*"' | sed 's/"file_path":"\([^"]*\)"/\1/')
|
|
16
|
+
fi
|
|
17
|
+
|
|
18
|
+
# 如果没有文件路径,则允许执行
|
|
19
|
+
if [ -z "$file_path" ]; then
|
|
20
|
+
exit 0
|
|
21
|
+
fi
|
|
22
|
+
|
|
23
|
+
# 敏感文件/目录列表
|
|
24
|
+
sensitive_patterns=(
|
|
25
|
+
"/.env$"
|
|
26
|
+
"/package-lock.json$"
|
|
27
|
+
"/yarn.lock$"
|
|
28
|
+
"/.git/"
|
|
29
|
+
"/node_modules/"
|
|
30
|
+
"/.ssh/"
|
|
31
|
+
"/.aws/"
|
|
32
|
+
"/.config/"
|
|
33
|
+
"/.local/"
|
|
34
|
+
)
|
|
35
|
+
|
|
36
|
+
# 检查文件路径是否敏感
|
|
37
|
+
for pattern in "${sensitive_patterns[@]}"; do
|
|
38
|
+
if [[ "$file_path" =~ $pattern ]]; then
|
|
39
|
+
# 记录安全警告
|
|
40
|
+
log_message "WARN" "阻止对敏感文件的修改: $file_path"
|
|
41
|
+
|
|
42
|
+
# 输出错误信息给Claude
|
|
43
|
+
echo "错误:安全策略阻止对敏感文件的修改: $file_path" >&2
|
|
44
|
+
echo "请检查文件路径是否包含敏感信息。" >&2
|
|
45
|
+
|
|
46
|
+
# exit 2表示阻止操作
|
|
47
|
+
exit 2
|
|
48
|
+
fi
|
|
49
|
+
done
|
|
50
|
+
|
|
51
|
+
# 记录安全检查通过
|
|
52
|
+
log_message "INFO" "文件安全检查通过: $file_path"
|
|
53
|
+
|
|
54
|
+
# 允许执行
|
|
55
|
+
exit 0
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
# PreToolUse Hook - PowerShell命令日志记录器
|
|
2
|
+
# 记录所有Bash命令的执行情况
|
|
3
|
+
|
|
4
|
+
# 加载跨平台工具模块
|
|
5
|
+
$scriptDir = Split-Path -Parent $MyInvocation.MyCommand.Definition
|
|
6
|
+
. "$PSScriptRoot\..\..\..\utils\crossplatform-detector.ps1"
|
|
7
|
+
|
|
8
|
+
# 读取JSON输入
|
|
9
|
+
$inputJson = $input | ConvertFrom-SafeJson
|
|
10
|
+
|
|
11
|
+
if ($inputJson) {
|
|
12
|
+
$command = $inputJson.tool_input.command
|
|
13
|
+
$description = if ($inputJson.tool_input.description) { $inputJson.tool_input.description } else { "No description" }
|
|
14
|
+
|
|
15
|
+
# 获取日志文件路径
|
|
16
|
+
$logFile = "$(Get-HooksDirectory)\bash-command-log.txt"
|
|
17
|
+
$logDir = Split-Path -Parent $logFile
|
|
18
|
+
|
|
19
|
+
# 确保日志目录存在
|
|
20
|
+
if (-not (Test-Path $logDir)) {
|
|
21
|
+
New-Item -ItemType Directory -Path $logDir -Force | Out-Null
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
# 记录命令执行信息
|
|
25
|
+
$timestamp = Get-Date -Format "yyyy-MM-dd HH:mm:ss"
|
|
26
|
+
$logEntry = "$timestamp`: $command - $description"
|
|
27
|
+
Add-Content -Path $logFile -Value $logEntry
|
|
28
|
+
|
|
29
|
+
# 记录调试信息
|
|
30
|
+
Write-HookLog "INFO" "Bash命令记录: $command - $description"
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
# 总是允许执行(exit 0表示继续执行)
|
|
34
|
+
exit 0
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
# PreToolUse Hook - 文件保护
|
|
2
|
+
# 阻止对敏感文件的修改操作
|
|
3
|
+
|
|
4
|
+
# 加载跨平台工具模块
|
|
5
|
+
. "$PSScriptRoot\..\..\..\utils\crossplatform-detector.ps1"
|
|
6
|
+
|
|
7
|
+
# 读取JSON输入
|
|
8
|
+
$inputJson = $input | ConvertFrom-SafeJson
|
|
9
|
+
|
|
10
|
+
if ($inputJson -and $inputJson.tool_input.file_path) {
|
|
11
|
+
$filePath = $inputJson.tool_input.file_path
|
|
12
|
+
|
|
13
|
+
# 敏感文件/目录模式列表
|
|
14
|
+
$sensitivePatterns = @(
|
|
15
|
+
"\.env$",
|
|
16
|
+
"package-lock\.json$",
|
|
17
|
+
"yarn\.lock$",
|
|
18
|
+
"\.git\\",
|
|
19
|
+
"node_modules\\",
|
|
20
|
+
"\.ssh\\",
|
|
21
|
+
"\.aws\\",
|
|
22
|
+
"\.config\\",
|
|
23
|
+
"\.local\\"
|
|
24
|
+
)
|
|
25
|
+
|
|
26
|
+
# 检查文件路径是否敏感
|
|
27
|
+
foreach ($pattern in $sensitivePatterns) {
|
|
28
|
+
if ($filePath -match $pattern) {
|
|
29
|
+
# 记录安全警告
|
|
30
|
+
Write-HookLog "WARN" "阻止对敏感文件的修改: $filePath"
|
|
31
|
+
|
|
32
|
+
# 输出错误信息给Claude
|
|
33
|
+
Write-Error "错误:安全策略阻止对敏感文件的修改: $filePath"
|
|
34
|
+
Write-Error "请检查文件路径是否包含敏感信息。"
|
|
35
|
+
|
|
36
|
+
# exit 2表示阻止操作
|
|
37
|
+
exit 2
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
# 记录安全检查通过
|
|
42
|
+
Write-HookLog "INFO" "文件安全检查通过: $filePath"
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
# 允许执行
|
|
46
|
+
exit 0
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# Stop Hook - 会话摘要
|
|
3
|
+
# 当Claude Code停止响应时记录会话摘要
|
|
4
|
+
|
|
5
|
+
# 加载跨平台工具
|
|
6
|
+
source "$(dirname "${BASH_SOURCE[0]}")/../../../utils/crossplatform-detector.sh"
|
|
7
|
+
|
|
8
|
+
# 获取当前时间信息
|
|
9
|
+
timestamp=$(date '+%Y-%m-%d %H:%M:%S')
|
|
10
|
+
end_time=$(date '+%Y-%m-%d %H:%M:%S')
|
|
11
|
+
session_file="$(get_hooks_dir)/session-summary.txt"
|
|
12
|
+
|
|
13
|
+
# 确保日志目录存在
|
|
14
|
+
mkdir -p "$(dirname "$session_file")"
|
|
15
|
+
|
|
16
|
+
# 创建会话摘要
|
|
17
|
+
create_session_summary() {
|
|
18
|
+
echo "=== Claude Code 会话摘要 ===" >> "$session_file"
|
|
19
|
+
echo "结束时间: $end_time" >> "$session_file"
|
|
20
|
+
echo "工作目录: $(get_project_dir)" >> "$session_file"
|
|
21
|
+
echo "操作系统: $(detect_os)" >> "$session_file"
|
|
22
|
+
echo "" >> "$session_file"
|
|
23
|
+
|
|
24
|
+
# 统计最近的命令执行情况
|
|
25
|
+
local command_log="$(get_hooks_dir)/bash-command-log.txt"
|
|
26
|
+
if [ -f "$command_log" ]; then
|
|
27
|
+
local today_commands=$(grep "$(date '+%Y-%m-%d')" "$command_log" | wc -l)
|
|
28
|
+
echo "今日执行命令数: $today_commands" >> "$session_file"
|
|
29
|
+
|
|
30
|
+
# 显示最近的几个命令
|
|
31
|
+
echo "最近执行的命令:" >> "$session_file"
|
|
32
|
+
tail -5 "$command_log" >> "$session_file"
|
|
33
|
+
else
|
|
34
|
+
echo "今日执行命令数: 0" >> "$session_file"
|
|
35
|
+
fi
|
|
36
|
+
|
|
37
|
+
echo "" >> "$session_file"
|
|
38
|
+
echo "---" >> "$session_file"
|
|
39
|
+
echo "" >> "$session_file"
|
|
40
|
+
|
|
41
|
+
# 记录到主日志
|
|
42
|
+
log_message "INFO" "Claude Code会话结束,已生成摘要"
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
# 创建会话摘要
|
|
46
|
+
create_session_summary
|
|
47
|
+
|
|
48
|
+
# 发送完成通知(可选)
|
|
49
|
+
send_completion_notification() {
|
|
50
|
+
local os_type=$(detect_os)
|
|
51
|
+
local message="Claude Code 会话已结束"
|
|
52
|
+
local title="Claude Code"
|
|
53
|
+
|
|
54
|
+
case "$os_type" in
|
|
55
|
+
"macos")
|
|
56
|
+
if command_exists osascript; then
|
|
57
|
+
osascript -e "display notification \"$message\" with title \"$title\""
|
|
58
|
+
fi
|
|
59
|
+
if command_exists afplay; then
|
|
60
|
+
afplay /System/Library/Sounds/Glass.aiff 2>/dev/null &
|
|
61
|
+
fi
|
|
62
|
+
;;
|
|
63
|
+
"linux")
|
|
64
|
+
if command_exists notify-send; then
|
|
65
|
+
notify-send "$title" "$message"
|
|
66
|
+
fi
|
|
67
|
+
if command_exists paplay; then
|
|
68
|
+
paplay /usr/share/sounds/freedesktop/stereo/complete.oga 2>/dev/null &
|
|
69
|
+
fi
|
|
70
|
+
;;
|
|
71
|
+
"windows")
|
|
72
|
+
if command_exists powershell.exe; then
|
|
73
|
+
powershell.exe -Command "Add-Type -AssemblyName System.Windows.Forms; [System.Windows.Forms.MessageBox]::Show('$message', '$title', [System.Windows.Forms.MessageBoxButtons]::OK, [System.Windows.Forms.MessageBoxIcon]::Information)" > /dev/null 2>&1 &
|
|
74
|
+
fi
|
|
75
|
+
;;
|
|
76
|
+
esac
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
# 发送完成通知
|
|
80
|
+
send_completion_notification
|
|
81
|
+
|
|
82
|
+
# 继续执行
|
|
83
|
+
exit 0
|