@felkot/think-mcp 1.1.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 (49) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +165 -0
  3. package/dist/constants/index.d.ts +5 -0
  4. package/dist/constants/index.js +5 -0
  5. package/dist/constants/patterns.d.ts +8 -0
  6. package/dist/constants/patterns.js +34 -0
  7. package/dist/constants/prompts.d.ts +1 -0
  8. package/dist/constants/prompts.js +44 -0
  9. package/dist/constants/thresholds.d.ts +39 -0
  10. package/dist/constants/thresholds.js +54 -0
  11. package/dist/index.d.ts +20 -0
  12. package/dist/index.js +711 -0
  13. package/dist/services/burst.service.d.ts +39 -0
  14. package/dist/services/burst.service.js +215 -0
  15. package/dist/services/coaching.service.d.ts +38 -0
  16. package/dist/services/coaching.service.js +258 -0
  17. package/dist/services/consolidate.service.d.ts +17 -0
  18. package/dist/services/consolidate.service.js +236 -0
  19. package/dist/services/context.service.d.ts +15 -0
  20. package/dist/services/context.service.js +113 -0
  21. package/dist/services/export.service.d.ts +33 -0
  22. package/dist/services/export.service.js +129 -0
  23. package/dist/services/insights.service.d.ts +103 -0
  24. package/dist/services/insights.service.js +216 -0
  25. package/dist/services/logic.service.d.ts +28 -0
  26. package/dist/services/logic.service.js +467 -0
  27. package/dist/services/nudge.service.d.ts +20 -0
  28. package/dist/services/nudge.service.js +114 -0
  29. package/dist/services/recall.service.d.ts +38 -0
  30. package/dist/services/recall.service.js +188 -0
  31. package/dist/services/stagnation.service.d.ts +14 -0
  32. package/dist/services/stagnation.service.js +48 -0
  33. package/dist/services/thinking.service.d.ts +263 -0
  34. package/dist/services/thinking.service.js +1048 -0
  35. package/dist/services/validation.service.d.ts +45 -0
  36. package/dist/services/validation.service.js +260 -0
  37. package/dist/services/visualization.service.d.ts +23 -0
  38. package/dist/services/visualization.service.js +211 -0
  39. package/dist/types/thought.types.d.ts +486 -0
  40. package/dist/types/thought.types.js +5 -0
  41. package/dist/utils/index.d.ts +6 -0
  42. package/dist/utils/index.js +6 -0
  43. package/dist/utils/sensitive-data.d.ts +2 -0
  44. package/dist/utils/sensitive-data.js +28 -0
  45. package/dist/utils/storage-paths.d.ts +9 -0
  46. package/dist/utils/storage-paths.js +28 -0
  47. package/dist/utils/text-analysis.d.ts +30 -0
  48. package/dist/utils/text-analysis.js +92 -0
  49. package/package.json +66 -0
