nodebench-mcp 2.15.0 → 2.18.0

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 (77) hide show
  1. package/LICENSE +21 -0
  2. package/NODEBENCH_AGENTS.md +2 -2
  3. package/README.md +514 -82
  4. package/dist/__tests__/analytics.test.d.ts +11 -0
  5. package/dist/__tests__/analytics.test.js +546 -0
  6. package/dist/__tests__/analytics.test.js.map +1 -0
  7. package/dist/__tests__/architectComplex.test.d.ts +1 -0
  8. package/dist/__tests__/architectComplex.test.js +375 -0
  9. package/dist/__tests__/architectComplex.test.js.map +1 -0
  10. package/dist/__tests__/architectSmoke.test.d.ts +1 -0
  11. package/dist/__tests__/architectSmoke.test.js +92 -0
  12. package/dist/__tests__/architectSmoke.test.js.map +1 -0
  13. package/dist/__tests__/dynamicLoading.test.d.ts +1 -0
  14. package/dist/__tests__/dynamicLoading.test.js +278 -0
  15. package/dist/__tests__/dynamicLoading.test.js.map +1 -0
  16. package/dist/__tests__/evalHarness.test.js +7 -2
  17. package/dist/__tests__/evalHarness.test.js.map +1 -1
  18. package/dist/__tests__/gaiaCapabilityEval.test.js +229 -12
  19. package/dist/__tests__/gaiaCapabilityEval.test.js.map +1 -1
  20. package/dist/__tests__/gaiaCapabilityMediaEval.test.js +194 -109
  21. package/dist/__tests__/gaiaCapabilityMediaEval.test.js.map +1 -1
  22. package/dist/__tests__/helpers/answerMatch.js +22 -22
  23. package/dist/__tests__/presetRealWorldBench.test.js +11 -2
  24. package/dist/__tests__/presetRealWorldBench.test.js.map +1 -1
  25. package/dist/__tests__/tools.test.js +10 -4
  26. package/dist/__tests__/tools.test.js.map +1 -1
  27. package/dist/__tests__/toolsetGatingEval.test.js +12 -4
  28. package/dist/__tests__/toolsetGatingEval.test.js.map +1 -1
  29. package/dist/analytics/index.d.ts +10 -0
  30. package/dist/analytics/index.js +11 -0
  31. package/dist/analytics/index.js.map +1 -0
  32. package/dist/analytics/projectDetector.d.ts +19 -0
  33. package/dist/analytics/projectDetector.js +259 -0
  34. package/dist/analytics/projectDetector.js.map +1 -0
  35. package/dist/analytics/schema.d.ts +57 -0
  36. package/dist/analytics/schema.js +157 -0
  37. package/dist/analytics/schema.js.map +1 -0
  38. package/dist/analytics/smartPreset.d.ts +63 -0
  39. package/dist/analytics/smartPreset.js +300 -0
  40. package/dist/analytics/smartPreset.js.map +1 -0
  41. package/dist/analytics/toolTracker.d.ts +59 -0
  42. package/dist/analytics/toolTracker.js +163 -0
  43. package/dist/analytics/toolTracker.js.map +1 -0
  44. package/dist/analytics/usageStats.d.ts +64 -0
  45. package/dist/analytics/usageStats.js +252 -0
  46. package/dist/analytics/usageStats.js.map +1 -0
  47. package/dist/db.js +359 -321
  48. package/dist/db.js.map +1 -1
  49. package/dist/index.d.ts +2 -1
  50. package/dist/index.js +653 -84
  51. package/dist/index.js.map +1 -1
  52. package/dist/tools/architectTools.d.ts +15 -0
  53. package/dist/tools/architectTools.js +304 -0
  54. package/dist/tools/architectTools.js.map +1 -0
  55. package/dist/tools/critterTools.js +14 -14
  56. package/dist/tools/emailTools.d.ts +15 -0
  57. package/dist/tools/emailTools.js +664 -0
  58. package/dist/tools/emailTools.js.map +1 -0
  59. package/dist/tools/metaTools.js +660 -0
  60. package/dist/tools/metaTools.js.map +1 -1
  61. package/dist/tools/parallelAgentTools.js +176 -176
  62. package/dist/tools/patternTools.js +11 -11
  63. package/dist/tools/progressiveDiscoveryTools.d.ts +5 -1
  64. package/dist/tools/progressiveDiscoveryTools.js +113 -21
  65. package/dist/tools/progressiveDiscoveryTools.js.map +1 -1
  66. package/dist/tools/researchWritingTools.js +42 -42
  67. package/dist/tools/rssTools.d.ts +8 -0
  68. package/dist/tools/rssTools.js +833 -0
  69. package/dist/tools/rssTools.js.map +1 -0
  70. package/dist/tools/toolRegistry.d.ts +17 -0
  71. package/dist/tools/toolRegistry.js +236 -17
  72. package/dist/tools/toolRegistry.js.map +1 -1
  73. package/dist/tools/voiceBridgeTools.js +498 -498
  74. package/dist/toolsetRegistry.d.ts +10 -0
  75. package/dist/toolsetRegistry.js +84 -0
  76. package/dist/toolsetRegistry.js.map +1 -0
  77. package/package.json +12 -5
