sumulige-claude 1.3.3 → 1.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.
Files changed (48) hide show
  1. package/.claude/.sumulige-claude-version +1 -0
  2. package/.claude/AGENTS.md +6 -6
  3. package/.claude/commands/workflow.md +81 -0
  4. package/.claude/hooks/auto-handoff.cjs +0 -0
  5. package/.claude/hooks/hook-dispatcher.cjs +304 -0
  6. package/.claude/hooks/hook-registry.json +73 -0
  7. package/.claude/hooks/lib/cache.cjs +161 -0
  8. package/.claude/hooks/lib/fs-utils.cjs +133 -0
  9. package/.claude/hooks/memory-loader.cjs +0 -0
  10. package/.claude/hooks/memory-saver.cjs +0 -0
  11. package/.claude/hooks/rag-skill-loader.cjs +84 -4
  12. package/.claude/settings.json +8 -82
  13. package/.claude/settings.local.json +4 -1
  14. package/CHANGELOG.md +132 -0
  15. package/README.md +160 -1
  16. package/config/version-manifest.json +85 -0
  17. package/lib/commands.js +56 -0
  18. package/lib/incremental-sync.js +274 -0
  19. package/lib/version-manifest.js +171 -0
  20. package/package.json +1 -1
  21. package/scripts/sync-to-home.sh +108 -0
  22. package/template/.claude/commands/workflow.md +81 -0
  23. package/template/.claude/hooks/hook-dispatcher.cjs +304 -0
  24. package/template/.claude/hooks/hook-registry.json +73 -0
  25. package/template/.claude/hooks/lib/cache.cjs +161 -0
  26. package/template/.claude/hooks/lib/fs-utils.cjs +133 -0
  27. package/template/.claude/hooks/rag-skill-loader.cjs +84 -4
  28. package/template/.claude/settings.json +8 -82
  29. package/template/CHANGELOG.md +297 -0
  30. package/template/README.md +558 -88
  31. package/.claude/sessions/active-sessions.json +0 -1
  32. package/.claude/sessions/session_2026-01-22T13-07-26-625Z.json +0 -23
  33. package/.claude/skills/api-tester/SKILL.md +0 -61
  34. package/.claude/skills/api-tester/examples/basic.md +0 -3
  35. package/.claude/skills/api-tester/metadata.yaml +0 -30
  36. package/.claude/skills/api-tester/templates/default.md +0 -3
  37. package/.claude/skills/code-reviewer-123/SKILL.md +0 -61
  38. package/.claude/skills/code-reviewer-123/examples/basic.md +0 -3
  39. package/.claude/skills/code-reviewer-123/metadata.yaml +0 -30
  40. package/.claude/skills/code-reviewer-123/templates/default.md +0 -3
  41. package/.claude/skills/my-skill/SKILL.md +0 -61
  42. package/.claude/skills/my-skill/examples/basic.md +0 -3
  43. package/.claude/skills/my-skill/metadata.yaml +0 -30
  44. package/.claude/skills/my-skill/templates/default.md +0 -3
  45. package/.claude/skills/test-skill-name/SKILL.md +0 -61
  46. package/.claude/skills/test-skill-name/examples/basic.md +0 -3
  47. package/.claude/skills/test-skill-name/metadata.yaml +0 -30
  48. package/.claude/skills/test-skill-name/templates/default.md +0 -3
