cmp-standards 2.8.0 → 2.8.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/dist/experts/ExpertVotePersistence.d.ts +86 -0
- package/dist/experts/ExpertVotePersistence.d.ts.map +1 -0
- package/dist/experts/ExpertVotePersistence.js +234 -0
- package/dist/experts/ExpertVotePersistence.js.map +1 -0
- package/dist/experts/index.d.ts +1 -0
- package/dist/experts/index.d.ts.map +1 -1
- package/dist/experts/index.js +2 -0
- package/dist/experts/index.js.map +1 -1
- package/dist/hooks/cloud-post-tool-use.d.ts +5 -0
- package/dist/hooks/cloud-post-tool-use.d.ts.map +1 -1
- package/dist/hooks/cloud-post-tool-use.js +43 -10
- package/dist/hooks/cloud-post-tool-use.js.map +1 -1
- package/dist/hooks/cloud-session-start.d.ts.map +1 -1
- package/dist/hooks/cloud-session-start.js +64 -0
- package/dist/hooks/cloud-session-start.js.map +1 -1
- package/dist/hooks/index.d.ts +1 -0
- package/dist/hooks/index.d.ts.map +1 -1
- package/dist/hooks/index.js +2 -0
- package/dist/hooks/index.js.map +1 -1
- package/dist/hooks/session-end.d.ts +67 -0
- package/dist/hooks/session-end.d.ts.map +1 -0
- package/dist/hooks/session-end.js +268 -0
- package/dist/hooks/session-end.js.map +1 -0
- package/dist/mcp/schemas.d.ts +2 -2
- package/dist/performance/Debouncer.d.ts +57 -0
- package/dist/performance/Debouncer.d.ts.map +1 -1
- package/dist/performance/Debouncer.js +149 -0
- package/dist/performance/Debouncer.js.map +1 -1
- package/dist/performance/index.d.ts +1 -1
- package/dist/performance/index.d.ts.map +1 -1
- package/dist/performance/index.js +3 -1
- package/dist/performance/index.js.map +1 -1
- package/dist/schema/expert-types.d.ts +2 -2
- package/dist/services/FeedbackCollector.d.ts +63 -0
- package/dist/services/FeedbackCollector.d.ts.map +1 -0
- package/dist/services/FeedbackCollector.js +219 -0
- package/dist/services/FeedbackCollector.js.map +1 -0
- package/dist/services/index.d.ts +2 -1
- package/dist/services/index.d.ts.map +1 -1
- package/dist/services/index.js +3 -1
- package/dist/services/index.js.map +1 -1
- package/dist/services/pattern-tracker.d.ts +50 -0
- package/dist/services/pattern-tracker.d.ts.map +1 -1
- package/dist/services/pattern-tracker.js +148 -0
- package/dist/services/pattern-tracker.js.map +1 -1
- package/package.json +1 -1
package/dist/hooks/index.d.ts
CHANGED
|
@@ -8,5 +8,6 @@ export { MemoryCheckpointHook, runMemoryCheckpointHook } from './memory-checkpoi
|
|
|
8
8
|
export { onSessionStart as cloudSessionStart } from './cloud-session-start.js';
|
|
9
9
|
export { onPreToolUse as cloudPreToolUse } from './cloud-pre-tool-use.js';
|
|
10
10
|
export { onPostToolUse as cloudPostToolUse } from './cloud-post-tool-use.js';
|
|
11
|
+
export { onSessionEnd, getSessionSummaries, getSessionStats, SessionEndEvent, SessionSummary, SessionEndResult, } from './session-end.js';
|
|
11
12
|
export { ExpertReviewHook, ExpertReviewConfig, ReviewRequest, ReviewResult, getExpertReviewHook, resetExpertReviewHook, onExpertReview, } from './expert-review.js';
|
|
12
13
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/hooks/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAGH,OAAO,EAAE,gBAAgB,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAA;AAC1E,OAAO,EAAE,cAAc,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAA;AACrE,OAAO,EAAE,eAAe,EAAE,kBAAkB,EAAE,MAAM,oBAAoB,CAAA;AACxE,OAAO,EAAE,oBAAoB,EAAE,uBAAuB,EAAE,MAAM,wBAAwB,CAAA;AAGtF,OAAO,EAAE,cAAc,IAAI,iBAAiB,EAAE,MAAM,0BAA0B,CAAA;AAC9E,OAAO,EAAE,YAAY,IAAI,eAAe,EAAE,MAAM,yBAAyB,CAAA;AACzE,OAAO,EAAE,aAAa,IAAI,gBAAgB,EAAE,MAAM,0BAA0B,CAAA;AAG5E,OAAO,EACL,gBAAgB,EAChB,kBAAkB,EAClB,aAAa,EACb,YAAY,EACZ,mBAAmB,EACnB,qBAAqB,EACrB,cAAc,GACf,MAAM,oBAAoB,CAAA"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/hooks/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAGH,OAAO,EAAE,gBAAgB,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAA;AAC1E,OAAO,EAAE,cAAc,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAA;AACrE,OAAO,EAAE,eAAe,EAAE,kBAAkB,EAAE,MAAM,oBAAoB,CAAA;AACxE,OAAO,EAAE,oBAAoB,EAAE,uBAAuB,EAAE,MAAM,wBAAwB,CAAA;AAGtF,OAAO,EAAE,cAAc,IAAI,iBAAiB,EAAE,MAAM,0BAA0B,CAAA;AAC9E,OAAO,EAAE,YAAY,IAAI,eAAe,EAAE,MAAM,yBAAyB,CAAA;AACzE,OAAO,EAAE,aAAa,IAAI,gBAAgB,EAAE,MAAM,0BAA0B,CAAA;AAG5E,OAAO,EACL,YAAY,EACZ,mBAAmB,EACnB,eAAe,EACf,eAAe,EACf,cAAc,EACd,gBAAgB,GACjB,MAAM,kBAAkB,CAAA;AAGzB,OAAO,EACL,gBAAgB,EAChB,kBAAkB,EAClB,aAAa,EACb,YAAY,EACZ,mBAAmB,EACnB,qBAAqB,EACrB,cAAc,GACf,MAAM,oBAAoB,CAAA"}
|
package/dist/hooks/index.js
CHANGED
|
@@ -10,6 +10,8 @@ export { MemoryCheckpointHook, runMemoryCheckpointHook } from './memory-checkpoi
|
|
|
10
10
|
export { onSessionStart as cloudSessionStart } from './cloud-session-start.js';
|
|
11
11
|
export { onPreToolUse as cloudPreToolUse } from './cloud-pre-tool-use.js';
|
|
12
12
|
export { onPostToolUse as cloudPostToolUse } from './cloud-post-tool-use.js';
|
|
13
|
+
// Session End hook (v2.8 - Analytics)
|
|
14
|
+
export { onSessionEnd, getSessionSummaries, getSessionStats, } from './session-end.js';
|
|
13
15
|
// Expert Review hook (v2.8)
|
|
14
16
|
export { ExpertReviewHook, getExpertReviewHook, resetExpertReviewHook, onExpertReview, } from './expert-review.js';
|
|
15
17
|
//# sourceMappingURL=index.js.map
|
package/dist/hooks/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/hooks/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,6BAA6B;AAC7B,OAAO,EAAE,gBAAgB,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAA;AAC1E,OAAO,EAAE,cAAc,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAA;AACrE,OAAO,EAAE,eAAe,EAAE,kBAAkB,EAAE,MAAM,oBAAoB,CAAA;AACxE,OAAO,EAAE,oBAAoB,EAAE,uBAAuB,EAAE,MAAM,wBAAwB,CAAA;AAEtF,gCAAgC;AAChC,OAAO,EAAE,cAAc,IAAI,iBAAiB,EAAE,MAAM,0BAA0B,CAAA;AAC9E,OAAO,EAAE,YAAY,IAAI,eAAe,EAAE,MAAM,yBAAyB,CAAA;AACzE,OAAO,EAAE,aAAa,IAAI,gBAAgB,EAAE,MAAM,0BAA0B,CAAA;AAE5E,4BAA4B;AAC5B,OAAO,EACL,gBAAgB,EAIhB,mBAAmB,EACnB,qBAAqB,EACrB,cAAc,GACf,MAAM,oBAAoB,CAAA"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/hooks/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,6BAA6B;AAC7B,OAAO,EAAE,gBAAgB,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAA;AAC1E,OAAO,EAAE,cAAc,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAA;AACrE,OAAO,EAAE,eAAe,EAAE,kBAAkB,EAAE,MAAM,oBAAoB,CAAA;AACxE,OAAO,EAAE,oBAAoB,EAAE,uBAAuB,EAAE,MAAM,wBAAwB,CAAA;AAEtF,gCAAgC;AAChC,OAAO,EAAE,cAAc,IAAI,iBAAiB,EAAE,MAAM,0BAA0B,CAAA;AAC9E,OAAO,EAAE,YAAY,IAAI,eAAe,EAAE,MAAM,yBAAyB,CAAA;AACzE,OAAO,EAAE,aAAa,IAAI,gBAAgB,EAAE,MAAM,0BAA0B,CAAA;AAE5E,sCAAsC;AACtC,OAAO,EACL,YAAY,EACZ,mBAAmB,EACnB,eAAe,GAIhB,MAAM,kBAAkB,CAAA;AAEzB,4BAA4B;AAC5B,OAAO,EACL,gBAAgB,EAIhB,mBAAmB,EACnB,qBAAqB,EACrB,cAAc,GACf,MAAM,oBAAoB,CAAA"}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file Session End Hook
|
|
3
|
+
* @description Captures session analytics and persists summary for learning
|
|
4
|
+
*
|
|
5
|
+
* Features:
|
|
6
|
+
* - Record session duration and tool usage
|
|
7
|
+
* - Track files modified during session
|
|
8
|
+
* - Count patterns detected and memories created
|
|
9
|
+
* - Enable session-over-session trend analysis
|
|
10
|
+
*
|
|
11
|
+
* @version 1.0.0
|
|
12
|
+
*/
|
|
13
|
+
import type { DevSystem } from '../types/index.js';
|
|
14
|
+
export interface SessionEndEvent {
|
|
15
|
+
cwd: string;
|
|
16
|
+
sessionId: string;
|
|
17
|
+
reason?: 'user_exit' | 'timeout' | 'error' | 'unknown';
|
|
18
|
+
}
|
|
19
|
+
export interface SessionSummary {
|
|
20
|
+
id: string;
|
|
21
|
+
sessionId: string;
|
|
22
|
+
system: DevSystem;
|
|
23
|
+
duration: number;
|
|
24
|
+
startedAt: string;
|
|
25
|
+
endedAt: string;
|
|
26
|
+
reason: string;
|
|
27
|
+
toolCalls: Record<string, number>;
|
|
28
|
+
totalToolCalls: number;
|
|
29
|
+
filesModified: string[];
|
|
30
|
+
filesRead: string[];
|
|
31
|
+
tasksStarted: number;
|
|
32
|
+
tasksCompleted: number;
|
|
33
|
+
memoriesCreated: number;
|
|
34
|
+
memoriesAccessed: number;
|
|
35
|
+
patternsDetected: number;
|
|
36
|
+
improvementsGenerated: number;
|
|
37
|
+
cacheHitRate: number;
|
|
38
|
+
debounceSkipRate: number;
|
|
39
|
+
}
|
|
40
|
+
export interface SessionEndResult {
|
|
41
|
+
success: boolean;
|
|
42
|
+
summaryId?: string;
|
|
43
|
+
duration?: number;
|
|
44
|
+
error?: string;
|
|
45
|
+
}
|
|
46
|
+
export declare function onSessionEnd(event: SessionEndEvent): Promise<SessionEndResult>;
|
|
47
|
+
/**
|
|
48
|
+
* Get session summaries for analytics
|
|
49
|
+
*/
|
|
50
|
+
export declare function getSessionSummaries(system: DevSystem, limit?: number): Promise<SessionSummary[]>;
|
|
51
|
+
/**
|
|
52
|
+
* Get aggregate statistics across sessions
|
|
53
|
+
*/
|
|
54
|
+
export declare function getSessionStats(system: DevSystem, days?: number): Promise<{
|
|
55
|
+
totalSessions: number;
|
|
56
|
+
avgDuration: number;
|
|
57
|
+
totalToolCalls: number;
|
|
58
|
+
avgTasksCompleted: number;
|
|
59
|
+
avgCacheHitRate: number;
|
|
60
|
+
avgDebounceRate: number;
|
|
61
|
+
topTools: Array<{
|
|
62
|
+
tool: string;
|
|
63
|
+
count: number;
|
|
64
|
+
}>;
|
|
65
|
+
}>;
|
|
66
|
+
export default onSessionEnd;
|
|
67
|
+
//# sourceMappingURL=session-end.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"session-end.d.ts","sourceRoot":"","sources":["../../src/hooks/session-end.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAUH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAA;AAMlD,MAAM,WAAW,eAAe;IAC9B,GAAG,EAAE,MAAM,CAAA;IACX,SAAS,EAAE,MAAM,CAAA;IACjB,MAAM,CAAC,EAAE,WAAW,GAAG,SAAS,GAAG,OAAO,GAAG,SAAS,CAAA;CACvD;AAED,MAAM,WAAW,cAAc;IAC7B,EAAE,EAAE,MAAM,CAAA;IACV,SAAS,EAAE,MAAM,CAAA;IACjB,MAAM,EAAE,SAAS,CAAA;IACjB,QAAQ,EAAE,MAAM,CAAA;IAChB,SAAS,EAAE,MAAM,CAAA;IACjB,OAAO,EAAE,MAAM,CAAA;IACf,MAAM,EAAE,MAAM,CAAA;IAGd,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IACjC,cAAc,EAAE,MAAM,CAAA;IAGtB,aAAa,EAAE,MAAM,EAAE,CAAA;IACvB,SAAS,EAAE,MAAM,EAAE,CAAA;IAGnB,YAAY,EAAE,MAAM,CAAA;IACpB,cAAc,EAAE,MAAM,CAAA;IAGtB,eAAe,EAAE,MAAM,CAAA;IACvB,gBAAgB,EAAE,MAAM,CAAA;IAGxB,gBAAgB,EAAE,MAAM,CAAA;IACxB,qBAAqB,EAAE,MAAM,CAAA;IAG7B,YAAY,EAAE,MAAM,CAAA;IACpB,gBAAgB,EAAE,MAAM,CAAA;CACzB;AAED,MAAM,WAAW,gBAAgB;IAC/B,OAAO,EAAE,OAAO,CAAA;IAChB,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,KAAK,CAAC,EAAE,MAAM,CAAA;CACf;AAuBD,wBAAsB,YAAY,CAAC,KAAK,EAAE,eAAe,GAAG,OAAO,CAAC,gBAAgB,CAAC,CAoKpF;AAMD;;GAEG;AACH,wBAAsB,mBAAmB,CACvC,MAAM,EAAE,SAAS,EACjB,KAAK,SAAK,GACT,OAAO,CAAC,cAAc,EAAE,CAAC,CAqB3B;AAED;;GAEG;AACH,wBAAsB,eAAe,CAAC,MAAM,EAAE,SAAS,EAAE,IAAI,SAAI,GAAG,OAAO,CAAC;IAC1E,aAAa,EAAE,MAAM,CAAA;IACrB,WAAW,EAAE,MAAM,CAAA;IACnB,cAAc,EAAE,MAAM,CAAA;IACtB,iBAAiB,EAAE,MAAM,CAAA;IACzB,eAAe,EAAE,MAAM,CAAA;IACvB,eAAe,EAAE,MAAM,CAAA;IACvB,QAAQ,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC,CAAA;CACjD,CAAC,CAoDD;AA0BD,eAAe,YAAY,CAAA"}
|
|
@@ -0,0 +1,268 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file Session End Hook
|
|
3
|
+
* @description Captures session analytics and persists summary for learning
|
|
4
|
+
*
|
|
5
|
+
* Features:
|
|
6
|
+
* - Record session duration and tool usage
|
|
7
|
+
* - Track files modified during session
|
|
8
|
+
* - Count patterns detected and memories created
|
|
9
|
+
* - Enable session-over-session trend analysis
|
|
10
|
+
*
|
|
11
|
+
* @version 1.0.0
|
|
12
|
+
*/
|
|
13
|
+
import { ulid } from 'ulid';
|
|
14
|
+
import { config } from 'dotenv';
|
|
15
|
+
import { resolve } from 'path';
|
|
16
|
+
import { turso } from '../db/turso-client.js';
|
|
17
|
+
import { upstash } from '../db/upstash-client.js';
|
|
18
|
+
import { getSmartDebouncer } from '../performance/Debouncer.js';
|
|
19
|
+
import { getEmbeddingCache } from '../cache/EmbeddingCache.js';
|
|
20
|
+
import { feedbackCollector } from '../services/FeedbackCollector.js';
|
|
21
|
+
// =============================================================================
|
|
22
|
+
// System Detection (copied from session-start for standalone use)
|
|
23
|
+
// =============================================================================
|
|
24
|
+
function detectSystem(cwd) {
|
|
25
|
+
if (cwd.includes('swarmscale') || cwd.includes('SwarmScale')) {
|
|
26
|
+
return 'SWARMSCALE';
|
|
27
|
+
}
|
|
28
|
+
if (cwd.includes('easycharter') || cwd.includes('charter')) {
|
|
29
|
+
return 'PANEL';
|
|
30
|
+
}
|
|
31
|
+
if (cwd.includes('carlosmartinpavon')) {
|
|
32
|
+
return 'ECOSYSTEM';
|
|
33
|
+
}
|
|
34
|
+
return 'ECOSYSTEM';
|
|
35
|
+
}
|
|
36
|
+
// =============================================================================
|
|
37
|
+
// Hook Implementation
|
|
38
|
+
// =============================================================================
|
|
39
|
+
export async function onSessionEnd(event) {
|
|
40
|
+
// Load environment
|
|
41
|
+
const envPaths = [
|
|
42
|
+
resolve(event.cwd, '.env'),
|
|
43
|
+
resolve(event.cwd, '../.env'),
|
|
44
|
+
resolve(event.cwd, '../../.env')
|
|
45
|
+
];
|
|
46
|
+
for (const envPath of envPaths) {
|
|
47
|
+
config({ path: envPath });
|
|
48
|
+
}
|
|
49
|
+
const system = detectSystem(event.cwd);
|
|
50
|
+
const endedAt = new Date().toISOString();
|
|
51
|
+
try {
|
|
52
|
+
const db = turso.getClient();
|
|
53
|
+
// 1. Get session info from Redis
|
|
54
|
+
let sessionInfo = null;
|
|
55
|
+
try {
|
|
56
|
+
const cached = await upstash.getCache(`session_metrics:${event.sessionId}`);
|
|
57
|
+
sessionInfo = cached;
|
|
58
|
+
}
|
|
59
|
+
catch {
|
|
60
|
+
// Redis might not be available
|
|
61
|
+
}
|
|
62
|
+
const startedAt = sessionInfo?.startedAt || new Date(Date.now() - 3600000).toISOString();
|
|
63
|
+
const duration = new Date(endedAt).getTime() - new Date(startedAt).getTime();
|
|
64
|
+
// 2. Get task counts for this session
|
|
65
|
+
const taskCounts = await db.execute({
|
|
66
|
+
sql: `SELECT
|
|
67
|
+
SUM(CASE WHEN json_extract(content, '$.sessionId') = ? AND status = 'active' THEN 1 ELSE 0 END) as started,
|
|
68
|
+
SUM(CASE WHEN json_extract(content, '$.sessionId') = ? AND status = 'done' THEN 1 ELSE 0 END) as completed
|
|
69
|
+
FROM items
|
|
70
|
+
WHERE system = ? AND type = 'task'`,
|
|
71
|
+
args: [event.sessionId, event.sessionId, system]
|
|
72
|
+
});
|
|
73
|
+
const taskRow = taskCounts.rows[0] || { started: 0, completed: 0 };
|
|
74
|
+
// 3. Get memory counts for this session
|
|
75
|
+
const memoryCounts = await db.execute({
|
|
76
|
+
sql: `SELECT COUNT(*) as created FROM items
|
|
77
|
+
WHERE system = ? AND type = 'memory'
|
|
78
|
+
AND json_extract(content, '$.sessionId') = ?`,
|
|
79
|
+
args: [system, event.sessionId]
|
|
80
|
+
});
|
|
81
|
+
const memoryRow = memoryCounts.rows[0] || { created: 0 };
|
|
82
|
+
// 4. Get pattern counts for this session
|
|
83
|
+
const patternCounts = await db.execute({
|
|
84
|
+
sql: `SELECT COUNT(*) as detected FROM items
|
|
85
|
+
WHERE system = ? AND type = 'pattern'
|
|
86
|
+
AND date(created_at) = date('now')`,
|
|
87
|
+
args: [system]
|
|
88
|
+
});
|
|
89
|
+
const patternRow = patternCounts.rows[0] || { detected: 0 };
|
|
90
|
+
// 5. Get improvement counts
|
|
91
|
+
const improvementCounts = await db.execute({
|
|
92
|
+
sql: `SELECT COUNT(*) as generated FROM items
|
|
93
|
+
WHERE system = ? AND type = 'auto_improvement'
|
|
94
|
+
AND date(created_at) = date('now')`,
|
|
95
|
+
args: [system]
|
|
96
|
+
});
|
|
97
|
+
const improvementRow = improvementCounts.rows[0] || { generated: 0 };
|
|
98
|
+
// 6. Get performance metrics
|
|
99
|
+
const embeddingCache = getEmbeddingCache();
|
|
100
|
+
const cacheStats = embeddingCache.getStats();
|
|
101
|
+
const smartDebouncer = getSmartDebouncer();
|
|
102
|
+
const debounceStats = smartDebouncer.getStats();
|
|
103
|
+
// 7. Get top-scored memories accessed count
|
|
104
|
+
const topScored = await feedbackCollector.getTopScoredMemories(system, 10);
|
|
105
|
+
const memoriesAccessed = topScored.reduce((sum, m) => sum + m.accessCount, 0);
|
|
106
|
+
// 8. Build summary
|
|
107
|
+
const summary = {
|
|
108
|
+
id: `ss_${ulid()}`,
|
|
109
|
+
sessionId: event.sessionId,
|
|
110
|
+
system,
|
|
111
|
+
duration,
|
|
112
|
+
startedAt,
|
|
113
|
+
endedAt,
|
|
114
|
+
reason: event.reason || 'unknown',
|
|
115
|
+
toolCalls: sessionInfo?.toolCalls || {},
|
|
116
|
+
totalToolCalls: Object.values(sessionInfo?.toolCalls || {}).reduce((a, b) => a + b, 0),
|
|
117
|
+
filesModified: sessionInfo?.filesModified || [],
|
|
118
|
+
filesRead: sessionInfo?.filesRead || [],
|
|
119
|
+
tasksStarted: Number(taskRow.started) || 0,
|
|
120
|
+
tasksCompleted: Number(taskRow.completed) || 0,
|
|
121
|
+
memoriesCreated: Number(memoryRow.created) || 0,
|
|
122
|
+
memoriesAccessed,
|
|
123
|
+
patternsDetected: Number(patternRow.detected) || 0,
|
|
124
|
+
improvementsGenerated: Number(improvementRow.generated) || 0,
|
|
125
|
+
cacheHitRate: cacheStats.hitRate,
|
|
126
|
+
debounceSkipRate: debounceStats.skipRate
|
|
127
|
+
};
|
|
128
|
+
// 9. Persist summary
|
|
129
|
+
await db.execute({
|
|
130
|
+
sql: `INSERT INTO items (id, type, system, status, content, created_at, updated_at)
|
|
131
|
+
VALUES (?, 'session_summary', ?, 'active', ?, ?, ?)`,
|
|
132
|
+
args: [
|
|
133
|
+
summary.id,
|
|
134
|
+
system,
|
|
135
|
+
JSON.stringify(summary),
|
|
136
|
+
endedAt,
|
|
137
|
+
endedAt
|
|
138
|
+
]
|
|
139
|
+
});
|
|
140
|
+
// 10. Cleanup Redis session data
|
|
141
|
+
try {
|
|
142
|
+
await upstash.deleteCache(`session_metrics:${event.sessionId}`);
|
|
143
|
+
await upstash.deleteCache(`session:${event.sessionId}`);
|
|
144
|
+
}
|
|
145
|
+
catch {
|
|
146
|
+
// Redis cleanup is best-effort
|
|
147
|
+
}
|
|
148
|
+
console.log(`[session-end] Session ${event.sessionId} completed:`);
|
|
149
|
+
console.log(` Duration: ${Math.round(duration / 1000 / 60)} minutes`);
|
|
150
|
+
console.log(` Tool calls: ${summary.totalToolCalls}`);
|
|
151
|
+
console.log(` Files modified: ${summary.filesModified.length}`);
|
|
152
|
+
console.log(` Tasks completed: ${summary.tasksCompleted}`);
|
|
153
|
+
console.log(` Cache hit rate: ${(summary.cacheHitRate * 100).toFixed(1)}%`);
|
|
154
|
+
return {
|
|
155
|
+
success: true,
|
|
156
|
+
summaryId: summary.id,
|
|
157
|
+
duration
|
|
158
|
+
};
|
|
159
|
+
}
|
|
160
|
+
catch (error) {
|
|
161
|
+
console.error('[session-end] Error:', error);
|
|
162
|
+
return {
|
|
163
|
+
success: false,
|
|
164
|
+
error: error instanceof Error ? error.message : 'Unknown error'
|
|
165
|
+
};
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
// =============================================================================
|
|
169
|
+
// Utility Functions
|
|
170
|
+
// =============================================================================
|
|
171
|
+
/**
|
|
172
|
+
* Get session summaries for analytics
|
|
173
|
+
*/
|
|
174
|
+
export async function getSessionSummaries(system, limit = 20) {
|
|
175
|
+
try {
|
|
176
|
+
const db = turso.getClient();
|
|
177
|
+
const result = await db.execute({
|
|
178
|
+
sql: `SELECT content FROM items
|
|
179
|
+
WHERE system = ? AND type = 'session_summary' AND status = 'active'
|
|
180
|
+
ORDER BY created_at DESC
|
|
181
|
+
LIMIT ?`,
|
|
182
|
+
args: [system, limit]
|
|
183
|
+
});
|
|
184
|
+
return result.rows.map(row => {
|
|
185
|
+
const content = typeof row.content === 'string'
|
|
186
|
+
? JSON.parse(row.content)
|
|
187
|
+
: row.content;
|
|
188
|
+
return content;
|
|
189
|
+
});
|
|
190
|
+
}
|
|
191
|
+
catch (error) {
|
|
192
|
+
console.error('[session-end] Failed to get summaries:', error);
|
|
193
|
+
return [];
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
/**
|
|
197
|
+
* Get aggregate statistics across sessions
|
|
198
|
+
*/
|
|
199
|
+
export async function getSessionStats(system, days = 7) {
|
|
200
|
+
const summaries = await getSessionSummaries(system, 100);
|
|
201
|
+
if (summaries.length === 0) {
|
|
202
|
+
return {
|
|
203
|
+
totalSessions: 0,
|
|
204
|
+
avgDuration: 0,
|
|
205
|
+
totalToolCalls: 0,
|
|
206
|
+
avgTasksCompleted: 0,
|
|
207
|
+
avgCacheHitRate: 0,
|
|
208
|
+
avgDebounceRate: 0,
|
|
209
|
+
topTools: []
|
|
210
|
+
};
|
|
211
|
+
}
|
|
212
|
+
// Filter to last N days
|
|
213
|
+
const cutoff = Date.now() - days * 24 * 60 * 60 * 1000;
|
|
214
|
+
const recent = summaries.filter(s => new Date(s.endedAt).getTime() > cutoff);
|
|
215
|
+
const toolCounts = new Map();
|
|
216
|
+
let totalDuration = 0;
|
|
217
|
+
let totalCalls = 0;
|
|
218
|
+
let totalTasksCompleted = 0;
|
|
219
|
+
let totalCacheRate = 0;
|
|
220
|
+
let totalDebounceRate = 0;
|
|
221
|
+
for (const s of recent) {
|
|
222
|
+
totalDuration += s.duration;
|
|
223
|
+
totalCalls += s.totalToolCalls;
|
|
224
|
+
totalTasksCompleted += s.tasksCompleted;
|
|
225
|
+
totalCacheRate += s.cacheHitRate;
|
|
226
|
+
totalDebounceRate += s.debounceSkipRate;
|
|
227
|
+
for (const [tool, count] of Object.entries(s.toolCalls)) {
|
|
228
|
+
toolCounts.set(tool, (toolCounts.get(tool) || 0) + count);
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
const topTools = Array.from(toolCounts.entries())
|
|
232
|
+
.map(([tool, count]) => ({ tool, count }))
|
|
233
|
+
.sort((a, b) => b.count - a.count)
|
|
234
|
+
.slice(0, 10);
|
|
235
|
+
return {
|
|
236
|
+
totalSessions: recent.length,
|
|
237
|
+
avgDuration: recent.length > 0 ? totalDuration / recent.length : 0,
|
|
238
|
+
totalToolCalls: totalCalls,
|
|
239
|
+
avgTasksCompleted: recent.length > 0 ? totalTasksCompleted / recent.length : 0,
|
|
240
|
+
avgCacheHitRate: recent.length > 0 ? totalCacheRate / recent.length : 0,
|
|
241
|
+
avgDebounceRate: recent.length > 0 ? totalDebounceRate / recent.length : 0,
|
|
242
|
+
topTools
|
|
243
|
+
};
|
|
244
|
+
}
|
|
245
|
+
// =============================================================================
|
|
246
|
+
// CLI Entry Point
|
|
247
|
+
// =============================================================================
|
|
248
|
+
if (process.argv[1]?.includes('session-end')) {
|
|
249
|
+
const cwd = process.cwd();
|
|
250
|
+
const sessionId = process.argv[2] || `session_${Date.now()}`;
|
|
251
|
+
const reason = process.argv[3] || 'user_exit';
|
|
252
|
+
onSessionEnd({ cwd, sessionId, reason })
|
|
253
|
+
.then(result => {
|
|
254
|
+
if (result.success) {
|
|
255
|
+
console.log(`Session ended successfully. Summary: ${result.summaryId}`);
|
|
256
|
+
}
|
|
257
|
+
else {
|
|
258
|
+
console.error(`Session end failed: ${result.error}`);
|
|
259
|
+
process.exit(1);
|
|
260
|
+
}
|
|
261
|
+
})
|
|
262
|
+
.catch(error => {
|
|
263
|
+
console.error('Error:', error.message);
|
|
264
|
+
process.exit(1);
|
|
265
|
+
});
|
|
266
|
+
}
|
|
267
|
+
export default onSessionEnd;
|
|
268
|
+
//# sourceMappingURL=session-end.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"session-end.js","sourceRoot":"","sources":["../../src/hooks/session-end.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAA;AAC3B,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAA;AAC/B,OAAO,EAAE,OAAO,EAAE,MAAM,MAAM,CAAA;AAC9B,OAAO,EAAE,KAAK,EAAE,MAAM,uBAAuB,CAAA;AAC7C,OAAO,EAAE,OAAO,EAAE,MAAM,yBAAyB,CAAA;AACjD,OAAO,EAAE,iBAAiB,EAAE,MAAM,6BAA6B,CAAA;AAC/D,OAAO,EAAE,iBAAiB,EAAE,MAAM,4BAA4B,CAAA;AAC9D,OAAO,EAAE,iBAAiB,EAAE,MAAM,kCAAkC,CAAA;AAsDpE,gFAAgF;AAChF,kEAAkE;AAClE,gFAAgF;AAEhF,SAAS,YAAY,CAAC,GAAW;IAC/B,IAAI,GAAG,CAAC,QAAQ,CAAC,YAAY,CAAC,IAAI,GAAG,CAAC,QAAQ,CAAC,YAAY,CAAC,EAAE,CAAC;QAC7D,OAAO,YAAY,CAAA;IACrB,CAAC;IACD,IAAI,GAAG,CAAC,QAAQ,CAAC,aAAa,CAAC,IAAI,GAAG,CAAC,QAAQ,CAAC,SAAS,CAAC,EAAE,CAAC;QAC3D,OAAO,OAAO,CAAA;IAChB,CAAC;IACD,IAAI,GAAG,CAAC,QAAQ,CAAC,mBAAmB,CAAC,EAAE,CAAC;QACtC,OAAO,WAAW,CAAA;IACpB,CAAC;IACD,OAAO,WAAW,CAAA;AACpB,CAAC;AAED,gFAAgF;AAChF,sBAAsB;AACtB,gFAAgF;AAEhF,MAAM,CAAC,KAAK,UAAU,YAAY,CAAC,KAAsB;IACvD,mBAAmB;IACnB,MAAM,QAAQ,GAAG;QACf,OAAO,CAAC,KAAK,CAAC,GAAG,EAAE,MAAM,CAAC;QAC1B,OAAO,CAAC,KAAK,CAAC,GAAG,EAAE,SAAS,CAAC;QAC7B,OAAO,CAAC,KAAK,CAAC,GAAG,EAAE,YAAY,CAAC;KACjC,CAAA;IAED,KAAK,MAAM,OAAO,IAAI,QAAQ,EAAE,CAAC;QAC/B,MAAM,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC,CAAA;IAC3B,CAAC;IAED,MAAM,MAAM,GAAG,YAAY,CAAC,KAAK,CAAC,GAAG,CAAC,CAAA;IACtC,MAAM,OAAO,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAA;IAExC,IAAI,CAAC;QACH,MAAM,EAAE,GAAG,KAAK,CAAC,SAAS,EAAE,CAAA;QAE5B,iCAAiC;QACjC,IAAI,WAAW,GAKJ,IAAI,CAAA;QAEf,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC,QAAQ,CAKlC,mBAAmB,KAAK,CAAC,SAAS,EAAE,CAAC,CAAA;YAExC,WAAW,GAAG,MAAM,CAAA;QACtB,CAAC;QAAC,MAAM,CAAC;YACP,+BAA+B;QACjC,CAAC;QAED,MAAM,SAAS,GAAG,WAAW,EAAE,SAAS,IAAI,IAAI,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,OAAO,CAAC,CAAC,WAAW,EAAE,CAAA;QACxF,MAAM,QAAQ,GAAG,IAAI,IAAI,CAAC,OAAO,CAAC,CAAC,OAAO,EAAE,GAAG,IAAI,IAAI,CAAC,SAAS,CAAC,CAAC,OAAO,EAAE,CAAA;QAE5E,sCAAsC;QACtC,MAAM,UAAU,GAAG,MAAM,EAAE,CAAC,OAAO,CAAC;YAClC,GAAG,EAAE;;;;+CAIoC;YACzC,IAAI,EAAE,CAAC,KAAK,CAAC,SAAS,EAAE,KAAK,CAAC,SAAS,EAAE,MAAM,CAAC;SACjD,CAAC,CAAA;QAEF,MAAM,OAAO,GAAG,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,EAAE,OAAO,EAAE,CAAC,EAAE,SAAS,EAAE,CAAC,EAAE,CAAA;QAElE,wCAAwC;QACxC,MAAM,YAAY,GAAG,MAAM,EAAE,CAAC,OAAO,CAAC;YACpC,GAAG,EAAE;;yDAE8C;YACnD,IAAI,EAAE,CAAC,MAAM,EAAE,KAAK,CAAC,SAAS,CAAC;SAChC,CAAC,CAAA;QAEF,MAAM,SAAS,GAAG,YAAY,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,EAAE,OAAO,EAAE,CAAC,EAAE,CAAA;QAExD,yCAAyC;QACzC,MAAM,aAAa,GAAG,MAAM,EAAE,CAAC,OAAO,CAAC;YACrC,GAAG,EAAE;;+CAEoC;YACzC,IAAI,EAAE,CAAC,MAAM,CAAC;SACf,CAAC,CAAA;QAEF,MAAM,UAAU,GAAG,aAAa,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,EAAE,QAAQ,EAAE,CAAC,EAAE,CAAA;QAE3D,4BAA4B;QAC5B,MAAM,iBAAiB,GAAG,MAAM,EAAE,CAAC,OAAO,CAAC;YACzC,GAAG,EAAE;;+CAEoC;YACzC,IAAI,EAAE,CAAC,MAAM,CAAC;SACf,CAAC,CAAA;QAEF,MAAM,cAAc,GAAG,iBAAiB,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,EAAE,SAAS,EAAE,CAAC,EAAE,CAAA;QAEpE,6BAA6B;QAC7B,MAAM,cAAc,GAAG,iBAAiB,EAAE,CAAA;QAC1C,MAAM,UAAU,GAAG,cAAc,CAAC,QAAQ,EAAE,CAAA;QAE5C,MAAM,cAAc,GAAG,iBAAiB,EAAE,CAAA;QAC1C,MAAM,aAAa,GAAG,cAAc,CAAC,QAAQ,EAAE,CAAA;QAE/C,4CAA4C;QAC5C,MAAM,SAAS,GAAG,MAAM,iBAAiB,CAAC,oBAAoB,CAAC,MAAM,EAAE,EAAE,CAAC,CAAA;QAC1E,MAAM,gBAAgB,GAAG,SAAS,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,CAAC,EAAE,EAAE,CAAC,GAAG,GAAG,CAAC,CAAC,WAAW,EAAE,CAAC,CAAC,CAAA;QAE7E,mBAAmB;QACnB,MAAM,OAAO,GAAmB;YAC9B,EAAE,EAAE,MAAM,IAAI,EAAE,EAAE;YAClB,SAAS,EAAE,KAAK,CAAC,SAAS;YAC1B,MAAM;YACN,QAAQ;YACR,SAAS;YACT,OAAO;YACP,MAAM,EAAE,KAAK,CAAC,MAAM,IAAI,SAAS;YAEjC,SAAS,EAAE,WAAW,EAAE,SAAS,IAAI,EAAE;YACvC,cAAc,EAAE,MAAM,CAAC,MAAM,CAAC,WAAW,EAAE,SAAS,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;YAEtF,aAAa,EAAE,WAAW,EAAE,aAAa,IAAI,EAAE;YAC/C,SAAS,EAAE,WAAW,EAAE,SAAS,IAAI,EAAE;YAEvC,YAAY,EAAE,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC;YAC1C,cAAc,EAAE,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,IAAI,CAAC;YAE9C,eAAe,EAAE,MAAM,CAAC,SAAS,CAAC,OAAO,CAAC,IAAI,CAAC;YAC/C,gBAAgB;YAEhB,gBAAgB,EAAE,MAAM,CAAC,UAAU,CAAC,QAAQ,CAAC,IAAI,CAAC;YAClD,qBAAqB,EAAE,MAAM,CAAC,cAAc,CAAC,SAAS,CAAC,IAAI,CAAC;YAE5D,YAAY,EAAE,UAAU,CAAC,OAAO;YAChC,gBAAgB,EAAE,aAAa,CAAC,QAAQ;SACzC,CAAA;QAED,qBAAqB;QACrB,MAAM,EAAE,CAAC,OAAO,CAAC;YACf,GAAG,EAAE;gEACqD;YAC1D,IAAI,EAAE;gBACJ,OAAO,CAAC,EAAE;gBACV,MAAM;gBACN,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC;gBACvB,OAAO;gBACP,OAAO;aACR;SACF,CAAC,CAAA;QAEF,iCAAiC;QACjC,IAAI,CAAC;YACH,MAAM,OAAO,CAAC,WAAW,CAAC,mBAAmB,KAAK,CAAC,SAAS,EAAE,CAAC,CAAA;YAC/D,MAAM,OAAO,CAAC,WAAW,CAAC,WAAW,KAAK,CAAC,SAAS,EAAE,CAAC,CAAA;QACzD,CAAC;QAAC,MAAM,CAAC;YACP,+BAA+B;QACjC,CAAC;QAED,OAAO,CAAC,GAAG,CAAC,yBAAyB,KAAK,CAAC,SAAS,aAAa,CAAC,CAAA;QAClE,OAAO,CAAC,GAAG,CAAC,eAAe,IAAI,CAAC,KAAK,CAAC,QAAQ,GAAG,IAAI,GAAG,EAAE,CAAC,UAAU,CAAC,CAAA;QACtE,OAAO,CAAC,GAAG,CAAC,iBAAiB,OAAO,CAAC,cAAc,EAAE,CAAC,CAAA;QACtD,OAAO,CAAC,GAAG,CAAC,qBAAqB,OAAO,CAAC,aAAa,CAAC,MAAM,EAAE,CAAC,CAAA;QAChE,OAAO,CAAC,GAAG,CAAC,sBAAsB,OAAO,CAAC,cAAc,EAAE,CAAC,CAAA;QAC3D,OAAO,CAAC,GAAG,CAAC,qBAAqB,CAAC,OAAO,CAAC,YAAY,GAAG,GAAG,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,CAAA;QAE5E,OAAO;YACL,OAAO,EAAE,IAAI;YACb,SAAS,EAAE,OAAO,CAAC,EAAE;YACrB,QAAQ;SACT,CAAA;IACH,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,OAAO,CAAC,KAAK,CAAC,sBAAsB,EAAE,KAAK,CAAC,CAAA;QAC5C,OAAO;YACL,OAAO,EAAE,KAAK;YACd,KAAK,EAAE,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,eAAe;SAChE,CAAA;IACH,CAAC;AACH,CAAC;AAED,gFAAgF;AAChF,oBAAoB;AACpB,gFAAgF;AAEhF;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,mBAAmB,CACvC,MAAiB,EACjB,KAAK,GAAG,EAAE;IAEV,IAAI,CAAC;QACH,MAAM,EAAE,GAAG,KAAK,CAAC,SAAS,EAAE,CAAA;QAC5B,MAAM,MAAM,GAAG,MAAM,EAAE,CAAC,OAAO,CAAC;YAC9B,GAAG,EAAE;;;oBAGS;YACd,IAAI,EAAE,CAAC,MAAM,EAAE,KAAK,CAAC;SACtB,CAAC,CAAA;QAEF,OAAO,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE;YAC3B,MAAM,OAAO,GAAG,OAAO,GAAG,CAAC,OAAO,KAAK,QAAQ;gBAC7C,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,OAAO,CAAC;gBACzB,CAAC,CAAC,GAAG,CAAC,OAAO,CAAA;YACf,OAAO,OAAyB,CAAA;QAClC,CAAC,CAAC,CAAA;IACJ,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,OAAO,CAAC,KAAK,CAAC,wCAAwC,EAAE,KAAK,CAAC,CAAA;QAC9D,OAAO,EAAE,CAAA;IACX,CAAC;AACH,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,eAAe,CAAC,MAAiB,EAAE,IAAI,GAAG,CAAC;IAS/D,MAAM,SAAS,GAAG,MAAM,mBAAmB,CAAC,MAAM,EAAE,GAAG,CAAC,CAAA;IAExD,IAAI,SAAS,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC3B,OAAO;YACL,aAAa,EAAE,CAAC;YAChB,WAAW,EAAE,CAAC;YACd,cAAc,EAAE,CAAC;YACjB,iBAAiB,EAAE,CAAC;YACpB,eAAe,EAAE,CAAC;YAClB,eAAe,EAAE,CAAC;YAClB,QAAQ,EAAE,EAAE;SACb,CAAA;IACH,CAAC;IAED,wBAAwB;IACxB,MAAM,MAAM,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI,CAAA;IACtD,MAAM,MAAM,GAAG,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,IAAI,IAAI,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,OAAO,EAAE,GAAG,MAAM,CAAC,CAAA;IAE5E,MAAM,UAAU,GAAG,IAAI,GAAG,EAAkB,CAAA;IAC5C,IAAI,aAAa,GAAG,CAAC,CAAA;IACrB,IAAI,UAAU,GAAG,CAAC,CAAA;IAClB,IAAI,mBAAmB,GAAG,CAAC,CAAA;IAC3B,IAAI,cAAc,GAAG,CAAC,CAAA;IACtB,IAAI,iBAAiB,GAAG,CAAC,CAAA;IAEzB,KAAK,MAAM,CAAC,IAAI,MAAM,EAAE,CAAC;QACvB,aAAa,IAAI,CAAC,CAAC,QAAQ,CAAA;QAC3B,UAAU,IAAI,CAAC,CAAC,cAAc,CAAA;QAC9B,mBAAmB,IAAI,CAAC,CAAC,cAAc,CAAA;QACvC,cAAc,IAAI,CAAC,CAAC,YAAY,CAAA;QAChC,iBAAiB,IAAI,CAAC,CAAC,gBAAgB,CAAA;QAEvC,KAAK,MAAM,CAAC,IAAI,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,SAAS,CAAC,EAAE,CAAC;YACxD,UAAU,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,GAAG,KAAK,CAAC,CAAA;QAC3D,CAAC;IACH,CAAC;IAED,MAAM,QAAQ,GAAG,KAAK,CAAC,IAAI,CAAC,UAAU,CAAC,OAAO,EAAE,CAAC;SAC9C,GAAG,CAAC,CAAC,CAAC,IAAI,EAAE,KAAK,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;SACzC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC,KAAK,CAAC;SACjC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAA;IAEf,OAAO;QACL,aAAa,EAAE,MAAM,CAAC,MAAM;QAC5B,WAAW,EAAE,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,aAAa,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;QAClE,cAAc,EAAE,UAAU;QAC1B,iBAAiB,EAAE,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,mBAAmB,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;QAC9E,eAAe,EAAE,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,cAAc,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;QACvE,eAAe,EAAE,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,iBAAiB,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;QAC1E,QAAQ;KACT,CAAA;AACH,CAAC;AAED,gFAAgF;AAChF,kBAAkB;AAClB,gFAAgF;AAEhF,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,QAAQ,CAAC,aAAa,CAAC,EAAE,CAAC;IAC7C,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,EAAE,CAAA;IACzB,MAAM,SAAS,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,WAAW,IAAI,CAAC,GAAG,EAAE,EAAE,CAAA;IAC5D,MAAM,MAAM,GAAI,OAAO,CAAC,IAAI,CAAC,CAAC,CAA+B,IAAI,WAAW,CAAA;IAE5E,YAAY,CAAC,EAAE,GAAG,EAAE,SAAS,EAAE,MAAM,EAAE,CAAC;SACrC,IAAI,CAAC,MAAM,CAAC,EAAE;QACb,IAAI,MAAM,CAAC,OAAO,EAAE,CAAC;YACnB,OAAO,CAAC,GAAG,CAAC,wCAAwC,MAAM,CAAC,SAAS,EAAE,CAAC,CAAA;QACzE,CAAC;aAAM,CAAC;YACN,OAAO,CAAC,KAAK,CAAC,uBAAuB,MAAM,CAAC,KAAK,EAAE,CAAC,CAAA;YACpD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;QACjB,CAAC;IACH,CAAC,CAAC;SACD,KAAK,CAAC,KAAK,CAAC,EAAE;QACb,OAAO,CAAC,KAAK,CAAC,QAAQ,EAAE,KAAK,CAAC,OAAO,CAAC,CAAA;QACtC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;IACjB,CAAC,CAAC,CAAA;AACN,CAAC;AAED,eAAe,YAAY,CAAA"}
|
package/dist/mcp/schemas.d.ts
CHANGED
|
@@ -139,12 +139,12 @@ export declare const FeedbackSubmitSchema: z.ZodObject<{
|
|
|
139
139
|
helpful: z.ZodBoolean;
|
|
140
140
|
comment: z.ZodOptional<z.ZodString>;
|
|
141
141
|
}, "strip", z.ZodTypeAny, {
|
|
142
|
-
memoryId: string;
|
|
143
142
|
helpful: boolean;
|
|
143
|
+
memoryId: string;
|
|
144
144
|
comment?: string | undefined;
|
|
145
145
|
}, {
|
|
146
|
-
memoryId: string;
|
|
147
146
|
helpful: boolean;
|
|
147
|
+
memoryId: string;
|
|
148
148
|
comment?: string | undefined;
|
|
149
149
|
}>;
|
|
150
150
|
export declare const TaskStartSchema: z.ZodObject<{
|
|
@@ -23,6 +23,19 @@ export interface DebouncerStats {
|
|
|
23
23
|
skipRate: number;
|
|
24
24
|
activeEntries: number;
|
|
25
25
|
}
|
|
26
|
+
/**
|
|
27
|
+
* Tool-specific debounce windows
|
|
28
|
+
* Different tools have different optimal debounce times
|
|
29
|
+
*/
|
|
30
|
+
export declare const TOOL_DEBOUNCE_CONFIG: Record<string, number>;
|
|
31
|
+
/**
|
|
32
|
+
* Get debounce window for a specific tool
|
|
33
|
+
*/
|
|
34
|
+
export declare function getToolDebounceMs(toolName: string): number;
|
|
35
|
+
/**
|
|
36
|
+
* Check if a tool should never be debounced (write operations)
|
|
37
|
+
*/
|
|
38
|
+
export declare function isWriteOperation(toolName: string): boolean;
|
|
26
39
|
export declare class Debouncer {
|
|
27
40
|
private config;
|
|
28
41
|
private entries;
|
|
@@ -84,8 +97,52 @@ export declare class HookDebouncer extends Debouncer {
|
|
|
84
97
|
constructor(config?: Partial<DebouncerConfig>);
|
|
85
98
|
shouldSkipHook(hookName: string, context: Record<string, unknown>): boolean;
|
|
86
99
|
}
|
|
100
|
+
/**
|
|
101
|
+
* Smart Debouncer with tool-specific windows
|
|
102
|
+
* Uses different debounce times based on tool type
|
|
103
|
+
*/
|
|
104
|
+
export declare class SmartDebouncer {
|
|
105
|
+
private entries;
|
|
106
|
+
private maxEntries;
|
|
107
|
+
private debug;
|
|
108
|
+
private stats;
|
|
109
|
+
constructor(options?: {
|
|
110
|
+
maxEntries?: number;
|
|
111
|
+
debug?: boolean;
|
|
112
|
+
});
|
|
113
|
+
/**
|
|
114
|
+
* Check if operation should be skipped based on tool-specific window
|
|
115
|
+
*/
|
|
116
|
+
shouldSkip(toolName: string, params: Record<string, unknown>): boolean;
|
|
117
|
+
private trackCall;
|
|
118
|
+
/**
|
|
119
|
+
* Cleanup old entries (uses longest debounce window)
|
|
120
|
+
*/
|
|
121
|
+
cleanup(): number;
|
|
122
|
+
/**
|
|
123
|
+
* Get statistics including per-tool breakdown
|
|
124
|
+
*/
|
|
125
|
+
getStats(): {
|
|
126
|
+
totalCalls: number;
|
|
127
|
+
skipped: number;
|
|
128
|
+
skipRate: number;
|
|
129
|
+
byTool: Record<string, {
|
|
130
|
+
total: number;
|
|
131
|
+
skipped: number;
|
|
132
|
+
skipRate: number;
|
|
133
|
+
}>;
|
|
134
|
+
};
|
|
135
|
+
/**
|
|
136
|
+
* Reset all state
|
|
137
|
+
*/
|
|
138
|
+
reset(): void;
|
|
139
|
+
}
|
|
87
140
|
export declare function getDebouncer(config?: Partial<DebouncerConfig>): Debouncer;
|
|
88
141
|
export declare function getEmbeddingDebouncer(config?: Partial<DebouncerConfig>): EmbeddingDebouncer;
|
|
89
142
|
export declare function getHookDebouncer(config?: Partial<DebouncerConfig>): HookDebouncer;
|
|
143
|
+
export declare function getSmartDebouncer(options?: {
|
|
144
|
+
maxEntries?: number;
|
|
145
|
+
debug?: boolean;
|
|
146
|
+
}): SmartDebouncer;
|
|
90
147
|
export declare function resetDebouncers(): void;
|
|
91
148
|
//# sourceMappingURL=Debouncer.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Debouncer.d.ts","sourceRoot":"","sources":["../../src/performance/Debouncer.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAQH,MAAM,WAAW,eAAe;IAC9B,sCAAsC;IACtC,QAAQ,EAAE,MAAM,CAAA;IAChB,0CAA0C;IAC1C,UAAU,EAAE,MAAM,CAAA;IAClB,2BAA2B;IAC3B,KAAK,EAAE,OAAO,CAAA;CACf;AAED,MAAM,WAAW,cAAc;IAC7B,UAAU,EAAE,MAAM,CAAA;IAClB,OAAO,EAAE,MAAM,CAAA;IACf,QAAQ,EAAE,MAAM,CAAA;IAChB,QAAQ,EAAE,MAAM,CAAA;IAChB,aAAa,EAAE,MAAM,CAAA;CACtB;AAiBD,qBAAa,SAAS;IACpB,OAAO,CAAC,MAAM,CAAiB;IAC/B,OAAO,CAAC,OAAO,CAAyC;IACxD,OAAO,CAAC,KAAK,CAGZ;gBAEW,MAAM,GAAE,OAAO,CAAC,eAAe,CAAM;IAIjD;;;OAGG;IACH,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO;IA4BhC;;OAEG;IACH,SAAS,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM;IAMpE;;OAEG;IACH,mBAAmB,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO;IAK/E;;OAEG;IACH,gBAAgB,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,OAAO;IAM1C;;OAEG;IACH,YAAY,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI;IAI/B;;OAEG;IACH,OAAO,IAAI,MAAM;IAkBjB;;OAEG;IACH,QAAQ,IAAI,cAAc;IAY1B;;OAEG;IACH,KAAK,IAAI,IAAI;IAKb;;OAEG;IACH,SAAS,IAAI,eAAe;IAI5B;;OAEG;IACH,SAAS,CAAC,MAAM,EAAE,OAAO,CAAC,eAAe,CAAC,GAAG,IAAI;CAGlD;AAMD;;GAEG;AACH,qBAAa,kBAAmB,SAAQ,SAAS;gBACnC,MAAM,GAAE,OAAO,CAAC,eAAe,CAAM;IAQjD,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO;CAIxC;AAED;;GAEG;AACH,qBAAa,aAAc,SAAQ,SAAS;gBAC9B,MAAM,GAAE,OAAO,CAAC,eAAe,CAAM;IAQjD,cAAc,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO;CAI5E;
|
|
1
|
+
{"version":3,"file":"Debouncer.d.ts","sourceRoot":"","sources":["../../src/performance/Debouncer.ts"],"names":[],"mappings":"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"}
|
|
@@ -15,6 +15,45 @@ const DEFAULT_CONFIG = {
|
|
|
15
15
|
debug: false,
|
|
16
16
|
};
|
|
17
17
|
// =============================================================================
|
|
18
|
+
// Smart Debouncing by Tool Type
|
|
19
|
+
// =============================================================================
|
|
20
|
+
/**
|
|
21
|
+
* Tool-specific debounce windows
|
|
22
|
+
* Different tools have different optimal debounce times
|
|
23
|
+
*/
|
|
24
|
+
export const TOOL_DEBOUNCE_CONFIG = {
|
|
25
|
+
// Read operations - frequent, short debounce
|
|
26
|
+
'Read': 1000,
|
|
27
|
+
'Glob': 2000,
|
|
28
|
+
'Grep': 2000,
|
|
29
|
+
'LSP': 1000,
|
|
30
|
+
// Write operations - no debounce (always execute)
|
|
31
|
+
'Write': 0,
|
|
32
|
+
'Edit': 0,
|
|
33
|
+
'NotebookEdit': 0,
|
|
34
|
+
// External operations - longer debounce
|
|
35
|
+
'WebSearch': 5000,
|
|
36
|
+
'WebFetch': 5000,
|
|
37
|
+
'Bash': 3000,
|
|
38
|
+
// Task/Agent operations - medium debounce
|
|
39
|
+
'Task': 3000,
|
|
40
|
+
'Skill': 2000,
|
|
41
|
+
// Default for unknown tools
|
|
42
|
+
'default': 3000
|
|
43
|
+
};
|
|
44
|
+
/**
|
|
45
|
+
* Get debounce window for a specific tool
|
|
46
|
+
*/
|
|
47
|
+
export function getToolDebounceMs(toolName) {
|
|
48
|
+
return TOOL_DEBOUNCE_CONFIG[toolName] ?? TOOL_DEBOUNCE_CONFIG['default'];
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Check if a tool should never be debounced (write operations)
|
|
52
|
+
*/
|
|
53
|
+
export function isWriteOperation(toolName) {
|
|
54
|
+
return ['Write', 'Edit', 'NotebookEdit'].includes(toolName);
|
|
55
|
+
}
|
|
56
|
+
// =============================================================================
|
|
18
57
|
// Debouncer Implementation
|
|
19
58
|
// =============================================================================
|
|
20
59
|
export class Debouncer {
|
|
@@ -166,12 +205,115 @@ export class HookDebouncer extends Debouncer {
|
|
|
166
205
|
return this.shouldSkip(`hook:${key}`);
|
|
167
206
|
}
|
|
168
207
|
}
|
|
208
|
+
/**
|
|
209
|
+
* Smart Debouncer with tool-specific windows
|
|
210
|
+
* Uses different debounce times based on tool type
|
|
211
|
+
*/
|
|
212
|
+
export class SmartDebouncer {
|
|
213
|
+
entries = new Map();
|
|
214
|
+
maxEntries;
|
|
215
|
+
debug;
|
|
216
|
+
stats = {
|
|
217
|
+
totalCalls: 0,
|
|
218
|
+
skipped: 0,
|
|
219
|
+
byTool: new Map()
|
|
220
|
+
};
|
|
221
|
+
constructor(options = {}) {
|
|
222
|
+
this.maxEntries = options.maxEntries ?? 500;
|
|
223
|
+
this.debug = options.debug ?? false;
|
|
224
|
+
}
|
|
225
|
+
/**
|
|
226
|
+
* Check if operation should be skipped based on tool-specific window
|
|
227
|
+
*/
|
|
228
|
+
shouldSkip(toolName, params) {
|
|
229
|
+
const debounceMs = getToolDebounceMs(toolName);
|
|
230
|
+
// Write operations are never debounced
|
|
231
|
+
if (debounceMs === 0) {
|
|
232
|
+
this.trackCall(toolName, false);
|
|
233
|
+
return false;
|
|
234
|
+
}
|
|
235
|
+
this.stats.totalCalls++;
|
|
236
|
+
const now = Date.now();
|
|
237
|
+
const paramsStr = JSON.stringify(params, Object.keys(params).sort());
|
|
238
|
+
const key = createHash('md5').update(`${toolName}:${paramsStr}`).digest('hex');
|
|
239
|
+
const entry = this.entries.get(key);
|
|
240
|
+
if (entry && now - entry.lastCall < debounceMs) {
|
|
241
|
+
this.stats.skipped++;
|
|
242
|
+
entry.callCount++;
|
|
243
|
+
this.trackCall(toolName, true);
|
|
244
|
+
if (this.debug) {
|
|
245
|
+
console.log(`[SmartDebouncer] Skipping ${toolName} (window: ${debounceMs}ms, called ${entry.callCount}x)`);
|
|
246
|
+
}
|
|
247
|
+
return true;
|
|
248
|
+
}
|
|
249
|
+
// Update or create entry
|
|
250
|
+
this.entries.set(key, { lastCall: now, callCount: 1 });
|
|
251
|
+
// Cleanup if needed
|
|
252
|
+
if (this.entries.size > this.maxEntries) {
|
|
253
|
+
this.cleanup();
|
|
254
|
+
}
|
|
255
|
+
this.trackCall(toolName, false);
|
|
256
|
+
return false;
|
|
257
|
+
}
|
|
258
|
+
trackCall(toolName, skipped) {
|
|
259
|
+
const existing = this.stats.byTool.get(toolName) ?? { total: 0, skipped: 0 };
|
|
260
|
+
existing.total++;
|
|
261
|
+
if (skipped)
|
|
262
|
+
existing.skipped++;
|
|
263
|
+
this.stats.byTool.set(toolName, existing);
|
|
264
|
+
}
|
|
265
|
+
/**
|
|
266
|
+
* Cleanup old entries (uses longest debounce window)
|
|
267
|
+
*/
|
|
268
|
+
cleanup() {
|
|
269
|
+
const now = Date.now();
|
|
270
|
+
const maxWindow = Math.max(...Object.values(TOOL_DEBOUNCE_CONFIG));
|
|
271
|
+
let removed = 0;
|
|
272
|
+
for (const [key, entry] of this.entries) {
|
|
273
|
+
if (now - entry.lastCall > maxWindow) {
|
|
274
|
+
this.entries.delete(key);
|
|
275
|
+
removed++;
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
return removed;
|
|
279
|
+
}
|
|
280
|
+
/**
|
|
281
|
+
* Get statistics including per-tool breakdown
|
|
282
|
+
*/
|
|
283
|
+
getStats() {
|
|
284
|
+
const byTool = {};
|
|
285
|
+
for (const [tool, stats] of this.stats.byTool) {
|
|
286
|
+
byTool[tool] = {
|
|
287
|
+
...stats,
|
|
288
|
+
skipRate: stats.total > 0 ? stats.skipped / stats.total : 0
|
|
289
|
+
};
|
|
290
|
+
}
|
|
291
|
+
return {
|
|
292
|
+
totalCalls: this.stats.totalCalls,
|
|
293
|
+
skipped: this.stats.skipped,
|
|
294
|
+
skipRate: this.stats.totalCalls > 0 ? this.stats.skipped / this.stats.totalCalls : 0,
|
|
295
|
+
byTool
|
|
296
|
+
};
|
|
297
|
+
}
|
|
298
|
+
/**
|
|
299
|
+
* Reset all state
|
|
300
|
+
*/
|
|
301
|
+
reset() {
|
|
302
|
+
this.entries.clear();
|
|
303
|
+
this.stats = {
|
|
304
|
+
totalCalls: 0,
|
|
305
|
+
skipped: 0,
|
|
306
|
+
byTool: new Map()
|
|
307
|
+
};
|
|
308
|
+
}
|
|
309
|
+
}
|
|
169
310
|
// =============================================================================
|
|
170
311
|
// Singleton Instances
|
|
171
312
|
// =============================================================================
|
|
172
313
|
let globalDebouncer = null;
|
|
173
314
|
let globalEmbeddingDebouncer = null;
|
|
174
315
|
let globalHookDebouncer = null;
|
|
316
|
+
let globalSmartDebouncer = null;
|
|
175
317
|
export function getDebouncer(config) {
|
|
176
318
|
if (!globalDebouncer) {
|
|
177
319
|
globalDebouncer = new Debouncer(config);
|
|
@@ -190,9 +332,16 @@ export function getHookDebouncer(config) {
|
|
|
190
332
|
}
|
|
191
333
|
return globalHookDebouncer;
|
|
192
334
|
}
|
|
335
|
+
export function getSmartDebouncer(options) {
|
|
336
|
+
if (!globalSmartDebouncer) {
|
|
337
|
+
globalSmartDebouncer = new SmartDebouncer(options);
|
|
338
|
+
}
|
|
339
|
+
return globalSmartDebouncer;
|
|
340
|
+
}
|
|
193
341
|
export function resetDebouncers() {
|
|
194
342
|
globalDebouncer = null;
|
|
195
343
|
globalEmbeddingDebouncer = null;
|
|
196
344
|
globalHookDebouncer = null;
|
|
345
|
+
globalSmartDebouncer = null;
|
|
197
346
|
}
|
|
198
347
|
//# sourceMappingURL=Debouncer.js.map
|