claudify-agent 0.0.0-stage → 1.0.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.
Files changed (48) hide show
  1. package/.claude/QUICK-REFERENCE.md +213 -0
  2. package/.claude/cost-dashboard.md +162 -0
  3. package/.claude/docs/COST-OPTIMIZATION.md +403 -0
  4. package/.claude/docs/MCP-INTEGRATION-GUIDE.md +348 -0
  5. package/.claude/docs/PLAN-MODE-OPTIMIZATION.md +836 -0
  6. package/.claude/hooks/auto-learning-review.ts +195 -0
  7. package/.claude/hooks/auto-lint-fix.ts +104 -0
  8. package/.claude/hooks/auto-security-review.ts +354 -0
  9. package/.claude/hooks/auto-validate.ts +348 -0
  10. package/.claude/hooks/plan-quality-tracker.ts +719 -0
  11. package/.claude/rules/anti-patterns.md +22 -0
  12. package/.claude/rules/context-tier-1.md +41 -0
  13. package/.claude/rules/context-tier-2.md +285 -0
  14. package/.claude/rules/general.md +25 -0
  15. package/.claude/rules/mcp-auto-use.md +46 -0
  16. package/.claude/rules/parallel-exploration-auto.md +31 -0
  17. package/.claude/rules/plan-mode-execution.md +289 -0
  18. package/.claude/rules/plan-mode-research.md +34 -0
  19. package/.claude/rules/plan-mode-structure.md +166 -0
  20. package/.claude/rules/plan-mode-validation.md +130 -0
  21. package/.claude/rules/security-critical.md +19 -0
  22. package/.claude/rules/tool-auto-selection.md +45 -0
  23. package/.claude/rules/tool-strategy.md +22 -0
  24. package/.claude/scripts/auto-validate.js +69 -0
  25. package/.claude/scripts/security-scan.js +45 -0
  26. package/.claude/security-dashboard.md +142 -0
  27. package/.claude/skills/backend-concurrency/SKILL.md +203 -0
  28. package/.claude/skills/debug-optimizer/SKILL.md +399 -0
  29. package/.claude/skills/debug-optimizer.md +12 -0
  30. package/.claude/skills/golang-guide/SKILL.md +177 -0
  31. package/.claude/skills/learning-loop/SKILL.md +308 -0
  32. package/.claude/skills/mcp-mastery/SKILL.md +214 -0
  33. package/.claude/skills/nestjs-guide/SKILL.md +197 -0
  34. package/.claude/skills/nextjs-guide/SKILL.md +687 -0
  35. package/.claude/skills/nextjs.md +13 -0
  36. package/.claude/skills/parallel-exploration/SKILL.md +193 -0
  37. package/.claude/skills/plan-mode-mastery/SKILL.md +263 -0
  38. package/.claude/skills/python-guide/SKILL.md +822 -0
  39. package/.claude/skills/react-guide/SKILL.md +762 -0
  40. package/.claude/skills/react.md +12 -0
  41. package/.claude/skills/security.md +18 -0
  42. package/.claude/skills/solidity-guide/SKILL.md +32 -0
  43. package/.claude/skills/tool-selection/SKILL.md +428 -0
  44. package/.claude/skills/vite-guide/SKILL.md +445 -0
  45. package/CLAUDE.md +49 -0
  46. package/README.md +65 -2
  47. package/bin/cli.js +50 -0
  48. package/package.json +44 -4
