@claudetools/tools 0.8.2 → 0.8.4
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/dist/cli.js +41 -0
- package/dist/context/deduplication.d.ts +72 -0
- package/dist/context/deduplication.js +77 -0
- package/dist/context/deduplication.test.d.ts +6 -0
- package/dist/context/deduplication.test.js +84 -0
- package/dist/context/emergency-eviction.d.ts +73 -0
- package/dist/context/emergency-eviction.example.d.ts +13 -0
- package/dist/context/emergency-eviction.example.js +94 -0
- package/dist/context/emergency-eviction.js +226 -0
- package/dist/context/eviction-engine.d.ts +76 -0
- package/dist/context/eviction-engine.example.d.ts +7 -0
- package/dist/context/eviction-engine.example.js +144 -0
- package/dist/context/eviction-engine.js +176 -0
- package/dist/context/example-usage.d.ts +1 -0
- package/dist/context/example-usage.js +128 -0
- package/dist/context/exchange-summariser.d.ts +80 -0
- package/dist/context/exchange-summariser.js +261 -0
- package/dist/context/health-monitor.d.ts +97 -0
- package/dist/context/health-monitor.example.d.ts +1 -0
- package/dist/context/health-monitor.example.js +164 -0
- package/dist/context/health-monitor.js +210 -0
- package/dist/context/importance-scorer.d.ts +94 -0
- package/dist/context/importance-scorer.example.d.ts +1 -0
- package/dist/context/importance-scorer.example.js +140 -0
- package/dist/context/importance-scorer.js +187 -0
- package/dist/context/index.d.ts +9 -0
- package/dist/context/index.js +16 -0
- package/dist/context/session-helper.d.ts +10 -0
- package/dist/context/session-helper.js +51 -0
- package/dist/context/session-store.d.ts +94 -0
- package/dist/context/session-store.js +286 -0
- package/dist/context/usage-estimator.d.ts +131 -0
- package/dist/context/usage-estimator.js +260 -0
- package/dist/context/usage-estimator.test.d.ts +1 -0
- package/dist/context/usage-estimator.test.js +208 -0
- package/dist/context-cli.d.ts +16 -0
- package/dist/context-cli.js +309 -0
- package/dist/evaluation/build-dataset.d.ts +1 -0
- package/dist/evaluation/build-dataset.js +135 -0
- package/dist/evaluation/threshold-eval.d.ts +63 -0
- package/dist/evaluation/threshold-eval.js +250 -0
- package/dist/handlers/codedna-handlers.d.ts +2 -2
- package/dist/handlers/tool-handlers.js +126 -165
- package/dist/helpers/api-client.d.ts +5 -1
- package/dist/helpers/api-client.js +3 -1
- package/dist/helpers/compact-formatter.d.ts +51 -0
- package/dist/helpers/compact-formatter.js +130 -0
- package/dist/helpers/engagement-tracker.d.ts +10 -0
- package/dist/helpers/engagement-tracker.js +61 -0
- package/dist/helpers/error-tracking.js +1 -1
- package/dist/helpers/session-validation.d.ts +76 -0
- package/dist/helpers/session-validation.js +221 -0
- package/dist/helpers/usage-analytics.js +1 -1
- package/dist/hooks/index.d.ts +4 -0
- package/dist/hooks/index.js +6 -0
- package/dist/hooks/post-tool-use-hook-cli.d.ts +2 -0
- package/dist/hooks/post-tool-use-hook-cli.js +34 -0
- package/dist/hooks/post-tool-use.d.ts +67 -0
- package/dist/hooks/post-tool-use.js +234 -0
- package/dist/hooks/stop-hook-cli.d.ts +2 -0
- package/dist/hooks/stop-hook-cli.js +34 -0
- package/dist/hooks/stop.d.ts +64 -0
- package/dist/hooks/stop.js +192 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.js +2 -0
- package/dist/logger.d.ts +1 -1
- package/dist/logger.js +4 -0
- package/dist/resources.js +3 -0
- package/dist/setup.js +206 -2
- package/dist/templates/claude-md.d.ts +1 -1
- package/dist/templates/claude-md.js +23 -35
- package/dist/templates/worker-prompt.js +35 -202
- package/dist/tools.js +26 -20
- package/package.json +6 -2
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
// =============================================================================
|
|
2
|
+
// Engagement Tracking Helper
|
|
3
|
+
// =============================================================================
|
|
4
|
+
// Tracks memory engagement events to the API for persistence
|
|
5
|
+
// =============================================================================
|
|
6
|
+
import { mcpLogger } from '../logger.js';
|
|
7
|
+
import { API_BASE_URL } from './config.js';
|
|
8
|
+
/**
|
|
9
|
+
* Track an engagement event via the API
|
|
10
|
+
* This persists the event to D1 for analytics
|
|
11
|
+
*/
|
|
12
|
+
export async function trackEngagementEvent(sessionId, projectId, eventType) {
|
|
13
|
+
try {
|
|
14
|
+
// Get API key from environment
|
|
15
|
+
const apiKey = process.env.CLAUDETOOLS_API_KEY;
|
|
16
|
+
if (!apiKey) {
|
|
17
|
+
mcpLogger.debug('API', 'No API key - skipping engagement tracking');
|
|
18
|
+
return;
|
|
19
|
+
}
|
|
20
|
+
const response = await fetch(`${API_BASE_URL}/api/v1/engagement/track`, {
|
|
21
|
+
method: 'POST',
|
|
22
|
+
headers: {
|
|
23
|
+
'Content-Type': 'application/json',
|
|
24
|
+
Authorization: `Bearer ${apiKey}`,
|
|
25
|
+
},
|
|
26
|
+
body: JSON.stringify({
|
|
27
|
+
session_id: sessionId,
|
|
28
|
+
project_id: projectId,
|
|
29
|
+
event_type: eventType,
|
|
30
|
+
}),
|
|
31
|
+
});
|
|
32
|
+
if (!response.ok) {
|
|
33
|
+
mcpLogger.warn('API', `Failed to track engagement event: ${response.status}`);
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
36
|
+
mcpLogger.debug('API', `Tracked ${eventType} event for session ${sessionId}`);
|
|
37
|
+
}
|
|
38
|
+
catch (error) {
|
|
39
|
+
// Don't fail the main operation if tracking fails
|
|
40
|
+
mcpLogger.debug('API', `Failed to track engagement event: ${error}`);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Get current session ID
|
|
45
|
+
* This should ideally come from Claude Code's session system
|
|
46
|
+
* For now, we'll use a simple timestamp-based session ID
|
|
47
|
+
*/
|
|
48
|
+
let currentSessionId = null;
|
|
49
|
+
export function getSessionId() {
|
|
50
|
+
if (!currentSessionId) {
|
|
51
|
+
// Generate session ID: session_<timestamp>
|
|
52
|
+
currentSessionId = `session_${Date.now()}`;
|
|
53
|
+
}
|
|
54
|
+
return currentSessionId;
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Reset session ID (for testing or explicit session boundaries)
|
|
58
|
+
*/
|
|
59
|
+
export function resetSessionId() {
|
|
60
|
+
currentSessionId = null;
|
|
61
|
+
}
|
|
@@ -28,7 +28,7 @@ export class CodeDNAErrorTracker {
|
|
|
28
28
|
// Store error in memory system as a fact
|
|
29
29
|
const userId = DEFAULT_USER_ID;
|
|
30
30
|
const projectId = error.projectId || resolveProjectId();
|
|
31
|
-
await storeFact(projectId, 'CodeDNA', 'ERROR_OCCURRED', error.operation, JSON.stringify(errorRecord), userId);
|
|
31
|
+
await storeFact(projectId, 'CodeDNA', 'ERROR_OCCURRED', error.operation, JSON.stringify(errorRecord), { userId });
|
|
32
32
|
// Log to console for immediate visibility
|
|
33
33
|
console.error('[CodeDNA Error]', {
|
|
34
34
|
operation: error.operation,
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Record a tool call in the session
|
|
3
|
+
*/
|
|
4
|
+
export declare function recordToolCall(name: string, args?: Record<string, unknown>): void;
|
|
5
|
+
/**
|
|
6
|
+
* Validate that memory_search was called before task_start
|
|
7
|
+
* Returns validation result with warnings if violated
|
|
8
|
+
*/
|
|
9
|
+
export declare function validateTaskStartSequence(taskId: string): {
|
|
10
|
+
valid: boolean;
|
|
11
|
+
warnings: string[];
|
|
12
|
+
};
|
|
13
|
+
/**
|
|
14
|
+
* Validate that codebase_map was called before code modification tools
|
|
15
|
+
* Code modification tools: codedna_generate_*, or any task involving file changes
|
|
16
|
+
*/
|
|
17
|
+
export declare function validateCodebaseMapSequence(): {
|
|
18
|
+
valid: boolean;
|
|
19
|
+
warnings: string[];
|
|
20
|
+
};
|
|
21
|
+
/**
|
|
22
|
+
* Check if a tool name indicates code modification
|
|
23
|
+
*/
|
|
24
|
+
export declare function isCodeModificationTool(toolName: string): boolean;
|
|
25
|
+
/**
|
|
26
|
+
* Record when auto-injected context is used
|
|
27
|
+
* This tracks the +20 point event when context is automatically provided
|
|
28
|
+
*/
|
|
29
|
+
export declare function recordContextReference(projectId?: string): void;
|
|
30
|
+
/**
|
|
31
|
+
* Calculate engagement score (0-100)
|
|
32
|
+
* - memory_search: +30
|
|
33
|
+
* - memory_detail: +20
|
|
34
|
+
* - memory_inject: +20
|
|
35
|
+
* - memory_store_fact: +10
|
|
36
|
+
* - context_referenced: +20
|
|
37
|
+
*/
|
|
38
|
+
export declare function calculateEngagementScore(): number;
|
|
39
|
+
/**
|
|
40
|
+
* Get engagement statistics
|
|
41
|
+
*/
|
|
42
|
+
export declare function getEngagementStats(): {
|
|
43
|
+
score: number;
|
|
44
|
+
breakdown: {
|
|
45
|
+
searchCount: number;
|
|
46
|
+
searchPoints: number;
|
|
47
|
+
detailCount: number;
|
|
48
|
+
detailPoints: number;
|
|
49
|
+
injectCount: number;
|
|
50
|
+
injectPoints: number;
|
|
51
|
+
storeFactCount: number;
|
|
52
|
+
storeFactPoints: number;
|
|
53
|
+
contextReferencedCount: number;
|
|
54
|
+
contextReferencedPoints: number;
|
|
55
|
+
};
|
|
56
|
+
};
|
|
57
|
+
/**
|
|
58
|
+
* Get session statistics for debugging
|
|
59
|
+
*/
|
|
60
|
+
export declare function getSessionStats(): {
|
|
61
|
+
totalCalls: number;
|
|
62
|
+
uniqueTaskStarts: number;
|
|
63
|
+
uniqueSearches: number;
|
|
64
|
+
codebaseMapCalled: boolean;
|
|
65
|
+
recentCalls: string[];
|
|
66
|
+
engagement: ReturnType<typeof getEngagementStats>;
|
|
67
|
+
};
|
|
68
|
+
/**
|
|
69
|
+
* Clear session state (for testing or manual reset)
|
|
70
|
+
*/
|
|
71
|
+
export declare function clearSessionState(): void;
|
|
72
|
+
/**
|
|
73
|
+
* Get formatted warnings for tool execution
|
|
74
|
+
* Returns null if no warnings
|
|
75
|
+
*/
|
|
76
|
+
export declare function getToolCallWarnings(toolName: string, args?: Record<string, unknown>): string | null;
|
|
@@ -0,0 +1,221 @@
|
|
|
1
|
+
// =============================================================================
|
|
2
|
+
// Session-level Tool Call Validation
|
|
3
|
+
// =============================================================================
|
|
4
|
+
// Tracks tool call sequences within a session to enforce best practices:
|
|
5
|
+
// - memory_search before task_start
|
|
6
|
+
// - codebase_map before code modifications
|
|
7
|
+
// - No code in task descriptions (enforced via validateTaskDescription)
|
|
8
|
+
import { mcpLogger } from '../logger.js';
|
|
9
|
+
import { trackEngagementEvent, getSessionId } from './engagement-tracker.js';
|
|
10
|
+
const sessionState = {
|
|
11
|
+
toolCalls: [],
|
|
12
|
+
taskStarts: new Set(),
|
|
13
|
+
memorySearches: new Set(),
|
|
14
|
+
codebaseMapCalled: false,
|
|
15
|
+
engagement: {
|
|
16
|
+
searchCount: 0,
|
|
17
|
+
detailCount: 0,
|
|
18
|
+
injectCount: 0,
|
|
19
|
+
storeFactCount: 0,
|
|
20
|
+
contextReferencedCount: 0,
|
|
21
|
+
},
|
|
22
|
+
};
|
|
23
|
+
/**
|
|
24
|
+
* Record a tool call in the session
|
|
25
|
+
*/
|
|
26
|
+
export function recordToolCall(name, args) {
|
|
27
|
+
sessionState.toolCalls.push({
|
|
28
|
+
name,
|
|
29
|
+
timestamp: Date.now(),
|
|
30
|
+
args,
|
|
31
|
+
});
|
|
32
|
+
// Track specific tool types
|
|
33
|
+
if (name === 'task_start' && args?.task_id) {
|
|
34
|
+
sessionState.taskStarts.add(args.task_id);
|
|
35
|
+
}
|
|
36
|
+
if (name === 'memory_search' && args?.query) {
|
|
37
|
+
sessionState.memorySearches.add(args.query);
|
|
38
|
+
}
|
|
39
|
+
if (name === 'codebase_map') {
|
|
40
|
+
sessionState.codebaseMapCalled = true;
|
|
41
|
+
}
|
|
42
|
+
// Track engagement and persist to API
|
|
43
|
+
const projectId = args?.project_id;
|
|
44
|
+
let eventType;
|
|
45
|
+
switch (name) {
|
|
46
|
+
case 'memory_search':
|
|
47
|
+
sessionState.engagement.searchCount++;
|
|
48
|
+
eventType = 'search';
|
|
49
|
+
break;
|
|
50
|
+
case 'memory_detail':
|
|
51
|
+
sessionState.engagement.detailCount++;
|
|
52
|
+
eventType = 'detail';
|
|
53
|
+
break;
|
|
54
|
+
case 'memory_inject':
|
|
55
|
+
sessionState.engagement.injectCount++;
|
|
56
|
+
eventType = 'inject';
|
|
57
|
+
break;
|
|
58
|
+
case 'memory_store_fact':
|
|
59
|
+
sessionState.engagement.storeFactCount++;
|
|
60
|
+
eventType = 'store_fact';
|
|
61
|
+
break;
|
|
62
|
+
}
|
|
63
|
+
// Track to API if this is a memory tool
|
|
64
|
+
if (eventType && projectId) {
|
|
65
|
+
trackEngagementEvent(getSessionId(), projectId, eventType).catch(() => {
|
|
66
|
+
// Silently fail - don't block the tool call
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
mcpLogger.debug('TOOL', `Recorded tool call: ${name}`);
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Validate that memory_search was called before task_start
|
|
73
|
+
* Returns validation result with warnings if violated
|
|
74
|
+
*/
|
|
75
|
+
export function validateTaskStartSequence(taskId) {
|
|
76
|
+
const warnings = [];
|
|
77
|
+
// Check if any memory_search happened in this session
|
|
78
|
+
if (sessionState.memorySearches.size === 0) {
|
|
79
|
+
warnings.push('BEST PRACTICE: Call memory_search() before task_start() to recall relevant context and past decisions.');
|
|
80
|
+
}
|
|
81
|
+
// Check recent tool calls (last 10 calls)
|
|
82
|
+
const recentCalls = sessionState.toolCalls.slice(-10).map(c => c.name);
|
|
83
|
+
const hasRecentMemorySearch = recentCalls.includes('memory_search');
|
|
84
|
+
if (!hasRecentMemorySearch && sessionState.memorySearches.size > 0) {
|
|
85
|
+
warnings.push('RECOMMENDATION: Consider calling memory_search() to check for updated context since your last search.');
|
|
86
|
+
}
|
|
87
|
+
return {
|
|
88
|
+
valid: warnings.length === 0,
|
|
89
|
+
warnings,
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Validate that codebase_map was called before code modification tools
|
|
94
|
+
* Code modification tools: codedna_generate_*, or any task involving file changes
|
|
95
|
+
*/
|
|
96
|
+
export function validateCodebaseMapSequence() {
|
|
97
|
+
const warnings = [];
|
|
98
|
+
if (!sessionState.codebaseMapCalled) {
|
|
99
|
+
warnings.push('BEST PRACTICE: Call codebase_map() before making code changes to understand project structure and prevent conflicts.');
|
|
100
|
+
}
|
|
101
|
+
return {
|
|
102
|
+
valid: warnings.length === 0,
|
|
103
|
+
warnings,
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* Check if a tool name indicates code modification
|
|
108
|
+
*/
|
|
109
|
+
export function isCodeModificationTool(toolName) {
|
|
110
|
+
const codeTools = [
|
|
111
|
+
'codedna_generate_api',
|
|
112
|
+
'codedna_generate_frontend',
|
|
113
|
+
'codedna_generate_component',
|
|
114
|
+
'task_start', // Tasks often involve code changes
|
|
115
|
+
];
|
|
116
|
+
return codeTools.includes(toolName);
|
|
117
|
+
}
|
|
118
|
+
/**
|
|
119
|
+
* Record when auto-injected context is used
|
|
120
|
+
* This tracks the +20 point event when context is automatically provided
|
|
121
|
+
*/
|
|
122
|
+
export function recordContextReference(projectId) {
|
|
123
|
+
sessionState.engagement.contextReferencedCount++;
|
|
124
|
+
// Track to API if project ID is available
|
|
125
|
+
if (projectId) {
|
|
126
|
+
trackEngagementEvent(getSessionId(), projectId, 'context_referenced').catch(() => {
|
|
127
|
+
// Silently fail - don't block the resource read
|
|
128
|
+
});
|
|
129
|
+
}
|
|
130
|
+
mcpLogger.debug('TOOL', 'Recorded context reference (auto-inject)');
|
|
131
|
+
}
|
|
132
|
+
/**
|
|
133
|
+
* Calculate engagement score (0-100)
|
|
134
|
+
* - memory_search: +30
|
|
135
|
+
* - memory_detail: +20
|
|
136
|
+
* - memory_inject: +20
|
|
137
|
+
* - memory_store_fact: +10
|
|
138
|
+
* - context_referenced: +20
|
|
139
|
+
*/
|
|
140
|
+
export function calculateEngagementScore() {
|
|
141
|
+
const { searchCount, detailCount, injectCount, storeFactCount, contextReferencedCount } = sessionState.engagement;
|
|
142
|
+
const rawScore = searchCount * 30 +
|
|
143
|
+
detailCount * 20 +
|
|
144
|
+
injectCount * 20 +
|
|
145
|
+
storeFactCount * 10 +
|
|
146
|
+
contextReferencedCount * 20;
|
|
147
|
+
// Cap at 100
|
|
148
|
+
return Math.min(rawScore, 100);
|
|
149
|
+
}
|
|
150
|
+
/**
|
|
151
|
+
* Get engagement statistics
|
|
152
|
+
*/
|
|
153
|
+
export function getEngagementStats() {
|
|
154
|
+
const { searchCount, detailCount, injectCount, storeFactCount, contextReferencedCount } = sessionState.engagement;
|
|
155
|
+
return {
|
|
156
|
+
score: calculateEngagementScore(),
|
|
157
|
+
breakdown: {
|
|
158
|
+
searchCount,
|
|
159
|
+
searchPoints: searchCount * 30,
|
|
160
|
+
detailCount,
|
|
161
|
+
detailPoints: detailCount * 20,
|
|
162
|
+
injectCount,
|
|
163
|
+
injectPoints: injectCount * 20,
|
|
164
|
+
storeFactCount,
|
|
165
|
+
storeFactPoints: storeFactCount * 10,
|
|
166
|
+
contextReferencedCount,
|
|
167
|
+
contextReferencedPoints: contextReferencedCount * 20,
|
|
168
|
+
},
|
|
169
|
+
};
|
|
170
|
+
}
|
|
171
|
+
/**
|
|
172
|
+
* Get session statistics for debugging
|
|
173
|
+
*/
|
|
174
|
+
export function getSessionStats() {
|
|
175
|
+
return {
|
|
176
|
+
totalCalls: sessionState.toolCalls.length,
|
|
177
|
+
uniqueTaskStarts: sessionState.taskStarts.size,
|
|
178
|
+
uniqueSearches: sessionState.memorySearches.size,
|
|
179
|
+
codebaseMapCalled: sessionState.codebaseMapCalled,
|
|
180
|
+
recentCalls: sessionState.toolCalls.slice(-10).map(c => c.name),
|
|
181
|
+
engagement: getEngagementStats(),
|
|
182
|
+
};
|
|
183
|
+
}
|
|
184
|
+
/**
|
|
185
|
+
* Clear session state (for testing or manual reset)
|
|
186
|
+
*/
|
|
187
|
+
export function clearSessionState() {
|
|
188
|
+
sessionState.toolCalls = [];
|
|
189
|
+
sessionState.taskStarts.clear();
|
|
190
|
+
sessionState.memorySearches.clear();
|
|
191
|
+
sessionState.codebaseMapCalled = false;
|
|
192
|
+
sessionState.engagement = {
|
|
193
|
+
searchCount: 0,
|
|
194
|
+
detailCount: 0,
|
|
195
|
+
injectCount: 0,
|
|
196
|
+
storeFactCount: 0,
|
|
197
|
+
contextReferencedCount: 0,
|
|
198
|
+
};
|
|
199
|
+
mcpLogger.debug('TOOL', 'Session state cleared');
|
|
200
|
+
}
|
|
201
|
+
/**
|
|
202
|
+
* Get formatted warnings for tool execution
|
|
203
|
+
* Returns null if no warnings
|
|
204
|
+
*/
|
|
205
|
+
export function getToolCallWarnings(toolName, args) {
|
|
206
|
+
const warnings = [];
|
|
207
|
+
// Validate task_start sequence
|
|
208
|
+
if (toolName === 'task_start' && args?.task_id) {
|
|
209
|
+
const validation = validateTaskStartSequence(args.task_id);
|
|
210
|
+
warnings.push(...validation.warnings);
|
|
211
|
+
}
|
|
212
|
+
// Validate codebase_map before code changes
|
|
213
|
+
if (isCodeModificationTool(toolName)) {
|
|
214
|
+
const validation = validateCodebaseMapSequence();
|
|
215
|
+
warnings.push(...validation.warnings);
|
|
216
|
+
}
|
|
217
|
+
if (warnings.length === 0) {
|
|
218
|
+
return null;
|
|
219
|
+
}
|
|
220
|
+
return `\n⚠️ WORKFLOW RECOMMENDATIONS:\n${warnings.map(w => ` - ${w}`).join('\n')}\n`;
|
|
221
|
+
}
|
|
@@ -29,7 +29,7 @@ export class UsageAnalytics {
|
|
|
29
29
|
const userId = DEFAULT_USER_ID;
|
|
30
30
|
const projectId = event.projectId || resolveProjectId();
|
|
31
31
|
// Store as fact in memory system
|
|
32
|
-
await storeFact(projectId, 'CodeDNA', 'GENERATION_COMPLETED', event.generator || event.operation, JSON.stringify(usageEvent), userId);
|
|
32
|
+
await storeFact(projectId, 'CodeDNA', 'GENERATION_COMPLETED', event.generator || event.operation, JSON.stringify(usageEvent), { userId });
|
|
33
33
|
console.log('[CodeDNA Analytics]', {
|
|
34
34
|
operation: event.operation,
|
|
35
35
|
generator: event.generator,
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
export { handleStopHook, sessionStore, usageEstimator } from './stop.js';
|
|
2
|
+
export type { StopHookInput, SessionData, ContextHealth } from './stop.js';
|
|
3
|
+
export { handlePostToolUseHook, sessionStore as postToolUseSessionStore, evictionEngine, } from './post-tool-use.js';
|
|
4
|
+
export type { PostToolUseInput, SessionData as PostToolUseSessionData, EvictionTrigger, } from './post-tool-use.js';
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
// =============================================================================
|
|
2
|
+
// Claude Code Hooks - Index
|
|
3
|
+
// =============================================================================
|
|
4
|
+
// Exports hook handlers for Claude Code integration
|
|
5
|
+
export { handleStopHook, sessionStore, usageEstimator } from './stop.js';
|
|
6
|
+
export { handlePostToolUseHook, sessionStore as postToolUseSessionStore, evictionEngine, } from './post-tool-use.js';
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// =============================================================================
|
|
3
|
+
// Post-Tool-Use Hook CLI Entry Point
|
|
4
|
+
// =============================================================================
|
|
5
|
+
// Called by Claude Code when PostToolUse event occurs
|
|
6
|
+
// Reads hook input from stdin, processes it, and outputs to stdout/stderr
|
|
7
|
+
import { handlePostToolUseHook } from './post-tool-use.js';
|
|
8
|
+
async function main() {
|
|
9
|
+
try {
|
|
10
|
+
// Read JSON input from stdin
|
|
11
|
+
let inputData = '';
|
|
12
|
+
// Set up stdin reading
|
|
13
|
+
process.stdin.setEncoding('utf8');
|
|
14
|
+
for await (const chunk of process.stdin) {
|
|
15
|
+
inputData += chunk;
|
|
16
|
+
}
|
|
17
|
+
// Parse hook input
|
|
18
|
+
const hookInput = JSON.parse(inputData);
|
|
19
|
+
// Validate hook event
|
|
20
|
+
if (hookInput.hook_event_name !== 'PostToolUse') {
|
|
21
|
+
console.error(`Error: Expected PostToolUse event, got ${hookInput.hook_event_name}`);
|
|
22
|
+
process.exit(1);
|
|
23
|
+
}
|
|
24
|
+
// Process the hook
|
|
25
|
+
await handlePostToolUseHook(hookInput);
|
|
26
|
+
// Success - exit code 0
|
|
27
|
+
process.exit(0);
|
|
28
|
+
}
|
|
29
|
+
catch (error) {
|
|
30
|
+
console.error('Error processing PostToolUse hook:', error);
|
|
31
|
+
process.exit(1);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
main();
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
interface PostToolUseInput {
|
|
2
|
+
session_id?: string;
|
|
3
|
+
hook_event_name: 'PostToolUse';
|
|
4
|
+
tool_name: string;
|
|
5
|
+
tool_input?: Record<string, unknown>;
|
|
6
|
+
tool_output?: string;
|
|
7
|
+
post_tool_use_active?: boolean;
|
|
8
|
+
}
|
|
9
|
+
interface EvictionTrigger {
|
|
10
|
+
triggered: boolean;
|
|
11
|
+
level: 'none' | 'standard' | 'emergency';
|
|
12
|
+
estimated_fill: number;
|
|
13
|
+
message: string;
|
|
14
|
+
}
|
|
15
|
+
interface SessionData {
|
|
16
|
+
session_id: string;
|
|
17
|
+
tool_executions: number;
|
|
18
|
+
estimated_tokens: number;
|
|
19
|
+
context_limit: number;
|
|
20
|
+
estimated_fill: number;
|
|
21
|
+
last_updated: Date;
|
|
22
|
+
tool_output_tokens: number;
|
|
23
|
+
}
|
|
24
|
+
declare class SessionStore {
|
|
25
|
+
/**
|
|
26
|
+
* Get or create session data
|
|
27
|
+
*/
|
|
28
|
+
getSession(sessionId: string): SessionData;
|
|
29
|
+
/**
|
|
30
|
+
* Update session with tool output tokens
|
|
31
|
+
*/
|
|
32
|
+
updateSession(sessionId: string, outputTokens: number): SessionData;
|
|
33
|
+
/**
|
|
34
|
+
* Clear session (for cleanup)
|
|
35
|
+
*/
|
|
36
|
+
clearSession(sessionId: string): void;
|
|
37
|
+
/**
|
|
38
|
+
* Get all sessions (for debugging)
|
|
39
|
+
*/
|
|
40
|
+
getAllSessions(): SessionData[];
|
|
41
|
+
}
|
|
42
|
+
declare const sessionStore: SessionStore;
|
|
43
|
+
declare class EvictionTriggerEngine {
|
|
44
|
+
/**
|
|
45
|
+
* Check if eviction should be triggered based on fill percentage
|
|
46
|
+
*/
|
|
47
|
+
checkEvictionTrigger(session: SessionData): EvictionTrigger;
|
|
48
|
+
/**
|
|
49
|
+
* Run standard eviction cycle
|
|
50
|
+
* NOTE: This is a placeholder - actual implementation would call into
|
|
51
|
+
* the context rotation/eviction system when it's built
|
|
52
|
+
*/
|
|
53
|
+
runStandardEviction(session: SessionData): Promise<void>;
|
|
54
|
+
/**
|
|
55
|
+
* Run emergency eviction cycle
|
|
56
|
+
* More aggressive eviction for critical situations
|
|
57
|
+
*/
|
|
58
|
+
runEmergencyEviction(session: SessionData): Promise<void>;
|
|
59
|
+
}
|
|
60
|
+
declare const evictionEngine: EvictionTriggerEngine;
|
|
61
|
+
/**
|
|
62
|
+
* Handle PostToolUse hook event
|
|
63
|
+
* Updates session state with tool output and triggers eviction if needed
|
|
64
|
+
*/
|
|
65
|
+
export declare function handlePostToolUseHook(input: PostToolUseInput): Promise<void>;
|
|
66
|
+
export { sessionStore, evictionEngine };
|
|
67
|
+
export type { PostToolUseInput, SessionData, EvictionTrigger };
|