bc-code-intelligence-mcp 1.1.1 → 1.2.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 (98) hide show
  1. package/README.md +99 -9
  2. package/dist/cli/bc-code-intel-cli.js +0 -1
  3. package/dist/cli/bc-code-intel-cli.js.map +1 -1
  4. package/dist/index.d.ts +8 -0
  5. package/dist/index.d.ts.map +1 -1
  6. package/dist/index.js +82 -5
  7. package/dist/index.js.map +1 -1
  8. package/dist/layers/embedded-layer.d.ts +74 -0
  9. package/dist/layers/embedded-layer.d.ts.map +1 -1
  10. package/dist/layers/embedded-layer.js +287 -3
  11. package/dist/layers/embedded-layer.js.map +1 -1
  12. package/dist/layers/layer-service.d.ts +6 -0
  13. package/dist/layers/layer-service.d.ts.map +1 -1
  14. package/dist/layers/layer-service.js +13 -0
  15. package/dist/layers/layer-service.js.map +1 -1
  16. package/dist/services/agent-onboarding-service.d.ts +45 -0
  17. package/dist/services/agent-onboarding-service.d.ts.map +1 -0
  18. package/dist/services/agent-onboarding-service.js +372 -0
  19. package/dist/services/agent-onboarding-service.js.map +1 -0
  20. package/dist/services/enhanced-prompt-service.d.ts +60 -0
  21. package/dist/services/enhanced-prompt-service.d.ts.map +1 -0
  22. package/dist/services/enhanced-prompt-service.js +162 -0
  23. package/dist/services/enhanced-prompt-service.js.map +1 -0
  24. package/dist/services/multi-content-layer-service.d.ts +92 -0
  25. package/dist/services/multi-content-layer-service.d.ts.map +1 -0
  26. package/dist/services/multi-content-layer-service.js +407 -0
  27. package/dist/services/multi-content-layer-service.js.map +1 -0
  28. package/dist/services/roleplay-engine.d.ts +121 -0
  29. package/dist/services/roleplay-engine.d.ts.map +1 -0
  30. package/dist/services/roleplay-engine.js +672 -0
  31. package/dist/services/roleplay-engine.js.map +1 -0
  32. package/dist/services/session-storage/file-storage.d.ts +30 -0
  33. package/dist/services/session-storage/file-storage.d.ts.map +1 -0
  34. package/dist/services/session-storage/file-storage.js +229 -0
  35. package/dist/services/session-storage/file-storage.js.map +1 -0
  36. package/dist/services/session-storage/in-memory-storage.d.ts +31 -0
  37. package/dist/services/session-storage/in-memory-storage.d.ts.map +1 -0
  38. package/dist/services/session-storage/in-memory-storage.js +142 -0
  39. package/dist/services/session-storage/in-memory-storage.js.map +1 -0
  40. package/dist/services/specialist-discovery.d.ts +76 -0
  41. package/dist/services/specialist-discovery.d.ts.map +1 -0
  42. package/dist/services/specialist-discovery.js +270 -0
  43. package/dist/services/specialist-discovery.js.map +1 -0
  44. package/dist/services/specialist-handoff-service.d.ts +81 -0
  45. package/dist/services/specialist-handoff-service.d.ts.map +1 -0
  46. package/dist/services/specialist-handoff-service.js +470 -0
  47. package/dist/services/specialist-handoff-service.js.map +1 -0
  48. package/dist/services/specialist-loader.d.ts +101 -0
  49. package/dist/services/specialist-loader.d.ts.map +1 -0
  50. package/dist/services/specialist-loader.js +249 -0
  51. package/dist/services/specialist-loader.js.map +1 -0
  52. package/dist/services/specialist-session-manager.d.ts +76 -0
  53. package/dist/services/specialist-session-manager.d.ts.map +1 -0
  54. package/dist/services/specialist-session-manager.js +255 -0
  55. package/dist/services/specialist-session-manager.js.map +1 -0
  56. package/dist/tools/specialist-discovery-tools.d.ts +27 -0
  57. package/dist/tools/specialist-discovery-tools.d.ts.map +1 -0
  58. package/dist/tools/specialist-discovery-tools.js +287 -0
  59. package/dist/tools/specialist-discovery-tools.js.map +1 -0
  60. package/dist/tools/specialist-tools.d.ts +38 -0
  61. package/dist/tools/specialist-tools.d.ts.map +1 -0
  62. package/dist/tools/specialist-tools.js +322 -0
  63. package/dist/tools/specialist-tools.js.map +1 -0
  64. package/dist/types/config-types.d.ts +2 -0
  65. package/dist/types/config-types.d.ts.map +1 -1
  66. package/dist/types/config-types.js.map +1 -1
  67. package/dist/types/enhanced-layer-types.d.ts +193 -0
  68. package/dist/types/enhanced-layer-types.d.ts.map +1 -0
  69. package/dist/types/enhanced-layer-types.js +9 -0
  70. package/dist/types/enhanced-layer-types.js.map +1 -0
  71. package/dist/types/layer-types.d.ts +2 -0
  72. package/dist/types/layer-types.d.ts.map +1 -1
  73. package/dist/types/layer-types.js.map +1 -1
  74. package/dist/types/roleplay-types.d.ts +149 -0
  75. package/dist/types/roleplay-types.d.ts.map +1 -0
  76. package/dist/types/roleplay-types.js +8 -0
  77. package/dist/types/roleplay-types.js.map +1 -0
  78. package/dist/types/session-types.d.ts +111 -0
  79. package/dist/types/session-types.d.ts.map +1 -0
  80. package/dist/types/session-types.js +8 -0
  81. package/dist/types/session-types.js.map +1 -0
  82. package/embedded-knowledge/AGENTS.md +119 -10
  83. package/embedded-knowledge/README.md +20 -3
  84. package/embedded-knowledge/specialists/alex-architect.md +216 -0
  85. package/embedded-knowledge/specialists/casey-copilot.md +226 -0
  86. package/embedded-knowledge/specialists/dean-debug.md +222 -0
  87. package/embedded-knowledge/specialists/eva-errors.md +235 -0
  88. package/embedded-knowledge/specialists/jordan-bridge.md +235 -0
  89. package/embedded-knowledge/specialists/logan-legacy.md +209 -0
  90. package/embedded-knowledge/specialists/maya-mentor.md +211 -0
  91. package/embedded-knowledge/specialists/morgan-market.md +226 -0
  92. package/embedded-knowledge/specialists/quinn-tester.md +235 -0
  93. package/embedded-knowledge/specialists/roger-reviewer.md +234 -0
  94. package/embedded-knowledge/specialists/sam-coder.md +181 -0
  95. package/embedded-knowledge/specialists/seth-security.md +235 -0
  96. package/embedded-knowledge/specialists/taylor-docs.md +257 -0
  97. package/embedded-knowledge/specialists/uma-ux.md +235 -0
  98. package/package.json +3 -3
