zco-claude 0.0.8__py3-none-any.whl
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.
- ClaudeSettings/DOT.claudeignore +7 -0
- ClaudeSettings/README.md +100 -0
- ClaudeSettings/commands/generate_changelog.sh +49 -0
- ClaudeSettings/commands/show_env +92 -0
- ClaudeSettings/commands/zco-clean +164 -0
- ClaudeSettings/commands/zco-git-summary +15 -0
- ClaudeSettings/commands/zco-git-tag +42 -0
- ClaudeSettings/hooks/CHANGELOG.md +157 -0
- ClaudeSettings/hooks/README.md +254 -0
- ClaudeSettings/hooks/save_chat_plain.py +148 -0
- ClaudeSettings/hooks/save_chat_spec.py +398 -0
- ClaudeSettings/rules/README.md +270 -0
- ClaudeSettings/rules/go/.golangci.yml.template +170 -0
- ClaudeSettings/rules/go/GoBuildAutoVersion.v250425.md +95 -0
- ClaudeSettings/rules/go/check-standards.sh +128 -0
- ClaudeSettings/rules/go/coding-standards.md +973 -0
- ClaudeSettings/rules/go/example.go +207 -0
- ClaudeSettings/rules/go/go-testing.md +691 -0
- ClaudeSettings/rules/go/list-comments.sh +85 -0
- ClaudeSettings/settings.sample.json +71 -0
- ClaudeSettings/skills/README.md +225 -0
- ClaudeSettings/skills/zco-docs-update/SKILL.md +381 -0
- ClaudeSettings/skills/zco-help/SKILL.md +601 -0
- ClaudeSettings/skills/zco-plan/SKILL.md +661 -0
- ClaudeSettings/skills/zco-plan-new/SKILL.md +585 -0
- ClaudeSettings/zco-scripts/co-docs-update.sh +150 -0
- ClaudeSettings/zco-scripts/test_update_plan_metadata.py +328 -0
- ClaudeSettings/zco-scripts/update-plan-metadata.py +324 -0
- zco_claude-0.0.8.dist-info/METADATA +190 -0
- zco_claude-0.0.8.dist-info/RECORD +34 -0
- zco_claude-0.0.8.dist-info/WHEEL +5 -0
- zco_claude-0.0.8.dist-info/entry_points.txt +3 -0
- zco_claude-0.0.8.dist-info/top_level.txt +1 -0
- zco_claude_init.py +1732 -0
ClaudeSettings/README.md
ADDED
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
# Claude Code 配置说明
|
|
2
|
+
|
|
3
|
+
本目录包含 Claude Code 的项目配置文件。
|
|
4
|
+
|
|
5
|
+
## 配置文件
|
|
6
|
+
|
|
7
|
+
### `settings.json`
|
|
8
|
+
项目级别的配置,包含了从以下文件转换而来的排除规则:
|
|
9
|
+
- 项目的 `.gitignore`
|
|
10
|
+
- 全局的 `~/.gitignore_global`
|
|
11
|
+
|
|
12
|
+
该配置确保 Claude Code 在分析代码时忽略:
|
|
13
|
+
- 构建产物和二进制文件
|
|
14
|
+
- IDE 配置文件 (.idea, .vscode, .DS_Store)
|
|
15
|
+
- 日志文件
|
|
16
|
+
- 临时文件和备份
|
|
17
|
+
- Python/Go 的依赖和缓存
|
|
18
|
+
- 敏感配置文件 (.env, conf/app.conf)
|
|
19
|
+
- 本地数据目录 (var, data, logs)
|
|
20
|
+
|
|
21
|
+
## 文件说明
|
|
22
|
+
|
|
23
|
+
| 文件 | 用途 | 是否提交到 Git |
|
|
24
|
+
|------|------|---------------|
|
|
25
|
+
| `settings.json` | 团队共享配置 | ✅ 是 |
|
|
26
|
+
| `settings.local.json` | 个人本地配置 | ❌ 否 (自动忽略) |
|
|
27
|
+
|
|
28
|
+
## 使用方法
|
|
29
|
+
|
|
30
|
+
配置已自动生效,无需额外操作。Claude Code 将自动读取此配置。
|
|
31
|
+
|
|
32
|
+
## 维护说明
|
|
33
|
+
|
|
34
|
+
### 当修改 .gitignore 时
|
|
35
|
+
|
|
36
|
+
由于 Claude Code 不会自动同步 `.gitignore` 的更改,当你更新项目的 `.gitignore` 或全局的 `~/.gitignore_global` 时,需要手动更新 `settings.json`。
|
|
37
|
+
|
|
38
|
+
可以使用以下方法:
|
|
39
|
+
|
|
40
|
+
1. **手动添加规则**
|
|
41
|
+
在 `settings.json` 的 `permissions.deny` 数组中添加新规则:
|
|
42
|
+
```json
|
|
43
|
+
"Read(./新增目录)",
|
|
44
|
+
"Read(./新增目录/**)"
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
2. **请求 Claude 重新生成**
|
|
48
|
+
告诉 Claude:
|
|
49
|
+
```
|
|
50
|
+
请重新读取 .gitignore 和 ~/.gitignore_global,更新 .claude/settings.json
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
### 常见排除模式
|
|
54
|
+
|
|
55
|
+
```json
|
|
56
|
+
{
|
|
57
|
+
"permissions": {
|
|
58
|
+
"deny": [
|
|
59
|
+
"Read(./单个文件.txt)", // 排除单个文件
|
|
60
|
+
"Read(./目录)", // 排除目录
|
|
61
|
+
"Read(./目录/**)", // 排除目录及所有子内容
|
|
62
|
+
"Read(**/*.扩展名)", // 排除所有该扩展名文件
|
|
63
|
+
"Read(**/目录名)", // 排除所有该名称的目录
|
|
64
|
+
"Read(**/目录名/**)" // 排除所有该名称目录的内容
|
|
65
|
+
]
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
## 个人配置
|
|
71
|
+
|
|
72
|
+
如果你有个人专属的排除需求,创建 `settings.local.json`:
|
|
73
|
+
|
|
74
|
+
```bash
|
|
75
|
+
cat > .claude/settings.local.json << 'EOF'
|
|
76
|
+
{
|
|
77
|
+
"permissions": {
|
|
78
|
+
"deny": [
|
|
79
|
+
"Read(./my-personal-notes)",
|
|
80
|
+
"Read(./my-personal-notes/**)"
|
|
81
|
+
]
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
EOF
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
该文件不会被提交到 Git(已在 .gitignore 中忽略)。
|
|
88
|
+
|
|
89
|
+
## 验证配置
|
|
90
|
+
|
|
91
|
+
测试配置是否生效:
|
|
92
|
+
|
|
93
|
+
```bash
|
|
94
|
+
# 在 Claude Code 会话中尝试读取被排除的文件
|
|
95
|
+
# 应该会被阻止
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
## 更新历史
|
|
99
|
+
|
|
100
|
+
- 2026-01-06: 初始配置,基于项目 .gitignore 和 ~/.gitignore_global
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
|
|
3
|
+
# 获取所有 yj3d-prod.v25* tags,按时间倒序
|
|
4
|
+
tags=$(git tag -l "yj3d-prod.v25*" --sort=-version:refname)
|
|
5
|
+
|
|
6
|
+
# 转换为数组
|
|
7
|
+
tag_array=($tags)
|
|
8
|
+
|
|
9
|
+
echo "找到 ${#tag_array[@]} 个 tags"
|
|
10
|
+
|
|
11
|
+
# 输出前 5 个 tag 的信息
|
|
12
|
+
for i in {0..4}; do
|
|
13
|
+
if [ $i -ge ${#tag_array[@]} ]; then
|
|
14
|
+
break
|
|
15
|
+
fi
|
|
16
|
+
|
|
17
|
+
current_tag="${tag_array[$i]}"
|
|
18
|
+
|
|
19
|
+
# 提取版本号 (去掉 yj3d-prod.v 前缀)
|
|
20
|
+
version="${current_tag#yj3d-prod.v}"
|
|
21
|
+
|
|
22
|
+
# 格式化版本号为 YY.MM.DD
|
|
23
|
+
formatted_version="${version:0:2}.${version:2:2}.${version:4:2}"
|
|
24
|
+
|
|
25
|
+
echo ""
|
|
26
|
+
echo "## v${formatted_version}"
|
|
27
|
+
|
|
28
|
+
# 获取到前一个 tag 的 commits
|
|
29
|
+
if [ $((i+1)) -lt ${#tag_array[@]} ]; then
|
|
30
|
+
prev_tag="${tag_array[$((i+1))]}"
|
|
31
|
+
|
|
32
|
+
# 获取 commits,按类型分组
|
|
33
|
+
commits=$(git log ${prev_tag}..${current_tag} --oneline --no-merges --format="%s")
|
|
34
|
+
|
|
35
|
+
# 分类处理
|
|
36
|
+
echo "$commits" | grep -i "^feat:" | sed 's/^feat: */- **feat**: /'
|
|
37
|
+
echo "$commits" | grep -i "^fix:" | sed 's/^fix: */- **fix**: /'
|
|
38
|
+
echo "$commits" | grep -i "^fixed:" | sed 's/^fixed: */- **fix**: /'
|
|
39
|
+
echo "$commits" | grep -i "^tofix:" | sed 's/^tofix: */- **fix**: /'
|
|
40
|
+
echo "$commits" | grep -i "^api:" | sed 's/^api: */- **api**: /'
|
|
41
|
+
echo "$commits" | grep -i "^chore:" | sed 's/^chore: */- **chore**: /'
|
|
42
|
+
echo "$commits" | grep -i "^dbm:" | sed 's/^dbm: */- **dbm**: /'
|
|
43
|
+
echo "$commits" | grep -i "^ci:" | sed 's/^ci: */- **ci**: /'
|
|
44
|
+
echo "$commits" | grep -i "^doc:" | sed 's/^doc: */- **doc**: /'
|
|
45
|
+
|
|
46
|
+
# 其他未分类的
|
|
47
|
+
echo "$commits" | grep -iv "^feat:\|^fix:\|^fixed:\|^tofix:\|^api:\|^chore:\|^dbm:\|^ci:\|^doc:" | sed 's/^/- /'
|
|
48
|
+
fi
|
|
49
|
+
done
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""
|
|
3
|
+
Display current Claude CLI session environment variables
|
|
4
|
+
|
|
5
|
+
Usage:
|
|
6
|
+
show_env # Show filtered env vars (default)
|
|
7
|
+
show_env --all # Show all env vars and save to _.env.txt
|
|
8
|
+
|
|
9
|
+
Default filters: AN, ACCESS, YJ, CODE, CLAUDE, KEY, IN
|
|
10
|
+
"""
|
|
11
|
+
import os
|
|
12
|
+
import sys
|
|
13
|
+
import argparse
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
DEFAULT_FILTERS = ['AN', 'ACCESS', 'YJ', 'CODE', 'CLAUDE', 'KEY', 'IN']
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def should_show_var(var_name, filters):
|
|
20
|
+
"""Check if variable name contains any filter keyword"""
|
|
21
|
+
var_upper = var_name.upper()
|
|
22
|
+
return any(f in var_upper for f in filters)
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
def main():
|
|
26
|
+
parser = argparse.ArgumentParser(
|
|
27
|
+
description='Show Claude CLI environment variables',
|
|
28
|
+
formatter_class=argparse.RawDescriptionHelpFormatter,
|
|
29
|
+
epilog="""
|
|
30
|
+
Examples:
|
|
31
|
+
show_env Show filtered environment variables
|
|
32
|
+
show_env --all Show all variables and save to _.env.txt
|
|
33
|
+
|
|
34
|
+
Default filters: AN, ACCESS, YJ, CODE, CLAUDE, KEY, IN
|
|
35
|
+
"""
|
|
36
|
+
)
|
|
37
|
+
parser.add_argument(
|
|
38
|
+
'--all',
|
|
39
|
+
action='store_true',
|
|
40
|
+
help='Show all environment variables and save to _.env.txt'
|
|
41
|
+
)
|
|
42
|
+
|
|
43
|
+
args = parser.parse_args()
|
|
44
|
+
|
|
45
|
+
env_vars = dict(os.environ)
|
|
46
|
+
|
|
47
|
+
if args.all:
|
|
48
|
+
# Show and save all environment variables
|
|
49
|
+
output_file = '_.env.txt'
|
|
50
|
+
print("📋 All Environment Variables\n")
|
|
51
|
+
|
|
52
|
+
with open(output_file, 'w', encoding='utf-8') as f:
|
|
53
|
+
f.write("# Environment Variables\n")
|
|
54
|
+
f.write(f"# Generated: {__import__('datetime').datetime.now().strftime('%Y-%m-%d %H:%M:%S')}\n\n")
|
|
55
|
+
|
|
56
|
+
for key in sorted(env_vars.keys()):
|
|
57
|
+
line = f"{key}={env_vars[key]}"
|
|
58
|
+
print(line)
|
|
59
|
+
f.write(line + '\n')
|
|
60
|
+
|
|
61
|
+
print(f"\n✅ All {len(env_vars)} environment variables saved to: {output_file}")
|
|
62
|
+
|
|
63
|
+
else:
|
|
64
|
+
# Show filtered environment variables
|
|
65
|
+
print("🔧 Claude CLI Environment Variables (Filtered)\n")
|
|
66
|
+
print(f"Filters: {', '.join(DEFAULT_FILTERS)}\n")
|
|
67
|
+
|
|
68
|
+
shown_vars = {}
|
|
69
|
+
for key in sorted(env_vars.keys()):
|
|
70
|
+
if should_show_var(key, DEFAULT_FILTERS):
|
|
71
|
+
shown_vars[key] = env_vars[key]
|
|
72
|
+
|
|
73
|
+
if not shown_vars:
|
|
74
|
+
print("(No matching variables found)")
|
|
75
|
+
else:
|
|
76
|
+
max_key_len = max(len(k) for k in shown_vars.keys())
|
|
77
|
+
for key, value in shown_vars.items():
|
|
78
|
+
print(f"{key:<{max_key_len}} = {value}")
|
|
79
|
+
|
|
80
|
+
print(f"\n✅ Showing {len(shown_vars)} of {len(env_vars)} variables")
|
|
81
|
+
print("💡 Use --all to see all environment variables")
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
if __name__ == '__main__':
|
|
85
|
+
try:
|
|
86
|
+
main()
|
|
87
|
+
except KeyboardInterrupt:
|
|
88
|
+
print("\n\nInterrupted by user")
|
|
89
|
+
sys.exit(1)
|
|
90
|
+
except Exception as e:
|
|
91
|
+
print(f"Error: {e}", file=sys.stderr)
|
|
92
|
+
sys.exit(1)
|
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""
|
|
3
|
+
Clean old log files from Claude conversation history
|
|
4
|
+
|
|
5
|
+
Usage:
|
|
6
|
+
zco-clean # Clean files older than 30 days
|
|
7
|
+
zco-clean --days 7 # Clean files older than 7 days
|
|
8
|
+
zco-clean --dir custom_logs # Clean custom directory
|
|
9
|
+
zco-clean --dry-run # Show what would be deleted
|
|
10
|
+
|
|
11
|
+
Environment Variables:
|
|
12
|
+
YJ_CLAUDE_CHAT_SAVE_DIR: Default directory to clean (default: _.claude_hist)
|
|
13
|
+
"""
|
|
14
|
+
import os
|
|
15
|
+
import sys
|
|
16
|
+
import argparse
|
|
17
|
+
from pathlib import Path
|
|
18
|
+
from datetime import datetime, timedelta
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def clean_old_files(directory, days, dry_run=False):
|
|
22
|
+
"""Delete files older than specified days"""
|
|
23
|
+
target_dir = Path(directory)
|
|
24
|
+
|
|
25
|
+
if not target_dir.exists():
|
|
26
|
+
print(f"❌ Error: Directory does not exist: {directory}")
|
|
27
|
+
return 0, 0
|
|
28
|
+
|
|
29
|
+
if not target_dir.is_dir():
|
|
30
|
+
print(f"❌ Error: Not a directory: {directory}")
|
|
31
|
+
return 0, 0
|
|
32
|
+
|
|
33
|
+
cutoff_date = datetime.now() - timedelta(days=days)
|
|
34
|
+
|
|
35
|
+
# Find all markdown and text files
|
|
36
|
+
all_files = list(target_dir.glob('*.md')) + list(target_dir.glob('*.txt'))
|
|
37
|
+
old_files = []
|
|
38
|
+
|
|
39
|
+
for file_path in all_files:
|
|
40
|
+
if file_path.is_file():
|
|
41
|
+
mtime = datetime.fromtimestamp(file_path.stat().st_mtime)
|
|
42
|
+
if mtime < cutoff_date:
|
|
43
|
+
old_files.append((file_path, mtime))
|
|
44
|
+
|
|
45
|
+
if not all_files:
|
|
46
|
+
print(f"ℹ️ No files found in {directory}")
|
|
47
|
+
return 0, 0
|
|
48
|
+
|
|
49
|
+
deleted_count = 0
|
|
50
|
+
|
|
51
|
+
if old_files:
|
|
52
|
+
if dry_run:
|
|
53
|
+
print(f"\n📝 Files that would be deleted:\n")
|
|
54
|
+
else:
|
|
55
|
+
print(f"\n🗑️ Deleting old files:\n")
|
|
56
|
+
|
|
57
|
+
# Sort by modification time (oldest first)
|
|
58
|
+
old_files.sort(key=lambda x: x[1])
|
|
59
|
+
|
|
60
|
+
for file_path, mtime in old_files:
|
|
61
|
+
age_days = (datetime.now() - mtime).days
|
|
62
|
+
age_str = f"({age_days} days old)"
|
|
63
|
+
|
|
64
|
+
if dry_run:
|
|
65
|
+
print(f" - {file_path.name} {age_str}")
|
|
66
|
+
else:
|
|
67
|
+
try:
|
|
68
|
+
file_path.unlink()
|
|
69
|
+
print(f" ✓ {file_path.name} {age_str}")
|
|
70
|
+
deleted_count += 1
|
|
71
|
+
except Exception as e:
|
|
72
|
+
print(f" ✗ {file_path.name} - Error: {e}")
|
|
73
|
+
else:
|
|
74
|
+
print(f"\nℹ️ No files older than {days} days found")
|
|
75
|
+
|
|
76
|
+
remaining_count = len(all_files) - deleted_count
|
|
77
|
+
|
|
78
|
+
return deleted_count, remaining_count
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
def main():
|
|
82
|
+
parser = argparse.ArgumentParser(
|
|
83
|
+
description='Clean old Claude conversation logs',
|
|
84
|
+
formatter_class=argparse.RawDescriptionHelpFormatter,
|
|
85
|
+
epilog="""
|
|
86
|
+
Examples:
|
|
87
|
+
zco-clean Clean default directory (30 days)
|
|
88
|
+
zco-clean --days 7 Clean files older than 7 days
|
|
89
|
+
zco-clean --dir my_logs Clean custom directory
|
|
90
|
+
zco-clean --dry-run Preview what would be deleted
|
|
91
|
+
|
|
92
|
+
Environment Variable:
|
|
93
|
+
YJ_CLAUDE_CHAT_SAVE_DIR Default directory (if --dir not specified)
|
|
94
|
+
"""
|
|
95
|
+
)
|
|
96
|
+
|
|
97
|
+
parser.add_argument(
|
|
98
|
+
'--days',
|
|
99
|
+
type=int,
|
|
100
|
+
default=30,
|
|
101
|
+
help='Delete files older than N days (default: 30)'
|
|
102
|
+
)
|
|
103
|
+
|
|
104
|
+
parser.add_argument(
|
|
105
|
+
'--dir',
|
|
106
|
+
type=str,
|
|
107
|
+
default=None,
|
|
108
|
+
help='Directory to clean (default: YJ_CLAUDE_CHAT_SAVE_DIR or _.claude_hist)'
|
|
109
|
+
)
|
|
110
|
+
|
|
111
|
+
parser.add_argument(
|
|
112
|
+
'--dry-run',
|
|
113
|
+
action='store_true',
|
|
114
|
+
help='Show what would be deleted without actually deleting'
|
|
115
|
+
)
|
|
116
|
+
|
|
117
|
+
args = parser.parse_args()
|
|
118
|
+
|
|
119
|
+
# Validate days parameter
|
|
120
|
+
if args.days < 0:
|
|
121
|
+
print(f"❌ Error: --days must be a positive number (got: {args.days})")
|
|
122
|
+
sys.exit(1)
|
|
123
|
+
|
|
124
|
+
# Determine directory
|
|
125
|
+
if args.dir:
|
|
126
|
+
target_dir = args.dir
|
|
127
|
+
else:
|
|
128
|
+
target_dir = os.environ.get('YJ_CLAUDE_CHAT_SAVE_DIR', '_.claude_hist')
|
|
129
|
+
|
|
130
|
+
print("=" * 60)
|
|
131
|
+
print("🧹 Claude Chat Log Cleanup")
|
|
132
|
+
print("=" * 60)
|
|
133
|
+
print(f"📂 Directory: {target_dir}")
|
|
134
|
+
print(f"📅 Delete files older than: {args.days} days")
|
|
135
|
+
|
|
136
|
+
if args.dry_run:
|
|
137
|
+
print("⚠️ DRY RUN MODE (no files will be actually deleted)")
|
|
138
|
+
|
|
139
|
+
print("=" * 60)
|
|
140
|
+
|
|
141
|
+
deleted, remaining = clean_old_files(target_dir, args.days, args.dry_run)
|
|
142
|
+
|
|
143
|
+
print("\n" + "=" * 60)
|
|
144
|
+
print("📊 Summary")
|
|
145
|
+
print("=" * 60)
|
|
146
|
+
print(f"✅ {'Would delete' if args.dry_run else 'Deleted'}: {deleted} file(s)")
|
|
147
|
+
print(f"📁 Remaining: {remaining} file(s)")
|
|
148
|
+
print("=" * 60)
|
|
149
|
+
|
|
150
|
+
if args.dry_run and deleted > 0:
|
|
151
|
+
print("\n💡 Run without --dry-run to actually delete files")
|
|
152
|
+
|
|
153
|
+
|
|
154
|
+
if __name__ == '__main__':
|
|
155
|
+
try:
|
|
156
|
+
main()
|
|
157
|
+
except KeyboardInterrupt:
|
|
158
|
+
print("\n\n⚠️ Interrupted by user")
|
|
159
|
+
sys.exit(1)
|
|
160
|
+
except Exception as e:
|
|
161
|
+
print(f"❌ Error: {e}", file=sys.stderr)
|
|
162
|
+
import traceback
|
|
163
|
+
traceback.print_exc(file=sys.stderr)
|
|
164
|
+
sys.exit(1)
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# git-summary - 显示 Git 仓库摘要
|
|
3
|
+
|
|
4
|
+
echo "📊 Git Repository Summary"
|
|
5
|
+
echo "========================"
|
|
6
|
+
echo ""
|
|
7
|
+
echo "📍 Branch: $(git branch --show-current)"
|
|
8
|
+
echo "📝 Commit: $(git rev-parse --short HEAD)"
|
|
9
|
+
echo "👤 Author: $(git config user.name)"
|
|
10
|
+
echo ""
|
|
11
|
+
echo "📈 Recent commits:"
|
|
12
|
+
git log --oneline -5
|
|
13
|
+
echo ""
|
|
14
|
+
echo "📊 Status:"
|
|
15
|
+
git status --short
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
## desc: show git tag info
|
|
3
|
+
## usage: zco-git-tag [RepoDir]
|
|
4
|
+
## author: ningrong@minieye.com
|
|
5
|
+
## version: v1.2024.11.24
|
|
6
|
+
|
|
7
|
+
zco_git_tag_() {
|
|
8
|
+
local x_entry=${1:-$(pwd)}
|
|
9
|
+
local x_root=$(cd $x_entry && git rev-parse --show-toplevel 2>/dev/null)
|
|
10
|
+
if [[ -z "${x_root}" ]]; then
|
|
11
|
+
echo "[error]: 这不是一个仓库:" $x_entry
|
|
12
|
+
exit 1
|
|
13
|
+
fi
|
|
14
|
+
local x_commit_id=$(cd $x_root && git rev-parse --short=8 HEAD 2>/dev/null)
|
|
15
|
+
local x_branch=$(cd $x_root && git rev-parse --abbrev-ref HEAD 2>/dev/null)
|
|
16
|
+
local x_commit_dt=$(cd $x_root && git show -s --format=%cd --date=format:'%y%m%d_%H%M' 2>/dev/null)
|
|
17
|
+
#local x_dirty_st1=$(cd $x_root && git diff --staged | wc -l 2>/dev/null)
|
|
18
|
+
#local x_dirty_st=$(cd $x_root && git diff --all | wc -l 2>/dev/null)
|
|
19
|
+
local x_dirty_st1=$(cd $x_root && git diff --staged | wc -l 2>/dev/null)
|
|
20
|
+
local x_dirty_st2=$(cd $x_root && git diff | wc -l 2>/dev/null)
|
|
21
|
+
if [[ -z "${x_dirty_st1}" && -z "${x_dirty_st2}" ]]; then
|
|
22
|
+
echo "Y${x_commit_dt}.${x_commit_id}"
|
|
23
|
+
else
|
|
24
|
+
echo "Y${x_commit_dt}.${x_commit_id}.${x_branch}.X"
|
|
25
|
+
fi
|
|
26
|
+
return 0
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
############################################
|
|
30
|
+
##; Run Main
|
|
31
|
+
if [ $# -eq 0 ]; then
|
|
32
|
+
zco_git_tag_ $(pwd)
|
|
33
|
+
elif [[ $1 == "help" || $1 == "--help" || $1 == "-h" || $# -gt 1 ]]; then
|
|
34
|
+
decho "[entry] $0"
|
|
35
|
+
decho "[usage] show git tag info"
|
|
36
|
+
decho "[eg0]: $(basename $0) <RepoDir>"
|
|
37
|
+
if [[ $# -gt 1 ]]; then
|
|
38
|
+
exit 1
|
|
39
|
+
fi
|
|
40
|
+
else
|
|
41
|
+
zco_git_tag_ $1
|
|
42
|
+
fi
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
# Hooks 变更日志
|
|
2
|
+
|
|
3
|
+
## 2026-01-06 - 增强版发布
|
|
4
|
+
|
|
5
|
+
### 新增功能
|
|
6
|
+
|
|
7
|
+
#### save-conversation-enhanced.py(增强版)
|
|
8
|
+
|
|
9
|
+
相比标准版,新增以下功能:
|
|
10
|
+
|
|
11
|
+
1. **📚 参考资源记录**
|
|
12
|
+
- 自动提取并记录所有引用的资源
|
|
13
|
+
- 支持的资源类型:
|
|
14
|
+
- 🌐 网络 URLs(WebFetch、WebSearch)
|
|
15
|
+
- 📄 本地文件路径(Read 工具)
|
|
16
|
+
- 🤖 Agent 调用(Task 工具)
|
|
17
|
+
|
|
18
|
+
2. **🔧 工具调用统计**
|
|
19
|
+
- 记录使用了哪些工具
|
|
20
|
+
- 统计每个工具的调用次数
|
|
21
|
+
- 在文档头部显示摘要
|
|
22
|
+
|
|
23
|
+
3. **📋 详细的工具调用记录**
|
|
24
|
+
- 在附录中记录每个工具的完整调用参数
|
|
25
|
+
- JSON 格式展示,便于调试和回溯
|
|
26
|
+
|
|
27
|
+
4. **🗂️ 独立的资源列表文件**
|
|
28
|
+
- 为每次对话生成独立的资源列表文件
|
|
29
|
+
- 文件名:`{timestamp}_{keywords}_resources.txt`
|
|
30
|
+
- 便于批量处理和检索
|
|
31
|
+
|
|
32
|
+
### 文件对比
|
|
33
|
+
|
|
34
|
+
| 功能 | 标准版 | 增强版 |
|
|
35
|
+
|------|--------|--------|
|
|
36
|
+
| 保存对话内容 | ✅ | ✅ |
|
|
37
|
+
| 提取关键词 | ✅ | ✅ |
|
|
38
|
+
| 记录参考资源 | ❌ | ✅ |
|
|
39
|
+
| 工具使用统计 | ❌ | ✅ |
|
|
40
|
+
| 工具调用详情 | ❌ | ✅ |
|
|
41
|
+
| 独立资源列表 | ❌ | ✅ |
|
|
42
|
+
| 性能开销 | 低 | 中等 |
|
|
43
|
+
|
|
44
|
+
### 输出示例
|
|
45
|
+
|
|
46
|
+
#### 对话文件(26010614_API文档_生成.md)
|
|
47
|
+
|
|
48
|
+
```markdown
|
|
49
|
+
# Claude Code 对话记录
|
|
50
|
+
|
|
51
|
+
**时间**: 2026-01-06 14:30:00
|
|
52
|
+
|
|
53
|
+
## 📚 参考资源
|
|
54
|
+
|
|
55
|
+
- 🤖 Agent: claude-code-guide
|
|
56
|
+
- 🤖 Agent: Explore
|
|
57
|
+
- 📄 /path/to/routers/router.go
|
|
58
|
+
- 📄 /path/to/models/auth/jwt.go
|
|
59
|
+
|
|
60
|
+
**使用工具**: 8 次
|
|
61
|
+
- Read: 5 次
|
|
62
|
+
- Task: 2 次
|
|
63
|
+
- Bash: 1 次
|
|
64
|
+
|
|
65
|
+
---
|
|
66
|
+
|
|
67
|
+
## 👤 用户提问 #1
|
|
68
|
+
|
|
69
|
+
请为我遍历项目的 API 接口...
|
|
70
|
+
|
|
71
|
+
## 🤖 Claude 回答 #1
|
|
72
|
+
|
|
73
|
+
好的!我来帮你遍历...
|
|
74
|
+
|
|
75
|
+
---
|
|
76
|
+
|
|
77
|
+
## 📋 附录:工具调用详情
|
|
78
|
+
|
|
79
|
+
### 工具 1: Task
|
|
80
|
+
```json
|
|
81
|
+
{
|
|
82
|
+
"subagent_type": "Explore",
|
|
83
|
+
"prompt": "探索项目 API 结构..."
|
|
84
|
+
}
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
---
|
|
88
|
+
*自动生成于 2026-01-06 14:30:00*
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
#### 资源列表文件(26010614_API文档_生成_resources.txt)
|
|
92
|
+
|
|
93
|
+
```
|
|
94
|
+
# 参考资源
|
|
95
|
+
# 生成时间: 2026-01-06 14:30:00
|
|
96
|
+
# 对话文件: 26010614_API文档_生成.md
|
|
97
|
+
|
|
98
|
+
🤖 Agent: Explore
|
|
99
|
+
🤖 Agent: claude-code-guide
|
|
100
|
+
📄 /home/lane/.../routers/router.go
|
|
101
|
+
📄 /home/lane/.../models/auth/jwt.go
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
### 如何切换版本
|
|
105
|
+
|
|
106
|
+
编辑 `.claude/settings.json`:
|
|
107
|
+
|
|
108
|
+
```json
|
|
109
|
+
{
|
|
110
|
+
"hooks": {
|
|
111
|
+
"Stop": [
|
|
112
|
+
{
|
|
113
|
+
"hooks": [
|
|
114
|
+
{
|
|
115
|
+
"type": "command",
|
|
116
|
+
// 标准版:
|
|
117
|
+
// "command": "python3 \"$CLAUDE_PROJECT_DIR\"/.claude/hooks/save-conversation.py"
|
|
118
|
+
|
|
119
|
+
// 增强版(当前):
|
|
120
|
+
"command": "python3 \"$CLAUDE_PROJECT_DIR\"/.claude/hooks/save-conversation-enhanced.py"
|
|
121
|
+
}
|
|
122
|
+
]
|
|
123
|
+
}
|
|
124
|
+
]
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
### 性能说明
|
|
130
|
+
|
|
131
|
+
- **标准版**: 处理时间 < 100ms,适合频繁对话
|
|
132
|
+
- **增强版**: 处理时间 100-300ms,适合需要详细记录的场景
|
|
133
|
+
|
|
134
|
+
### 推荐使用场景
|
|
135
|
+
|
|
136
|
+
#### 标准版适合:
|
|
137
|
+
- 日常快速对话
|
|
138
|
+
- 不需要追溯参考资源
|
|
139
|
+
- 注重性能
|
|
140
|
+
|
|
141
|
+
#### 增强版适合:
|
|
142
|
+
- 技术研究和学习
|
|
143
|
+
- 需要记录资料来源
|
|
144
|
+
- 团队协作和知识分享
|
|
145
|
+
- 生成可审计的对话记录
|
|
146
|
+
|
|
147
|
+
---
|
|
148
|
+
|
|
149
|
+
## 历史版本
|
|
150
|
+
|
|
151
|
+
### v1.0 - 2026-01-06
|
|
152
|
+
- 初始版本:save-conversation.py
|
|
153
|
+
- 功能:基础对话保存
|
|
154
|
+
|
|
155
|
+
### v2.0 - 2026-01-06(当前)
|
|
156
|
+
- 增强版:save-conversation-enhanced.py
|
|
157
|
+
- 新增:参考资源记录、工具调用统计、详细调用记录
|