@@ -0,0 +1,216 @@
1
+ /**
2
+ * InsightsService - Cross-session learning from winning paths
3
+ * Version 1.0.0
4
+ *
5
+ * Stores successful reasoning patterns for future recall.
6
+ * NO LLM, NO Vector DB - just JSON persistence + Fuse.js search.
7
+ */
8
+ import { promises as fs } from 'fs';
9
+ import { dirname } from 'path';
10
+ import Fuse from 'fuse.js';
11
+ import { getThinkStoragePaths } from '../utils/storage-paths.js';
12
+ import { redactSensitiveContent } from '../utils/sensitive-data.js';
13
+ // Constants
14
+ const STORAGE_PATHS = getThinkStoragePaths(import.meta.url);
15
+ const INSIGHTS_FILE = STORAGE_PATHS.insightsFile;
16
+ const LEGACY_INSIGHTS_FILE = STORAGE_PATHS.legacyInsightsFile;
17
+ const INSIGHTS_DIR = dirname(INSIGHTS_FILE);
18
+ const MAX_INSIGHTS = 100; // FIFO limit to prevent bloat
19
+ const INSIGHTS_SEARCH_THRESHOLD = 0.4;
20
+ export class InsightsService {
21
+ data = null;
22
+ fuseIndex = null;
23
+ isDirty = false;
24
+ sanitizeText(value) {
25
+ if (!value)
26
+ return value;
27
+ return redactSensitiveContent(value).slice(0, 2000);
28
+ }
29
+ async loadFromFile(filePath) {
30
+ const content = await fs.readFile(filePath, 'utf-8');
31
+ return JSON.parse(content);
32
+ }
33
+ /**
34
+ * Extract keywords from text for pattern tracking
35
+ */
36
+ extractKeywords(text) {
37
+ const stopWords = new Set([
38
+ 'the', 'a', 'an', 'is', 'are', 'was', 'were', 'be', 'been', 'being',
39
+ 'have', 'has', 'had', 'do', 'does', 'did', 'will', 'would', 'could',
40
+ 'should', 'may', 'might', 'must', 'shall', 'can', 'need', 'dare',
41
+ 'to', 'of', 'in', 'for', 'on', 'with', 'at', 'by', 'from', 'as',
42
+ 'into', 'through', 'during', 'before', 'after', 'above', 'below',
43
+ 'and', 'but', 'or', 'nor', 'so', 'yet', 'both', 'either', 'neither',
44
+ 'this', 'that', 'these', 'those', 'it', 'its', 'i', 'we', 'you', 'they',
45
+ ]);
46
+ return text
47
+ .toLowerCase()
48
+ .replace(/[^a-z0-9\s-]/g, ' ')
49
+ .split(/\s+/)
50
+ .filter(word => word.length >= 3 && !stopWords.has(word))
51
+ .slice(0, 10); // Limit to 10 keywords per insight
52
+ }
53
+ /**
54
+ * Load insights from file
55
+ */
56
+ async load() {
57
+ try {
58
+ this.data = await this.loadFromFile(INSIGHTS_FILE);
59
+ this.rebuildIndex();
60
+ console.error(`📚 Loaded ${this.data.winningPaths.length} insights from ${this.data.totalSessions} sessions`);
61
+ }
62
+ catch {
63
+ try {
64
+ this.data = await this.loadFromFile(LEGACY_INSIGHTS_FILE);
65
+ this.rebuildIndex();
66
+ console.error(`📚 Loaded legacy insights from ${LEGACY_INSIGHTS_FILE}`);
67
+ }
68
+ catch {
69
+ // File doesn't exist - initialize empty
70
+ this.data = {
71
+ winningPaths: [],
72
+ patterns: {},
73
+ totalSessions: 0,
74
+ lastUpdated: new Date().toISOString(),
75
+ };
76
+ console.error('📚 No insights file found, starting fresh');
77
+ }
78
+ }
79
+ }
80
+ /**
81
+ * Rebuild Fuse.js index for search
82
+ */
83
+ rebuildIndex() {
84
+ if (!this.data)
85
+ return;
86
+ this.fuseIndex = new Fuse(this.data.winningPaths, {
87
+ keys: [
88
+ { name: 'summary', weight: 0.5 },
89
+ { name: 'goal', weight: 0.3 },
90
+ { name: 'keywords', weight: 0.2 },
91
+ ],
92
+ threshold: INSIGHTS_SEARCH_THRESHOLD,
93
+ includeScore: true,
94
+ ignoreLocation: true,
95
+ });
96
+ }
97
+ /**
98
+ * Save insights to file (atomic write)
99
+ */
100
+ async save() {
101
+ if (!this.data || !this.isDirty)
102
+ return;
103
+ this.data.lastUpdated = new Date().toISOString();
104
+ const tempFile = `${INSIGHTS_FILE}.tmp`;
105
+ try {
106
+ await fs.mkdir(INSIGHTS_DIR, { recursive: true });
107
+ await fs.writeFile(tempFile, JSON.stringify(this.data, null, 2), 'utf-8');
108
+ await fs.rename(tempFile, INSIGHTS_FILE);
109
+ this.isDirty = false;
110
+ console.error(`💾 Saved ${this.data.winningPaths.length} insights`);
111
+ }
112
+ catch (error) {
113
+ console.error('Failed to save insights:', error);
114
+ try {
115
+ await fs.unlink(tempFile);
116
+ }
117
+ catch { /* ignore */ }
118
+ }
119
+ }
120
+ /**
121
+ * Save a winning path as an insight
122
+ */
123
+ async saveWinningPath(input) {
124
+ if (!this.data)
125
+ await this.load();
126
+ const { path, summary, goal, avgConfidence, sessionLength } = input;
127
+ const safeSummary = this.sanitizeText(summary) ?? '';
128
+ const safeGoal = this.sanitizeText(goal);
129
+ // Extract keywords from summary and goal
130
+ const keywords = [
131
+ ...this.extractKeywords(safeSummary),
132
+ ...(safeGoal ? this.extractKeywords(safeGoal) : []),
133
+ ];
134
+ // Create record
135
+ const record = {
136
+ path,
137
+ summary: safeSummary,
138
+ goal: safeGoal,
139
+ keywords: [...new Set(keywords)], // Dedupe
140
+ timestamp: new Date().toISOString(),
141
+ avgConfidence,
142
+ sessionLength,
143
+ };
144
+ // Add to winningPaths (FIFO)
145
+ this.data.winningPaths.push(record);
146
+ if (this.data.winningPaths.length > MAX_INSIGHTS) {
147
+ this.data.winningPaths.shift();
148
+ }
149
+ // Update pattern counts
150
+ for (const keyword of record.keywords) {
151
+ this.data.patterns[keyword] = (this.data.patterns[keyword] || 0) + 1;
152
+ }
153
+ this.data.totalSessions++;
154
+ this.isDirty = true;
155
+ // Rebuild index and save
156
+ this.rebuildIndex();
157
+ await this.save();
158
+ console.error(`📝 Saved insight: "${summary.substring(0, 50)}..." (${record.keywords.length} keywords)`);
159
+ }
160
+ /**
161
+ * Search insights by query
162
+ */
163
+ async search(query, limit = 3) {
164
+ if (!this.data)
165
+ await this.load();
166
+ if (!this.fuseIndex || this.data.winningPaths.length === 0) {
167
+ return {
168
+ matches: [],
169
+ totalInsights: 0,
170
+ topPatterns: [],
171
+ };
172
+ }
173
+ // Search using Fuse.js
174
+ const results = this.fuseIndex.search(query, { limit });
175
+ const matches = results.map(r => ({
176
+ insight: r.item,
177
+ relevance: r.score ?? 1,
178
+ }));
179
+ // Get top patterns
180
+ const topPatterns = Object.entries(this.data.patterns)
181
+ .sort((a, b) => b[1] - a[1])
182
+ .slice(0, 5)
183
+ .map(([keyword, count]) => ({ keyword, count }));
184
+ return {
185
+ matches,
186
+ totalInsights: this.data.winningPaths.length,
187
+ topPatterns,
188
+ };
189
+ }
190
+ /**
191
+ * Get statistics about stored insights
192
+ */
193
+ async getStats() {
194
+ if (!this.data)
195
+ await this.load();
196
+ const paths = this.data.winningPaths;
197
+ const avgSessionLength = paths.length > 0
198
+ ? paths.reduce((sum, p) => sum + p.sessionLength, 0) / paths.length
199
+ : 0;
200
+ const withConfidence = paths.filter(p => p.avgConfidence !== undefined);
201
+ const avgConfidence = withConfidence.length > 0
202
+ ? withConfidence.reduce((sum, p) => sum + (p.avgConfidence ?? 0), 0) / withConfidence.length
203
+ : 0;
204
+ const topPatterns = Object.entries(this.data.patterns)
205
+ .sort((a, b) => b[1] - a[1])
206
+ .slice(0, 10)
207
+ .map(([keyword, count]) => ({ keyword, count }));
208
+ return {
209
+ totalInsights: paths.length,
210
+ totalSessions: this.data.totalSessions,
211
+ topPatterns,
212
+ avgSessionLength: Math.round(avgSessionLength * 10) / 10,
213
+ avgConfidence: Math.round(avgConfidence * 10) / 10,
214
+ };
215
+ }
216
+ }
@@ -0,0 +1,28 @@
1
+ /**
2
+ * LogicService - Pure Thinking Methodology Generator
3
+ * Version 5.0.0 - Methodology Edition
4
+ *
5
+ * PURPOSE: Teach AI HOW to think about code analysis, not WHAT to find.
6
+ * Output is a thinking ALGORITHM that AI applies to specific code.
7
+ *
8
+ * Philosophy: "Teach to fish, don't give fish"
9
+ * - Not: "Is there N+1 query?" (specific question)
10
+ * - But: "For each data access, ask: is this inside a loop?" (thinking pattern)
11
+ */
12
+ import type { LogicAnalysisInput, LogicAnalysisResult } from '../types/thought.types.js';
13
+ export declare class LogicService {
14
+ /**
15
+ * Generate thinking methodology for the target
16
+ */
17
+ analyze(input: LogicAnalysisInput): LogicAnalysisResult;
18
+ private buildMethodology;
19
+ private buildExecutionOrder;
20
+ private buildPriorityPlan;
21
+ private buildVerifyChecklist;
22
+ private buildPreMortem;
23
+ private errorResult;
24
+ /**
25
+ * Format as markdown for AI consumption
26
+ */
27
+ formatAsMarkdown(result: LogicAnalysisResult): string;
28
+ }