@@ -0,0 +1,161 @@
1
+ /**
2
+ * Hooks Shared Library - Cache Utilities
3
+ *
4
+ * 统一的缓存管理,支持内存和文件缓存
5
+ */
6
+
7
+ const fs = require('fs');
8
+ const path = require('path');
9
+
10
+ /**
11
+ * 内存缓存类
12
+ */
13
+ class MemoryCache {
14
+ constructor(defaultTTL = 60000) {
15
+ this.cache = new Map();
16
+ this.defaultTTL = defaultTTL;
17
+ }
18
+
19
+ get(key) {
20
+ const item = this.cache.get(key);
21
+ if (!item) return null;
22
+
23
+ if (Date.now() > item.expiry) {
24
+ this.cache.delete(key);
25
+ return null;
26
+ }
27
+
28
+ return item.value;
29
+ }
30
+
31
+ set(key, value, ttl = this.defaultTTL) {
32
+ this.cache.set(key, {
33
+ value,
34
+ expiry: Date.now() + ttl
35
+ });
36
+ }
37
+
38
+ delete(key) {
39
+ this.cache.delete(key);
40
+ }
41
+
42
+ clear() {
43
+ this.cache.clear();
44
+ }
45
+
46
+ cleanup() {
47
+ const now = Date.now();
48
+ for (const [key, item] of this.cache.entries()) {
49
+ if (now > item.expiry) {
50
+ this.cache.delete(key);
51
+ }
52
+ }
53
+ }
54
+ }
55
+
56
+ /**
57
+ * 文件缓存类
58
+ */
59
+ class FileCache {
60
+ constructor(cacheFile, defaultTTL = 300000) {
61
+ this.cacheFile = cacheFile;
62
+ this.defaultTTL = defaultTTL;
63
+ this.cache = null;
64
+ }
65
+
66
+ load() {
67
+ if (this.cache !== null) return;
68
+
69
+ if (!fs.existsSync(this.cacheFile)) {
70
+ this.cache = {};
71
+ return;
72
+ }
73
+
74
+ try {
75
+ this.cache = JSON.parse(fs.readFileSync(this.cacheFile, 'utf-8'));
76
+ } catch (e) {
77
+ this.cache = {};
78
+ }
79
+ }
80
+
81
+ save() {
82
+ try {
83
+ const dir = path.dirname(this.cacheFile);
84
+ if (!fs.existsSync(dir)) {
85
+ fs.mkdirSync(dir, { recursive: true });
86
+ }
87
+ fs.writeFileSync(this.cacheFile, JSON.stringify(this.cache, null, 2));
88
+ } catch (e) {
89
+ // 忽略保存错误
90
+ }
91
+ }
92
+
93
+ get(key) {
94
+ this.load();
95
+ const item = this.cache[key];
96
+ if (!item) return null;
97
+
98
+ if (Date.now() > item.expiry) {
99
+ delete this.cache[key];
100
+ return null;
101
+ }
102
+
103
+ return item.value;
104
+ }
105
+
106
+ set(key, value, ttl = this.defaultTTL) {
107
+ this.load();
108
+ this.cache[key] = {
109
+ value,
110
+ expiry: Date.now() + ttl
111
+ };
112
+ this.save();
113
+ }
114
+
115
+ delete(key) {
116
+ this.load();
117
+ delete this.cache[key];
118
+ this.save();
119
+ }
120
+
121
+ clear() {
122
+ this.cache = {};
123
+ this.save();
124
+ }
125
+
126
+ cleanup() {
127
+ this.load();
128
+ const now = Date.now();
129
+ let changed = false;
130
+
131
+ for (const key of Object.keys(this.cache)) {
132
+ if (now > this.cache[key].expiry) {
133
+ delete this.cache[key];
134
+ changed = true;
135
+ }
136
+ }
137
+
138
+ if (changed) {
139
+ this.save();
140
+ }
141
+ }
142
+ }
143
+
144
+ /**
145
+ * 简单哈希函数
146
+ */
147
+ function hashString(str) {
148
+ let hash = 0;
149
+ for (let i = 0; i < str.length; i++) {
150
+ const char = str.charCodeAt(i);
151
+ hash = ((hash << 5) - hash) + char;
152
+ hash = hash & hash;
153
+ }
154
+ return hash.toString(16);
155
+ }
156
+
157
+ module.exports = {
158
+ MemoryCache,
159
+ FileCache,
160
+ hashString
161
+ };
@@ -0,0 +1,133 @@
1
+ /**
2
+ * Hooks Shared Library - File System Utilities
3
+ *
4
+ * 带缓存的文件操作,减少重复读写
5
+ */
6
+
7
+ const fs = require('fs');
8
+ const path = require('path');
9
+
10
+ // 内存缓存
11
+ const fileCache = new Map();
12
+ const DEFAULT_TTL = 60000; // 1分钟
13
+
14
+ /**
15
+ * 带缓存的 JSON 文件读取
16
+ */
17
+ function readJsonCached(filePath, ttl = DEFAULT_TTL) {
18
+ const cached = fileCache.get(filePath);
19
+ const now = Date.now();
20
+
21
+ if (cached && now - cached.time < ttl) {
22
+ return cached.data;
23
+ }
24
+
25
+ if (!fs.existsSync(filePath)) {
26
+ return null;
27
+ }
28
+
29
+ try {
30
+ const data = JSON.parse(fs.readFileSync(filePath, 'utf-8'));
31
+ fileCache.set(filePath, { data, time: now });
32
+ return data;
33
+ } catch (e) {
34
+ return null;
35
+ }
36
+ }
37
+
38
+ /**
39
+ * 写入 JSON 文件并更新缓存
40
+ */
41
+ function writeJsonCached(filePath, data) {
42
+ try {
43
+ const dir = path.dirname(filePath);
44
+ if (!fs.existsSync(dir)) {
45
+ fs.mkdirSync(dir, { recursive: true });
46
+ }
47
+ fs.writeFileSync(filePath, JSON.stringify(data, null, 2));
48
+ fileCache.set(filePath, { data, time: Date.now() });
49
+ return true;
50
+ } catch (e) {
51
+ return false;
52
+ }
53
+ }
54
+
55
+ /**
56
+ * 带缓存的文本文件读取
57
+ */
58
+ function readTextCached(filePath, ttl = DEFAULT_TTL) {
59
+ const cached = fileCache.get(filePath);
60
+ const now = Date.now();
61
+
62
+ if (cached && now - cached.time < ttl) {
63
+ return cached.data;
64
+ }
65
+
66
+ if (!fs.existsSync(filePath)) {
67
+ return null;
68
+ }
69
+
70
+ try {
71
+ const data = fs.readFileSync(filePath, 'utf-8');
72
+ fileCache.set(filePath, { data, time: now });
73
+ return data;
74
+ } catch (e) {
75
+ return null;
76
+ }
77
+ }
78
+
79
+ /**
80
+ * 清除缓存
81
+ */
82
+ function clearCache(filePath = null) {
83
+ if (filePath) {
84
+ fileCache.delete(filePath);
85
+ } else {
86
+ fileCache.clear();
87
+ }
88
+ }
89
+
90
+ /**
91
+ * 确保目录存在
92
+ */
93
+ function ensureDir(dirPath) {
94
+ if (!fs.existsSync(dirPath)) {
95
+ fs.mkdirSync(dirPath, { recursive: true });
96
+ }
97
+ }
98
+
99
+ /**
100
+ * 安全文件操作 - 写入
101
+ */
102
+ function safeWriteFile(filePath, content) {
103
+ try {
104
+ ensureDir(path.dirname(filePath));
105
+ fs.writeFileSync(filePath, content);
106
+ return true;
107
+ } catch (e) {
108
+ return false;
109
+ }
110
+ }
111
+
112
+ /**
113
+ * 安全文件操作 - 追加
114
+ */
115
+ function safeAppendFile(filePath, content) {
116
+ try {
117
+ ensureDir(path.dirname(filePath));
118
+ fs.appendFileSync(filePath, content);
119
+ return true;
120
+ } catch (e) {
121
+ return false;
122
+ }
123
+ }
124
+
125
+ module.exports = {
126
+ readJsonCached,
127
+ writeJsonCached,
128
+ readTextCached,
129
+ clearCache,
130
+ ensureDir,
131
+ safeWriteFile,
132
+ safeAppendFile
133
+ };
@@ -13,6 +13,10 @@ const PROJECT_DIR = process.env.CLAUDE_PROJECT_DIR || process.cwd();
13
13
  const RAG_DIR = path.join(PROJECT_DIR, '.claude/rag');