@@ -0,0 +1,719 @@
1
+ // .cursor/hooks/plan-quality-tracker.ts
2
+ // Unified plan metrics tracking with real tool usage and accuracy calculations
3
+
4
+ import { writeFileSync, readFileSync, existsSync } from "fs";
5
+ import { join } from "path";
6
+
7
+ export {};
8
+
9
+ interface StopHookInput {
10
+ conversation_id: string;
11
+ status: "completed" | "aborted" | "error";
12
+ loop_count: number;
13
+ }
14
+
15
+ interface StopHookOutput {
16
+ followup_message?: string;
17
+ }
18
+
19
+ interface AntiPattern {
20
+ id: string;
21
+ name: string;
22
+ description: string;
23
+ detectionRule: (metrics: PlanMetrics[]) => boolean;
24
+ suggestion: string;
25
+ severity: "critical" | "high" | "medium" | "low";
26
+ }
27
+
28
+ interface PlanMetrics {
29
+ plan_accuracy: number;
30
+ time_variance: number;
31
+ tool_usage: Record<string, number>;
32
+ iteration_count: number;
33
+ blocker_count: number;
34
+ timestamp: string;
35
+ plan_type: string;
36
+ mcp_usage: Record<string, number>;
37
+ tool_efficiency: number;
38
+ parallel_subagents: number;
39
+ mcp_tools_used: string[];
40
+ failed_tools: string[];
41
+ conversation_duration_ms?: number;
42
+ cost_estimate?: number;
43
+ anti_patterns_detected?: string[];
44
+ repeated_mistakes?: string[];
45
+ }
46
+
47
+ interface MCPEffectiveness {
48
+ usage: number;
49
+ success_rate: number;
50
+ }
51
+
52
+ interface PatternAnalysis {
53
+ detectedPatterns: AntiPattern[];
54
+ repeatedMistakes: string[];
55
+ improvementSuggestions: string[];
56
+ trendDirection: "improving" | "stable" | "declining";
57
+ }
58
+
59
+ interface ToolCall {
60
+ name: string;
61
+ execution_time_ms?: number;
62
+ success: boolean;
63
+ mcp_server?: string;
64
+ }
65
+
66
+ interface HooksConfig {
67
+ planTracking?: {
68
+ trackMetrics?: boolean;
69
+ accuracyThreshold?: number;
70
+ efficiencyThreshold?: number;
71
+ maxIterations?: number;
72
+ provideFeedback?: boolean;
73
+ enableCostTracking?: boolean;
74
+ enablePatternAnalysis?: boolean;
75
+ };
76
+ }
77
+
78
+ const METRICS_FILE = join(process.cwd(), ".cursor/plan-metrics.json");
79
+ const CONVERSATIONS_DIR = join(process.cwd(), ".cursor/conversations");
80
+
81
+ // Load configuration
82
+ const configPath = join(process.cwd(), '.cursor/hooks.config.json');
83
+ const config: HooksConfig = existsSync(configPath)
84
+ ? JSON.parse(readFileSync(configPath, 'utf-8'))
85
+ : {};
86
+
87
+ const planTrackingConfig = {
88
+ trackMetrics: config.planTracking?.trackMetrics !== false,
89
+ accuracyThreshold: config.planTracking?.accuracyThreshold || 70,
90
+ efficiencyThreshold: config.planTracking?.efficiencyThreshold || 60,
91
+ maxIterations: config.planTracking?.maxIterations || 5,
92
+ provideFeedback: config.planTracking?.provideFeedback !== false,
93
+ enableCostTracking: config.planTracking?.enableCostTracking !== false,
94
+ enablePatternAnalysis: config.planTracking?.enablePatternAnalysis !== false
95
+ };
96
+
97
+ // Read input from stdin
98
+ const stdin = await new Promise<string>((resolve) => {
99
+ let data = "";
100
+ process.stdin.on("data", (chunk) => (data += chunk));
101
+ process.stdin.on("end", () => resolve(data));
102
+ });
103
+
104
+ const input: StopHookInput = JSON.parse(stdin);
105
+
106
+ console.error(`[Plan Tracker] Processing execution data for conversation ${input.conversation_id}...`);
107
+
108
+ // Helper functions
109
+ function loadConversation(conversationId: string): any {
110
+ const conversationPath = join(CONVERSATIONS_DIR, `${conversationId}.json`);
111
+ if (!existsSync(conversationPath)) {
112
+ console.error("[Plan Tracker] ⚠ Conversation file not found");
113
+ return null;
114
+ }
115
+
116
+ try {
117
+ return JSON.parse(readFileSync(conversationPath, 'utf-8'));
118
+ } catch (error) {
119
+ console.error("[Plan Tracker] Error loading conversation:", error);
120
+ return null;
121
+ }
122
+ }
123
+
124
+ function extractToolCalls(conversation: any): ToolCall[] {
125
+ const tools: ToolCall[] = [];
126
+
127
+ if (!conversation?.messages) return tools;
128
+
129
+ for (const message of conversation.messages) {
130
+ if (message.tool_calls) {
131
+ for (const toolCall of message.tool_calls) {
132
+ const toolName = toolCall.function?.name || 'unknown';
133
+
134
+ // Determine if it's an MCP tool and which server
135
+ let mcpServer: string | undefined;
136
+ if (toolName.startsWith('browser_')) mcpServer = 'cursor-ide-browser';
137
+ else if (toolName.startsWith('github_')) mcpServer = 'user-github';
138
+ else if (toolName.includes('eslint')) mcpServer = 'user-ESLint';
139
+ else if (toolName.includes('context7')) mcpServer = 'user-context7';
140
+ else if (toolName.includes('chrome')) mcpServer = 'user-chrome-devtools';
141
+ else if (toolName.includes('playwright')) mcpServer = 'user-playwright';
142
+ else if (toolName.includes('selenium')) mcpServer = 'user-selenium';
143
+ else if (toolName.includes('dart')) mcpServer = 'user-dart';
144
+ else if (toolName.includes('stitch')) mcpServer = 'user-stitch';
145
+ else if (toolName.includes('shadcn')) mcpServer = 'user-shadcn';
146
+
147
+ tools.push({
148
+ name: toolName,
149
+ success: true, // Simplified - would check actual results in production
150
+ mcp_server: mcpServer
151
+ });
152
+ }
153
+ }
154
+ }
155
+
156
+ return tools;
157
+ }
158
+
159
+ function countParallelSubagents(conversation: any): number {
160
+ if (!conversation?.messages) return 0;
161
+
162
+ let count = 0;
163
+ for (const message of conversation.messages) {
164
+ if (message.tool_calls) {
165
+ for (const toolCall of message.tool_calls) {
166
+ if (toolCall.function?.name === 'Task' ||
167
+ toolCall.function?.name?.includes('subagent')) {
168
+ count++;
169
+ }
170
+ }
171
+ }
172
+ }
173
+
174
+ return count;
175
+ }
176
+
177
+ function detectPlanType(conversation: any): string {
178
+ if (!conversation?.messages) return 'unknown';
179
+
180
+ const conversationText = JSON.stringify(conversation.messages).toLowerCase();
181
+
182
+ if (conversationText.includes('plan mode')) return 'plan-mode';
183
+ if (conversationText.includes('browser') || conversationText.includes('web')) return 'browser-automation';
184
+ if (conversationText.includes('github') || conversationText.includes('pr') || conversationText.includes('issue')) return 'github-ops';
185
+ if (conversationText.includes('test')) return 'testing';
186
+ if (conversationText.includes('refactor')) return 'refactoring';
187
+ if (conversationText.includes('bug') || conversationText.includes('fix')) return 'bug-fix';
188
+ if (conversationText.includes('feature') || conversationText.includes('implement')) return 'feature-development';
189
+
190
+ return 'general';
191
+ }
192
+
193
+ function calculatePlanAccuracy(input: StopHookInput, conversation: any): number {
194
+ if (input.status !== "completed") return 0;
195
+
196
+ // Base accuracy on loop count (fewer iterations = higher accuracy)
197
+ let baseAccuracy: number;
198
+ if (input.loop_count === 0) baseAccuracy = 100;
199
+ else if (input.loop_count <= 2) baseAccuracy = 85;
200
+ else if (input.loop_count <= 5) baseAccuracy = 70;
201
+ else baseAccuracy = 50;
202
+
203
+ // Adjust based on tool usage patterns
204
+ const tools = extractToolCalls(conversation);
205
+ const failedTools = tools.filter(t => !t.success).length;
206
+
207
+ if (failedTools > 0) {
208
+ baseAccuracy -= (failedTools * 5); // Penalty for failed tools
209
+ }
210
+
211
+ return Math.max(0, Math.min(100, baseAccuracy));
212
+ }
213
+
214
+ function calculateToolEfficiency(tools: ToolCall[]): number {
215
+ if (tools.length === 0) return 75; // Neutral score if no tools
216
+
217
+ // Tier 1: Simple tools (Shell, Read, Write, Glob, Grep)
218
+ // Tier 2: Analysis (ReadLints, SemanticSearch)
219
+ // Tier 3: Complex (Task, WebSearch, WebFetch)
220
+ // Tier 4: MCP tools
221
+
222
+ const tierScores: Record<string, number> = {
223
+ 'Shell': 100, 'Read': 100, 'Write': 100, 'Glob': 100, 'Grep': 100,
224
+ 'ReadLints': 80, 'SemanticSearch': 80,
225
+ 'Task': 60, 'WebSearch': 60, 'WebFetch': 60,
226
+ };
227
+
228
+ let totalScore = 0;
229
+ let toolCount = 0;
230
+
231
+ for (const tool of tools) {
232
+ if (tool.mcp_server) {
233
+ totalScore += 40; // MCP tools are most expensive
234
+ toolCount++;
235
+ } else {
236
+ const tierScore = tierScores[tool.name] || 75; // Default to middle tier
237
+ totalScore += tierScore;
238
+ toolCount++;
239
+ }
240
+ }
241
+
242
+ return toolCount > 0 ? Math.round(totalScore / toolCount) : 75;
243
+ }
244
+
245
+ function estimateCost(tools: ToolCall[]): number {
246
+ // Estimated token cost per tool type
247
+ const costEstimates: Record<string, number> = {
248
+ 'Shell': 100, 'Read': 500, 'Write': 1000, 'Glob': 200, 'Grep': 300,
249
+ 'ReadLints': 800, 'SemanticSearch': 1500,
250
+ 'Task': 3000, 'WebSearch': 2000, 'WebFetch': 2500,
251
+ };
252
+
253
+ let totalCost = 0;
254
+ for (const tool of tools) {
255
+ if (tool.mcp_server) {
256
+ totalCost += 5000; // MCP tools estimated higher cost
257
+ } else {
258
+ totalCost += costEstimates[tool.name] || 1000;
259
+ }
260
+ }
261
+
262
+ return totalCost;
263
+ }
264
+
265
+ // Anti-pattern definitions based on AGENT-INSTRUCTION-BEST-PRACTICES.md
266
+ const ANTI_PATTERNS: AntiPattern[] = [
267
+ {
268
+ id: "over-engineering",
269
+ name: "Over-Engineering",
270
+ description: "Using expensive tools when cheaper alternatives would work",
271
+ detectionRule: (metrics: PlanMetrics[]) => {
272
+ if (metrics.length < 3) return false;
273
+ const recent = metrics.slice(-3);
274
+ const avgEfficiency = recent.reduce((sum, m) => sum + (m.tool_efficiency || 75), 0) / recent.length;
275
+ return avgEfficiency < 50;
276
+ },
277
+ suggestion: "Start with Tier 1 tools (Read, Grep, Glob) before escalating to Tier 3-4",
278
+ severity: "high"
279
+ },
280
+ {
281
+ id: "no-research",
282
+ name: "Planning Without Research",
283
+ description: "Creating plans without using SemanticSearch or exploration tools",
284
+ detectionRule: (metrics: PlanMetrics[]) => {
285
+ if (metrics.length < 3) return false;
286
+ const recent = metrics.slice(-3);
287
+ return recent.every(m => !m.tool_usage['SemanticSearch'] && m.parallel_subagents === 0);
288
+ },
289
+ suggestion: "Always use SemanticSearch and parallel subagents before planning complex features",
290
+ severity: "critical"
291
+ },
292
+ {
293
+ id: "repeated-failures",
294
+ name: "Repeated Execution Failures",
295
+ description: "Multiple consecutive plans with low accuracy or high iterations",
296
+ detectionRule: (metrics: PlanMetrics[]) => {
297
+ if (metrics.length < 3) return false;
298
+ const recent = metrics.slice(-3);
299
+ const lowAccuracy = recent.filter(m => m.plan_accuracy < 60).length;
300
+ return lowAccuracy >= 2;
301
+ },
302
+ suggestion: "Review plan validation process, add more thorough feasibility checks",
303
+ severity: "critical"
304
+ },
305
+ {
306
+ id: "mcp-overuse",
307
+ name: "MCP Overuse",
308
+ description: "Using MCP tools for tasks that don't require them",
309
+ detectionRule: (metrics: PlanMetrics[]) => {
310
+ if (metrics.length < 3) return false;
311
+ const recent = metrics.slice(-3);
312
+ const highMCPUsage = recent.filter(m => Object.keys(m.mcp_usage).length > 3).length;
313
+ const lowAccuracy = recent.filter(m => m.plan_accuracy < 70).length;
314
+ return highMCPUsage >= 2 && lowAccuracy >= 2;
315
+ },
316
+ suggestion: "Use MCP tools only when essential (visual verification, git ops, docs)",
317
+ severity: "medium"
318
+ },
319
+ {
320
+ id: "no-validation",
321
+ name: "Skipping Validation",
322
+ description: "Not running ReadLints or tests after code changes",
323
+ detectionRule: (metrics: PlanMetrics[]) => {
324
+ if (metrics.length < 3) return false;
325
+ const recent = metrics.slice(-3);
326
+ return recent.every(m => !m.tool_usage['ReadLints'] && !m.tool_usage['Shell']);
327
+ },
328
+ suggestion: "Always run ReadLints after edits and tests after substantive changes",
329
+ severity: "high"
330
+ },
331
+ {
332
+ id: "context-bloat",
333
+ name: "Context Bloat",
334
+ description: "Loading too much context, violating minimalism principle",
335
+ detectionRule: (metrics: PlanMetrics[]) => {
336
+ // Detect via low efficiency + high iteration pattern
337
+ if (metrics.length < 3) return false;
338
+ const recent = metrics.slice(-3);
339
+ return recent.every(m => m.iteration_count > 3 && m.tool_efficiency < 60);
340
+ },
341
+ suggestion: "Apply tiered injection, use references over content, keep rules under 20 lines",
342
+ severity: "medium"
343
+ }
344
+ ];
345
+
346
+ function detectAntiPatterns(metrics: PlanMetrics[]): AntiPattern[] {
347
+ const detected: AntiPattern[] = [];
348
+
349
+ for (const pattern of ANTI_PATTERNS) {
350
+ if (pattern.detectionRule(metrics)) {
351
+ detected.push(pattern);
352
+ }
353
+ }
354
+
355
+ return detected;
356
+ }
357
+
358
+ function identifyRepeatedMistakes(metrics: PlanMetrics[]): string[] {
359
+ const mistakes: string[] = [];
360
+
361
+ if (metrics.length < 5) return mistakes;
362
+
363
+ const recent = metrics.slice(-5);
364
+
365
+ // Check for repeated low accuracy
366
+ const lowAccuracyCount = recent.filter(m => m.plan_accuracy < 70).length;
367
+ if (lowAccuracyCount >= 3) {
368
+ mistakes.push("Consistently low plan accuracy (<70%)");
369
+ }
370
+
371
+ // Check for repeated high iterations
372
+ const highIterationCount = recent.filter(m => m.iteration_count > 3).length;
373
+ if (highIterationCount >= 3) {
374
+ mistakes.push("Frequently requiring many iterations (>3)");
375
+ }
376
+
377
+ // Check for repeated tool failures
378
+ const toolFailureCount = recent.filter(m => m.failed_tools && m.failed_tools.length > 0).length;
379
+ if (toolFailureCount >= 3) {
380
+ mistakes.push("Recurring tool failures");
381
+ }
382
+
383
+ // Check for declining performance
384
+ const firstHalf = recent.slice(0, Math.floor(recent.length / 2));
385
+ const secondHalf = recent.slice(Math.floor(recent.length / 2));
386
+ const firstAvg = firstHalf.reduce((sum, m) => sum + m.plan_accuracy, 0) / firstHalf.length;
387
+ const secondAvg = secondHalf.reduce((sum, m) => sum + m.plan_accuracy, 0) / secondHalf.length;
388
+
389
+ if (secondAvg < firstAvg - 10) {
390
+ mistakes.push("Performance declining over time");
391
+ }
392
+
393
+ return mistakes;
394
+ }
395
+
396
+ function generateImprovementSuggestions(antiPatterns: AntiPattern[], mistakes: string[]): string[] {
397
+ const suggestions: string[] = [];
398
+
399
+ // Add suggestions from detected anti-patterns
400
+ for (const pattern of antiPatterns) {
401
+ suggestions.push(`[${pattern.severity.toUpperCase()}] ${pattern.suggestion}`);
402
+ }
403
+
404
+ // Add suggestions for repeated mistakes
405
+ if (mistakes.includes("Consistently low plan accuracy (<70%)")) {
406
+ suggestions.push("Improve pre-plan research phase - spend 2-3 min on SemanticSearch");
407
+ suggestions.push("Add validation subagent before presenting plans");
408
+ }
409
+
410
+ if (mistakes.includes("Frequently requiring many iterations (>3)")) {
411
+ suggestions.push("Add more thorough feasibility validation");
412
+ suggestions.push("Create checkpoints before risky changes");
413
+ suggestions.push("Use /grind loop strategically (max 5 iterations)");
414
+ }
415
+
416
+ if (mistakes.includes("Recurring tool failures")) {
417
+ suggestions.push("Verify tool prerequisites before use");
418
+ suggestions.push("Follow tool escalation protocol (Tier 1 → Tier 4)");
419
+ suggestions.push("Check MCP server availability");
420
+ }
421
+
422
+ if (mistakes.includes("Performance declining over time")) {
423
+ suggestions.push("Review recent changes to workflow or rules");
424
+ suggestions.push("Analyze failing plans for common patterns");
425
+ suggestions.push("Consider updating anti-pattern detection rules");
426
+ }
427
+
428
+ return suggestions;
429
+ }
430
+
431
+ function analyzeTrend(metrics: PlanMetrics[]): "improving" | "stable" | "declining" {
432
+ if (metrics.length < 5) return "stable";
433
+
434
+ const recent = metrics.slice(-5);
435
+ const firstHalf = recent.slice(0, Math.floor(recent.length / 2));
436
+ const secondHalf = recent.slice(Math.floor(recent.length / 2));
437
+
438
+ const firstAvg = firstHalf.reduce((sum, m) => sum + m.plan_accuracy, 0) / firstHalf.length;
439
+ const secondAvg = secondHalf.reduce((sum, m) => sum + m.plan_accuracy, 0) / secondHalf.length;
440
+
441
+ if (secondAvg > firstAvg + 5) return "improving";
442
+ if (secondAvg < firstAvg - 5) return "declining";
443
+ return "stable";
444
+ }
445
+
446
+ function performPatternAnalysis(metrics: PlanMetrics[]): PatternAnalysis {
447
+ const antiPatterns = detectAntiPatterns(metrics);
448
+ const mistakes = identifyRepeatedMistakes(metrics);
449
+ const suggestions = generateImprovementSuggestions(antiPatterns, mistakes);
450
+ const trend = analyzeTrend(metrics);
451
+
452
+ return {
453
+ detectedPatterns: antiPatterns,
454
+ repeatedMistakes: mistakes,
455
+ improvementSuggestions: suggestions,
456
+ trendDirection: trend
457
+ };
458
+ }
459
+
460
+ // Load existing metrics
461
+ let allMetrics: PlanMetrics[] = [];
462
+ if (existsSync(METRICS_FILE)) {
463
+ try {
464
+ const content = readFileSync(METRICS_FILE, "utf-8");
465
+ allMetrics = JSON.parse(content);
466
+ } catch (error) {
467
+ console.error("[Plan Tracker] Error loading metrics:", error);
468
+ allMetrics = [];
469
+ }
470
+ }
471
+
472
+ // Load conversation and extract data
473
+ const conversation = loadConversation(input.conversation_id);
474
+ const toolCalls = conversation ? extractToolCalls(conversation) : [];
475
+ const parallelSubagents = conversation ? countParallelSubagents(conversation) : 0;
476
+ const planType = conversation ? detectPlanType(conversation) : 'unknown';
477
+
478
+ // Track MCP usage and effectiveness
479
+ const mcpUsage: Record<string, number> = {};
480
+ const mcpToolsUsed: string[] = [];
481
+ const failedTools: string[] = [];
482
+
483
+ for (const tool of toolCalls) {
484
+ if (tool.mcp_server) {
485
+ mcpUsage[tool.mcp_server] = (mcpUsage[tool.mcp_server] || 0) + 1;
486
+ if (!mcpToolsUsed.includes(tool.name)) {
487
+ mcpToolsUsed.push(tool.name);
488
+ }
489
+ }
490
+
491
+ if (!tool.success) {
492
+ failedTools.push(tool.name);
493
+ }
494
+ }
495
+
496
+ // MCP Effectiveness Analysis
497
+ if (Object.keys(mcpUsage).length > 0) {
498
+ const mcpServers = Object.keys(mcpUsage).join(', ');
499
+ console.error(`[Plan Tracker] MCP servers used: ${mcpServers}`);
500
+
501
+ // Track MCP effectiveness per server
502
+ const mcpEffectiveness: Record<string, { usage: number; success: number }> = {};
503
+ toolCalls.forEach(tool => {
504
+ if (tool.mcp_server) {
505
+ if (!mcpEffectiveness[tool.mcp_server]) {
506
+ mcpEffectiveness[tool.mcp_server] = { usage: 0, success: 0 };
507
+ }
508
+ mcpEffectiveness[tool.mcp_server].usage++;
509
+ if (tool.success) mcpEffectiveness[tool.mcp_server].success++;
510
+ }
511
+ });
512
+
513
+ // Report effectiveness
514
+ Object.entries(mcpEffectiveness).forEach(([server, data]) => {
515
+ const successRate = Math.round((data.success / data.usage) * 100);
516
+ console.error(`[Plan Tracker] ${server}: ${data.usage} calls, ${successRate}% success rate`);
517
+
518
+ if (successRate < 50) {
519
+ console.error(`[Plan Tracker] ⚠ ${server} has low success rate (<50%). Consider disabling or reviewing usage.`);
520
+ }
521
+ });
522
+ }
523
+
524
+ // Track general tool usage
525
+ const toolUsage: Record<string, number> = {};
526
+ for (const tool of toolCalls) {
527
+ toolUsage[tool.name] = (toolUsage[tool.name] || 0) + 1;
528
+ }
529
+
530
+ // Estimate cost
531
+ const estimatedCost = planTrackingConfig.enableCostTracking ? estimateCost(toolCalls) : undefined;
532
+
533
+ // Perform pattern analysis (if enabled)
534
+ let detectedAntiPatterns: string[] = [];
535
+ let repeatedMistakes: string[] = [];
536
+
537
+ if (planTrackingConfig.enablePatternAnalysis && allMetrics.length >= 3) {
538
+ const analysis = performPatternAnalysis(allMetrics);
539
+ detectedAntiPatterns = analysis.detectedPatterns.map(p => p.id);
540
+ repeatedMistakes = analysis.repeatedMistakes;
541
+
542
+ if (analysis.detectedPatterns.length > 0) {
543
+ console.error(`[Plan Tracker] ⚠ Detected ${analysis.detectedPatterns.length} anti-pattern(s):`);
544
+ for (const pattern of analysis.detectedPatterns) {
545
+ console.error(` - [${pattern.severity.toUpperCase()}] ${pattern.name}: ${pattern.suggestion}`);
546
+ }
547
+ }
548
+
549
+ if (analysis.repeatedMistakes.length > 0) {
550
+ console.error(`[Plan Tracker] ⚠ Repeated mistakes detected:`);
551
+ for (const mistake of analysis.repeatedMistakes) {
552
+ console.error(` - ${mistake}`);
553
+ }
554
+ }
555
+
556
+ console.error(`[Plan Tracker] Trend: ${analysis.trendDirection}`);
557
+ }
558
+
559
+ // Create metric entry (used whether tracking is enabled or not)
560
+ const newMetric: PlanMetrics = {
561
+ plan_accuracy: calculatePlanAccuracy(input, conversation),
562
+ time_variance: 0,
563
+ tool_usage: toolUsage,
564
+ iteration_count: input.loop_count,
565
+ blocker_count: input.status === "error" ? 1 : 0,
566
+ timestamp: new Date().toISOString(),
567
+ plan_type: planType,
568
+ mcp_usage: mcpUsage,
569
+ tool_efficiency: calculateToolEfficiency(toolCalls),
570
+ parallel_subagents: parallelSubagents,
571
+ mcp_tools_used: mcpToolsUsed,
572
+ failed_tools: failedTools,
573
+ conversation_duration_ms: undefined,
574
+ cost_estimate: estimatedCost,
575
+ anti_patterns_detected: detectedAntiPatterns,
576
+ repeated_mistakes: repeatedMistakes
577
+ };
578
+
579
+ // Save metric entry if tracking is enabled
580
+ if (planTrackingConfig.trackMetrics) {
581
+ // Add to metrics
582
+ allMetrics.push(newMetric);
583
+
584
+ // Save updated metrics
585
+ try {
586
+ writeFileSync(METRICS_FILE, JSON.stringify(allMetrics, null, 2));
587
+ console.error("[Plan Tracker] ✓ Metrics saved");
588
+ } catch (error) {
589
+ console.error("[Plan Tracker] Error saving metrics:", error);
590
+ }
591
+ } else {
592
+ console.error("[Plan Tracker] ⚠ Metrics tracking disabled in config");
593
+ }
594
+
595
+ // Calculate rolling averages (only if tracking is enabled)
596
+ let avgAccuracy = 75;
597
+ let avgIterations = 2;
598
+ let avgToolEfficiency = 75;
599
+ let avgParallelSubagents = 0;
600
+ let avgCost = 0;
601
+
602
+ if (planTrackingConfig.trackMetrics && allMetrics.length > 0) {
603
+ const recentMetrics = allMetrics.slice(-10);
604
+ avgAccuracy = recentMetrics.reduce((sum, m) => sum + m.plan_accuracy, 0) / recentMetrics.length;
605
+ avgIterations = recentMetrics.reduce((sum, m) => sum + m.iteration_count, 0) / recentMetrics.length;
606
+ avgToolEfficiency = recentMetrics.reduce((sum, m) => sum + (m.tool_efficiency || 75), 0) / recentMetrics.length;
607
+ avgParallelSubagents = recentMetrics.reduce((sum, m) => sum + (m.parallel_subagents || 0), 0) / recentMetrics.length;
608
+
609
+ if (planTrackingConfig.enableCostTracking) {
610
+ avgCost = recentMetrics.reduce((sum, m) => sum + (m.cost_estimate || 0), 0) / recentMetrics.length;
611
+ }
612
+
613
+ console.error(`[Plan Tracker] Rolling averages (last 10 plans):`);
614
+ console.error(` - Accuracy: ${avgAccuracy.toFixed(1)}%`);
615
+ console.error(` - Avg iterations: ${avgIterations.toFixed(1)}`);
616
+ console.error(` - Tool efficiency: ${avgToolEfficiency.toFixed(1)}`);
617
+ console.error(` - Avg parallel subagents: ${avgParallelSubagents.toFixed(1)}`);
618
+ if (planTrackingConfig.enableCostTracking) {
619
+ console.error(` - Avg estimated cost: ${avgCost.toFixed(0)} tokens`);
620
+ }
621
+ }
622
+
623
+ // Analyze MCP effectiveness
624
+ const currentAccuracy = calculatePlanAccuracy(input, conversation);
625
+
626
+ if (Object.keys(mcpUsage).length > 0) {
627
+ console.error(`[Plan Tracker] MCP tools used in this session: ${mcpToolsUsed.join(', ')}`);
628
+
629
+ // Check correlation with success
630
+ if (currentAccuracy > 85 && Object.keys(mcpUsage).length > 0) {
631
+ console.error("[Plan Tracker] ✓ High accuracy with MCP tools - good tool selection");
632
+ }
633
+ }
634
+
635
+ // Analyze parallel subagent usage
636
+ if (parallelSubagents > 0) {
637
+ console.error(`[Plan Tracker] Used ${parallelSubagents} parallel subagent(s)`);
638
+
639
+ if (parallelSubagents > 2 && currentAccuracy > 80) {
640
+ console.error("[Plan Tracker] ✓ Parallel exploration appears effective");
641
+ }
642
+ }
643
+
644
+ // Provide feedback based on metrics (if enabled)
645
+ if (planTrackingConfig.provideFeedback) {
646
+ if (input.status === "completed") {
647
+ if (input.loop_count === 0) {
648
+ console.error("[Plan Tracker] ✓ Perfect execution (no iterations needed)");
649
+ } else if (input.loop_count <= 2) {
650
+ console.error("[Plan Tracker] ✓ Good execution (minimal iterations)");
651
+ } else if (input.loop_count > planTrackingConfig.maxIterations) {
652
+ console.error("[Plan Tracker] ⚠ High iteration count - plan accuracy may need improvement");
653
+ }
654
+
655
+ // Suggest improvements if accuracy is low
656
+ if (avgAccuracy < planTrackingConfig.accuracyThreshold) {
657
+ const output: StopHookOutput = {
658
+ followup_message: `Plan accuracy has been below ${planTrackingConfig.accuracyThreshold}% recently. Consider:\n1. More thorough pre-plan research\n2. Better validation before execution\n3. More specific tool selection`,
659
+ };
660
+ console.log(JSON.stringify(output));
661
+ process.exit(0);
662
+ }
663
+
664
+ // Suggest tool efficiency improvements
665
+ if (avgToolEfficiency < planTrackingConfig.efficiencyThreshold) {
666
+ const output: StopHookOutput = {
667
+ followup_message: "Tool efficiency has been low. Consider:\n1. Using simpler tools when possible (Tier 1: Shell, Read, Write)\n2. Avoiding expensive MCP calls for simple tasks\n3. Using 'fast' model for subagents",
668
+ };
669
+ console.log(JSON.stringify(output));
670
+ process.exit(0);
671
+ }
672
+ }
673
+
674
+ if (input.status === "error") {
675
+ console.error("[Plan Tracker] ✗ Execution failed - analyzing patterns");
676
+
677
+ // Check for recurring failures
678
+ if (planTrackingConfig.trackMetrics) {
679
+ const recentFailures = allMetrics.slice(-10).filter(m => m.blocker_count > 0).length;
680
+ if (recentFailures > 2) {
681
+ const output: StopHookOutput = {
682
+ followup_message: "Multiple execution failures detected. Common causes:\n1. Insufficient research phase\n2. Missing validation steps\n3. Unrealistic time estimates\n\nWould you like to review the plan approach?",
683
+ };
684
+ console.log(JSON.stringify(output));
685
+ process.exit(0);
686
+ }
687
+ }
688
+
689
+ // Check for tool-related failures
690
+ if (failedTools.length > 0) {
691
+ console.error(`[Plan Tracker] Failed tools: ${failedTools.join(', ')}`);
692
+ const output: StopHookOutput = {
693
+ followup_message: `Execution failed. Failed tools: ${failedTools.join(', ')}. Consider:\n1. Verifying tool prerequisites\n2. Using alternative tools\n3. Checking tool configuration`,
694
+ };
695
+ console.log(JSON.stringify(output));
696
+ process.exit(0);
697
+ }
698
+ }
699
+
700
+ // Handle aborted execution (from plan-mode-monitor merge)
701
+ if (input.status === "aborted") {
702
+ console.error("[Plan Tracker] ⚠ Plan execution aborted by user");
703
+
704
+ // Gather feedback
705
+ if (input.loop_count < 2) {
706
+ const output: StopHookOutput = {
707
+ followup_message: "Plan execution aborted. What was the main issue?\n1. Plan was inaccurate\n2. Requirements changed\n3. Found better approach\n4. Other",
708
+ };
709
+ console.log(JSON.stringify(output));
710
+ process.exit(0);
711
+ }
712
+ }
713
+ } else {
714
+ console.error("[Plan Tracker] ⚠ Feedback disabled in config");
715
+ }
716
+
717
+ // Default: stop without followup
718
+ console.log(JSON.stringify({}));
719
+ process.exit(0);