fivocell 4.0.0 → 4.1.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 (166) hide show
  1. package/dist/__tests__/behavior-intelligence-bug.test.d.ts +2 -0
  2. package/dist/__tests__/behavior-intelligence-bug.test.d.ts.map +1 -0
  3. package/dist/__tests__/behavior-intelligence-bug.test.js +21 -0
  4. package/dist/__tests__/behavior-intelligence-bug.test.js.map +1 -0
  5. package/dist/__tests__/code-scanner-arrow-return-type.test.d.ts +2 -0
  6. package/dist/__tests__/code-scanner-arrow-return-type.test.d.ts.map +1 -0
  7. package/dist/__tests__/code-scanner-arrow-return-type.test.js +76 -0
  8. package/dist/__tests__/code-scanner-arrow-return-type.test.js.map +1 -0
  9. package/dist/__tests__/code-scanner-blindspot.test.d.ts +2 -0
  10. package/dist/__tests__/code-scanner-blindspot.test.d.ts.map +1 -0
  11. package/dist/__tests__/code-scanner-blindspot.test.js +18 -0
  12. package/dist/__tests__/code-scanner-blindspot.test.js.map +1 -0
  13. package/dist/__tests__/code-scanner-error-recovery.test.d.ts +2 -0
  14. package/dist/__tests__/code-scanner-error-recovery.test.d.ts.map +1 -0
  15. package/dist/__tests__/code-scanner-error-recovery.test.js +21 -0
  16. package/dist/__tests__/code-scanner-error-recovery.test.js.map +1 -0
  17. package/dist/__tests__/code-scanner-n1-detection.test.d.ts +2 -0
  18. package/dist/__tests__/code-scanner-n1-detection.test.d.ts.map +1 -0
  19. package/dist/__tests__/code-scanner-n1-detection.test.js +113 -0
  20. package/dist/__tests__/code-scanner-n1-detection.test.js.map +1 -0
  21. package/dist/__tests__/code-scanner-nesting.test.d.ts +2 -0
  22. package/dist/__tests__/code-scanner-nesting.test.d.ts.map +1 -0
  23. package/dist/__tests__/code-scanner-nesting.test.js +113 -0
  24. package/dist/__tests__/code-scanner-nesting.test.js.map +1 -0
  25. package/dist/__tests__/code-scanner-null-check.test.d.ts +2 -0
  26. package/dist/__tests__/code-scanner-null-check.test.d.ts.map +1 -0
  27. package/dist/__tests__/code-scanner-null-check.test.js +126 -0
  28. package/dist/__tests__/code-scanner-null-check.test.js.map +1 -0
  29. package/dist/__tests__/code-scanner-sql-fix.test.d.ts +2 -0
  30. package/dist/__tests__/code-scanner-sql-fix.test.d.ts.map +1 -0
  31. package/dist/__tests__/code-scanner-sql-fix.test.js +21 -0
  32. package/dist/__tests__/code-scanner-sql-fix.test.js.map +1 -0
  33. package/dist/__tests__/code-scanner-trust-score.test.d.ts +1 -0
  34. package/dist/__tests__/code-scanner-trust-score.test.d.ts.map +1 -0
  35. package/dist/__tests__/code-scanner-trust-score.test.js +39 -0
  36. package/dist/__tests__/code-scanner-trust-score.test.js.map +1 -0
  37. package/dist/__tests__/code-scanner-validation.test.d.ts +2 -0
  38. package/dist/__tests__/code-scanner-validation.test.d.ts.map +1 -0
  39. package/dist/__tests__/code-scanner-validation.test.js +131 -0
  40. package/dist/__tests__/code-scanner-validation.test.js.map +1 -0
  41. package/dist/__tests__/community-store.test.d.ts +2 -0
  42. package/dist/__tests__/community-store.test.d.ts.map +1 -0
  43. package/dist/__tests__/community-store.test.js +231 -0
  44. package/dist/__tests__/community-store.test.js.map +1 -0
  45. package/dist/__tests__/enhanced-blind-spots.test.d.ts +2 -0
  46. package/dist/__tests__/enhanced-blind-spots.test.d.ts.map +1 -0
  47. package/dist/__tests__/enhanced-blind-spots.test.js +347 -0
  48. package/dist/__tests__/enhanced-blind-spots.test.js.map +1 -0
  49. package/dist/__tests__/knowledge-graph-store.test.d.ts +2 -0
  50. package/dist/__tests__/knowledge-graph-store.test.d.ts.map +1 -0
  51. package/dist/__tests__/knowledge-graph-store.test.js +252 -0
  52. package/dist/__tests__/knowledge-graph-store.test.js.map +1 -0
  53. package/dist/__tests__/live-watcher.test.d.ts +2 -0
  54. package/dist/__tests__/live-watcher.test.d.ts.map +1 -0
  55. package/dist/__tests__/live-watcher.test.js +312 -0
  56. package/dist/__tests__/live-watcher.test.js.map +1 -0
  57. package/dist/__tests__/mcp-cell-tools.test.d.ts +2 -0
  58. package/dist/__tests__/mcp-cell-tools.test.d.ts.map +1 -0
  59. package/dist/__tests__/mcp-cell-tools.test.js +176 -0
  60. package/dist/__tests__/mcp-cell-tools.test.js.map +1 -0
  61. package/dist/__tests__/multi-project.test.d.ts +2 -0
  62. package/dist/__tests__/multi-project.test.d.ts.map +1 -0
  63. package/dist/__tests__/multi-project.test.js +145 -0
  64. package/dist/__tests__/multi-project.test.js.map +1 -0
  65. package/dist/__tests__/pc-scanner-paths.test.d.ts +2 -0
  66. package/dist/__tests__/pc-scanner-paths.test.d.ts.map +1 -0
  67. package/dist/__tests__/pc-scanner-paths.test.js +16 -0
  68. package/dist/__tests__/pc-scanner-paths.test.js.map +1 -0
  69. package/dist/__tests__/prompt-builder-realdata.test.d.ts +2 -0
  70. package/dist/__tests__/prompt-builder-realdata.test.d.ts.map +1 -0
  71. package/dist/__tests__/prompt-builder-realdata.test.js +94 -0
  72. package/dist/__tests__/prompt-builder-realdata.test.js.map +1 -0
  73. package/dist/__tests__/prompt-builder-sessions.test.d.ts +2 -0
  74. package/dist/__tests__/prompt-builder-sessions.test.d.ts.map +1 -0
  75. package/dist/__tests__/prompt-builder-sessions.test.js +124 -0
  76. package/dist/__tests__/prompt-builder-sessions.test.js.map +1 -0
  77. package/dist/__tests__/security.test.d.ts +1 -0
  78. package/dist/__tests__/security.test.d.ts.map +1 -0
  79. package/dist/__tests__/security.test.js +161 -0
  80. package/dist/__tests__/security.test.js.map +1 -0
  81. package/dist/__tests__/session-bridge.test.d.ts +2 -0
  82. package/dist/__tests__/session-bridge.test.d.ts.map +1 -0
  83. package/dist/__tests__/session-bridge.test.js +158 -0
  84. package/dist/__tests__/session-bridge.test.js.map +1 -0
  85. package/dist/__tests__/session-memory-tables.test.d.ts +2 -0
  86. package/dist/__tests__/session-memory-tables.test.d.ts.map +1 -0
  87. package/dist/__tests__/session-memory-tables.test.js +169 -0
  88. package/dist/__tests__/session-memory-tables.test.js.map +1 -0
  89. package/dist/__tests__/staleness-detection.test.d.ts +2 -0
  90. package/dist/__tests__/staleness-detection.test.d.ts.map +1 -0
  91. package/dist/__tests__/staleness-detection.test.js +105 -0
  92. package/dist/__tests__/staleness-detection.test.js.map +1 -0
  93. package/dist/__tests__/team-collaboration.test.d.ts +2 -0
  94. package/dist/__tests__/team-collaboration.test.d.ts.map +1 -0
  95. package/dist/__tests__/team-collaboration.test.js +224 -0
  96. package/dist/__tests__/team-collaboration.test.js.map +1 -0
  97. package/dist/__tests__/tool-specific-format.test.d.ts +2 -0
  98. package/dist/__tests__/tool-specific-format.test.d.ts.map +1 -0
  99. package/dist/__tests__/tool-specific-format.test.js +130 -0
  100. package/dist/__tests__/tool-specific-format.test.js.map +1 -0
  101. package/dist/__tests__/usage-intelligence-store.test.d.ts +2 -0
  102. package/dist/__tests__/usage-intelligence-store.test.d.ts.map +1 -0
  103. package/dist/__tests__/usage-intelligence-store.test.js +266 -0
  104. package/dist/__tests__/usage-intelligence-store.test.js.map +1 -0
  105. package/dist/behavior-intelligence.d.ts.map +1 -1
  106. package/dist/behavior-intelligence.js +12 -1
  107. package/dist/behavior-intelligence.js.map +1 -1
  108. package/dist/cli.js +403 -4
  109. package/dist/cli.js.map +1 -1
  110. package/dist/code-scanner.d.ts.map +1 -1
  111. package/dist/code-scanner.js +344 -102
  112. package/dist/code-scanner.js.map +1 -1
  113. package/dist/core/community-store.d.ts +128 -0
  114. package/dist/core/community-store.d.ts.map +1 -0
  115. package/dist/core/community-store.js +329 -0
  116. package/dist/core/community-store.js.map +1 -0
  117. package/dist/core/database.d.ts +0 -3
  118. package/dist/core/database.d.ts.map +1 -1
  119. package/dist/core/database.js +287 -15
  120. package/dist/core/database.js.map +1 -1
  121. package/dist/core/enhanced-blind-spots.d.ts +27 -0
  122. package/dist/core/enhanced-blind-spots.d.ts.map +1 -0
  123. package/dist/core/enhanced-blind-spots.js +710 -0
  124. package/dist/core/enhanced-blind-spots.js.map +1 -0
  125. package/dist/core/knowledge-graph-store.d.ts +69 -0
  126. package/dist/core/knowledge-graph-store.d.ts.map +1 -0
  127. package/dist/core/knowledge-graph-store.js +269 -0
  128. package/dist/core/knowledge-graph-store.js.map +1 -0
  129. package/dist/core/live-watcher.d.ts +52 -0
  130. package/dist/core/live-watcher.d.ts.map +1 -0
  131. package/dist/core/live-watcher.js +369 -0
  132. package/dist/core/live-watcher.js.map +1 -0
  133. package/dist/core/project-registry.d.ts +24 -0
  134. package/dist/core/project-registry.d.ts.map +1 -0
  135. package/dist/core/project-registry.js +70 -0
  136. package/dist/core/project-registry.js.map +1 -0
  137. package/dist/core/prompt-builder.d.ts +49 -0
  138. package/dist/core/prompt-builder.d.ts.map +1 -1
  139. package/dist/core/prompt-builder.js +540 -67
  140. package/dist/core/prompt-builder.js.map +1 -1
  141. package/dist/core/security.d.ts +23 -0
  142. package/dist/core/security.d.ts.map +1 -0
  143. package/dist/core/security.js +117 -0
  144. package/dist/core/security.js.map +1 -0
  145. package/dist/core/session-memory.d.ts +64 -0
  146. package/dist/core/session-memory.d.ts.map +1 -1
  147. package/dist/core/session-memory.js +111 -0
  148. package/dist/core/session-memory.js.map +1 -1
  149. package/dist/core/syntax-engine.d.ts.map +1 -1
  150. package/dist/core/syntax-engine.js +5 -2
  151. package/dist/core/syntax-engine.js.map +1 -1
  152. package/dist/core/usage-intelligence-store.d.ts +126 -0
  153. package/dist/core/usage-intelligence-store.d.ts.map +1 -0
  154. package/dist/core/usage-intelligence-store.js +405 -0
  155. package/dist/core/usage-intelligence-store.js.map +1 -0
  156. package/dist/daemon/server.d.ts.map +1 -1
  157. package/dist/daemon/server.js +936 -17
  158. package/dist/daemon/server.js.map +1 -1
  159. package/dist/knowledge-graph-builder.d.ts.map +1 -1
  160. package/dist/knowledge-graph-builder.js +18 -2
  161. package/dist/knowledge-graph-builder.js.map +1 -1
  162. package/dist/pc-scanner.d.ts +1 -0
  163. package/dist/pc-scanner.d.ts.map +1 -1
  164. package/dist/pc-scanner.js +64 -33
  165. package/dist/pc-scanner.js.map +1 -1
  166. package/package.json +1 -1