@@ -0,0 +1,672 @@
1
+ /**
2
+ * BC Specialist Roleplay Engine
3
+ *
4
+ * Brings specialist personas to life through personality-driven responses,
5
+ * consistent character adoption, and context-aware knowledge integration.
6
+ */
7
+ export class BCSpecialistRoleplayEngine {
8
+ layerService;
9
+ knowledgeService;
10
+ config;
11
+ responseTemplates = new Map();
12
+ knowledgeRetriever;
13
+ constructor(layerService, knowledgeService, config) {
14
+ this.layerService = layerService;
15
+ this.knowledgeService = knowledgeService;
16
+ this.config = {
17
+ personality_strength: 'moderate',
18
+ response_length: 'adaptive',
19
+ knowledge_integration: 'balanced',
20
+ suggest_handoffs: true,
21
+ suggest_collaborations: true,
22
+ learn_user_preferences: true,
23
+ adapt_communication_style: true,
24
+ ...config
25
+ };
26
+ this.knowledgeRetriever = new BCKnowledgeRetriever(layerService, knowledgeService);
27
+ this.initializeResponseTemplates();
28
+ }
29
+ /**
30
+ * Generate a personality-driven response from a specialist
31
+ */
32
+ async generateResponse(context) {
33
+ const { specialist, userMessage, session } = context;
34
+ // Analyze the specialist's personality
35
+ const personality = this.analyzePersonality(specialist);
36
+ // Find relevant knowledge
37
+ const relevantTopics = await this.knowledgeRetriever.findRelevantTopics(userMessage, specialist.expertise.primary.concat(specialist.expertise.secondary), 5);
38
+ // Generate personality-driven response
39
+ const response = await this.buildPersonalityResponse(specialist, personality, context, relevantTopics);
40
+ // Apply session context updates
41
+ const contextUpdates = this.generateContextUpdates(context, relevantTopics);
42
+ // Check for collaboration opportunities
43
+ const suggestedHandoffs = await this.suggestCollaborations(context, relevantTopics);
44
+ return {
45
+ content: response.content,
46
+ specialist_id: specialist.specialist_id,
47
+ personality_elements: response.personality_elements,
48
+ topics_referenced: relevantTopics.map(t => t.id),
49
+ knowledge_applied: relevantTopics.map(topic => ({
50
+ topic_id: topic.id,
51
+ application_context: this.getApplicationContext(topic, userMessage)
52
+ })),
53
+ suggested_handoffs: suggestedHandoffs,
54
+ context_updates: contextUpdates,
55
+ recommendations_added: response.recommendations,
56
+ response_type: response.response_type,
57
+ confidence_level: response.confidence_level
58
+ };
59
+ }
60
+ /**
61
+ * Analyze user message to suggest appropriate specialist
62
+ */
63
+ async suggestSpecialist(userMessage, currentContext) {
64
+ const specialists = await this.layerService.getAllSpecialists();
65
+ const suggestions = [];
66
+ for (const specialist of specialists) {
67
+ const confidence = await this.calculateSpecialistConfidence(userMessage, specialist, currentContext);
68
+ if (confidence > 0.3) { // Threshold for relevant suggestions
69
+ suggestions.push({
70
+ specialist_id: specialist.specialist_id,
71
+ confidence,
72
+ reasoning: this.generateSuggestionReasoning(userMessage, specialist, confidence)
73
+ });
74
+ }
75
+ }
76
+ return suggestions.sort((a, b) => b.confidence - a.confidence).slice(0, 3);
77
+ }
78
+ /**
79
+ * Generate a specialist greeting for session start
80
+ */
81
+ async generateGreeting(specialist, context) {
82
+ const personality = this.analyzePersonality(specialist);
83
+ const greeting = this.buildGreeting(specialist, personality, context);
84
+ return {
85
+ content: greeting,
86
+ specialist_id: specialist.specialist_id,
87
+ personality_elements: {
88
+ greeting_used: true,
89
+ characteristic_phrases: [specialist.persona.greeting],
90
+ expertise_demonstrated: specialist.expertise.primary.slice(0, 2),
91
+ communication_style_applied: specialist.persona.communication_style
92
+ },
93
+ topics_referenced: [],
94
+ knowledge_applied: [],
95
+ response_type: 'greeting',
96
+ confidence_level: 'high'
97
+ };
98
+ }
99
+ /**
100
+ * Generate handoff message when transferring between specialists
101
+ */
102
+ async generateHandoff(fromSpecialist, toSpecialist, context) {
103
+ const fromPersonality = this.analyzePersonality(fromSpecialist);
104
+ const toPersonality = this.analyzePersonality(toSpecialist);
105
+ const farewell = this.buildHandoffFarewell(fromSpecialist, toSpecialist, context);
106
+ const introduction = this.buildHandoffIntroduction(toSpecialist, fromSpecialist, context);
107
+ return {
108
+ farewell: {
109
+ content: farewell,
110
+ specialist_id: fromSpecialist.specialist_id,
111
+ personality_elements: {
112
+ greeting_used: false,
113
+ characteristic_phrases: [],
114
+ expertise_demonstrated: [],
115
+ communication_style_applied: fromSpecialist.persona.communication_style
116
+ },
117
+ topics_referenced: [],
118
+ knowledge_applied: [],
119
+ response_type: 'handoff',
120
+ confidence_level: 'high'
121
+ },
122
+ introduction: {
123
+ content: introduction,
124
+ specialist_id: toSpecialist.specialist_id,
125
+ personality_elements: {
126
+ greeting_used: true,
127
+ characteristic_phrases: [toSpecialist.persona.greeting],
128
+ expertise_demonstrated: toSpecialist.expertise.primary.slice(0, 2),
129
+ communication_style_applied: toSpecialist.persona.communication_style
130
+ },
131
+ topics_referenced: [],
132
+ knowledge_applied: [],
133
+ response_type: 'handoff',
134
+ confidence_level: 'high'
135
+ }
136
+ };
137
+ }
138
+ /**
139
+ * Update configuration
140
+ */
141
+ updateConfig(config) {
142
+ this.config = { ...this.config, ...config };
143
+ }
144
+ /**
145
+ * Get personality analysis for a specialist
146
+ */
147
+ analyzePersonality(specialist) {
148
+ return {
149
+ communication_style: specialist.persona.communication_style,
150
+ expertise_focus: specialist.expertise.primary,
151
+ problem_approach: this.extractProblemApproach(specialist),
152
+ collaboration_style: this.extractCollaborationStyle(specialist),
153
+ characteristic_phrases: [
154
+ specialist.persona.greeting,
155
+ ...this.extractCharacteristicPhrases(specialist)
156
+ ]
157
+ };
158
+ }
159
+ /**
160
+ * Build personality-driven response
161
+ */
162
+ async buildPersonalityResponse(specialist, personality, context, relevantTopics) {
163
+ const { userMessage, session } = context;
164
+ // Start with specialist greeting if it's a new conversation
165
+ let response = session.messageCount <= 1 ? `${specialist.persona.greeting} ` : '';
166
+ // Apply personality-driven response patterns
167
+ response += await this.generatePersonalityContent(specialist, personality, userMessage, relevantTopics, context);
168
+ // Add recommendations based on knowledge
169
+ const recommendations = this.generateRecommendations(relevantTopics, userMessage);
170
+ // Determine response type and confidence
171
+ const responseType = this.determineResponseType(userMessage, relevantTopics);
172
+ const confidenceLevel = this.calculateConfidenceLevel(specialist, userMessage, relevantTopics);
173
+ return {
174
+ content: response,
175
+ personality_elements: {
176
+ greeting_used: session.messageCount <= 1,
177
+ characteristic_phrases: personality.characteristic_phrases.slice(0, 2),
178
+ expertise_demonstrated: personality.expertise_focus.slice(0, 3),
179
+ communication_style_applied: personality.communication_style
180
+ },
181
+ recommendations,
182
+ response_type: responseType,
183
+ confidence_level: confidenceLevel
184
+ };
185
+ }
186
+ /**
187
+ * Generate personality-driven content
188
+ */
189
+ async generatePersonalityContent(specialist, personality, userMessage, relevantTopics, context) {
190
+ // This is where we'd integrate with the actual BC knowledge to generate responses
191
+ // For now, let's create template-based responses that demonstrate personality
192
+ const templates = this.getResponseTemplates(specialist.specialist_id);
193
+ const selectedTemplate = this.selectBestTemplate(templates, userMessage, relevantTopics);
194
+ if (selectedTemplate) {
195
+ return this.fillTemplate(selectedTemplate, specialist, userMessage, relevantTopics, context);
196
+ }
197
+ // Fallback to basic personality-driven response
198
+ return this.generateBasicPersonalityResponse(specialist, userMessage, relevantTopics);
199
+ }
200
+ /**
201
+ * Generate a basic personality-driven response
202
+ */
203
+ generateBasicPersonalityResponse(specialist, userMessage, relevantTopics) {
204
+ // Apply specialist's communication style and expertise focus
205
+ const styleApproach = this.getStyleApproach(specialist);
206
+ let response = `${styleApproach} `;
207
+ if (relevantTopics.length > 0) {
208
+ response += `I can see this relates to ${relevantTopics[0].title}. `;
209
+ response += this.generateKnowledgeBasedGuidance(specialist, relevantTopics[0], userMessage);
210
+ }
211
+ else {
212
+ response += `While this might be outside my primary expertise in ${specialist.expertise.primary.join(', ')}, `;
213
+ response += this.generateGeneralGuidance(specialist, userMessage);
214
+ }
215
+ return response;
216
+ }
217
+ /**
218
+ * Generate style-appropriate opening
219
+ */
220
+ getStyleApproach(specialist) {
221
+ const communication = specialist.persona.communication_style.toLowerCase();
222
+ if (communication.includes('technical')) {
223
+ return "Let's dive into the technical details.";
224
+ }
225
+ else if (communication.includes('business')) {
226
+ return "Let's think about this from a business perspective.";
227
+ }
228
+ else if (communication.includes('practical')) {
229
+ return "Here's a practical approach to your question.";
230
+ }
231
+ else if (communication.includes('teaching')) {
232
+ return "Let me walk you through this step by step.";
233
+ }
234
+ return "I'd be happy to help with this!";
235
+ }
236
+ /**
237
+ * Generate knowledge-based guidance
238
+ */
239
+ generateKnowledgeBasedGuidance(specialist, topic, userMessage) {
240
+ // Create specialist-specific framing of the knowledge
241
+ const specialistLens = this.getSpecialistPerspective(specialist, topic);
242
+ // Extract key points from the topic content
243
+ const keyPoints = this.extractKeyGuidancePoints(topic);
244
+ return `${specialistLens} Looking at **${topic.title}**, ${keyPoints}. This ${topic.frontmatter.difficulty === 'advanced' ? 'advanced' : topic.frontmatter.difficulty} pattern applies directly to your situation.`;
245
+ }
246
+ /**
247
+ * Get specialist-specific perspective on a topic
248
+ */
249
+ getSpecialistPerspective(specialist, topic) {
250
+ const specialistId = specialist.specialist_id;
251
+ if (specialistId.includes('performance') || specialistId.includes('debug')) {
252
+ return `From a performance optimization standpoint,`;
253
+ }
254
+ else if (specialistId.includes('security')) {
255
+ return `From a security perspective,`;
256
+ }
257
+ else if (specialistId.includes('architect')) {
258
+ return `From an architectural design perspective,`;
259
+ }
260
+ else if (specialistId.includes('test')) {
261
+ return `From a testing and quality standpoint,`;
262
+ }
263
+ else if (specialistId.includes('mentor') || specialistId.includes('docs')) {
264
+ return `Let me explain this step by step:`;
265
+ }
266
+ return `Based on my expertise in ${specialist.expertise.primary[0]},`;
267
+ }
268
+ /**
269
+ * Extract key guidance points from topic content
270
+ */
271
+ extractKeyGuidancePoints(topic) {
272
+ const content = topic.content;
273
+ // Look for key implementation patterns
274
+ if (content.includes('## Implementation') || content.includes('## How to')) {
275
+ return `the key implementation approach focuses on ${this.extractImplementationFocus(content)}`;
276
+ }
277
+ // Look for best practices
278
+ if (content.includes('## Best Practices') || content.includes('### Best Practices')) {
279
+ return `the best practices emphasize ${this.extractBestPractices(content)}`;
280
+ }
281
+ // Look for common pitfalls
282
+ if (content.includes('## Common Pitfalls') || content.includes('### Pitfalls')) {
283
+ return `it's important to avoid ${this.extractPitfalls(content)}`;
284
+ }
285
+ // Default to title-based guidance
286
+ return `this pattern provides essential guidance for ${topic.title.toLowerCase()}`;
287
+ }
288
+ /**
289
+ * Extract implementation focus from content
290
+ */
291
+ extractImplementationFocus(content) {
292
+ // Find implementation section and extract first few points
293
+ const lines = content.split('\n');
294
+ const implIndex = lines.findIndex(line => line.includes('## Implementation') || line.includes('## How to'));
295
+ if (implIndex >= 0 && implIndex < lines.length - 1) {
296
+ const nextFewLines = lines.slice(implIndex + 1, implIndex + 4)
297
+ .filter(line => line.trim() && !line.startsWith('#'))
298
+ .join(' ');
299
+ return this.summarizeIntoPhrase(nextFewLines);
300
+ }
301
+ return 'proper implementation patterns';
302
+ }
303
+ /**
304
+ * Extract best practices from content
305
+ */
306
+ extractBestPractices(content) {
307
+ const lines = content.split('\n');
308
+ const practicesIndex = lines.findIndex(line => line.includes('Best Practices'));
309
+ if (practicesIndex >= 0 && practicesIndex < lines.length - 1) {
310
+ const nextFewLines = lines.slice(practicesIndex + 1, practicesIndex + 3)
311
+ .filter(line => line.trim() && !line.startsWith('#'))
312
+ .join(' ');
313
+ return this.summarizeIntoPhrase(nextFewLines);
314
+ }
315
+ return 'following established patterns and maintaining code quality';
316
+ }
317
+ /**
318
+ * Extract pitfalls from content
319
+ */
320
+ extractPitfalls(content) {
321
+ const lines = content.split('\n');
322
+ const pitfallsIndex = lines.findIndex(line => line.includes('Pitfalls') || line.includes('Common Issues'));
323
+ if (pitfallsIndex >= 0 && pitfallsIndex < lines.length - 1) {
324
+ const nextFewLines = lines.slice(pitfallsIndex + 1, pitfallsIndex + 3)
325
+ .filter(line => line.trim() && !line.startsWith('#'))
326
+ .join(' ');
327
+ return this.summarizeIntoPhrase(nextFewLines);
328
+ }
329
+ return 'common implementation mistakes';
330
+ }
331
+ /**
332
+ * Summarize content into a concise phrase
333
+ */
334
+ summarizeIntoPhrase(text) {
335
+ // Clean up the text and create a concise summary
336
+ const cleaned = text
337
+ .replace(/[*#-]/g, '')
338
+ .replace(/\s+/g, ' ')
339
+ .trim();
340
+ // Take first sentence or first 60 characters
341
+ const firstSentence = cleaned.split('.')[0];
342
+ const truncated = firstSentence.length > 60
343
+ ? firstSentence.substring(0, 60) + '...'
344
+ : firstSentence;
345
+ return truncated.toLowerCase();
346
+ }
347
+ /**
348
+ * Generate general guidance when no specific topics match
349
+ */
350
+ generateGeneralGuidance(specialist, userMessage) {
351
+ return `I'd suggest we start by understanding the specific requirements and then I can point you toward the right specialist or resources that would be most helpful.`;
352
+ }
353
+ // Additional helper methods...
354
+ initializeResponseTemplates() {
355
+ // Initialize with basic templates - these could be loaded from configuration
356
+ this.responseTemplates.set('performance', [
357
+ {
358
+ trigger_keywords: ['slow', 'performance', 'optimize', 'speed'],
359
+ specialist_types: ['dean-debug'],
360
+ template_pattern: "🔧 Dean here! Performance issues are my specialty. {problem_analysis} {solution_approach} {next_steps}",
361
+ personality_emphasis: ['technical', 'systematic', 'thorough'],
362
+ knowledge_domains: ['performance', 'optimization']
363
+ }
364
+ ]);
365
+ }
366
+ getResponseTemplates(specialistId) {
367
+ // Return templates relevant to this specialist
368
+ return Array.from(this.responseTemplates.values()).flat()
369
+ .filter(template => template.specialist_types.includes(specialistId));
370
+ }
371
+ selectBestTemplate(templates, userMessage, relevantTopics) {
372
+ // Simple keyword matching for now
373
+ const messageLower = userMessage.toLowerCase();
374
+ for (const template of templates) {
375
+ if (template.trigger_keywords.some(keyword => messageLower.includes(keyword))) {
376
+ return template;
377
+ }
378
+ }
379
+ return null;
380
+ }
381
+ fillTemplate(template, specialist, userMessage, relevantTopics, context) {
382
+ // Basic template filling - would be more sophisticated in practice
383
+ let content = template.template_pattern;
384
+ content = content.replace('{problem_analysis}', 'Let me analyze this issue systematically.');
385
+ content = content.replace('{solution_approach}', 'Here\'s how I\'d approach solving this:');
386
+ content = content.replace('{next_steps}', 'Next steps would be to examine the specific implementation details.');
387
+ return content;
388
+ }
389
+ extractProblemApproach(specialist) {
390
+ // Extract problem-solving approach from specialist definition
391
+ return specialist.persona.communication_style;
392
+ }
393
+ extractCollaborationStyle(specialist) {
394
+ // Extract collaboration preferences
395
+ return specialist.collaboration?.natural_handoffs?.length > 0 ? 'collaborative' : 'independent';
396
+ }
397
+ extractCharacteristicPhrases(specialist) {
398
+ // Extract characteristic phrases from the content
399
+ return []; // Would parse from the specialist's content
400
+ }
401
+ buildGreeting(specialist, personality, context) {
402
+ let greeting = specialist.persona.greeting;
403
+ if (context?.problem) {
404
+ greeting += ` I understand you're working on ${context.problem}. `;
405
+ }
406
+ greeting += ` I'm here to help with ${specialist.expertise.primary.join(', ')}. What specific challenge are you facing?`;
407
+ return greeting;
408
+ }
409
+ buildHandoffFarewell(fromSpecialist, toSpecialist, context) {
410
+ return `I think ${toSpecialist.persona.greeting.replace('!', '')} would be perfect for this! They're our expert in ${toSpecialist.expertise.primary.join(' and ')}. Let me hand you over to them.`;
411
+ }
412
+ buildHandoffIntroduction(toSpecialist, fromSpecialist, context) {
413
+ return `${toSpecialist.persona.greeting} ${fromSpecialist.specialist_id.split('-')[0]} filled me in on what you're working on. I'm excited to help with ${toSpecialist.expertise.primary[0]}! Let's dive in.`;
414
+ }
415
+ async calculateSpecialistConfidence(userMessage, specialist, context) {
416
+ const messageLower = userMessage.toLowerCase();
417
+ let confidence = 0;
418
+ // Check against primary expertise
419
+ for (const expertise of specialist.expertise.primary) {
420
+ if (messageLower.includes(expertise.toLowerCase().replace('-', ' '))) {
421
+ confidence += 0.3;
422
+ }
423
+ }
424
+ // Check against secondary expertise
425
+ for (const expertise of specialist.expertise.secondary) {
426
+ if (messageLower.includes(expertise.toLowerCase().replace('-', ' '))) {
427
+ confidence += 0.2;
428
+ }
429
+ }
430
+ // Check against domains
431
+ for (const domain of specialist.domains) {
432
+ if (messageLower.includes(domain.toLowerCase().replace('-', ' '))) {
433
+ confidence += 0.1;
434
+ }
435
+ }
436
+ return Math.min(confidence, 1.0);
437
+ }
438
+ generateSuggestionReasoning(userMessage, specialist, confidence) {
439
+ return `${specialist.specialist_id} specializes in ${specialist.expertise.primary.join(', ')} which aligns with your question about ${userMessage.substring(0, 50)}...`;
440
+ }
441
+ generateContextUpdates(context, relevantTopics) {
442
+ return {
443
+ // Add discovered topics to context
444
+ // Update problem understanding
445
+ // Track user preferences
446
+ };
447
+ }
448
+ async suggestCollaborations(context, relevantTopics) {
449
+ const suggestions = [];
450
+ // Check if other specialists might be helpful
451
+ const { specialist } = context;
452
+ if (specialist.collaboration?.natural_handoffs) {
453
+ for (const handoffId of specialist.collaboration.natural_handoffs) {
454
+ suggestions.push({
455
+ specialist_id: handoffId,
456
+ reason: `Natural collaboration partner for ${specialist.expertise.primary[0]}`
457
+ });
458
+ }
459
+ }
460
+ return suggestions.slice(0, 2); // Limit suggestions
461
+ }
462
+ getApplicationContext(topic, userMessage) {
463
+ const messageWords = userMessage.toLowerCase().split(' ');
464
+ const topicTags = topic.frontmatter.tags || [];
465
+ // Identify context based on user message and topic
466
+ let context = `Applied ${topic.title} to address`;
467
+ if (messageWords.some(word => ['performance', 'slow', 'optimize', 'speed'].includes(word))) {
468
+ context += ` performance concerns in ${this.extractEntityFromMessage(userMessage)}`;
469
+ }
470
+ else if (messageWords.some(word => ['security', 'permission', 'access'].includes(word))) {
471
+ context += ` security requirements for ${this.extractEntityFromMessage(userMessage)}`;
472
+ }
473
+ else if (messageWords.some(word => ['integration', 'api', 'connect'].includes(word))) {
474
+ context += ` integration challenges with ${this.extractEntityFromMessage(userMessage)}`;
475
+ }
476
+ else if (messageWords.some(word => ['test', 'testing', 'validation'].includes(word))) {
477
+ context += ` testing strategy for ${this.extractEntityFromMessage(userMessage)}`;
478
+ }
479
+ else {
480
+ context += ` the development challenge in ${userMessage.substring(0, 50)}...`;
481
+ }
482
+ // Add BC version context if available
483
+ if (topic.frontmatter.bc_versions) {
484
+ context += ` (BC ${topic.frontmatter.bc_versions} compatible)`;
485
+ }
486
+ return context;
487
+ }
488
+ /**
489
+ * Extract business entity or object from user message
490
+ */
491
+ extractEntityFromMessage(message) {
492
+ const commonEntities = [
493
+ 'table', 'page', 'report', 'codeunit', 'api', 'service',
494
+ 'customer', 'vendor', 'item', 'purchase', 'sales', 'inventory'
495
+ ];
496
+ const messageLower = message.toLowerCase();
497
+ for (const entity of commonEntities) {
498
+ if (messageLower.includes(entity)) {
499
+ return entity;
500
+ }
501
+ }
502
+ return 'your BC implementation';
503
+ }
504
+ generateRecommendations(topics, userMessage) {
505
+ const recommendations = [];
506
+ for (const topic of topics.slice(0, 3)) {
507
+ // Create actionable recommendations based on the topic
508
+ if (topic.frontmatter.bc_versions) {
509
+ recommendations.push(`Apply **${topic.title}** patterns (compatible with ${topic.frontmatter.bc_versions})`);
510
+ }
511
+ else {
512
+ recommendations.push(`Consider implementing **${topic.title}** best practices`);
513
+ }
514
+ // Add specific action based on topic type
515
+ if (topic.frontmatter.tags?.includes('performance')) {
516
+ recommendations.push(`Measure performance impact of ${topic.title.toLowerCase()} implementation`);
517
+ }
518
+ else if (topic.frontmatter.tags?.includes('security')) {
519
+ recommendations.push(`Review security implications when applying ${topic.title.toLowerCase()}`);
520
+ }
521
+ else if (topic.frontmatter.tags?.includes('testing')) {
522
+ recommendations.push(`Create test cases to validate ${topic.title.toLowerCase()} implementation`);
523
+ }
524
+ }
525
+ return recommendations.slice(0, 4); // Limit to 4 recommendations
526
+ }
527
+ determineResponseType(userMessage, topics) {
528
+ const messageLower = userMessage.toLowerCase();
529
+ if (messageLower.includes('how') || messageLower.includes('help')) {
530
+ return 'guidance';
531
+ }
532
+ else if (messageLower.includes('fix') || messageLower.includes('solve')) {
533
+ return 'solution';
534
+ }
535
+ else if (messageLower.includes('?')) {
536
+ return 'question';
537
+ }
538
+ return 'guidance';
539
+ }
540
+ calculateConfidenceLevel(specialist, userMessage, topics) {
541
+ if (topics.length >= 2)
542
+ return 'high';
543
+ if (topics.length === 1)
544
+ return 'medium';
545
+ return 'low';
546
+ }
547
+ }
548
+ /**
549
+ * Knowledge retriever implementation for BC topics
550
+ */
551
+ class BCKnowledgeRetriever {
552
+ layerService;
553
+ knowledgeService;
554
+ constructor(layerService, knowledgeService) {
555
+ this.layerService = layerService;
556
+ this.knowledgeService = knowledgeService;
557
+ }
558
+ async findRelevantTopics(userMessage, specialistExpertise, limit = 5) {
559
+ try {
560
+ // Convert specialist expertise to broader search terms that match topic content
561
+ const broadSearchTerms = specialistExpertise.map(exp => {
562
+ // Map specific expertise terms to broader, more searchable terms
563
+ const mappings = {
564
+ 'performance-analysis': 'performance',
565
+ 'error-diagnosis': 'error',
566
+ 'system-monitoring': 'monitoring',
567
+ 'optimization-implementation': 'optimization',
568
+ 'query-optimization': 'query performance',
569
+ 'memory-management': 'memory',
570
+ 'integration-performance': 'integration',
571
+ 'user-experience-optimization': 'user experience'
572
+ };
573
+ return mappings[exp] || exp.replace('-', ' ');
574
+ });
575
+ // Search for topics using the user's message in code_context field
576
+ const searchParams = {
577
+ code_context: `${userMessage} ${broadSearchTerms.join(' ')}`, // Combine user message with expertise terms
578
+ limit,
579
+ bc_version: 'BC22' // Default - could be made configurable
580
+ };
581
+ // Use the existing knowledge service to find relevant topics
582
+ const searchResults = await this.knowledgeService.searchTopics(searchParams);
583
+ // Get full topic details for each search result
584
+ if (searchResults && Array.isArray(searchResults)) {
585
+ const topics = [];
586
+ for (const result of searchResults.slice(0, limit)) {
587
+ const topic = await this.knowledgeService.getTopic(result.id);
588
+ if (topic) {
589
+ topics.push(topic);
590
+ }
591
+ }
592
+ return topics;
593
+ }
594
+ return [];
595
+ }
596
+ catch (error) {
597
+ console.error('Error finding relevant topics:', error);
598
+ return [];
599
+ }
600
+ }
601
+ async getRelatedTopics(topicId, limit = 3) {
602
+ try {
603
+ // Get the main topic first
604
+ const mainTopic = await this.knowledgeService.getTopic(topicId);
605
+ if (!mainTopic) {
606
+ return [];
607
+ }
608
+ // Use domain-based search to find related topics
609
+ const searchParams = {
610
+ query: mainTopic.frontmatter.domain,
611
+ search_type: 'fuzzy',
612
+ limit: limit + 1, // Get one extra to exclude the main topic
613
+ bc_version: 'BC22',
614
+ domains: [mainTopic.frontmatter.domain]
615
+ };
616
+ const searchResults = await this.knowledgeService.searchTopics(searchParams);
617
+ const relatedTopics = [];
618
+ for (const result of searchResults) {
619
+ if (result.id !== topicId && relatedTopics.length < limit) {
620
+ const topic = await this.knowledgeService.getTopic(result.id);
621
+ if (topic) {
622
+ relatedTopics.push(topic);
623
+ }
624
+ }
625
+ }
626
+ return relatedTopics;
627
+ }
628
+ catch (error) {
629
+ console.error('Error getting related topics:', error);
630
+ return [];
631
+ }
632
+ }
633
+ async searchSolutions(problemDescription, domains, limit = 5) {
634
+ try {
635
+ // Search for solution-oriented topics in the specified domains
636
+ const searchParams = {
637
+ query: `${problemDescription} solution implementation fix pattern`,
638
+ search_type: 'hybrid',
639
+ limit: limit * 2, // Get more results to filter
640
+ bc_version: 'BC22',
641
+ domains
642
+ };
643
+ const searchResults = await this.knowledgeService.searchTopics(searchParams);
644
+ const solutionTopics = [];
645
+ for (const result of searchResults) {
646
+ if (solutionTopics.length >= limit)
647
+ break;
648
+ const topic = await this.knowledgeService.getTopic(result.id);
649
+ if (topic) {
650
+ // Filter for topics that are more solution-oriented
651
+ const content = topic.content.toLowerCase();
652
+ const title = topic.title.toLowerCase();
653
+ if (content.includes('solution') ||
654
+ content.includes('implementation') ||
655
+ content.includes('fix') ||
656
+ content.includes('pattern') ||
657
+ title.includes('pattern') ||
658
+ title.includes('optimization') ||
659
+ title.includes('best practice')) {
660
+ solutionTopics.push(topic);
661
+ }
662
+ }
663
+ }
664
+ return solutionTopics;
665
+ }
666
+ catch (error) {
667
+ console.error('Error searching solutions:', error);
668
+ return [];
669
+ }
670
+ }
671
+ }
672
+ //# sourceMappingURL=roleplay-engine.js.map