@claude-flow/cli 3.1.0-alpha.20 → 3.1.0-alpha.21
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/helpers/hook-handler.cjs +136 -124
- package/package.json +1 -1
|
@@ -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
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@claude-flow/cli",
|
|
3
|
-
"version": "3.1.0-alpha.
|
|
3
|
+
"version": "3.1.0-alpha.21",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Claude Flow CLI - Enterprise AI agent orchestration with 60+ specialized agents, swarm coordination, MCP server, self-learning hooks, and vector memory for Claude Code",
|
|
6
6
|
"main": "dist/src/index.js",
|