@@ -117,6 +117,12 @@ const database_1 = require("../core/database");
117
117
  const logger_1 = require("../core/logger");
118
118
  const CELL_DIR = path.join(os.homedir(), '.fivo', 'cell');
119
119
  (0, database_1.initializeDatabase)();
120
+ try {
121
+ require('../behavioral-tracker').initBehaviorTables();
122
+ }
123
+ catch (e) {
124
+ console.error('Behavior tables init failed:', e);
125
+ }
120
126
  const META_PATH = path.join(CELL_DIR, 'cell-meta.json');
121
127
  const PORT = 9876;
122
128
  function getCloudConfig() {
@@ -132,18 +138,19 @@ function getCloudConfig() {
132
138
  const app = (0, express_1.default)();
133
139
  exports.app = app;
134
140
  // All 40 modules instantiated — verifies they work in daemon context
141
+ const sharedPatternStore = new pattern_store_1.PatternStore(CELL_DIR);
135
142
  const engines = {
136
143
  signalCapture: new signal_capture_1.SignalCapture(),
137
- patternStore: new pattern_store_1.PatternStore(CELL_DIR),
144
+ patternStore: sharedPatternStore,
138
145
  learningLayer: null,
139
146
  confidenceEngine: new confidence_engine_1.ConfidenceEngine(),
140
147
  extractionCascade: new extraction_cascade_1.ExtractionCascade(),
141
148
  decayEngine: new decay_engine_1.DecayEngine(),
142
- configAttribution: new config_attribution_1.ConfigAttribution(process.cwd()),
149
+ configAttribution: new config_attribution_1.ConfigAttribution(CELL_DIR),
143
150
  communityPrior: new community_prior_1.CommunityPrior(CELL_DIR),
144
151
  communityLive: new community_live_1.CommunityLive(CELL_DIR),
145
152
  communityFull: new community_full_1.CommunityFull(CELL_DIR),
146
- teamComposer: new team_composer_1.TeamComposer(new pattern_store_1.PatternStore(CELL_DIR), CELL_DIR),
153
+ teamComposer: new team_composer_1.TeamComposer(sharedPatternStore, CELL_DIR),
147
154
  conflictDetector: new conflict_detector_1.ConflictDetector(CELL_DIR),
148
155
  promptConditioner: new prompt_conditioner_1.PromptConditioner(),
149
156
  buildFailurePredictor: new build_failure_predictor_1.BuildFailurePredictor(),
@@ -154,7 +161,7 @@ const engines = {
154
161
  mergeConflictPredictor: new merge_conflict_predictor_1.MergeConflictPredictor(),
155
162
  testAnticipator: new test_anticipator_1.TestAnticipator(),
156
163
  contextRestore: new context_restore_1.ContextRestore(CELL_DIR),
157
- crossProjectSync: new cross_project_sync_1.CrossProjectSync(new pattern_store_1.PatternStore(CELL_DIR), CELL_DIR),
164
+ crossProjectSync: new cross_project_sync_1.CrossProjectSync(sharedPatternStore, CELL_DIR),
158
165
  solutionIndex: new solution_index_1.SolutionIndex(CELL_DIR),
159
166
  languageSwitchAssistant: new language_switch_assistant_1.LanguageSwitchAssistant(),
160
167
  interruptionRecovery: new interruption_recovery_1.InterruptionRecovery(CELL_DIR),
@@ -189,7 +196,7 @@ if (cloudConfig.cloudSyncEnabled) {
189
196
  if (patterns.length > 0)
190
197
  (0, ws_client_1.streamPatterns)(patterns);
191
198
  }
192
- app.use((0, cors_1.default)({ origin: true }));
199
+ app.use((0, cors_1.default)({ origin: ['http://localhost', 'http://127.0.0.1'], credentials: false }));
193
200
  app.use(express_1.default.json({ limit: '1mb' }));
194
201
  app.use((0, morgan_1.default)('short'));
195
202
  app.get('/health', (_req, res) => {
@@ -1717,15 +1724,38 @@ app.get('/behavior/stuck', (req, res) => {
1717
1724
  res.json({ stuck: getStuckPatterns(String(req.query.project || undefined)) });
1718
1725
  });
1719
1726
  // ─── Session Bridge Helper ────────────────────────────────────────────────
1720
- function formatSessionBridge(fromTool, toTool, context, decisions) {
1727
+ function formatSessionBridge(fromTool, toTool, context, decisions, options) {
1721
1728
  const lines = [];
1722
1729
  lines.push(`═══ CROSS-SESSION BRIDGE ═══`);
1723
1730
  lines.push(`From: ${fromTool} → To: ${toTool}`);
1724
1731
  if (context)
1725
1732
  lines.push(`Last context: ${context}`);
1726
- if (decisions && decisions !== 'none' && decisions !== '[]') {
1733
+ if (decisions && decisions !== 'none' && decisions !== '[]' && decisions !== 'undefined') {
1727
1734
  lines.push(`Decisions made: ${decisions}`);
1728
1735
  }
1736
+ if (options?.triedApproaches && options.triedApproaches.length > 0) {
1737
+ lines.push('');
1738
+ lines.push('🔄 TRIED ALREADY (don\'t suggest these):');
1739
+ for (const a of options.triedApproaches.slice(0, 5)) {
1740
+ const countSuffix = a.count > 1 ? ` (${a.count}x)` : '';
1741
+ lines.push(` → ${a.approach} — ${a.status}${countSuffix}`);
1742
+ }
1743
+ }
1744
+ if (options?.openQuestions && options.openQuestions.length > 0) {
1745
+ lines.push('');
1746
+ lines.push('💭 OPEN QUESTIONS (unresolved):');
1747
+ for (const q of options.openQuestions.slice(0, 5)) {
1748
+ lines.push(` → [${q.priority}] ${q.question}`);
1749
+ }
1750
+ }
1751
+ if (options?.hotFiles && options.hotFiles.length > 0) {
1752
+ lines.push('');
1753
+ lines.push('🔥 HOT FILES (recently active):');
1754
+ for (const f of options.hotFiles.slice(0, 5)) {
1755
+ lines.push(` → ${f.filePath} (${f.touchCount} touches)`);
1756
+ }
1757
+ }
1758
+ lines.push('');
1729
1759
  lines.push(`Cell remembers. No need to re-explain.`);
1730
1760
  return lines.join('\n');
1731
1761
  }
@@ -1745,6 +1775,56 @@ const MCP_TOOLS = [
1745
1775
  { name: 'cell_log_context', description: 'Log current context', inputSchema: { type: 'object', properties: { project: { type: 'string' }, task: { type: 'string' }, files: { type: 'array', items: { type: 'string' } } }, required: ['task'] } },
1746
1776
  { name: 'cell_log_stuck', description: 'Log when stuck', inputSchema: { type: 'object', properties: { project: { type: 'string' }, file: { type: 'string' }, description: { type: 'string' } }, required: ['description'] } },
1747
1777
  { name: 'cell_session_bridge', description: 'Cross-session memory bridge — get last session context when switching tools', inputSchema: { type: 'object', properties: { project: { type: 'string' }, tool: { type: 'string' } }, required: ['project'] } },
1778
+ { name: 'cell_session_end', description: 'End a session — save final files, decisions, context snapshot', inputSchema: { type: 'object', properties: { sessionId: { type: 'number' }, filesTouched: { type: 'array', items: { type: 'string' } }, keyDecisions: { type: 'array', items: { type: 'string' } }, contextSnapshot: { type: 'string' } }, required: ['sessionId'] } },
1779
+ { name: 'cell_session_log', description: 'Log session activity — approach (tried/failed), file (touched), question (open), resolve (answered)', inputSchema: { type: 'object', properties: { type: { type: 'string' }, sessionId: { type: 'number' }, project: { type: 'string' }, approach: { type: 'string' }, status: { type: 'string' }, reason: { type: 'string' }, filePath: { type: 'string' }, question: { type: 'string' }, priority: { type: 'string' }, questionId: { type: 'number' }, answer: { type: 'string' } }, required: ['type'] } },
1780
+ { name: 'cell_session_start', description: 'Start a new session explicitly — returns session ID for tracking', inputSchema: { type: 'object', properties: { project: { type: 'string' }, tool: { type: 'string' } }, required: ['project', 'tool'] } },
1781
+ { name: 'cell_session_status', description: 'Get current status of a session — files, approaches, active state', inputSchema: { type: 'object', properties: { sessionId: { type: 'number' } }, required: ['sessionId'] } },
1782
+ { name: 'cell_session_recent', description: 'Get recent sessions for a project (or all projects)', inputSchema: { type: 'object', properties: { project: { type: 'string' }, limit: { type: 'number' } }, required: [] } },
1783
+ { name: 'cell_session_recommendations', description: 'Get AI guidance — what to avoid, open questions, hot files for context', inputSchema: { type: 'object', properties: { project: { type: 'string' } }, required: ['project'] } },
1784
+ { name: 'cell_list_projects', description: 'List all registered projects in the workspace', inputSchema: { type: 'object', properties: {} } },
1785
+ { name: 'cell_get_project', description: 'Get full metadata for a project — stack, file count, last scan', inputSchema: { type: 'object', properties: { name: { type: 'string' } }, required: ['name'] } },
1786
+ { name: 'cell_detect_project', description: 'Auto-detect project from current working directory path', inputSchema: { type: 'object', properties: { cwd: { type: 'string' } }, required: ['cwd'] } },
1787
+ { name: 'cell_register_project', description: 'Register a new project explicitly (auto-detected on scan too)', inputSchema: { type: 'object', properties: { name: { type: 'string' }, path: { type: 'string' }, stack: { type: 'string' }, fileCount: { type: 'number' } }, required: ['name', 'path'] } },
1788
+ { name: 'cell_graph_files', description: 'Get file dependency graph (complexity, coupling, risk) for project', inputSchema: { type: 'object', properties: { project: { type: 'string' }, limit: { type: 'number', description: 'Max files to return (default 20)' } }, required: ['project'] } },
1789
+ { name: 'cell_graph_blast_radius', description: 'Compute blast radius — which files break if I change this one?', inputSchema: { type: 'object', properties: { project: { type: 'string' }, file: { type: 'string' } }, required: ['project', 'file'] } },
1790
+ { name: 'cell_graph_tech', description: 'Show technology proficiency (languages, frameworks, architecture)', inputSchema: { type: 'object', properties: { project: { type: 'string' } }, required: ['project'] } },
1791
+ { name: 'cell_graph_stats', description: 'Get knowledge graph statistics (file + pattern + tech nodes/edges)', inputSchema: { type: 'object', properties: { project: { type: 'string' } }, required: ['project'] } },
1792
+ { name: 'cell_team_silos', description: 'Detect knowledge silos (bus factor risks) in the team', inputSchema: { type: 'object', properties: {} } },
1793
+ { name: 'cell_team_bus_factor', description: 'Calculate bus factor report — who knows what, single points of failure', inputSchema: { type: 'object', properties: {} } },
1794
+ { name: 'cell_team_health', description: 'Team health score (bus factor, silos, skill gaps, strengths)', inputSchema: { type: 'object', properties: { project: { type: 'string' } } } },
1795
+ { name: 'cell_team_onboard', description: 'Generate onboarding doc for new team member', inputSchema: { type: 'object', properties: { teamName: { type: 'string' }, project: { type: 'string' } }, required: ['teamName'] } },
1796
+ { name: 'cell_team_retro', description: 'Sprint retrospective (commits, files, contributors, key decisions)', inputSchema: { type: 'object', properties: { days: { type: 'number', description: 'Days to look back (default 14)' }, project: { type: 'string' } } } },
1797
+ { name: 'cell_team_handoff', description: 'Generate handoff context when transferring work between team members', inputSchema: { type: 'object', properties: { from: { type: 'string' }, to: { type: 'string' }, project: { type: 'string' } }, required: ['from', 'to', 'project'] } },
1798
+ { name: 'cell_team_knowledge_transfer', description: 'Suggest knowledge transfer pairs to reduce bus factor risk', inputSchema: { type: 'object', properties: {} } },
1799
+ { name: 'cell_team_style', description: 'Compose team coding style (languages, patterns, conventions)', inputSchema: { type: 'object', properties: { project: { type: 'string' } } } },
1800
+ { name: 'cell_team_dashboard', description: 'Combined team intelligence — silos, bus factor, health, style, all in one call', inputSchema: { type: 'object', properties: { project: { type: 'string' } } } },
1801
+ { name: 'cell_community_stats', description: 'Community-wide stats: total patterns, insights, benchmarks, top contributors', inputSchema: { type: 'object', properties: {} } },
1802
+ { name: 'cell_community_share', description: 'Share an anonymized pattern with the community (privacy-validated)', inputSchema: { type: 'object', properties: { category: { type: 'string' }, rule: { type: 'string' }, language: { type: 'string' }, framework: { type: 'string' }, successRate: { type: 'number' } }, required: ['category', 'rule'] } },
1803
+ { name: 'cell_community_patterns', description: 'Browse community patterns (top voted, by category, by language)', inputSchema: { type: 'object', properties: { category: { type: 'string' }, language: { type: 'string' }, minVotes: { type: 'number' }, limit: { type: 'number' } } } },
1804
+ { name: 'cell_community_vote', description: 'Upvote or downvote a community pattern', inputSchema: { type: 'object', properties: { patternId: { type: 'string' }, upvote: { type: 'boolean' } }, required: ['patternId', 'upvote'] } },
1805
+ { name: 'cell_community_insights', description: 'Get community insights (failure patterns, security warnings, best practices)', inputSchema: { type: 'object', properties: { severity: { type: 'string', enum: ['critical', 'warning', 'info'] }, category: { type: 'string' }, limit: { type: 'number' } } } },
1806
+ { name: 'cell_community_benchmarks', description: 'Get benchmarks — your code vs community averages', inputSchema: { type: 'object', properties: { category: { type: 'string' }, limit: { type: 'number' } } } },
1807
+ { name: 'cell_community_trends', description: 'Technology evolution signals — adoption phase, 30d/90d trends, migrations', inputSchema: { type: 'object', properties: {} } },
1808
+ { name: 'cell_community_failures', description: 'Failure pattern library — most common errors by language with mitigations', inputSchema: { type: 'object', properties: { language: { type: 'string' }, limit: { type: 'number' } } } },
1809
+ { name: 'cell_community_validate', description: 'Validate a rule string for privacy safety before sharing', inputSchema: { type: 'object', properties: { rule: { type: 'string' } }, required: ['rule'] } },
1810
+ { name: 'cell_community_dashboard', description: 'Combined community dashboard — stats + trends + insights + benchmarks', inputSchema: { type: 'object', properties: {} } },
1811
+ { name: 'cell_usage_decision_log', description: 'Log a decision with outcome (was it the right call?)', inputSchema: { type: 'object', properties: { project: { type: 'string' }, technology: { type: 'string' }, reason: { type: 'string' }, outcome: { type: 'string' }, wasRight: { type: 'boolean' }, confidence: { type: 'number' } }, required: ['project', 'technology', 'wasRight'] } },
1812
+ { name: 'cell_usage_decision_patterns', description: 'Detect decision patterns — e.g. always picks MongoDB, always regrets it', inputSchema: { type: 'object', properties: { project: { type: 'string' } }, required: ['project'] } },
1813
+ { name: 'cell_usage_repeat_mistakes', description: 'Find repeated error patterns — "you keep making this mistake" alerts', inputSchema: { type: 'object', properties: { project: { type: 'string' } }, required: ['project'] } },
1814
+ { name: 'cell_usage_ai_stats', description: 'AI interaction stats — acceptance rate, iterations, recommendations per model', inputSchema: { type: 'object', properties: { project: { type: 'string' } }, required: ['project'] } },
1815
+ { name: 'cell_usage_productivity', description: 'Productivity signals — flow state, friction, context switches', inputSchema: { type: 'object', properties: { project: { type: 'string' }, signalType: { type: 'string', enum: ['flow', 'friction', 'context_switch', 'long_session'] }, durationMinutes: { type: 'number' }, filesTouched: { type: 'number' }, contextSwitches: { type: 'number' } }, required: ['project'] } },
1816
+ { name: 'cell_usage_skills', description: 'Skill progression map — improving/regressing/plateau per technology', inputSchema: { type: 'object', properties: { project: { type: 'string' } }, required: ['project'] } },
1817
+ { name: 'cell_usage_burnout', description: 'Burnout risk detection from session patterns and friction signals', inputSchema: { type: 'object', properties: { project: { type: 'string' } }, required: ['project'] } },
1818
+ { name: 'cell_usage_dashboard', description: 'Combined usage intelligence dashboard — decisions + mistakes + AI + productivity + skills + burnout', inputSchema: { type: 'object', properties: { project: { type: 'string' } }, required: ['project'] } },
1819
+ { name: 'cell_watch_start', description: 'Start live file watcher for a project directory', inputSchema: { type: 'object', properties: { project: { type: 'string' }, dir: { type: 'string' } }, required: ['project', 'dir'] } },
1820
+ { name: 'cell_watch_stop', description: 'Stop the live file watcher for a project', inputSchema: { type: 'object', properties: { project: { type: 'string' } }, required: ['project'] } },
1821
+ { name: 'cell_watch_status', description: 'Get watcher status (active, event count, last event)', inputSchema: { type: 'object', properties: { project: { type: 'string' } } } },
1822
+ { name: 'cell_watch_events', description: 'Get recent live events (file save/create/delete) for a project', inputSchema: { type: 'object', properties: { project: { type: 'string' }, limit: { type: 'number' }, eventType: { type: 'string', enum: ['file_save', 'file_create', 'file_delete', 'file_rename', 'git_commit', 'package_change'] } } } },
1823
+ { name: 'cell_watch_refresh', description: 'Manually trigger auto-refresh; force=true to bypass staleness check', inputSchema: { type: 'object', properties: { project: { type: 'string' }, force: { type: 'boolean' } }, required: ['project'] } },
1824
+ { name: 'cell_watch_check', description: 'Check if project needs refresh (staleness detection)', inputSchema: { type: 'object', properties: { project: { type: 'string' } }, required: ['project'] } },
1825
+ { name: 'cell_blindspots_scan', description: 'Scan a directory for 15+ types of blind spots (error handling, null safety, perf, quality, etc.)', inputSchema: { type: 'object', properties: { dir: { type: 'string' }, maxFiles: { type: 'number' } } } },
1826
+ { name: 'cell_blindspots_report', description: 'Get a formatted blind spot report with severity groupings and recommendations', inputSchema: { type: 'object', properties: { dir: { type: 'string' }, maxFiles: { type: 'number' } } } },
1827
+ { name: 'cell_blindspots_summary', description: 'Get blind spot counts by category only (quick check)', inputSchema: { type: 'object', properties: { dir: { type: 'string' } } } },
1748
1828
  { name: 'cell_predict', description: 'Predictive intelligence — repeat mistakes, decision regret, energy warnings, complexity traps', inputSchema: { type: 'object', properties: { project: { type: 'string' } }, required: [] } },
1749
1829
  { name: 'cell_model_track', description: 'Track AI model interaction — which tool was used, what task, accepted/rejected', inputSchema: { type: 'object', properties: { modelName: { type: 'string' }, taskType: { type: 'string' }, accepted: { type: 'boolean' }, responseTimeMs: { type: 'number' }, project: { type: 'string' }, suggestion: { type: 'string' } }, required: ['modelName', 'taskType', 'accepted'] } },
1750
1830
  { name: 'cell_model_recommend', description: 'Get AI model recommendations — which tool works best for which task', inputSchema: { type: 'object', properties: {} } },
@@ -1787,9 +1867,10 @@ async function handleMCPToolCall(name, args) {
1787
1867
  return { recorded: true };
1788
1868
  }
1789
1869
  case 'cell_get_context': {
1790
- const { buildContext, formatContextForInjection } = require('../core/prompt-builder');
1870
+ const { buildContext, formatContextForTool } = require('../core/prompt-builder');
1791
1871
  const ctx = buildContext(args.project, args.tool);
1792
- return { content: [{ type: 'text', text: formatContextForInjection(ctx, false) }], context: ctx };
1872
+ const toolName = args.tool || (args.project ? 'claude-code' : undefined);
1873
+ return { content: [{ type: 'text', text: formatContextForTool(ctx, toolName) }], context: ctx };
1793
1874
  }
1794
1875
  case 'cell_scan_full_pc': {
1795
1876
  const { scanFullPC } = require('../pc-scanner');
@@ -1827,23 +1908,26 @@ async function handleMCPToolCall(name, args) {
1827
1908
  const project = args.project;
1828
1909
  const tool = args.tool || 'unknown';
1829
1910
  try {
1830
- // Get last session for this project
1831
1911
  const lastSession = memory.getLastSessionForProject(project);
1832
- // Start new session for current tool
1833
1912
  const newSessionId = memory.startSession(tool, project);
1834
- // If there was a previous session with a different tool, bridge it
1835
1913
  let bridgeContext = '';
1836
1914
  if (lastSession && lastSession.toolName !== tool) {
1837
- const decisions = lastSession.keyDecisions ? JSON.stringify(lastSession.keyDecisions) : 'none';
1838
- bridgeContext = formatSessionBridge(lastSession.toolName, tool, lastSession.contextSnapshot, decisions);
1915
+ const triedApproaches = memory.getRecentApproaches(project, 5);
1916
+ const openQuestions = memory.getOpenQuestions(project);
1917
+ const hotFiles = memory.getMostTouchedFiles(project, 5);
1918
+ const decisions = Array.isArray(lastSession.keyDecisions) ? JSON.stringify(lastSession.keyDecisions) : 'none';
1919
+ bridgeContext = formatSessionBridge(lastSession.toolName, tool, lastSession.contextSnapshot, decisions, {
1920
+ triedApproaches,
1921
+ openQuestions,
1922
+ hotFiles,
1923
+ });
1839
1924
  }
1840
- // Get recent sessions for context chain
1841
1925
  const recentSessions = memory.getRecentSessions(3).filter((s) => s.project === project);
1842
1926
  const sessionHistory = recentSessions.map((s) => ({
1843
1927
  tool: s.toolName,
1844
1928
  when: s.startTime,
1845
- files: JSON.parse(String(s.filesTouched || '[]')),
1846
- decisions: JSON.parse(String(s.keyDecisions || '[]')),
1929
+ files: s.filesTouched,
1930
+ decisions: s.keyDecisions,
1847
1931
  }));
1848
1932
  return {
1849
1933
  newSessionId,
@@ -1854,6 +1938,9 @@ async function handleMCPToolCall(name, args) {
1854
1938
  } : null,
1855
1939
  bridgeContext,
1856
1940
  sessionHistory,
1941
+ triedApproaches: memory.getRecentApproaches(project, 5),
1942
+ openQuestions: memory.getOpenQuestions(project),
1943
+ hotFiles: memory.getMostTouchedFiles(project, 5),
1857
1944
  message: bridgeContext || 'No previous session to bridge. Start a new session!',
1858
1945
  };
1859
1946
  }
@@ -1862,6 +1949,819 @@ async function handleMCPToolCall(name, args) {
1862
1949
  return { error: `Session bridge failed: ${msg}`, crossedSession: false };
1863
1950
  }
1864
1951
  }
1952
+ case 'cell_session_end': {
1953
+ const { SessionMemory } = require('../core/session-memory');
1954
+ const memory = new SessionMemory();
1955
+ const sessionId = args.sessionId;
1956
+ try {
1957
+ memory.endSession(sessionId, {
1958
+ filesTouched: Array.isArray(args.filesTouched) ? args.filesTouched : [],
1959
+ keyDecisions: Array.isArray(args.keyDecisions) ? args.keyDecisions : [],
1960
+ contextSnapshot: args.contextSnapshot || '',
1961
+ });
1962
+ return { ended: true, sessionId };
1963
+ }
1964
+ catch (err) {
1965
+ const msg = err instanceof Error ? err.message : String(err);
1966
+ return { error: `Session end failed: ${msg}`, ended: false };
1967
+ }
1968
+ }
1969
+ case 'cell_session_log': {
1970
+ const { SessionMemory } = require('../core/session-memory');
1971
+ const memory = new SessionMemory();
1972
+ try {
1973
+ const sessionId = args.sessionId || 0;
1974
+ const project = args.project || 'unknown';
1975
+ if (args.type === 'approach' && args.approach) {
1976
+ const id = memory.recordApproach({
1977
+ sessionId: sessionId || undefined,
1978
+ project,
1979
+ approach: args.approach,
1980
+ status: args.status || 'tried',
1981
+ reason: args.reason,
1982
+ });
1983
+ return { recorded: 'approach', id };
1984
+ }
1985
+ if (args.type === 'file' && args.filePath) {
1986
+ memory.recordFileTouch({ sessionId: sessionId || undefined, project, filePath: args.filePath });
1987
+ return { recorded: 'file' };
1988
+ }
1989
+ if (args.type === 'question' && args.question) {
1990
+ const id = memory.recordQuestion({
1991
+ sessionId: sessionId || undefined,
1992
+ project,
1993
+ question: args.question,
1994
+ priority: args.priority || 'medium',
1995
+ });
1996
+ return { recorded: 'question', id };
1997
+ }
1998
+ if (args.type === 'resolve' && args.questionId) {
1999
+ memory.resolveQuestion(args.questionId, args.answer || '');
2000
+ return { recorded: 'resolve' };
2001
+ }
2002
+ return { error: 'unknown log type or missing field' };
2003
+ }
2004
+ catch (err) {
2005
+ const msg = err instanceof Error ? err.message : String(err);
2006
+ return { error: `Session log failed: ${msg}` };
2007
+ }
2008
+ }
2009
+ case 'cell_session_start': {
2010
+ const { SessionMemory } = require('../core/session-memory');
2011
+ const memory = new SessionMemory();
2012
+ try {
2013
+ const project = args.project || 'unknown';
2014
+ const tool = args.tool || 'unknown';
2015
+ const sessionId = memory.startSession(tool, project);
2016
+ return {
2017
+ sessionId,
2018
+ project,
2019
+ tool,
2020
+ startedAt: new Date().toISOString(),
2021
+ message: `Session ${sessionId} started for ${project} on ${tool}`,
2022
+ };
2023
+ }
2024
+ catch (err) {
2025
+ const msg = err instanceof Error ? err.message : String(err);
2026
+ return { error: `Session start failed: ${msg}` };
2027
+ }
2028
+ }
2029
+ case 'cell_session_status': {
2030
+ const { SessionMemory } = require('../core/session-memory');
2031
+ const memory = new SessionMemory();
2032
+ try {
2033
+ const sessionId = args.sessionId;
2034
+ const db = (0, database_1.getDb)();
2035
+ const sess = db.prepare('SELECT * FROM sessions WHERE id = ?').get(sessionId);
2036
+ if (!sess)
2037
+ return { error: 'Session not found', sessionId };
2038
+ const files = memory.getSessionFiles(sessionId);
2039
+ const approaches = memory.getSessionApproaches(sessionId);
2040
+ const isActive = !sess.end_time;
2041
+ return {
2042
+ sessionId,
2043
+ tool: String(sess.tool_name || ''),
2044
+ project: String(sess.project || ''),
2045
+ startTime: String(sess.start_time || ''),
2046
+ endTime: sess.end_time ? String(sess.end_time) : null,
2047
+ isActive,
2048
+ filesCount: files.length,
2049
+ approachesCount: approaches.length,
2050
+ files: files.slice(0, 10),
2051
+ approaches: approaches.slice(0, 10),
2052
+ };
2053
+ }
2054
+ catch (err) {
2055
+ const msg = err instanceof Error ? err.message : String(err);
2056
+ return { error: `Session status failed: ${msg}` };
2057
+ }
2058
+ }
2059
+ case 'cell_session_recent': {
2060
+ const { SessionMemory } = require('../core/session-memory');
2061
+ const memory = new SessionMemory();
2062
+ try {
2063
+ const project = args.project;
2064
+ const limit = args.limit || 10;
2065
+ let sessions = memory.getRecentSessions(limit);
2066
+ if (project)
2067
+ sessions = sessions.filter((s) => s.project === project);
2068
+ return {
2069
+ count: sessions.length,
2070
+ sessions: sessions.slice(0, limit).map((s) => ({
2071
+ sessionId: s.id,
2072
+ tool: s.toolName,
2073
+ project: s.project,
2074
+ startTime: s.startTime,
2075
+ endTime: s.endTime || null,
2076
+ filesCount: s.filesTouched.length,
2077
+ decisionsCount: s.keyDecisions.length,
2078
+ })),
2079
+ };
2080
+ }
2081
+ catch (err) {
2082
+ const msg = err instanceof Error ? err.message : String(err);
2083
+ return { error: `Session recent failed: ${msg}` };
2084
+ }
2085
+ }
2086
+ case 'cell_session_recommendations': {
2087
+ const { SessionMemory } = require('../core/session-memory');
2088
+ const memory = new SessionMemory();
2089
+ try {
2090
+ const project = args.project || 'unknown';
2091
+ const triedApproaches = memory.getRecentApproaches(project, 10);
2092
+ const openQuestions = memory.getOpenQuestions(project);
2093
+ const hotFiles = memory.getMostTouchedFiles(project, 10);
2094
+ const lastSession = memory.getLastSessionForProject(project);
2095
+ const avoid = [];
2096
+ for (const a of triedApproaches) {
2097
+ if (a.status === 'failed') {
2098
+ avoid.push({ approach: a.approach, reason: `failed ${a.count}x` });
2099
+ }
2100
+ else if (a.status === 'partial') {
2101
+ avoid.push({ approach: a.approach, reason: `partial (${a.count}x)` });
2102
+ }
2103
+ }
2104
+ return {
2105
+ avoid,
2106
+ openQuestions: openQuestions.map((q) => ({ id: q.id, question: q.question, priority: q.priority })),
2107
+ hotFiles: hotFiles.slice(0, 5).map((f) => ({ path: f.filePath, touches: f.touchCount })),
2108
+ lastSession: lastSession ? {
2109
+ tool: lastSession.toolName,
2110
+ when: lastSession.endTime,
2111
+ context: lastSession.contextSnapshot,
2112
+ } : null,
2113
+ message: avoid.length > 0
2114
+ ? `Don't suggest: ${avoid.map(a => a.approach).slice(0, 3).join(', ')}`
2115
+ : 'No anti-repetition data yet',
2116
+ };
2117
+ }
2118
+ catch (err) {
2119
+ const msg = err instanceof Error ? err.message : String(err);
2120
+ return { error: `Session recommendations failed: ${msg}` };
2121
+ }
2122
+ }
2123
+ case 'cell_list_projects': {
2124
+ const { ProjectRegistry } = require('../core/project-registry');
2125
+ const registry = new ProjectRegistry();
2126
+ try {
2127
+ const projects = registry.listProjects();
2128
+ return {
2129
+ count: projects.length,
2130
+ projects: projects.map((p) => ({
2131
+ name: p.name,
2132
+ path: p.path,
2133
+ stack: p.stack,
2134
+ fileCount: p.fileCount,
2135
+ lastScanAt: p.lastScanAt,
2136
+ })),
2137
+ };
2138
+ }
2139
+ catch (err) {
2140
+ const msg = err instanceof Error ? err.message : String(err);
2141
+ return { error: `List projects failed: ${msg}` };
2142
+ }
2143
+ }
2144
+ case 'cell_get_project': {
2145
+ const { ProjectRegistry } = require('../core/project-registry');
2146
+ const registry = new ProjectRegistry();
2147
+ try {
2148
+ const name = args.name || '';
2149
+ const project = registry.getProject(name);
2150
+ if (!project)
2151
+ return { error: 'Project not found', name };
2152
+ return {
2153
+ name: project.name,
2154
+ path: project.path,
2155
+ stack: project.stack,
2156
+ fileCount: project.fileCount,
2157
+ lastScanAt: project.lastScanAt,
2158
+ };
2159
+ }
2160
+ catch (err) {
2161
+ const msg = err instanceof Error ? err.message : String(err);
2162
+ return { error: `Get project failed: ${msg}` };
2163
+ }
2164
+ }
2165
+ case 'cell_detect_project': {
2166
+ const { ProjectRegistry } = require('../core/project-registry');
2167
+ const registry = new ProjectRegistry();
2168
+ try {
2169
+ const cwd = args.cwd || '';
2170
+ const detected = registry.detectProjectFromCwd(cwd);
2171
+ if (!detected) {
2172
+ return { detected: null, cwd, message: 'No matching project found for this path' };
2173
+ }
2174
+ const project = registry.getProject(detected);
2175
+ return {
2176
+ detected,
2177
+ cwd,
2178
+ project: project ? {
2179
+ name: project.name,
2180
+ stack: project.stack,
2181
+ fileCount: project.fileCount,
2182
+ lastScanAt: project.lastScanAt,
2183
+ } : null,
2184
+ message: `Detected project: ${detected}`,
2185
+ };
2186
+ }
2187
+ catch (err) {
2188
+ const msg = err instanceof Error ? err.message : String(err);
2189
+ return { error: `Detect project failed: ${msg}` };
2190
+ }
2191
+ }
2192
+ case 'cell_register_project': {
2193
+ const { ProjectRegistry } = require('../core/project-registry');
2194
+ const registry = new ProjectRegistry();
2195
+ try {
2196
+ const id = registry.registerProject({
2197
+ name: args.name || '',
2198
+ path: args.path || '',
2199
+ stack: args.stack,
2200
+ fileCount: args.fileCount,
2201
+ });
2202
+ return { id, name: args.name, registered: true };
2203
+ }
2204
+ catch (err) {
2205
+ const msg = err instanceof Error ? err.message : String(err);
2206
+ return { error: `Register project failed: ${msg}` };
2207
+ }
2208
+ }
2209
+ case 'cell_graph_files': {
2210
+ try {
2211
+ const project = args.project || '';
2212
+ const limit = args.limit || 20;
2213
+ const { getFileKnowledgeGraph } = require('../core/knowledge-graph-store');
2214
+ const graph = getFileKnowledgeGraph(project);
2215
+ return {
2216
+ stats: graph.stats,
2217
+ topRiskFiles: graph.files.slice(0, limit),
2218
+ entryPoints: graph.files.filter((f) => f.isEntryPoint).slice(0, 10),
2219
+ sampleDeps: graph.deps.slice(0, limit),
2220
+ };
2221
+ }
2222
+ catch (err) {
2223
+ const msg = err instanceof Error ? err.message : String(err);
2224
+ return { error: `Graph files failed: ${msg}` };
2225
+ }
2226
+ }
2227
+ case 'cell_graph_blast_radius': {
2228
+ try {
2229
+ const project = args.project || '';
2230
+ const file = args.file || '';
2231
+ const { computeBlastRadius } = require('../core/knowledge-graph-store');
2232
+ const radius = computeBlastRadius(project, file);
2233
+ return radius;
2234
+ }
2235
+ catch (err) {
2236
+ const msg = err instanceof Error ? err.message : String(err);
2237
+ return { error: `Blast radius failed: ${msg}` };
2238
+ }
2239
+ }
2240
+ case 'cell_graph_tech': {
2241
+ try {
2242
+ const project = args.project || '';
2243
+ const { getTechProficiency } = require('../core/knowledge-graph-store');
2244
+ const techs = getTechProficiency(project);
2245
+ const strong = techs.filter((t) => t.proficiencyScore >= 70);
2246
+ const learning = techs.filter((t) => t.proficiencyScore < 50);
2247
+ return {
2248
+ totalTechs: techs.length,
2249
+ strong,
2250
+ learning,
2251
+ all: techs,
2252
+ message: strong.length > 0
2253
+ ? `Strong in: ${strong.map((t) => t.technology).slice(0, 3).join(', ')}`
2254
+ : 'No strong tech tracked yet',
2255
+ };
2256
+ }
2257
+ catch (err) {
2258
+ const msg = err instanceof Error ? err.message : String(err);
2259
+ return { error: `Graph tech failed: ${msg}` };
2260
+ }
2261
+ }
2262
+ case 'cell_graph_stats': {
2263
+ try {
2264
+ const project = args.project || '';
2265
+ const { getPatternGraphStats, getFileKnowledgeGraph, getTechProficiency } = require('../core/knowledge-graph-store');
2266
+ const patternStats = getPatternGraphStats(project);
2267
+ const fileGraph = getFileKnowledgeGraph(project);
2268
+ const techs = getTechProficiency(project);
2269
+ return {
2270
+ patternGraph: patternStats,
2271
+ fileGraph: fileGraph.stats,
2272
+ techCount: techs.length,
2273
+ highRiskFiles: fileGraph.files.filter((f) => f.riskScore >= 50).length,
2274
+ };
2275
+ }
2276
+ catch (err) {
2277
+ const msg = err instanceof Error ? err.message : String(err);
2278
+ return { error: `Graph stats failed: ${msg}` };
2279
+ }
2280
+ }
2281
+ case 'cell_team_silos': {
2282
+ try {
2283
+ const { detectKnowledgeSilos } = require('../team-collaboration');
2284
+ const silos = detectKnowledgeSilos();
2285
+ return {
2286
+ count: silos.length,
2287
+ high: silos.filter((s) => s.riskLevel === 'high').length,
2288
+ silos,
2289
+ message: silos.length > 0
2290
+ ? `${silos.filter((s) => s.riskLevel === 'high').length} high-risk silos detected`
2291
+ : 'No knowledge silos detected',
2292
+ };
2293
+ }
2294
+ catch (err) {
2295
+ const msg = err instanceof Error ? err.message : String(err);
2296
+ return { error: `Team silos failed: ${msg}` };
2297
+ }
2298
+ }
2299
+ case 'cell_team_bus_factor': {
2300
+ try {
2301
+ const { calculateBusFactor } = require('../team-collaboration');
2302
+ return calculateBusFactor();
2303
+ }
2304
+ catch (err) {
2305
+ const msg = err instanceof Error ? err.message : String(err);
2306
+ return { error: `Bus factor failed: ${msg}` };
2307
+ }
2308
+ }
2309
+ case 'cell_team_health': {
2310
+ try {
2311
+ const { getTeamHealth } = require('../team-collaboration');
2312
+ return getTeamHealth(args.project || undefined);
2313
+ }
2314
+ catch (err) {
2315
+ const msg = err instanceof Error ? err.message : String(err);
2316
+ return { error: `Team health failed: ${msg}` };
2317
+ }
2318
+ }
2319
+ case 'cell_team_onboard': {
2320
+ try {
2321
+ const { generateOnboardingDoc } = require('../team-collaboration');
2322
+ const teamName = args.teamName || 'Team';
2323
+ const project = args.project || undefined;
2324
+ return generateOnboardingDoc(teamName, project);
2325
+ }
2326
+ catch (err) {
2327
+ const msg = err instanceof Error ? err.message : String(err);
2328
+ return { error: `Onboard failed: ${msg}` };
2329
+ }
2330
+ }
2331
+ case 'cell_team_retro': {
2332
+ try {
2333
+ const { generateSprintRetro } = require('../team-collaboration');
2334
+ const days = args.days || 14;
2335
+ const project = args.project || undefined;
2336
+ return generateSprintRetro(days, project);
2337
+ }
2338
+ catch (err) {
2339
+ const msg = err instanceof Error ? err.message : String(err);
2340
+ return { error: `Retro failed: ${msg}` };
2341
+ }
2342
+ }
2343
+ case 'cell_team_handoff': {
2344
+ try {
2345
+ const { generateHandoff } = require('../team-collaboration');
2346
+ return generateHandoff(args.from || '', args.to || '', args.project || '');
2347
+ }
2348
+ catch (err) {
2349
+ const msg = err instanceof Error ? err.message : String(err);
2350
+ return { error: `Handoff failed: ${msg}` };
2351
+ }
2352
+ }
2353
+ case 'cell_team_knowledge_transfer': {
2354
+ try {
2355
+ const { suggestKnowledgeTransfer } = require('../team-collaboration');
2356
+ const suggestions = suggestKnowledgeTransfer();
2357
+ return {
2358
+ count: suggestions.length,
2359
+ suggestions,
2360
+ message: suggestions.length > 0
2361
+ ? `${suggestions.length} transfer pairs suggested`
2362
+ : 'No urgent transfers needed',
2363
+ };
2364
+ }
2365
+ catch (err) {
2366
+ const msg = err instanceof Error ? err.message : String(err);
2367
+ return { error: `Knowledge transfer failed: ${msg}` };
2368
+ }
2369
+ }
2370
+ case 'cell_team_style': {
2371
+ try {
2372
+ const { composeTeamStyle } = require('../team-collaboration');
2373
+ return composeTeamStyle(args.project || undefined);
2374
+ }
2375
+ catch (err) {
2376
+ const msg = err instanceof Error ? err.message : String(err);
2377
+ return { error: `Team style failed: ${msg}` };
2378
+ }
2379
+ }
2380
+ case 'cell_team_dashboard': {
2381
+ try {
2382
+ const { detectKnowledgeSilos, calculateBusFactor, getTeamHealth, composeTeamStyle } = require('../team-collaboration');
2383
+ const project = args.project || undefined;
2384
+ const silos = detectKnowledgeSilos();
2385
+ const busFactor = calculateBusFactor();
2386
+ const health = getTeamHealth(project);
2387
+ const style = composeTeamStyle(project);
2388
+ return {
2389
+ silos: { count: silos.length, high: silos.filter((s) => s.riskLevel === 'high').length, top: silos.slice(0, 5) },
2390
+ busFactor,
2391
+ health,
2392
+ style,
2393
+ generatedAt: new Date().toISOString(),
2394
+ };
2395
+ }
2396
+ catch (err) {
2397
+ const msg = err instanceof Error ? err.message : String(err);
2398
+ return { error: `Team dashboard failed: ${msg}` };
2399
+ }
2400
+ }
2401
+ case 'cell_community_stats': {
2402
+ try {
2403
+ const { getCommunityStats } = require('../core/community-store');
2404
+ return getCommunityStats();
2405
+ }
2406
+ catch (err) {
2407
+ const msg = err instanceof Error ? err.message : String(err);
2408
+ return { error: `Community stats failed: ${msg}` };
2409
+ }
2410
+ }
2411
+ case 'cell_community_share': {
2412
+ try {
2413
+ const { shareCommunityPattern, validatePrivacy } = require('../core/community-store');
2414
+ const rule = args.rule || '';
2415
+ const validation = validatePrivacy(rule);
2416
+ if (!validation.safe) {
2417
+ return { shared: false, errors: validation.errors, warnings: validation.warnings };
2418
+ }
2419
+ const result = shareCommunityPattern({
2420
+ category: args.category || 'unknown',
2421
+ rule,
2422
+ language: args.language,
2423
+ framework: args.framework,
2424
+ successRate: args.successRate,
2425
+ });
2426
+ return { ...result, warnings: [...validation.warnings, ...result.warnings] };
2427
+ }
2428
+ catch (err) {
2429
+ const msg = err instanceof Error ? err.message : String(err);
2430
+ return { error: `Community share failed: ${msg}` };
2431
+ }
2432
+ }
2433
+ case 'cell_community_patterns': {
2434
+ try {
2435
+ const { getCommunityPatterns } = require('../core/community-store');
2436
+ const patterns = getCommunityPatterns({
2437
+ category: args.category,
2438
+ language: args.language,
2439
+ minVotes: args.minVotes,
2440
+ limit: args.limit || 20,
2441
+ });
2442
+ return { count: patterns.length, patterns };
2443
+ }
2444
+ catch (err) {
2445
+ const msg = err instanceof Error ? err.message : String(err);
2446
+ return { error: `Community patterns failed: ${msg}` };
2447
+ }
2448
+ }
2449
+ case 'cell_community_vote': {
2450
+ try {
2451
+ const { voteCommunityPattern } = require('../core/community-store');
2452
+ return voteCommunityPattern(args.patternId || '', args.upvote !== false);
2453
+ }
2454
+ catch (err) {
2455
+ const msg = err instanceof Error ? err.message : String(err);
2456
+ return { error: `Community vote failed: ${msg}` };
2457
+ }
2458
+ }
2459
+ case 'cell_community_insights': {
2460
+ try {
2461
+ const { getCommunityInsights } = require('../core/community-store');
2462
+ const insights = getCommunityInsights({
2463
+ severity: args.severity,
2464
+ category: args.category,
2465
+ limit: args.limit || 20,
2466
+ });
2467
+ return { count: insights.length, insights };
2468
+ }
2469
+ catch (err) {
2470
+ const msg = err instanceof Error ? err.message : String(err);
2471
+ return { error: `Community insights failed: ${msg}` };
2472
+ }
2473
+ }
2474
+ case 'cell_community_benchmarks': {
2475
+ try {
2476
+ const { getBenchmarks } = require('../core/community-store');
2477
+ const benchmarks = getBenchmarks({
2478
+ category: args.category,
2479
+ limit: args.limit || 50,
2480
+ });
2481
+ return { count: benchmarks.length, benchmarks };
2482
+ }
2483
+ catch (err) {
2484
+ const msg = err instanceof Error ? err.message : String(err);
2485
+ return { error: `Community benchmarks failed: ${msg}` };
2486
+ }
2487
+ }
2488
+ case 'cell_community_trends': {
2489
+ try {
2490
+ const { getTechEvolution } = require('../core/community-store');
2491
+ return getTechEvolution();
2492
+ }
2493
+ catch (err) {
2494
+ const msg = err instanceof Error ? err.message : String(err);
2495
+ return { error: `Community trends failed: ${msg}` };
2496
+ }
2497
+ }
2498
+ case 'cell_community_failures': {
2499
+ try {
2500
+ const { getFailurePatterns } = require('../core/community-store');
2501
+ const failures = getFailurePatterns({
2502
+ language: args.language,
2503
+ limit: args.limit || 10,
2504
+ });
2505
+ return { count: failures.length, failures };
2506
+ }
2507
+ catch (err) {
2508
+ const msg = err instanceof Error ? err.message : String(err);
2509
+ return { error: `Community failures failed: ${msg}` };
2510
+ }
2511
+ }
2512
+ case 'cell_community_validate': {
2513
+ try {
2514
+ const { validatePrivacy } = require('../core/community-store');
2515
+ return validatePrivacy(args.rule || '');
2516
+ }
2517
+ catch (err) {
2518
+ const msg = err instanceof Error ? err.message : String(err);
2519
+ return { error: `Community validate failed: ${msg}` };
2520
+ }
2521
+ }
2522
+ case 'cell_community_dashboard': {
2523
+ try {
2524
+ const { getCommunityStats, getTechEvolution, getCommunityInsights, getBenchmarks } = require('../core/community-store');
2525
+ const stats = getCommunityStats();
2526
+ const trends = getTechEvolution();
2527
+ const insights = getCommunityInsights({ severity: 'critical', limit: 5 });
2528
+ const benchmarks = getBenchmarks({ limit: 5 });
2529
+ return {
2530
+ stats,
2531
+ trends: trends.slice(0, 10),
2532
+ insights,
2533
+ benchmarks,
2534
+ generatedAt: new Date().toISOString(),
2535
+ };
2536
+ }
2537
+ catch (err) {
2538
+ const msg = err instanceof Error ? err.message : String(err);
2539
+ return { error: `Community dashboard failed: ${msg}` };
2540
+ }
2541
+ }
2542
+ case 'cell_usage_decision_log': {
2543
+ try {
2544
+ const { logDecisionOutcome } = require('../core/usage-intelligence-store');
2545
+ return logDecisionOutcome({
2546
+ project: args.project || 'unknown',
2547
+ technology: args.technology || '',
2548
+ reason: args.reason || '',
2549
+ outcome: args.outcome || '',
2550
+ wasRight: args.wasRight === true,
2551
+ confidence: args.confidence,
2552
+ });
2553
+ }
2554
+ catch (err) {
2555
+ const msg = err instanceof Error ? err.message : String(err);
2556
+ return { error: `Decision log failed: ${msg}` };
2557
+ }
2558
+ }
2559
+ case 'cell_usage_decision_patterns': {
2560
+ try {
2561
+ const { getDecisionPatterns } = require('../core/usage-intelligence-store');
2562
+ const patterns = getDecisionPatterns(args.project || 'unknown');
2563
+ return {
2564
+ count: patterns.length,
2565
+ patterns,
2566
+ message: patterns.length > 0
2567
+ ? `Analyzed ${patterns.length} technology decision patterns`
2568
+ : 'Need more decisions (>= 2 per tech) to detect patterns',
2569
+ };
2570
+ }
2571
+ catch (err) {
2572
+ const msg = err instanceof Error ? err.message : String(err);
2573
+ return { error: `Decision patterns failed: ${msg}` };
2574
+ }
2575
+ }
2576
+ case 'cell_usage_repeat_mistakes': {
2577
+ try {
2578
+ const { detectRepeatMistakes } = require('../core/usage-intelligence-store');
2579
+ const mistakes = detectRepeatMistakes(args.project || 'unknown');
2580
+ return {
2581
+ count: mistakes.length,
2582
+ critical: mistakes.filter((m) => m.severity === 'critical').length,
2583
+ mistakes: mistakes.slice(0, 20),
2584
+ message: mistakes.length > 0
2585
+ ? `Found ${mistakes.length} repeated error patterns`
2586
+ : 'No repeated mistakes — clean track record',
2587
+ };
2588
+ }
2589
+ catch (err) {
2590
+ const msg = err instanceof Error ? err.message : String(err);
2591
+ return { error: `Repeat mistakes failed: ${msg}` };
2592
+ }
2593
+ }
2594
+ case 'cell_usage_ai_stats': {
2595
+ try {
2596
+ const { getAIInteractionStats } = require('../core/usage-intelligence-store');
2597
+ return getAIInteractionStats(args.project || 'unknown');
2598
+ }
2599
+ catch (err) {
2600
+ const msg = err instanceof Error ? err.message : String(err);
2601
+ return { error: `AI stats failed: ${msg}` };
2602
+ }
2603
+ }
2604
+ case 'cell_usage_productivity': {
2605
+ try {
2606
+ const { logProductivitySignal, getProductivitySignals } = require('../core/usage-intelligence-store');
2607
+ const project = args.project || 'unknown';
2608
+ // If signalType + duration provided, log; otherwise just read
2609
+ if (args.signalType && args.durationMinutes !== undefined) {
2610
+ const result = logProductivitySignal({
2611
+ project,
2612
+ signalType: args.signalType,
2613
+ durationMinutes: args.durationMinutes,
2614
+ filesTouched: args.filesTouched || 0,
2615
+ contextSwitches: args.contextSwitches || 0,
2616
+ });
2617
+ return { logged: true, ...result };
2618
+ }
2619
+ return getProductivitySignals(project, 30);
2620
+ }
2621
+ catch (err) {
2622
+ const msg = err instanceof Error ? err.message : String(err);
2623
+ return { error: `Productivity failed: ${msg}` };
2624
+ }
2625
+ }
2626
+ case 'cell_usage_skills': {
2627
+ try {
2628
+ const { getSkillProgression } = require('../core/usage-intelligence-store');
2629
+ return getSkillProgression(args.project || 'unknown');
2630
+ }
2631
+ catch (err) {
2632
+ const msg = err instanceof Error ? err.message : String(err);
2633
+ return { error: `Skill progression failed: ${msg}` };
2634
+ }
2635
+ }
2636
+ case 'cell_usage_burnout': {
2637
+ try {
2638
+ const { getBurnoutSignals } = require('../core/usage-intelligence-store');
2639
+ return getBurnoutSignals(args.project || 'unknown');
2640
+ }
2641
+ catch (err) {
2642
+ const msg = err instanceof Error ? err.message : String(err);
2643
+ return { error: `Burnout check failed: ${msg}` };
2644
+ }
2645
+ }
2646
+ case 'cell_usage_dashboard': {
2647
+ try {
2648
+ const { getUsageDashboard } = require('../core/usage-intelligence-store');
2649
+ return getUsageDashboard(args.project || 'unknown');
2650
+ }
2651
+ catch (err) {
2652
+ const msg = err instanceof Error ? err.message : String(err);
2653
+ return { error: `Usage dashboard failed: ${msg}` };
2654
+ }
2655
+ }
2656
+ case 'cell_watch_start': {
2657
+ try {
2658
+ const { startWatcher } = require('../core/live-watcher');
2659
+ return startWatcher(args.project || 'unknown', args.dir || process.cwd());
2660
+ }
2661
+ catch (err) {
2662
+ const msg = err instanceof Error ? err.message : String(err);
2663
+ return { error: `Watch start failed: ${msg}` };
2664
+ }
2665
+ }
2666
+ case 'cell_watch_stop': {
2667
+ try {
2668
+ const { stopWatcher } = require('../core/live-watcher');
2669
+ return stopWatcher(args.project || 'unknown');
2670
+ }
2671
+ catch (err) {
2672
+ const msg = err instanceof Error ? err.message : String(err);
2673
+ return { error: `Watch stop failed: ${msg}` };
2674
+ }
2675
+ }
2676
+ case 'cell_watch_status': {
2677
+ try {
2678
+ const { getWatcherStatus, getActiveWatchers } = require('../core/live-watcher');
2679
+ if (args.project) {
2680
+ const status = getWatcherStatus(args.project);
2681
+ if (!status)
2682
+ return { project: args.project, active: false, message: 'No watcher found' };
2683
+ const isLive = status.active;
2684
+ return { ...status, message: isLive ? 'Live' : 'Stopped' };
2685
+ }
2686
+ return { active: getActiveWatchers() };
2687
+ }
2688
+ catch (err) {
2689
+ const msg = err instanceof Error ? err.message : String(err);
2690
+ return { error: `Watch status failed: ${msg}` };
2691
+ }
2692
+ }
2693
+ case 'cell_watch_events': {
2694
+ try {
2695
+ const { getLiveEvents } = require('../core/live-watcher');
2696
+ return { events: getLiveEvents(args.project || 'unknown', args.limit || 50, args.eventType) };
2697
+ }
2698
+ catch (err) {
2699
+ const msg = err instanceof Error ? err.message : String(err);
2700
+ return { error: `Watch events failed: ${msg}` };
2701
+ }
2702
+ }
2703
+ case 'cell_watch_refresh': {
2704
+ try {
2705
+ const { performAutoRefresh } = require('../core/live-watcher');
2706
+ return performAutoRefresh(args.project || 'unknown', args.force === true);
2707
+ }
2708
+ catch (err) {
2709
+ const msg = err instanceof Error ? err.message : String(err);
2710
+ return { error: `Auto-refresh failed: ${msg}` };
2711
+ }
2712
+ }
2713
+ case 'cell_watch_check': {
2714
+ try {
2715
+ const { checkIfNeedsRefresh } = require('../core/live-watcher');
2716
+ return checkIfNeedsRefresh(args.project || 'unknown');
2717
+ }
2718
+ catch (err) {
2719
+ const msg = err instanceof Error ? err.message : String(err);
2720
+ return { error: `Refresh check failed: ${msg}` };
2721
+ }
2722
+ }
2723
+ case 'cell_blindspots_scan': {
2724
+ try {
2725
+ const { scanDirectoryForBlindSpots } = require('../core/enhanced-blind-spots');
2726
+ const dir = args.dir || process.cwd();
2727
+ const max = args.maxFiles || 200;
2728
+ const spots = scanDirectoryForBlindSpots(dir, max);
2729
+ return { directory: dir, scanned: max, count: spots.length, blindSpots: spots };
2730
+ }
2731
+ catch (err) {
2732
+ const msg = err instanceof Error ? err.message : String(err);
2733
+ return { error: `Blind spot scan failed: ${msg}` };
2734
+ }
2735
+ }
2736
+ case 'cell_blindspots_report': {
2737
+ try {
2738
+ const { scanDirectoryForBlindSpots, formatBlindSpotReport, summarizeBlindSpots } = require('../core/enhanced-blind-spots');
2739
+ const dir = args.dir || process.cwd();
2740
+ const max = args.maxFiles || 200;
2741
+ const spots = scanDirectoryForBlindSpots(dir, max);
2742
+ return {
2743
+ directory: dir,
2744
+ summary: summarizeBlindSpots(spots),
2745
+ report: formatBlindSpotReport(spots),
2746
+ blindSpots: spots,
2747
+ };
2748
+ }
2749
+ catch (err) {
2750
+ const msg = err instanceof Error ? err.message : String(err);
2751
+ return { error: `Blind spot report failed: ${msg}` };
2752
+ }
2753
+ }
2754
+ case 'cell_blindspots_summary': {
2755
+ try {
2756
+ const { getCategoryCounts } = require('../core/enhanced-blind-spots');
2757
+ const dir = args.dir || process.cwd();
2758
+ return { directory: dir, byCategory: getCategoryCounts(dir) };
2759
+ }
2760
+ catch (err) {
2761
+ const msg = err instanceof Error ? err.message : String(err);
2762
+ return { error: `Blind spot summary failed: ${msg}` };
2763
+ }
2764
+ }
1865
2765
  case 'cell_predict': {
1866
2766
  const { generatePredictions } = require('../predictive-engine');
1867
2767
  return generatePredictions(args.project);
@@ -1887,9 +2787,28 @@ async function handleMCPToolCall(name, args) {
1887
2787
  }
1888
2788
  }
1889
2789
  app.post('/mcp', async (req, res) => {
2790
+ // ─── Security: rate limit + input validation ─────────────────────────
2791
+ const { checkRateLimit, getClientId, validateToolArgs, securityHeaders } = require('../core/security');
2792
+ for (const [k, v] of Object.entries(securityHeaders()))
2793
+ res.setHeader(k, v);
2794
+ const clientId = getClientId(req);
2795
+ const rl = checkRateLimit(clientId);
2796
+ res.setHeader('X-RateLimit-Remaining', String(rl.remaining));
2797
+ if (!rl.allowed) {
2798
+ res.status(429).json({ jsonrpc: '2.0', id: null, error: { code: -32000, message: `Rate limit exceeded. Retry in ${Math.ceil(rl.resetIn / 1000)}s` } });
2799
+ return;
2800
+ }
1890
2801
  const rpc = req.body;
1891
2802
  const { method, params, id } = rpc;
1892
2803
  try {
2804
+ // Validate tool args before execution
2805
+ if (method === 'tools/call') {
2806
+ const validation = validateToolArgs(params?.name || '', params?.arguments);
2807
+ if (!validation.valid) {
2808
+ res.status(400).json({ jsonrpc: '2.0', id, error: { code: -32602, message: `Invalid arguments: ${validation.reason}` } });
2809
+ return;
2810
+ }
2811
+ }
1893
2812
  let result;
1894
2813
  switch (method) {
1895
2814
  case 'initialize':