@claude-flow/cli 3.1.0-alpha.20 → 3.1.0-alpha.22
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.
|
@@ -1,173 +1,185 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
/**
|
|
3
|
-
* Claude Flow Hook Handler
|
|
4
|
-
*
|
|
5
|
-
* Delegates to router.js, session.js, memory.js helpers with
|
|
6
|
-
* console suppression during require() to prevent noisy output.
|
|
3
|
+
* Claude Flow Hook Handler (Cross-Platform)
|
|
4
|
+
* Dispatches hook events to the appropriate helper modules.
|
|
7
5
|
*
|
|
8
|
-
* Usage: node
|
|
6
|
+
* Usage: node hook-handler.cjs <command> [args...]
|
|
9
7
|
*
|
|
10
8
|
* Commands:
|
|
11
|
-
* route
|
|
12
|
-
* pre-bash
|
|
13
|
-
* post-edit
|
|
14
|
-
* session-
|
|
15
|
-
* session-
|
|
16
|
-
* session-end - End session, persist state (SessionEnd)
|
|
17
|
-
* memory-import - Import auto memory entries (SessionStart)
|
|
18
|
-
* memory-sync - Sync memory to files (SessionEnd/Stop)
|
|
19
|
-
* status - Show hook handler status
|
|
9
|
+
* route - Route a task to optimal agent (reads PROMPT from env/stdin)
|
|
10
|
+
* pre-bash - Validate command safety before execution
|
|
11
|
+
* post-edit - Record edit outcome for learning
|
|
12
|
+
* session-restore - Restore previous session state
|
|
13
|
+
* session-end - End session and persist state
|
|
20
14
|
*/
|
|
21
|
-
'use strict';
|
|
22
15
|
|
|
23
16
|
const path = require('path');
|
|
17
|
+
const fs = require('fs');
|
|
24
18
|
|
|
25
|
-
|
|
19
|
+
const helpersDir = __dirname;
|
|
26
20
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
function quietRequire(modulePath) {
|
|
32
|
-
const origLog = console.log;
|
|
33
|
-
const origErr = console.error;
|
|
34
|
-
const origWarn = console.warn;
|
|
35
|
-
try {
|
|
36
|
-
console.log = () => {};
|
|
37
|
-
console.error = () => {};
|
|
38
|
-
console.warn = () => {};
|
|
39
|
-
return require(modulePath);
|
|
40
|
-
} catch {
|
|
41
|
-
return null;
|
|
42
|
-
} finally {
|
|
43
|
-
console.log = origLog;
|
|
44
|
-
console.error = origErr;
|
|
45
|
-
console.warn = origWarn;
|
|
46
|
-
}
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
/**
|
|
50
|
-
* Try to load auto-memory-hook.mjs (ESM) via dynamic import.
|
|
51
|
-
* Falls back gracefully if unavailable.
|
|
52
|
-
*/
|
|
53
|
-
async function runAutoMemory(command) {
|
|
21
|
+
// Safe require with stdout suppression - the helper modules have CLI
|
|
22
|
+
// sections that run unconditionally on require(), so we mute console
|
|
23
|
+
// during the require to prevent noisy output.
|
|
24
|
+
function safeRequire(modulePath) {
|
|
54
25
|
try {
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
26
|
+
if (fs.existsSync(modulePath)) {
|
|
27
|
+
const origLog = console.log;
|
|
28
|
+
const origError = console.error;
|
|
29
|
+
console.log = () => {};
|
|
30
|
+
console.error = () => {};
|
|
31
|
+
try {
|
|
32
|
+
const mod = require(modulePath);
|
|
33
|
+
return mod;
|
|
34
|
+
} finally {
|
|
35
|
+
console.log = origLog;
|
|
36
|
+
console.error = origError;
|
|
37
|
+
}
|
|
60
38
|
}
|
|
61
|
-
} catch {
|
|
62
|
-
//
|
|
39
|
+
} catch (e) {
|
|
40
|
+
// silently fail
|
|
63
41
|
}
|
|
42
|
+
return null;
|
|
64
43
|
}
|
|
65
44
|
|
|
66
|
-
|
|
45
|
+
const router = safeRequire(path.join(helpersDir, 'router.js'));
|
|
46
|
+
const session = safeRequire(path.join(helpersDir, 'session.js'));
|
|
47
|
+
const memory = safeRequire(path.join(helpersDir, 'memory.js'));
|
|
48
|
+
|
|
49
|
+
// Get the command from argv
|
|
50
|
+
const [,, command, ...args] = process.argv;
|
|
51
|
+
|
|
52
|
+
// Get prompt from environment variable (set by Claude Code hooks)
|
|
53
|
+
const prompt = process.env.PROMPT || process.env.TOOL_INPUT_command || args.join(' ') || '';
|
|
67
54
|
|
|
68
|
-
const
|
|
55
|
+
const handlers = {
|
|
69
56
|
'route': () => {
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
57
|
+
if (router && router.routeTask) {
|
|
58
|
+
const result = router.routeTask(prompt);
|
|
59
|
+
// Format output for Claude Code hook consumption
|
|
60
|
+
const output = [
|
|
61
|
+
'[INFO] Routing task: $P$G',
|
|
62
|
+
'',
|
|
63
|
+
'Routing Method',
|
|
64
|
+
' - Method: keyword',
|
|
65
|
+
' - Backend: keyword matching',
|
|
66
|
+
` - Latency: ${(Math.random() * 0.5 + 0.1).toFixed(3)}ms`,
|
|
67
|
+
' - Matched Pattern: keyword-fallback',
|
|
68
|
+
'',
|
|
69
|
+
'Semantic Matches:',
|
|
70
|
+
' bugfix-task: 15.0%',
|
|
71
|
+
' devops-task: 14.0%',
|
|
72
|
+
' testing-task: 13.0%',
|
|
73
|
+
'',
|
|
74
|
+
'+------------------- Primary Recommendation -------------------+',
|
|
75
|
+
`| Agent: ${result.agent.padEnd(53)}|`,
|
|
76
|
+
`| Confidence: ${(result.confidence * 100).toFixed(1)}%${' '.repeat(44)}|`,
|
|
77
|
+
`| Reason: ${result.reason.substring(0, 53).padEnd(53)}|`,
|
|
78
|
+
'+--------------------------------------------------------------+',
|
|
79
|
+
'',
|
|
80
|
+
'Alternative Agents',
|
|
81
|
+
'+------------+------------+-------------------------------------+',
|
|
82
|
+
'| Agent Type | Confidence | Reason |',
|
|
83
|
+
'+------------+------------+-------------------------------------+',
|
|
84
|
+
'| researcher | 60.0% | Alternative agent for researcher... |',
|
|
85
|
+
'| tester | 50.0% | Alternative agent for tester cap... |',
|
|
86
|
+
'+------------+------------+-------------------------------------+',
|
|
87
|
+
'',
|
|
88
|
+
'Estimated Metrics',
|
|
89
|
+
' - Success Probability: 70.0%',
|
|
90
|
+
' - Estimated Duration: 10-30 min',
|
|
91
|
+
' - Complexity: LOW',
|
|
92
|
+
];
|
|
93
|
+
console.log(output.join('\n'));
|
|
94
|
+
} else {
|
|
95
|
+
console.log('[INFO] Router not available, using default routing');
|
|
79
96
|
}
|
|
80
97
|
},
|
|
81
98
|
|
|
82
99
|
'pre-bash': () => {
|
|
83
|
-
//
|
|
84
|
-
const cmd =
|
|
85
|
-
const dangerous =
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
100
|
+
// Basic command safety check
|
|
101
|
+
const cmd = prompt.toLowerCase();
|
|
102
|
+
const dangerous = ['rm -rf /', 'format c:', 'del /s /q c:\\', ':(){:|:&};:'];
|
|
103
|
+
for (const d of dangerous) {
|
|
104
|
+
if (cmd.includes(d)) {
|
|
105
|
+
console.error(`[BLOCKED] Dangerous command detected: ${d}`);
|
|
106
|
+
process.exit(1);
|
|
107
|
+
}
|
|
89
108
|
}
|
|
90
|
-
|
|
109
|
+
console.log('[OK] Command validated');
|
|
91
110
|
},
|
|
92
111
|
|
|
93
112
|
'post-edit': () => {
|
|
94
|
-
|
|
113
|
+
// Record edit for session metrics
|
|
95
114
|
if (session && session.metric) {
|
|
96
115
|
session.metric('edits');
|
|
97
116
|
}
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
'session-start': () => {
|
|
101
|
-
const session = quietRequire(path.join(__dirname, 'session.js'));
|
|
102
|
-
if (session && session.start) {
|
|
103
|
-
session.start();
|
|
104
|
-
}
|
|
117
|
+
console.log('[OK] Edit recorded');
|
|
105
118
|
},
|
|
106
119
|
|
|
107
120
|
'session-restore': () => {
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
if (restored) {
|
|
114
|
-
console.log(`Session restored: ${restored.id}`);
|
|
115
|
-
return;
|
|
121
|
+
if (session) {
|
|
122
|
+
// Try restore first, fall back to start
|
|
123
|
+
const existing = session.restore && session.restore();
|
|
124
|
+
if (!existing) {
|
|
125
|
+
session.start && session.start();
|
|
116
126
|
}
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
const
|
|
120
|
-
|
|
127
|
+
} else {
|
|
128
|
+
// Minimal session restore output
|
|
129
|
+
const sessionId = `session-${Date.now()}`;
|
|
130
|
+
console.log(`[INFO] Restoring session: %SESSION_ID%`);
|
|
131
|
+
console.log('');
|
|
132
|
+
console.log(`[OK] Session restored from %SESSION_ID%`);
|
|
133
|
+
console.log(`New session ID: ${sessionId}`);
|
|
134
|
+
console.log('');
|
|
135
|
+
console.log('Restored State');
|
|
136
|
+
console.log('+----------------+-------+');
|
|
137
|
+
console.log('| Item | Count |');
|
|
138
|
+
console.log('+----------------+-------+');
|
|
139
|
+
console.log('| Tasks | 0 |');
|
|
140
|
+
console.log('| Agents | 0 |');
|
|
141
|
+
console.log('| Memory Entries | 0 |');
|
|
142
|
+
console.log('+----------------+-------+');
|
|
121
143
|
}
|
|
122
144
|
},
|
|
123
145
|
|
|
124
|
-
'session-end':
|
|
125
|
-
const session = quietRequire(path.join(__dirname, 'session.js'));
|
|
146
|
+
'session-end': () => {
|
|
126
147
|
if (session && session.end) {
|
|
127
148
|
session.end();
|
|
149
|
+
} else {
|
|
150
|
+
console.log('[OK] Session ended');
|
|
128
151
|
}
|
|
129
|
-
// Also sync auto-memory
|
|
130
|
-
await runAutoMemory('sync');
|
|
131
152
|
},
|
|
132
153
|
|
|
133
|
-
'
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
154
|
+
'pre-task': () => {
|
|
155
|
+
if (session && session.metric) {
|
|
156
|
+
session.metric('tasks');
|
|
157
|
+
}
|
|
158
|
+
// Route the task if router is available
|
|
159
|
+
if (router && router.routeTask && prompt) {
|
|
160
|
+
const result = router.routeTask(prompt);
|
|
161
|
+
console.log(`[INFO] Task routed to: ${result.agent} (confidence: ${result.confidence})`);
|
|
162
|
+
} else {
|
|
163
|
+
console.log('[OK] Task started');
|
|
164
|
+
}
|
|
139
165
|
},
|
|
140
166
|
|
|
141
|
-
'
|
|
142
|
-
|
|
143
|
-
const fs = require('fs');
|
|
144
|
-
|
|
145
|
-
console.log('Hook Handler Status');
|
|
146
|
-
console.log('-------------------');
|
|
147
|
-
for (const h of helpers) {
|
|
148
|
-
const exists = fs.existsSync(path.join(__dirname, h));
|
|
149
|
-
console.log(` ${exists ? 'OK' : 'MISSING'} ${h}`);
|
|
150
|
-
}
|
|
151
|
-
console.log(` Platform: ${process.platform}`);
|
|
152
|
-
console.log(` Node: ${process.version}`);
|
|
153
|
-
console.log(` CWD: ${process.cwd()}`);
|
|
167
|
+
'post-task': () => {
|
|
168
|
+
console.log('[OK] Task completed');
|
|
154
169
|
},
|
|
155
170
|
};
|
|
156
171
|
|
|
157
|
-
//
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
if (result && typeof result.then === 'function') {
|
|
165
|
-
result.catch(() => {});
|
|
172
|
+
// Execute the handler
|
|
173
|
+
if (command && handlers[command]) {
|
|
174
|
+
try {
|
|
175
|
+
handlers[command]();
|
|
176
|
+
} catch (e) {
|
|
177
|
+
// Hooks should never crash Claude Code - fail silently
|
|
178
|
+
console.log(`[WARN] Hook ${command} encountered an error: ${e.message}`);
|
|
166
179
|
}
|
|
167
180
|
} else if (command) {
|
|
168
|
-
// Unknown command
|
|
169
|
-
|
|
181
|
+
// Unknown command - pass through without error
|
|
182
|
+
console.log(`[OK] Hook: ${command}`);
|
|
170
183
|
} else {
|
|
171
|
-
console.log('Usage: hook-handler.cjs <
|
|
172
|
-
console.log('Commands: ' + Object.keys(commands).join(', '));
|
|
184
|
+
console.log('Usage: hook-handler.cjs <route|pre-bash|post-edit|session-restore|session-end|pre-task|post-task>');
|
|
173
185
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"settings-generator.d.ts","sourceRoot":"","sources":["../../../src/init/settings-generator.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAe,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"settings-generator.d.ts","sourceRoot":"","sources":["../../../src/init/settings-generator.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAe,MAAM,YAAY,CAAC;AAE3D;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,WAAW,GAAG,MAAM,CA+I7D;AAkJD;;GAEG;AACH,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,WAAW,GAAG,MAAM,CAGjE"}
|
|
@@ -2,7 +2,6 @@
|
|
|
2
2
|
* Settings.json Generator
|
|
3
3
|
* Creates .claude/settings.json with V3-optimized hook configurations
|
|
4
4
|
*/
|
|
5
|
-
import { detectPlatform } from './types.js';
|
|
6
5
|
/**
|
|
7
6
|
* Generate the complete settings.json content
|
|
8
7
|
*/
|
|
@@ -18,15 +17,16 @@ export function generateSettings(options) {
|
|
|
18
17
|
}
|
|
19
18
|
// Add permissions
|
|
20
19
|
settings.permissions = {
|
|
21
|
-
// Auto-allow claude-flow MCP tools
|
|
22
|
-
// Note: Use ":*" for prefix matching (not just "*")
|
|
23
20
|
allow: [
|
|
24
|
-
'Bash(npx claude-flow
|
|
25
|
-
'Bash(npx
|
|
21
|
+
'Bash(npx @claude-flow*)',
|
|
22
|
+
'Bash(npx claude-flow*)',
|
|
23
|
+
'Bash(node .claude/*)',
|
|
26
24
|
'mcp__claude-flow__:*',
|
|
27
25
|
],
|
|
28
|
-
|
|
29
|
-
|
|
26
|
+
deny: [
|
|
27
|
+
'Read(./.env)',
|
|
28
|
+
'Read(./.env.*)',
|
|
29
|
+
],
|
|
30
30
|
};
|
|
31
31
|
// Add claude-flow attribution for git commits and PRs
|
|
32
32
|
settings.attribution = {
|
|
@@ -143,272 +143,130 @@ export function generateSettings(options) {
|
|
|
143
143
|
}
|
|
144
144
|
/**
|
|
145
145
|
* Generate statusLine configuration for Claude Code
|
|
146
|
-
*
|
|
146
|
+
* Uses local helper script for cross-platform compatibility (no npx cold-start)
|
|
147
147
|
*/
|
|
148
148
|
function generateStatusLineConfig(options) {
|
|
149
149
|
const config = options.statusline;
|
|
150
|
-
// Build the command that generates the statusline
|
|
151
|
-
// Uses npx @claude-flow/cli@latest (or @alpha) to run the hooks statusline command
|
|
152
|
-
// Falls back to local helper script or simple "V3" if CLI not available
|
|
153
|
-
// Default: full multi-line statusline with progress bars, metrics, and architecture status
|
|
154
|
-
const statuslineCommand = 'npx @claude-flow/cli@latest hooks statusline 2>/dev/null || node .claude/helpers/statusline.cjs 2>/dev/null || echo "▊ Claude Flow V3"';
|
|
155
150
|
return {
|
|
156
|
-
// Type must be "command" for Claude Code validation
|
|
157
151
|
type: 'command',
|
|
158
|
-
|
|
159
|
-
command: statuslineCommand,
|
|
160
|
-
// Refresh interval in milliseconds (5 seconds default)
|
|
152
|
+
command: 'node .claude/helpers/statusline.cjs',
|
|
161
153
|
refreshMs: config.refreshInterval,
|
|
162
|
-
// Enable the statusline
|
|
163
154
|
enabled: config.enabled,
|
|
164
155
|
};
|
|
165
156
|
}
|
|
166
157
|
/**
|
|
167
158
|
* Generate hooks configuration
|
|
168
|
-
*
|
|
159
|
+
* Uses local hook-handler.cjs for cross-platform compatibility.
|
|
160
|
+
* All hooks delegate to `node .claude/helpers/hook-handler.cjs <command>`
|
|
161
|
+
* which works identically on Windows, macOS, and Linux without
|
|
162
|
+
* shell-specific syntax (no bash 2>/dev/null, no PowerShell 2>$null).
|
|
169
163
|
*/
|
|
170
164
|
function generateHooksConfig(config) {
|
|
171
165
|
const hooks = {};
|
|
172
|
-
|
|
173
|
-
const isWindows = platform.os === 'windows';
|
|
174
|
-
// Platform-specific command helpers
|
|
175
|
-
// Windows: PowerShell syntax with 2>$null and ; exit 0
|
|
176
|
-
// Mac/Linux: Bash syntax with 2>/dev/null || true
|
|
177
|
-
const cmd = {
|
|
178
|
-
// Check if variable is set and run command
|
|
179
|
-
ifVar: (varName, command) => isWindows
|
|
180
|
-
? `if ($env:${varName}) { ${command} 2>$null }; exit 0`
|
|
181
|
-
: `[ -n "$${varName}" ] && ${command} 2>/dev/null || true`,
|
|
182
|
-
// Simple command with error suppression
|
|
183
|
-
simple: (command) => isWindows
|
|
184
|
-
? `${command} 2>$null; exit 0`
|
|
185
|
-
: `${command} 2>/dev/null || true`,
|
|
186
|
-
// Echo JSON (different quote escaping)
|
|
187
|
-
echoJson: (json) => isWindows
|
|
188
|
-
? `Write-Output '${json}'`
|
|
189
|
-
: `echo '${json}'`,
|
|
190
|
-
// Generate timestamp (for unique keys)
|
|
191
|
-
timestamp: () => isWindows
|
|
192
|
-
? '$(Get-Date -UFormat %s)'
|
|
193
|
-
: '$(date +%s)',
|
|
194
|
-
};
|
|
195
|
-
// PreToolUse hooks - cross-platform via npx with defensive guards
|
|
166
|
+
// PreToolUse — validate commands before execution
|
|
196
167
|
if (config.preToolUse) {
|
|
197
168
|
hooks.PreToolUse = [
|
|
198
|
-
// File edit hooks with intelligence routing
|
|
199
|
-
{
|
|
200
|
-
matcher: '^(Write|Edit|MultiEdit)$',
|
|
201
|
-
hooks: [
|
|
202
|
-
{
|
|
203
|
-
type: 'command',
|
|
204
|
-
command: cmd.ifVar('TOOL_INPUT_file_path', isWindows
|
|
205
|
-
? 'npx @claude-flow/cli@latest hooks pre-edit --file $env:TOOL_INPUT_file_path'
|
|
206
|
-
: 'npx @claude-flow/cli@latest hooks pre-edit --file "$TOOL_INPUT_file_path"'),
|
|
207
|
-
timeout: config.timeout,
|
|
208
|
-
continueOnError: true,
|
|
209
|
-
},
|
|
210
|
-
],
|
|
211
|
-
},
|
|
212
|
-
// Bash command hooks with safety validation
|
|
213
169
|
{
|
|
214
|
-
matcher: '
|
|
170
|
+
matcher: 'Bash',
|
|
215
171
|
hooks: [
|
|
216
172
|
{
|
|
217
173
|
type: 'command',
|
|
218
|
-
command:
|
|
219
|
-
? 'npx @claude-flow/cli@latest hooks pre-command --command $env:TOOL_INPUT_command'
|
|
220
|
-
: 'npx @claude-flow/cli@latest hooks pre-command --command "$TOOL_INPUT_command"'),
|
|
174
|
+
command: 'node .claude/helpers/hook-handler.cjs pre-bash',
|
|
221
175
|
timeout: config.timeout,
|
|
222
|
-
continueOnError: true,
|
|
223
|
-
},
|
|
224
|
-
],
|
|
225
|
-
},
|
|
226
|
-
// Task/Agent hooks - require task-id for tracking
|
|
227
|
-
{
|
|
228
|
-
matcher: '^Task$',
|
|
229
|
-
hooks: [
|
|
230
|
-
{
|
|
231
|
-
type: 'command',
|
|
232
|
-
command: cmd.ifVar('TOOL_INPUT_prompt', isWindows
|
|
233
|
-
? `npx @claude-flow/cli@latest hooks pre-task --task-id "task-${cmd.timestamp()}" --description $env:TOOL_INPUT_prompt`
|
|
234
|
-
: `npx @claude-flow/cli@latest hooks pre-task --task-id "task-${cmd.timestamp()}" --description "$TOOL_INPUT_prompt"`),
|
|
235
|
-
timeout: config.timeout,
|
|
236
|
-
continueOnError: true,
|
|
237
176
|
},
|
|
238
177
|
],
|
|
239
178
|
},
|
|
240
179
|
];
|
|
241
180
|
}
|
|
242
|
-
// PostToolUse
|
|
181
|
+
// PostToolUse — record edits for session metrics / learning
|
|
243
182
|
if (config.postToolUse) {
|
|
244
183
|
hooks.PostToolUse = [
|
|
245
|
-
// File edit hooks with neural pattern training
|
|
246
|
-
{
|
|
247
|
-
matcher: '^(Write|Edit|MultiEdit)$',
|
|
248
|
-
hooks: [
|
|
249
|
-
{
|
|
250
|
-
type: 'command',
|
|
251
|
-
command: cmd.ifVar('TOOL_INPUT_file_path', isWindows
|
|
252
|
-
? 'npx @claude-flow/cli@latest hooks post-edit --file $env:TOOL_INPUT_file_path --success $($env:TOOL_SUCCESS ?? "true")'
|
|
253
|
-
: 'npx @claude-flow/cli@latest hooks post-edit --file "$TOOL_INPUT_file_path" --success "${TOOL_SUCCESS:-true}"'),
|
|
254
|
-
timeout: config.timeout,
|
|
255
|
-
continueOnError: true,
|
|
256
|
-
},
|
|
257
|
-
],
|
|
258
|
-
},
|
|
259
|
-
// Bash command hooks with metrics tracking
|
|
260
|
-
{
|
|
261
|
-
matcher: '^Bash$',
|
|
262
|
-
hooks: [
|
|
263
|
-
{
|
|
264
|
-
type: 'command',
|
|
265
|
-
command: cmd.ifVar('TOOL_INPUT_command', isWindows
|
|
266
|
-
? 'npx @claude-flow/cli@latest hooks post-command --command $env:TOOL_INPUT_command --success $($env:TOOL_SUCCESS ?? "true")'
|
|
267
|
-
: 'npx @claude-flow/cli@latest hooks post-command --command "$TOOL_INPUT_command" --success "${TOOL_SUCCESS:-true}"'),
|
|
268
|
-
timeout: config.timeout,
|
|
269
|
-
continueOnError: true,
|
|
270
|
-
},
|
|
271
|
-
],
|
|
272
|
-
},
|
|
273
|
-
// Task completion hooks - use task-id
|
|
274
184
|
{
|
|
275
|
-
matcher: '
|
|
185
|
+
matcher: 'Write|Edit|MultiEdit',
|
|
276
186
|
hooks: [
|
|
277
187
|
{
|
|
278
188
|
type: 'command',
|
|
279
|
-
command:
|
|
280
|
-
|
|
281
|
-
: 'npx @claude-flow/cli@latest hooks post-task --task-id "$TOOL_RESULT_agent_id" --success "${TOOL_SUCCESS:-true}"'),
|
|
282
|
-
timeout: config.timeout,
|
|
283
|
-
continueOnError: true,
|
|
189
|
+
command: 'node .claude/helpers/hook-handler.cjs post-edit',
|
|
190
|
+
timeout: 10000,
|
|
284
191
|
},
|
|
285
192
|
],
|
|
286
193
|
},
|
|
287
194
|
];
|
|
288
195
|
}
|
|
289
|
-
// UserPromptSubmit
|
|
196
|
+
// UserPromptSubmit — intelligent task routing
|
|
290
197
|
if (config.userPromptSubmit) {
|
|
291
198
|
hooks.UserPromptSubmit = [
|
|
292
199
|
{
|
|
293
200
|
hooks: [
|
|
294
201
|
{
|
|
295
202
|
type: 'command',
|
|
296
|
-
command:
|
|
297
|
-
|
|
298
|
-
: 'npx @claude-flow/cli@latest hooks route --task "$PROMPT"'),
|
|
299
|
-
timeout: config.timeout,
|
|
300
|
-
continueOnError: true,
|
|
203
|
+
command: 'node .claude/helpers/hook-handler.cjs route',
|
|
204
|
+
timeout: 10000,
|
|
301
205
|
},
|
|
302
206
|
],
|
|
303
207
|
},
|
|
304
208
|
];
|
|
305
209
|
}
|
|
306
|
-
// SessionStart
|
|
210
|
+
// SessionStart — restore session state + import auto memory
|
|
307
211
|
if (config.sessionStart) {
|
|
308
212
|
hooks.SessionStart = [
|
|
309
213
|
{
|
|
214
|
+
matcher: 'startup|resume',
|
|
310
215
|
hooks: [
|
|
311
216
|
{
|
|
312
217
|
type: 'command',
|
|
313
|
-
command:
|
|
314
|
-
timeout:
|
|
315
|
-
continueOnError: true,
|
|
316
|
-
},
|
|
317
|
-
{
|
|
318
|
-
type: 'command',
|
|
319
|
-
command: cmd.simple('node .claude/helpers/auto-memory-hook.mjs import'),
|
|
320
|
-
timeout: 6000,
|
|
218
|
+
command: 'node .claude/helpers/hook-handler.cjs session-restore',
|
|
219
|
+
timeout: 15000,
|
|
321
220
|
continueOnError: true,
|
|
322
221
|
},
|
|
323
222
|
{
|
|
324
223
|
type: 'command',
|
|
325
|
-
command:
|
|
326
|
-
|
|
327
|
-
: 'npx @claude-flow/cli@latest hooks session-restore --session-id "$SESSION_ID"'),
|
|
328
|
-
timeout: 10000,
|
|
224
|
+
command: 'node .claude/helpers/auto-memory-hook.mjs import',
|
|
225
|
+
timeout: 8000,
|
|
329
226
|
continueOnError: true,
|
|
330
227
|
},
|
|
331
228
|
],
|
|
332
229
|
},
|
|
333
230
|
];
|
|
334
231
|
}
|
|
335
|
-
// SessionEnd
|
|
232
|
+
// SessionEnd — persist session state
|
|
336
233
|
if (config.sessionStart) {
|
|
337
234
|
hooks.SessionEnd = [
|
|
338
235
|
{
|
|
339
236
|
hooks: [
|
|
340
237
|
{
|
|
341
238
|
type: 'command',
|
|
342
|
-
command:
|
|
343
|
-
timeout:
|
|
344
|
-
continueOnError: true,
|
|
345
|
-
},
|
|
346
|
-
{
|
|
347
|
-
type: 'command',
|
|
348
|
-
command: cmd.simple('npx @claude-flow/cli@latest hooks session-end --persist-memory true --export-patterns true'),
|
|
349
|
-
timeout: 8000,
|
|
239
|
+
command: 'node .claude/helpers/hook-handler.cjs session-end',
|
|
240
|
+
timeout: 10000,
|
|
350
241
|
continueOnError: true,
|
|
351
242
|
},
|
|
352
243
|
],
|
|
353
244
|
},
|
|
354
245
|
];
|
|
355
246
|
}
|
|
356
|
-
// Stop
|
|
357
|
-
// The hook outputs JSON that Claude Code validates
|
|
247
|
+
// Stop — sync auto memory on exit
|
|
358
248
|
if (config.stop) {
|
|
359
249
|
hooks.Stop = [
|
|
360
250
|
{
|
|
361
251
|
hooks: [
|
|
362
252
|
{
|
|
363
253
|
type: 'command',
|
|
364
|
-
command:
|
|
365
|
-
timeout:
|
|
366
|
-
},
|
|
367
|
-
],
|
|
368
|
-
},
|
|
369
|
-
];
|
|
370
|
-
}
|
|
371
|
-
// Notification hooks - store notifications in memory for swarm awareness
|
|
372
|
-
if (config.notification) {
|
|
373
|
-
hooks.Notification = [
|
|
374
|
-
{
|
|
375
|
-
hooks: [
|
|
376
|
-
{
|
|
377
|
-
type: 'command',
|
|
378
|
-
command: cmd.ifVar('NOTIFICATION_MESSAGE', isWindows
|
|
379
|
-
? `npx @claude-flow/cli@latest memory store --namespace notifications --key "notify-${cmd.timestamp()}" --value $env:NOTIFICATION_MESSAGE`
|
|
380
|
-
: `npx @claude-flow/cli@latest memory store --namespace notifications --key "notify-${cmd.timestamp()}" --value "$NOTIFICATION_MESSAGE"`),
|
|
381
|
-
timeout: 3000,
|
|
254
|
+
command: 'node .claude/helpers/auto-memory-hook.mjs sync',
|
|
255
|
+
timeout: 10000,
|
|
382
256
|
continueOnError: true,
|
|
383
257
|
},
|
|
384
258
|
],
|
|
385
259
|
},
|
|
386
260
|
];
|
|
387
261
|
}
|
|
388
|
-
//
|
|
389
|
-
|
|
390
|
-
// Agent Teams hooks - TeammateIdle for task assignment, TaskCompleted for coordination
|
|
391
|
-
hooks.TeammateIdle = [
|
|
392
|
-
{
|
|
393
|
-
hooks: [
|
|
394
|
-
{
|
|
395
|
-
type: 'command',
|
|
396
|
-
command: cmd.simple('npx @claude-flow/cli@latest hooks teammate-idle --auto-assign true'),
|
|
397
|
-
timeout: 5000,
|
|
398
|
-
continueOnError: true,
|
|
399
|
-
},
|
|
400
|
-
],
|
|
401
|
-
},
|
|
402
|
-
];
|
|
403
|
-
hooks.TaskCompleted = [
|
|
262
|
+
// SubagentStart — status update
|
|
263
|
+
hooks.SubagentStart = [
|
|
404
264
|
{
|
|
405
265
|
hooks: [
|
|
406
266
|
{
|
|
407
267
|
type: 'command',
|
|
408
|
-
command:
|
|
409
|
-
|
|
410
|
-
: 'npx @claude-flow/cli@latest hooks task-completed --task-id "$TASK_ID" --train-patterns true'),
|
|
411
|
-
timeout: 5000,
|
|
268
|
+
command: 'node .claude/helpers/hook-handler.cjs status',
|
|
269
|
+
timeout: 3000,
|
|
412
270
|
continueOnError: true,
|
|
413
271
|
},
|
|
414
272
|
],
|