@@ -0,0 +1,57 @@
1
+ /**
2
+ * Usage Analytics Schema for NodeBench MCP
3
+ *
4
+ * Tracks tool usage, project context, and generates smart preset recommendations.
5
+ * All data stored locally in SQLite at ~/.nodebench/analytics.db
6
+ */
7
+ import Database from 'better-sqlite3';
8
+ export interface ToolUsageRecord {
9
+ id?: number;
10
+ toolName: string;
11
+ toolset: string;
12
+ timestamp: number;
13
+ duration: number;
14
+ success: boolean;
15
+ errorMessage?: string;
16
+ projectPath: string;
17
+ preset: string;
18
+ args?: string;
19
+ }
20
+ export interface ProjectContextRecord {
21
+ id?: number;
22
+ projectPath: string;
23
+ projectType: string;
24
+ detectedAt: number;
25
+ lastSeen: number;
26
+ language: string;
27
+ framework?: string;
28
+ hasTests: boolean;
29
+ hasCI: boolean;
30
+ hasDocs: boolean;
31
+ fileCount: number;
32
+ }
33
+ export interface PresetHistoryRecord {
34
+ id?: number;
35
+ projectPath: string;
36
+ preset: string;
37
+ toolsetCount: number;
38
+ selectedAt: number;
39
+ selectionReason: 'manual' | 'smart' | 'default';
40
+ }
41
+ export interface UsageStatsCacheRecord {
42
+ id?: number;
43
+ projectPath: string;
44
+ cacheKey: string;
45
+ stats: string;
46
+ computedAt: number;
47
+ ttl: number;
48
+ }
49
+ export declare function initAnalyticsDb(): Database.Database;
50
+ export declare function getAnalyticsDb(): Database.Database;
51
+ export declare function closeAnalyticsDb(db: Database.Database): void;
52
+ export declare function recordToolUsage(db: Database.Database, record: Omit<ToolUsageRecord, 'id'>): void;
53
+ export declare function updateProjectContext(db: Database.Database, context: Omit<ProjectContextRecord, 'id'>): void;
54
+ export declare function recordPresetSelection(db: Database.Database, record: Omit<PresetHistoryRecord, 'id'>): void;
55
+ export declare function getCachedStats(db: Database.Database, projectPath: string, cacheKey: string): string | null;
56
+ export declare function setCachedStats(db: Database.Database, record: Omit<UsageStatsCacheRecord, 'id'>): void;
57
+ export declare function clearOldRecords(db: Database.Database, daysToKeep?: number): void;
@@ -0,0 +1,157 @@
1
+ /**
2
+ * Usage Analytics Schema for NodeBench MCP
3
+ *
4
+ * Tracks tool usage, project context, and generates smart preset recommendations.
5
+ * All data stored locally in SQLite at ~/.nodebench/analytics.db
6
+ */
7
+ import Database from 'better-sqlite3';
8
+ import path from 'path';
9
+ import os from 'os';
10
+ import fs from 'fs';
11
+ const DB_DIR = path.join(os.homedir(), '.nodebench');
12
+ const DB_PATH = path.join(DB_DIR, 'analytics.db');
13
+ let _analyticsDb = null;
14
+ export function initAnalyticsDb() {
15
+ fs.mkdirSync(DB_DIR, { recursive: true });
16
+ const db = new Database(DB_PATH);
17
+ // Enable WAL mode for better concurrency
18
+ db.pragma('journal_mode = WAL');
19
+ // Create tables
20
+ db.exec(`
21
+ CREATE TABLE IF NOT EXISTS tool_usage (
22
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
23
+ tool_name TEXT NOT NULL,
24
+ toolset TEXT NOT NULL,
25
+ timestamp INTEGER NOT NULL,
26
+ duration INTEGER NOT NULL,
27
+ success BOOLEAN NOT NULL,
28
+ error_message TEXT,
29
+ project_path TEXT NOT NULL,
30
+ preset TEXT NOT NULL,
31
+ args TEXT
32
+ );
33
+
34
+ CREATE INDEX IF NOT EXISTS idx_tool_usage_tool ON tool_usage(tool_name);
35
+ CREATE INDEX IF NOT EXISTS idx_tool_usage_toolset ON tool_usage(toolset);
36
+ CREATE INDEX IF NOT EXISTS idx_tool_usage_project ON tool_usage(project_path);
37
+ CREATE INDEX IF NOT EXISTS idx_tool_usage_timestamp ON tool_usage(timestamp);
38
+
39
+ CREATE TABLE IF NOT EXISTS project_context (
40
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
41
+ project_path TEXT UNIQUE NOT NULL,
42
+ project_type TEXT NOT NULL,
43
+ detected_at INTEGER NOT NULL,
44
+ last_seen INTEGER NOT NULL,
45
+ language TEXT NOT NULL,
46
+ framework TEXT,
47
+ has_tests BOOLEAN NOT NULL,
48
+ has_ci BOOLEAN NOT NULL,
49
+ has_docs BOOLEAN NOT NULL,
50
+ file_count INTEGER NOT NULL
51
+ );
52
+
53
+ CREATE INDEX IF NOT EXISTS idx_project_context_type ON project_context(project_type);
54
+ CREATE INDEX IF NOT EXISTS idx_project_context_last_seen ON project_context(last_seen);
55
+
56
+ CREATE TABLE IF NOT EXISTS preset_history (
57
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
58
+ project_path TEXT NOT NULL,
59
+ preset TEXT NOT NULL,
60
+ toolset_count INTEGER NOT NULL,
61
+ selected_at INTEGER NOT NULL,
62
+ selection_reason TEXT NOT NULL
63
+ );
64
+
65
+ CREATE INDEX IF NOT EXISTS idx_preset_history_project ON preset_history(project_path);
66
+ CREATE INDEX IF NOT EXISTS idx_preset_history_timestamp ON preset_history(selected_at);
67
+
68
+ CREATE TABLE IF NOT EXISTS usage_stats_cache (
69
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
70
+ project_path TEXT NOT NULL,
71
+ cache_key TEXT NOT NULL,
72
+ stats TEXT NOT NULL,
73
+ computed_at INTEGER NOT NULL,
74
+ ttl INTEGER NOT NULL,
75
+ UNIQUE(project_path, cache_key)
76
+ );
77
+
78
+ CREATE INDEX IF NOT EXISTS idx_usage_stats_cache_key ON usage_stats_cache(project_path, cache_key);
79
+ `);
80
+ return db;
81
+ }
82
+ export function getAnalyticsDb() {
83
+ if (_analyticsDb)
84
+ return _analyticsDb;
85
+ _analyticsDb = initAnalyticsDb();
86
+ return _analyticsDb;
87
+ }
88
+ export function closeAnalyticsDb(db) {
89
+ db.close();
90
+ if (_analyticsDb === db)
91
+ _analyticsDb = null;
92
+ }
93
+ // Helper functions for common queries
94
+ export function recordToolUsage(db, record) {
95
+ const stmt = db.prepare(`
96
+ INSERT INTO tool_usage (
97
+ tool_name, toolset, timestamp, duration, success,
98
+ error_message, project_path, preset, args
99
+ ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
100
+ `);
101
+ stmt.run(record.toolName, record.toolset, record.timestamp, record.duration, record.success ? 1 : 0, record.errorMessage || null, record.projectPath, record.preset, record.args || null);
102
+ }
103
+ export function updateProjectContext(db, context) {
104
+ const stmt = db.prepare(`
105
+ INSERT INTO project_context (
106
+ project_path, project_type, detected_at, last_seen,
107
+ language, framework, has_tests, has_ci, has_docs, file_count
108
+ ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
109
+ ON CONFLICT(project_path) DO UPDATE SET
110
+ project_type = excluded.project_type,
111
+ last_seen = excluded.last_seen,
112
+ language = excluded.language,
113
+ framework = excluded.framework,
114
+ has_tests = excluded.has_tests,
115
+ has_ci = excluded.has_ci,
116
+ has_docs = excluded.has_docs,
117
+ file_count = excluded.file_count
118
+ `);
119
+ stmt.run(context.projectPath, context.projectType, context.detectedAt, context.lastSeen, context.language, context.framework || null, context.hasTests ? 1 : 0, context.hasCI ? 1 : 0, context.hasDocs ? 1 : 0, context.fileCount);
120
+ }
121
+ export function recordPresetSelection(db, record) {
122
+ const stmt = db.prepare(`
123
+ INSERT INTO preset_history (
124
+ project_path, preset, toolset_count, selected_at, selection_reason
125
+ ) VALUES (?, ?, ?, ?, ?)
126
+ `);
127
+ stmt.run(record.projectPath, record.preset, record.toolsetCount, record.selectedAt, record.selectionReason);
128
+ }
129
+ export function getCachedStats(db, projectPath, cacheKey) {
130
+ const stmt = db.prepare(`
131
+ SELECT stats FROM usage_stats_cache
132
+ WHERE project_path = ? AND cache_key = ?
133
+ AND computed_at + (ttl * 1000) > ?
134
+ `);
135
+ const now = Date.now();
136
+ const result = stmt.get(projectPath, cacheKey, now);
137
+ return result?.stats || null;
138
+ }
139
+ export function setCachedStats(db, record) {
140
+ const stmt = db.prepare(`
141
+ INSERT INTO usage_stats_cache (
142
+ project_path, cache_key, stats, computed_at, ttl
143
+ ) VALUES (?, ?, ?, ?, ?)
144
+ ON CONFLICT(project_path, cache_key) DO UPDATE SET
145
+ stats = excluded.stats,
146
+ computed_at = excluded.computed_at,
147
+ ttl = excluded.ttl
148
+ `);
149
+ stmt.run(record.projectPath, record.cacheKey, record.stats, record.computedAt, record.ttl);
150
+ }
151
+ export function clearOldRecords(db, daysToKeep = 90) {
152
+ const cutoff = Date.now() - (daysToKeep * 24 * 60 * 60 * 1000);
153
+ db.prepare('DELETE FROM tool_usage WHERE timestamp < ?').run(cutoff);
154
+ db.prepare('DELETE FROM usage_stats_cache WHERE computed_at < ?').run(cutoff);
155
+ // Don't delete project_context or preset_history - they're useful for history
156
+ }
157
+ //# sourceMappingURL=schema.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"schema.js","sourceRoot":"","sources":["../../src/analytics/schema.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,63 @@
1
+ /**
2
+ * Smart Preset Generator — Weighted Multi-Signal Scoring Model
3
+ *
4
+ * Recommends preset (default vs full) using 5 weighted signals derived from
5
+ * actual project context and historical usage data:
6
+ *
7
+ * 1. Project Type Affinity — static: how many specialized toolsets fit this project type
8
+ * 2. Usage Breadth — empirical: how many distinct toolsets were actually used
9
+ * 3. Specialized Usage Depth — empirical: calls to non-default toolsets (weighted by recency)
10
+ * 4. Failure Penalty — empirical: frequently failing tools penalize confidence
11
+ * 5. History Weight — meta: more history = higher confidence in the recommendation
12
+ *
13
+ * The final score is a weighted sum normalized to [0, 1].
14
+ * score > 0.55 → recommend full
15
+ * score <= 0.55 → recommend default
16
+ * confidence = f(history_weight, failure_penalty)
17
+ */
18
+ import Database from 'better-sqlite3';
19
+ import { type ProjectContext } from './projectDetector.js';
20
+ import type { McpTool } from '../types.js';
21
+ export interface PresetRecommendation {
22
+ preset: 'default' | 'full';
23
+ reason: string;
24
+ confidence: number;
25
+ score: number;
26
+ suggestedToolsets: string[];
27
+ optionalToolsets: string[];
28
+ projectContext: ProjectContext;
29
+ usageInsights: UsageInsights;
30
+ signals: SignalBreakdown;
31
+ }
32
+ export interface UsageInsights {
33
+ mostUsedToolsets: string[];
34
+ unusedToolsets: string[];
35
+ frequentlyFailingTools: Array<{
36
+ name: string;
37
+ failures: number;
38
+ lastError: string | null;
39
+ }>;
40
+ totalCallsLast30d: number;
41
+ uniqueToolsetsUsed: number;
42
+ }
43
+ export interface SignalBreakdown {
44
+ projectTypeAffinity: number;
45
+ usageBreadth: number;
46
+ specializedDepth: number;
47
+ failurePenalty: number;
48
+ historyWeight: number;
49
+ }
50
+ export interface PresetConfig {
51
+ name: 'default' | 'full';
52
+ toolsets: string[];
53
+ toolCount: number;
54
+ }
55
+ export declare function generateSmartPreset(db: Database.Database, toolsetMap: Record<string, McpTool[]>, projectPath?: string): PresetRecommendation;
56
+ export declare function getPresetConfig(preset: 'default' | 'full', toolsetMap: Record<string, McpTool[]>): PresetConfig;
57
+ export declare function listPresets(toolsetMap: Record<string, McpTool[]>): Array<{
58
+ name: string;
59
+ toolsets: string[];
60
+ toolCount: number;
61
+ description: string;
62
+ }>;
63
+ export declare function formatPresetRecommendation(recommendation: PresetRecommendation, toolsetMap: Record<string, McpTool[]>): string;
@@ -0,0 +1,300 @@
1
+ /**
2
+ * Smart Preset Generator — Weighted Multi-Signal Scoring Model
3
+ *
4
+ * Recommends preset (default vs full) using 5 weighted signals derived from
5
+ * actual project context and historical usage data:
6
+ *
7
+ * 1. Project Type Affinity — static: how many specialized toolsets fit this project type
8
+ * 2. Usage Breadth — empirical: how many distinct toolsets were actually used
9
+ * 3. Specialized Usage Depth — empirical: calls to non-default toolsets (weighted by recency)
10
+ * 4. Failure Penalty — empirical: frequently failing tools penalize confidence
11
+ * 5. History Weight — meta: more history = higher confidence in the recommendation
12
+ *
13
+ * The final score is a weighted sum normalized to [0, 1].
14
+ * score > 0.55 → recommend full
15
+ * score <= 0.55 → recommend default
16
+ * confidence = f(history_weight, failure_penalty)
17
+ */
18
+ import { detectProject } from './projectDetector.js';
19
+ import { getToolUsageStats, getToolsetUsageStats, getFrequentlyFailingTools, } from './usageStats.js';
20
+ // ── Constants ───────────────────────────────────────────────────────────
21
+ const DEFAULT_TOOLSETS = ['verification', 'eval', 'quality_gate', 'learning', 'flywheel', 'recon', 'security', 'boilerplate'];
22
+ const DEFAULT_TOOLSET_SET = new Set(DEFAULT_TOOLSETS);
23
+ const SCORE_THRESHOLD = 0.55; // above this → recommend full
24
+ // Signal weights (sum to 1.0)
25
+ const W_PROJECT_TYPE = 0.25;
26
+ const W_USAGE_BREADTH = 0.30;
27
+ const W_SPECIALIZED_DEPTH = 0.30;
28
+ const W_HISTORY = 0.15;
29
+ // Project type → extra toolsets beyond default
30
+ const PROJECT_TYPE_EXTRAS = {
31
+ web_frontend: ['ui_capture', 'vision'],
32
+ web_backend: ['web', 'github'],
33
+ fullstack: ['ui_capture', 'vision', 'web', 'github', 'llm'],
34
+ mobile: [],
35
+ desktop: [],
36
+ cli: [],
37
+ library: ['docs', 'github'],
38
+ data_science: ['local_file', 'llm'],
39
+ devops: ['github'],
40
+ unknown: [],
41
+ };
42
+ // All toolsets considered "specialized" (not in default)
43
+ const SPECIALIZED_TOOLSETS = [
44
+ 'ui_capture', 'vision', 'web', 'github', 'docs', 'local_file',
45
+ 'self_eval', 'parallel', 'llm', 'platform', 'research_writing',
46
+ 'bootstrap', 'flicker_detection', 'figma_flow', 'benchmark',
47
+ 'gaia_solvers', 'session_memory', 'toon', 'pattern', 'git_workflow',
48
+ 'seo', 'voice_bridge', 'critter', 'email', 'rss', 'architect',
49
+ ];
50
+ // ── Helpers ─────────────────────────────────────────────────────────────
51
+ function calculateToolsetCount(toolsets, toolsetMap) {
52
+ let count = 0;
53
+ for (const ts of toolsets)
54
+ count += toolsetMap[ts]?.length || 0;
55
+ return count + 6; // +6 meta/discovery
56
+ }
57
+ function createPresets(toolsetMap) {
58
+ return {
59
+ default: {
60
+ name: 'default',
61
+ toolsets: DEFAULT_TOOLSETS,
62
+ toolCount: calculateToolsetCount(DEFAULT_TOOLSETS, toolsetMap),
63
+ },
64
+ full: {
65
+ name: 'full',
66
+ toolsets: Object.keys(toolsetMap),
67
+ toolCount: Object.values(toolsetMap).reduce((s, t) => s + t.length, 0) + 6,
68
+ },
69
+ };
70
+ }
71
+ // ── Signal computation ──────────────────────────────────────────────────
72
+ function computeProjectTypeAffinity(projectType) {
73
+ const extras = PROJECT_TYPE_EXTRAS[projectType] || [];
74
+ // 0 extras → 0.0 (default is fine), 5+ extras → 1.0 (needs full)
75
+ return Math.min(extras.length / 5, 1.0);
76
+ }
77
+ function computeUsageBreadth(toolsetStats, totalAvailableToolsets) {
78
+ if (totalAvailableToolsets === 0)
79
+ return 0;
80
+ const usedCount = toolsetStats.filter(ts => ts.totalCalls > 0).length;
81
+ // Fraction of available toolsets that were actually used
82
+ return Math.min(usedCount / totalAvailableToolsets, 1.0);
83
+ }
84
+ function computeSpecializedDepth(toolsetStats, totalCalls) {
85
+ if (totalCalls === 0)
86
+ return 0;
87
+ // What fraction of total calls went to non-default toolsets?
88
+ const specializedCalls = toolsetStats
89
+ .filter(ts => !DEFAULT_TOOLSET_SET.has(ts.toolset))
90
+ .reduce((sum, ts) => sum + ts.totalCalls, 0);
91
+ return Math.min(specializedCalls / totalCalls, 1.0);
92
+ }
93
+ function computeFailurePenalty(failingTools, totalCalls) {
94
+ if (totalCalls === 0 || failingTools.length === 0)
95
+ return 0;
96
+ const totalFailures = failingTools.reduce((s, t) => s + t.failureCount, 0);
97
+ // Cap at 0.5 — failures reduce confidence but don't dominate
98
+ return Math.min(totalFailures / totalCalls, 0.5);
99
+ }
100
+ function computeHistoryWeight(totalCalls) {
101
+ // No history → 0, 10 calls → 0.5, 100+ calls → 1.0 (logarithmic)
102
+ if (totalCalls === 0)
103
+ return 0;
104
+ return Math.min(Math.log10(totalCalls + 1) / 2, 1.0);
105
+ }
106
+ // ── Core: generate recommendation ───────────────────────────────────────
107
+ export function generateSmartPreset(db, toolsetMap, projectPath = process.cwd()) {
108
+ const projectContext = detectProject(projectPath);
109
+ const presets = createPresets(toolsetMap);
110
+ const availableToolsets = Object.keys(toolsetMap);
111
+ // Gather empirical data
112
+ const toolsetStats = getToolsetUsageStats(db, projectPath, 30);
113
+ const toolStats = getToolUsageStats(db, projectPath, 30);
114
+ const failingToolsRaw = getFrequentlyFailingTools(db, projectPath, 30, 2);
115
+ const totalCalls = toolStats.reduce((s, t) => s + t.callCount, 0);
116
+ // Compute 5 signals
117
+ const projectTypeAffinity = computeProjectTypeAffinity(projectContext.projectType);
118
+ const usageBreadth = computeUsageBreadth(toolsetStats, availableToolsets.length);
119
+ const specializedDepth = computeSpecializedDepth(toolsetStats, totalCalls);
120
+ const failurePenalty = computeFailurePenalty(failingToolsRaw, totalCalls);
121
+ const historyWeight = computeHistoryWeight(totalCalls);
122
+ const signals = {
123
+ projectTypeAffinity,
124
+ usageBreadth,
125
+ specializedDepth,
126
+ failurePenalty,
127
+ historyWeight,
128
+ };
129
+ // Weighted score: blend static (project type) with empirical signals
130
+ // When history is low, project type dominates. When history is rich, usage dominates.
131
+ const empiricalBlend = historyWeight; // 0 = no history, 1 = trust history fully
132
+ const staticScore = projectTypeAffinity;
133
+ const empiricalScore = (usageBreadth * W_USAGE_BREADTH + specializedDepth * W_SPECIALIZED_DEPTH + historyWeight * W_HISTORY)
134
+ / (W_USAGE_BREADTH + W_SPECIALIZED_DEPTH + W_HISTORY);
135
+ // Normalize: simple weighted average where empirical grows with history
136
+ const score = Math.min(staticScore * (1 - empiricalBlend) + empiricalScore * empiricalBlend, 1.0);
137
+ // Decision
138
+ const preset = score > SCORE_THRESHOLD ? 'full' : 'default';
139
+ // Confidence: higher with more history, penalized by failures
140
+ const baseConfidence = historyWeight > 0
141
+ ? 0.6 + historyWeight * 0.35 // 0.6 → 0.95 as history grows
142
+ : 0.5 + projectTypeAffinity * 0.3; // 0.5 → 0.8 for static-only
143
+ const confidence = Math.max(0.3, baseConfidence - failurePenalty * 0.2);
144
+ // Build reason
145
+ const reason = buildReason(preset, signals, projectContext, totalCalls);
146
+ // Build suggested toolsets: default + project-type extras + actually-used specialized
147
+ const extras = PROJECT_TYPE_EXTRAS[projectContext.projectType] || [];
148
+ const usedSpecialized = toolsetStats
149
+ .filter(ts => !DEFAULT_TOOLSET_SET.has(ts.toolset) && ts.totalCalls > 0)
150
+ .map(ts => ts.toolset);
151
+ const suggestedToolsets = [...new Set([...DEFAULT_TOOLSETS, ...extras, ...usedSpecialized])];
152
+ const optionalToolsets = SPECIALIZED_TOOLSETS.filter(ts => !suggestedToolsets.includes(ts));
153
+ // Usage insights
154
+ const mostUsedToolsets = toolsetStats
155
+ .filter(ts => ts.totalCalls > 0)
156
+ .sort((a, b) => b.totalCalls - a.totalCalls)
157
+ .map(ts => ts.toolset)
158
+ .slice(0, 5);
159
+ const usedSet = new Set(toolsetStats.filter(ts => ts.totalCalls > 0).map(ts => ts.toolset));
160
+ const unusedToolsets = availableToolsets.filter(ts => !usedSet.has(ts));
161
+ return {
162
+ preset,
163
+ reason,
164
+ confidence: Math.round(confidence * 100) / 100,
165
+ score: Math.round(score * 1000) / 1000,
166
+ suggestedToolsets,
167
+ optionalToolsets,
168
+ projectContext,
169
+ usageInsights: {
170
+ mostUsedToolsets,
171
+ unusedToolsets,
172
+ frequentlyFailingTools: failingToolsRaw.map(t => ({
173
+ name: t.toolName,
174
+ failures: t.failureCount,
175
+ lastError: t.lastError,
176
+ })),
177
+ totalCallsLast30d: totalCalls,
178
+ uniqueToolsetsUsed: toolsetStats.filter(ts => ts.totalCalls > 0).length,
179
+ },
180
+ signals,
181
+ };
182
+ }
183
+ function buildReason(preset, signals, ctx, totalCalls) {
184
+ const parts = [];
185
+ if (totalCalls === 0) {
186
+ parts.push(`No usage history yet.`);
187
+ if (preset === 'full') {
188
+ parts.push(`Project type (${ctx.projectType}) suggests specialized toolsets would help.`);
189
+ }
190
+ else {
191
+ parts.push(`Project type (${ctx.projectType}) aligns with default preset.`);
192
+ }
193
+ parts.push(`As you use more tools, this recommendation will improve.`);
194
+ }
195
+ else {
196
+ parts.push(`Based on ${totalCalls} tool calls across ${signals.historyWeight > 0.5 ? 'rich' : 'limited'} history.`);
197
+ if (signals.specializedDepth > 0.3) {
198
+ parts.push(`${(signals.specializedDepth * 100).toFixed(0)}% of calls use specialized (non-default) toolsets.`);
199
+ }
200
+ if (signals.usageBreadth > 0.4) {
201
+ parts.push(`Broad toolset usage detected across ${(signals.usageBreadth * 100).toFixed(0)}% of available toolsets.`);
202
+ }
203
+ if (preset === 'full') {
204
+ parts.push(`Full preset recommended for comprehensive coverage.`);
205
+ }
206
+ else {
207
+ parts.push(`Default preset covers your current usage patterns.`);
208
+ }
209
+ }
210
+ if (signals.failurePenalty > 0.1) {
211
+ parts.push(`Note: ${(signals.failurePenalty * 100).toFixed(0)}% failure rate detected - check failing tools below.`);
212
+ }
213
+ return parts.join(' ');
214
+ }
215
+ // ── Preset listing ──────────────────────────────────────────────────────
216
+ export function getPresetConfig(preset, toolsetMap) {
217
+ return createPresets(toolsetMap)[preset];
218
+ }
219
+ export function listPresets(toolsetMap) {
220
+ const presets = createPresets(toolsetMap);
221
+ const THEMED_PRESETS = [
222
+ { name: 'web_dev', extras: ['ui_capture', 'vision', 'web', 'seo', 'git_workflow', 'architect'], description: 'Web projects — adds visual QA, SEO audit, git workflow, code architecture' },
223
+ { name: 'research', extras: ['web', 'llm', 'rss', 'email', 'docs'], description: 'Research workflows — adds web search, LLM calls, RSS feeds, email, docs' },
224
+ { name: 'data', extras: ['local_file', 'llm', 'web'], description: 'Data analysis — adds CSV/XLSX/PDF/JSON parsing, LLM extraction, web fetch' },
225
+ { name: 'devops', extras: ['git_workflow', 'session_memory', 'benchmark', 'pattern'], description: 'CI/CD & ops — adds git compliance, session memory, benchmarks, pattern mining' },
226
+ { name: 'mobile', extras: ['ui_capture', 'vision', 'flicker_detection'], description: 'Mobile apps — adds screenshot capture, vision analysis, flicker detection' },
227
+ { name: 'academic', extras: ['research_writing', 'llm', 'web', 'local_file'], description: 'Academic papers — adds polish, review, translate, logic check, data analysis' },
228
+ { name: 'multi_agent', extras: ['parallel', 'self_eval', 'session_memory', 'pattern', 'toon'], description: 'Multi-agent teams — adds task locking, messaging, roles, oracle testing' },
229
+ { name: 'content', extras: ['llm', 'critter', 'email', 'rss', 'platform', 'architect'], description: 'Content & publishing — adds LLM, accountability, email, RSS, platform queue' },
230
+ ];
231
+ const result = [
232
+ {
233
+ name: 'default',
234
+ toolsets: presets.default.toolsets,
235
+ toolCount: presets.default.toolCount,
236
+ description: 'Core AI Flywheel methodology — verification, eval, quality gates, learning, recon, security, boilerplate',
237
+ },
238
+ ];
239
+ for (const themed of THEMED_PRESETS) {
240
+ const toolsets = [...DEFAULT_TOOLSETS, ...themed.extras];
241
+ result.push({
242
+ name: themed.name,
243
+ toolsets,
244
+ toolCount: calculateToolsetCount(toolsets, toolsetMap),
245
+ description: themed.description,
246
+ });
247
+ }
248
+ result.push({
249
+ name: 'full',
250
+ toolsets: presets.full.toolsets,
251
+ toolCount: presets.full.toolCount,
252
+ description: `All ${presets.full.toolCount} tools across ${Object.keys(toolsetMap).length} toolsets — complete coverage`,
253
+ });
254
+ return result;
255
+ }
256
+ // ── Formatted output ────────────────────────────────────────────────────
257
+ export function formatPresetRecommendation(recommendation, toolsetMap) {
258
+ const lines = [];
259
+ const { signals: s, usageInsights: u, projectContext: p } = recommendation;
260
+ lines.push(`\n=== Smart Preset Recommendation ===\n`);
261
+ lines.push(` Preset: ${recommendation.preset.toUpperCase()}`);
262
+ lines.push(` Confidence: ${(recommendation.confidence * 100).toFixed(0)}%`);
263
+ lines.push(` Score: ${recommendation.score.toFixed(3)} (threshold: ${SCORE_THRESHOLD})\n`);
264
+ lines.push(` ${recommendation.reason}`);
265
+ // Signal breakdown
266
+ lines.push(`\n--- Signal Breakdown ---`);
267
+ lines.push(` Project Type Affinity: ${(s.projectTypeAffinity * 100).toFixed(0)}% (${p.projectType}/${p.language}${p.framework ? '/' + p.framework : ''})`);
268
+ lines.push(` Usage Breadth: ${(s.usageBreadth * 100).toFixed(0)}% (${u.uniqueToolsetsUsed}/${Object.keys(toolsetMap).length} toolsets used)`);
269
+ lines.push(` Specialized Depth: ${(s.specializedDepth * 100).toFixed(0)}% (non-default call share)`);
270
+ lines.push(` History Weight: ${(s.historyWeight * 100).toFixed(0)}% (${u.totalCallsLast30d} calls in 30d)`);
271
+ lines.push(` Failure Penalty: ${(s.failurePenalty * 100).toFixed(0)}%`);
272
+ // Project context
273
+ lines.push(`\n--- Project ---`);
274
+ lines.push(` Type: ${p.projectType} | Language: ${p.language}${p.framework ? ' | Framework: ' + p.framework : ''}`);
275
+ lines.push(` Tests: ${p.hasTests ? 'Yes' : 'No'} | CI: ${p.hasCI ? 'Yes' : 'No'} | Files: ${p.fileCount}`);
276
+ // Suggested toolsets
277
+ lines.push(`\n--- Suggested Toolsets (${calculateToolsetCount(recommendation.suggestedToolsets, toolsetMap)} tools) ---`);
278
+ lines.push(` ${recommendation.suggestedToolsets.join(', ')}`);
279
+ // Usage insights
280
+ if (u.mostUsedToolsets.length > 0) {
281
+ lines.push(`\n--- Most Used (30d) ---`);
282
+ lines.push(` ${u.mostUsedToolsets.join(', ')}`);
283
+ }
284
+ // Failing tools warnings
285
+ if (u.frequentlyFailingTools.length > 0) {
286
+ lines.push(`\n--- Failing Tools (action required) ---`);
287
+ for (const t of u.frequentlyFailingTools) {
288
+ lines.push(` ! ${t.name}: ${t.failures} failures${t.lastError ? ' - ' + t.lastError.slice(0, 80) : ''}`);
289
+ }
290
+ }
291
+ // How to apply
292
+ lines.push(`\n--- Apply ---`);
293
+ lines.push(` npx nodebench-mcp --preset ${recommendation.preset}`);
294
+ if (recommendation.suggestedToolsets.length > DEFAULT_TOOLSETS.length) {
295
+ lines.push(` npx nodebench-mcp --toolsets ${recommendation.suggestedToolsets.join(',')}`);
296
+ }
297
+ lines.push('');
298
+ return lines.join('\n');
299
+ }
300
+ //# sourceMappingURL=smartPreset.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"smartPreset.js","sourceRoot":"","sources":["../../src/analytics/smartPreset.ts"],"names":[],"mappings":"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"}