14
14
  const SKILL_INDEX_FILE = path.join(RAG_DIR, 'skill-index.json');
15
15
  const SKILLS_DIR = path.join(PROJECT_DIR, '.claude/skills');
16
+ const CACHE_FILE = path.join(RAG_DIR, '.match-cache.json');
17
+
18
+ // 缓存配置
19
+ const CACHE_TTL = 300000; // 5分钟缓存有效期
16
20
 
17
21
  // 技能关键词匹配权重
18
22
  const KEYWORD_WEIGHTS = {
@@ -21,6 +25,67 @@ const KEYWORD_WEIGHTS = {
21
25
  related: 0.5 // 相关匹配
22
26
  };
23
27
 
28
+ // 简单哈希函数
29
+ function hashInput(input) {
30
+ let hash = 0;
31
+ for (let i = 0; i < input.length; i++) {
32
+ const char = input.charCodeAt(i);
33
+ hash = ((hash << 5) - hash) + char;
34
+ hash = hash & hash;
35
+ }
36
+ return hash.toString(16);
37
+ }
38
+
39
+ // 加载缓存
40
+ function loadCache() {
41
+ if (!fs.existsSync(CACHE_FILE)) {
42
+ return {};
43
+ }
44
+ try {
45
+ return JSON.parse(fs.readFileSync(CACHE_FILE, 'utf-8'));
46
+ } catch (e) {
47
+ return {};
48
+ }
49
+ }
50
+
51
+ // 保存缓存
52
+ function saveCache(cache) {
53
+ try {
54
+ // 清理过期条目
55
+ const now = Date.now();
56
+ const cleaned = {};
57
+ for (const [key, value] of Object.entries(cache)) {
58
+ if (now - value.timestamp < (value.ttl || CACHE_TTL)) {
59
+ cleaned[key] = value;
60
+ }
61
+ }
62
+ fs.writeFileSync(CACHE_FILE, JSON.stringify(cleaned, null, 2));
63
+ } catch (e) {
64
+ // 忽略保存错误
65
+ }
66
+ }
67
+
68
+ // 从缓存获取结果
69
+ function getCachedResult(inputHash) {
70
+ const cache = loadCache();
71
+ const cached = cache[inputHash];
72
+ if (cached && Date.now() - cached.timestamp < (cached.ttl || CACHE_TTL)) {
73
+ return cached.result;
74
+ }
75
+ return null;
76
+ }
77
+
78
+ // 保存结果到缓存
79
+ function setCachedResult(inputHash, result) {
80
+ const cache = loadCache();
81
+ cache[inputHash] = {
82
+ result,
83
+ timestamp: Date.now(),
84
+ ttl: CACHE_TTL
85
+ };
86
+ saveCache(cache);
87
+ }
88
+
24
89
  // 加载技能索引
25
90
  function loadSkillIndex() {
26
91
  if (!fs.existsSync(SKILL_INDEX_FILE)) {
@@ -134,12 +199,27 @@ function main() {
134
199
  process.exit(0);
135
200
  }
136
201
 
137
- const analysis = analyzeInput(toolInput);
138
- if (analysis.keywords.length === 0) {
139
- process.exit(0);
202
+ // 检查缓存
203
+ const inputHash = hashInput(toolInput);
204
+ const cachedResult = getCachedResult(inputHash);
205
+
206
+ let matches;
207
+ if (cachedResult) {
208
+ // 使用缓存结果
209
+ matches = cachedResult;
210
+ } else {
211
+ // 分析并匹配
212
+ const analysis = analyzeInput(toolInput);
213
+ if (analysis.keywords.length === 0) {
214
+ process.exit(0);
215
+ }
216
+
217
+ matches = matchSkills(analysis, skillIndex);
218
+
219
+ // 缓存结果
220
+ setCachedResult(inputHash, matches);
140
221
  }
141
222
 
142
- const matches = matchSkills(analysis, skillIndex);
143
223
  if (matches.length === 0) {
144
224
  process.exit(0);
145
225
  }
@@ -45,82 +45,23 @@
45
45
  "hooks": [
46
46
  {
47
47
  "type": "command",
48
- "command": "node \"$CLAUDE_PROJECT_DIR\"/.claude/hooks/project-kickoff.cjs",
49
- "timeout": 1000
50
- },
51
- {
52
- "type": "command",
53
- "command": "node \"$CLAUDE_PROJECT_DIR\"/.claude/hooks/rag-skill-loader.cjs",
54
- "timeout": 1000
55
- },
56
- {
57
- "type": "command",
58
- "command": "node \"$CLAUDE_PROJECT_DIR\"/.claude/hooks/thinking-silent.cjs",
59
- "timeout": 1000
60
- },
61
- {
62
- "type": "command",
63
- "command": "node \"$CLAUDE_PROJECT_DIR\"/.claude/hooks/multi-session.cjs",
64
- "timeout": 1000
65
- },
66
- {
67
- "type": "command",
68
- "command": "node \"$CLAUDE_PROJECT_DIR\"/.claude/hooks/todo-manager.cjs",
69
- "timeout": 1000
70
- }
71
- ]
72
- }
73
- ],
74
- "PreToolUse": [
75
- {
76
- "matcher": {},
77
- "hooks": [
78
- {
79
- "type": "command",
80
- "command": "node \"$CLAUDE_PROJECT_DIR\"/.claude/hooks/thinking-silent.cjs",
81
- "timeout": 1000
82
- },
83
- {
84
- "type": "command",
85
- "command": "node \"$CLAUDE_PROJECT_DIR\"/.claude/hooks/multi-session.cjs",
86
- "timeout": 1000
87
- },
88
- {
89
- "type": "command",
90
- "command": "node \"$CLAUDE_PROJECT_DIR\"/.claude/hooks/todo-manager.cjs",
91
- "timeout": 1000
48
+ "command": "CLAUDE_EVENT_TYPE=UserPromptSubmit node \"$CLAUDE_PROJECT_DIR\"/.claude/hooks/hook-dispatcher.cjs",
49
+ "timeout": 3000
92
50
  }
93
51
  ]
94
52
  }
95
53
  ],
54
+ "PreToolUse": [],
96
55
  "PostToolUse": [
97
56
  {
98
- "matcher": {},
57
+ "matcher": {
58
+ "tool_name": "^(Write|Edit)$"
59
+ },
99
60
  "hooks": [
100
61
  {
101
62
  "type": "command",
102
63
  "command": "node \"$CLAUDE_PROJECT_DIR\"/.claude/hooks/code-formatter.cjs",
103
64
  "timeout": 5000
104
- },
105
- {
106
- "type": "command",
107
- "command": "node \"$CLAUDE_PROJECT_DIR\"/.claude/hooks/verify-work.cjs",
108
- "timeout": 1000
109
- },
110
- {
111
- "type": "command",
112
- "command": "node \"$CLAUDE_PROJECT_DIR\"/.claude/hooks/thinking-silent.cjs",
113
- "timeout": 1000
114
- },
115
- {
116
- "type": "command",
117
- "command": "node \"$CLAUDE_PROJECT_DIR\"/.claude/hooks/multi-session.cjs",
118
- "timeout": 1000
119
- },
120
- {
121
- "type": "command",
122
- "command": "node \"$CLAUDE_PROJECT_DIR\"/.claude/hooks/todo-manager.cjs",
123
- "timeout": 1000
124
65
  }
125
66
  ]
126
67
  }
@@ -131,23 +72,8 @@
131
72
  "hooks": [
132
73
  {
133
74
  "type": "command",
134
- "command": "node \"$CLAUDE_PROJECT_DIR\"/.claude/hooks/verify-work.cjs",
135
- "timeout": 1000
136
- },
137
- {
138
- "type": "command",
139
- "command": "node \"$CLAUDE_PROJECT_DIR\"/.claude/hooks/thinking-silent.cjs",
140
- "timeout": 1000
141
- },
142
- {
143
- "type": "command",
144
- "command": "node \"$CLAUDE_PROJECT_DIR\"/.claude/hooks/multi-session.cjs",
145
- "timeout": 1000
146
- },
147
- {
148
- "type": "command",
149
- "command": "node \"$CLAUDE_PROJECT_DIR\"/.claude/hooks/todo-manager.cjs",
150
- "timeout": 1000
75
+ "command": "CLAUDE_EVENT_TYPE=AgentStop node \"$CLAUDE_PROJECT_DIR\"/.claude/hooks/hook-dispatcher.cjs",
76
+ "timeout": 3000
151
77
  }
152
78
  ]
153
79
  }