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.
- package/.claude/.sumulige-claude-version +1 -0
- package/.claude/AGENTS.md +6 -6
- package/.claude/commands/workflow.md +81 -0
- package/.claude/hooks/auto-handoff.cjs +0 -0
- package/.claude/hooks/hook-dispatcher.cjs +304 -0
- package/.claude/hooks/hook-registry.json +73 -0
- package/.claude/hooks/lib/cache.cjs +161 -0
- package/.claude/hooks/lib/fs-utils.cjs +133 -0
- package/.claude/hooks/memory-loader.cjs +0 -0
- package/.claude/hooks/memory-saver.cjs +0 -0
- package/.claude/hooks/rag-skill-loader.cjs +84 -4
- package/.claude/settings.json +8 -82
- package/.claude/settings.local.json +4 -1
- package/CHANGELOG.md +132 -0
- package/README.md +160 -1
- package/config/version-manifest.json +85 -0
- package/lib/commands.js +56 -0
- package/lib/incremental-sync.js +274 -0
- package/lib/version-manifest.js +171 -0
- package/package.json +1 -1
- package/scripts/sync-to-home.sh +108 -0
- package/template/.claude/commands/workflow.md +81 -0
- package/template/.claude/hooks/hook-dispatcher.cjs +304 -0
- package/template/.claude/hooks/hook-registry.json +73 -0
- package/template/.claude/hooks/lib/cache.cjs +161 -0
- package/template/.claude/hooks/lib/fs-utils.cjs +133 -0
- package/template/.claude/hooks/rag-skill-loader.cjs +84 -4
- package/template/.claude/settings.json +8 -82
- package/template/CHANGELOG.md +297 -0
- package/template/README.md +558 -88
- package/.claude/sessions/active-sessions.json +0 -1
- package/.claude/sessions/session_2026-01-22T13-07-26-625Z.json +0 -23
- package/.claude/skills/api-tester/SKILL.md +0 -61
- package/.claude/skills/api-tester/examples/basic.md +0 -3
- package/.claude/skills/api-tester/metadata.yaml +0 -30
- package/.claude/skills/api-tester/templates/default.md +0 -3
- package/.claude/skills/code-reviewer-123/SKILL.md +0 -61
- package/.claude/skills/code-reviewer-123/examples/basic.md +0 -3
- package/.claude/skills/code-reviewer-123/metadata.yaml +0 -30
- package/.claude/skills/code-reviewer-123/templates/default.md +0 -3
- package/.claude/skills/my-skill/SKILL.md +0 -61
- package/.claude/skills/my-skill/examples/basic.md +0 -3
- package/.claude/skills/my-skill/metadata.yaml +0 -30
- package/.claude/skills/my-skill/templates/default.md +0 -3
- package/.claude/skills/test-skill-name/SKILL.md +0 -61
- package/.claude/skills/test-skill-name/examples/basic.md +0 -3
- package/.claude/skills/test-skill-name/metadata.yaml +0 -30
- 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
|
-
|
|
138
|
-
|
|
139
|
-
|
|
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/
|
|
49
|
-
"timeout":
|
|
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/
|
|
135
|
-
"timeout":
|
|
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
|
}
|