aiwf 0.3.21 → 0.3.23

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 (140) hide show
  1. package/package.json +3 -2
  2. package/src/cli/index.js +39 -336
  3. package/src/lib/installer.js +310 -90
  4. package/src/utils/messages.js +24 -0
  5. package/src/DEPENDENCY_MAP.md +0 -90
  6. package/src/cli/cache-cli.js +0 -459
  7. package/src/cli/checkpoint-cli.js +0 -417
  8. package/src/cli/language-cli.js +0 -286
  9. package/src/cli/sprint-cli.js +0 -287
  10. package/src/commands/ai-tool.js +0 -383
  11. package/src/commands/compress.js +0 -60
  12. package/src/commands/create-project.js +0 -160
  13. package/src/commands/evaluate.js +0 -459
  14. package/src/commands/persona.js +0 -309
  15. package/src/commands/sprint-task.js +0 -262
  16. package/src/commands/token.js +0 -312
  17. package/src/lib/ai-persona-manager.js +0 -711
  18. package/src/lib/cache-system.js +0 -332
  19. package/src/lib/context-engine.js +0 -568
  20. package/src/lib/github-integration.js +0 -402
  21. package/src/lib/memory-profiler.js +0 -471
  22. package/src/lib/metrics-collector.js +0 -885
  23. package/src/lib/offline-detector.js +0 -386
  24. package/src/lib/resource-loader-enhanced.js +0 -399
  25. package/src/lib/resource-loader.js +0 -250
  26. package/src/lib/resources/commands/ai-persona.js +0 -602
  27. package/src/lib/resources/commands/compress-context.js +0 -389
  28. package/src/lib/resources/commands/evaluate.js +0 -246
  29. package/src/lib/resources/commands/persona-context-apply.js +0 -562
  30. package/src/lib/resources/commands/token-tracking.js +0 -443
  31. package/src/lib/resources/config/commit-patterns.js +0 -103
  32. package/src/lib/resources/config/language.json +0 -6
  33. package/src/lib/resources/personas/PERSONA_INDEX.md +0 -57
  34. package/src/lib/resources/personas/analyst.json +0 -44
  35. package/src/lib/resources/personas/architect/best_practices.md +0 -136
  36. package/src/lib/resources/personas/architect/knowledge_base.md +0 -377
  37. package/src/lib/resources/personas/architect.json +0 -44
  38. package/src/lib/resources/personas/backend/best_practices.md +0 -766
  39. package/src/lib/resources/personas/backend/knowledge_base.md +0 -1070
  40. package/src/lib/resources/personas/data_analyst/best_practices.md +0 -594
  41. package/src/lib/resources/personas/data_analyst/knowledge_base.md +0 -1057
  42. package/src/lib/resources/personas/developer.json +0 -44
  43. package/src/lib/resources/personas/developer.md +0 -37
  44. package/src/lib/resources/personas/evaluation_criteria.json +0 -137
  45. package/src/lib/resources/personas/frontend/best_practices.md +0 -445
  46. package/src/lib/resources/personas/frontend/knowledge_base.md +0 -729
  47. package/src/lib/resources/personas/persona-index.json +0 -31
  48. package/src/lib/resources/personas/reviewer.json +0 -44
  49. package/src/lib/resources/personas/security/best_practices.md +0 -307
  50. package/src/lib/resources/personas/security/knowledge_base.md +0 -498
  51. package/src/lib/resources/personas/tester.json +0 -44
  52. package/src/lib/resources/templates/README.md +0 -78
  53. package/src/lib/resources/templates/api-server/config.json +0 -64
  54. package/src/lib/resources/templates/api-server/template/.aiwf/config.json +0 -56
  55. package/src/lib/resources/templates/api-server/template/.aiwf/feature-ledger.json +0 -42
  56. package/src/lib/resources/templates/api-server/template/.aiwf/personas/backend-engineer.json +0 -40
  57. package/src/lib/resources/templates/api-server/template/.aiwf/scripts/cli.js +0 -111
  58. package/src/lib/resources/templates/api-server/template/.env.example +0 -29
  59. package/src/lib/resources/templates/api-server/template/.eslintrc.json +0 -23
  60. package/src/lib/resources/templates/api-server/template/README.md +0 -171
  61. package/src/lib/resources/templates/api-server/template/jest.config.js +0 -26
  62. package/src/lib/resources/templates/api-server/template/nodemon.json +0 -9
  63. package/src/lib/resources/templates/api-server/template/package.json +0 -61
  64. package/src/lib/resources/templates/api-server/template/src/app.ts +0 -60
  65. package/src/lib/resources/templates/api-server/template/src/config/swagger.ts +0 -38
  66. package/src/lib/resources/templates/api-server/template/src/controllers/aiwfController.ts +0 -54
  67. package/src/lib/resources/templates/api-server/template/src/controllers/authController.ts +0 -128
  68. package/src/lib/resources/templates/api-server/template/src/controllers/statusController.ts +0 -28
  69. package/src/lib/resources/templates/api-server/template/src/index.ts +0 -28
  70. package/src/lib/resources/templates/api-server/template/src/middleware/aiwfMiddleware.ts +0 -50
  71. package/src/lib/resources/templates/api-server/template/src/middleware/authMiddleware.ts +0 -41
  72. package/src/lib/resources/templates/api-server/template/src/middleware/errorHandler.ts +0 -42
  73. package/src/lib/resources/templates/api-server/template/src/middleware/notFoundHandler.ts +0 -14
  74. package/src/lib/resources/templates/api-server/template/src/middleware/requestLogger.ts +0 -20
  75. package/src/lib/resources/templates/api-server/template/src/routes/aiwf.ts +0 -31
  76. package/src/lib/resources/templates/api-server/template/src/routes/index.ts +0 -13
  77. package/src/lib/resources/templates/api-server/template/src/routes/v1/index.ts +0 -67
  78. package/src/lib/resources/templates/api-server/template/src/utils/logger.ts +0 -37
  79. package/src/lib/resources/templates/api-server/template/tests/app.test.ts +0 -40
  80. package/src/lib/resources/templates/api-server/template/tsconfig.json +0 -43
  81. package/src/lib/resources/templates/npm-library/config.json +0 -61
  82. package/src/lib/resources/templates/npm-library/template/LICENSE +0 -21
  83. package/src/lib/resources/templates/npm-library/template/README.md +0 -201
  84. package/src/lib/resources/templates/npm-library/template/package.json +0 -78
  85. package/src/lib/resources/templates/web-app/config.json +0 -53
  86. package/src/lib/resources/templates/web-app/template/.aiwf/config.json +0 -54
  87. package/src/lib/resources/templates/web-app/template/.aiwf/feature-ledger.json +0 -37
  88. package/src/lib/resources/templates/web-app/template/.aiwf/personas/fullstack-developer.json +0 -40
  89. package/src/lib/resources/templates/web-app/template/.aiwf/scripts/cli.js +0 -110
  90. package/src/lib/resources/templates/web-app/template/.eslintrc.cjs +0 -20
  91. package/src/lib/resources/templates/web-app/template/README.md +0 -151
  92. package/src/lib/resources/templates/web-app/template/index.html +0 -14
  93. package/src/lib/resources/templates/web-app/template/package.json +0 -44
  94. package/src/lib/resources/templates/web-app/template/postcss.config.js +0 -6
  95. package/src/lib/resources/templates/web-app/template/public/vite.svg +0 -1
  96. package/src/lib/resources/templates/web-app/template/src/App.tsx +0 -21
  97. package/src/lib/resources/templates/web-app/template/src/components/Layout.tsx +0 -57
  98. package/src/lib/resources/templates/web-app/template/src/components/aiwf/ContextStatus.tsx +0 -107
  99. package/src/lib/resources/templates/web-app/template/src/components/aiwf/TokenUsage.tsx +0 -71
  100. package/src/lib/resources/templates/web-app/template/src/index.css +0 -60
  101. package/src/lib/resources/templates/web-app/template/src/main.tsx +0 -10
  102. package/src/lib/resources/templates/web-app/template/src/pages/AiwfDashboard.tsx +0 -57
  103. package/src/lib/resources/templates/web-app/template/src/pages/HomePage.tsx +0 -89
  104. package/src/lib/resources/templates/web-app/template/src/pages/NotFound.tsx +0 -25
  105. package/src/lib/resources/templates/web-app/template/src/stores/aiwfStore.ts +0 -126
  106. package/src/lib/resources/templates/web-app/template/src/types/global.d.ts +0 -9
  107. package/src/lib/resources/templates/web-app/template/src/vite-env.d.ts +0 -1
  108. package/src/lib/resources/templates/web-app/template/tailwind.config.js +0 -30
  109. package/src/lib/resources/templates/web-app/template/tsconfig.json +0 -37
  110. package/src/lib/resources/templates/web-app/template/tsconfig.node.json +0 -10
  111. package/src/lib/resources/templates/web-app/template/vite.config.ts +0 -23
  112. package/src/lib/resources/utils/background-monitor.js +0 -223
  113. package/src/lib/resources/utils/compression-metrics.js +0 -1031
  114. package/src/lib/resources/utils/compression-strategies.js +0 -557
  115. package/src/lib/resources/utils/content-normalizer.js +0 -455
  116. package/src/lib/resources/utils/context-compressor.js +0 -583
  117. package/src/lib/resources/utils/context-rule-parser.js +0 -180
  118. package/src/lib/resources/utils/context-token-monitor.js +0 -463
  119. package/src/lib/resources/utils/context-update-manager.js +0 -502
  120. package/src/lib/resources/utils/git-utils.js +0 -220
  121. package/src/lib/resources/utils/importance-classifier.js +0 -645
  122. package/src/lib/resources/utils/information-filter.js +0 -710
  123. package/src/lib/resources/utils/persona-aware-compressor.js +0 -598
  124. package/src/lib/resources/utils/prompt-injector.js +0 -242
  125. package/src/lib/resources/utils/simplified-evaluator.js +0 -119
  126. package/src/lib/resources/utils/text-summarizer.js +0 -492
  127. package/src/lib/resources/utils/token-counter.js +0 -177
  128. package/src/lib/resources/utils/token-monitor.js +0 -484
  129. package/src/lib/resources/utils/token-reporter.js +0 -452
  130. package/src/lib/resources/utils/token-storage.js +0 -433
  131. package/src/lib/resources/utils/token-tracker.js +0 -283
  132. package/src/lib/state/priority-calculator.js +0 -217
  133. package/src/lib/state/state-index.js +0 -155
  134. package/src/lib/state/task-scanner.js +0 -328
  135. package/src/lib/task-analyzer.js +0 -599
  136. package/src/lib/template-cache-system.js +0 -559
  137. package/src/lib/template-downloader.js +0 -467
  138. package/src/lib/template-version-manager.js +0 -491
  139. package/src/lib/token-optimizer.js +0 -517
  140. package/src/utils/engineering-guard.js +0 -399
@@ -1,711 +0,0 @@
1
- /**
2
- * AI Persona Manager
3
- * Manages AI behavior personas for different development tasks
4
- */
5
-
6
- import fs from 'fs/promises';
7
- import path from 'path';
8
- import { EventEmitter } from 'events';
9
- import { fileURLToPath } from 'url';
10
- import { dirname } from 'path';
11
-
12
- const __filename = fileURLToPath(import.meta.url);
13
- const __dirname = dirname(__filename);
14
-
15
- // Import related modules
16
- import { ContextEngine } from './context-engine.js';
17
- import { MetricsCollector } from './metrics-collector.js';
18
- import { TaskAnalyzer } from './task-analyzer.js';
19
-
20
- class AIPersonaManager extends EventEmitter {
21
- constructor(options = {}) {
22
- super();
23
-
24
- this.options = {
25
- personaConfigPath: options.personaConfigPath ||
26
- path.join(process.cwd(), '.aiwf', 'personas'),
27
- autoDetectionEnabled: options.autoDetectionEnabled !== false,
28
- metricsEnabled: options.metricsEnabled !== false,
29
- cacheTimeout: options.cacheTimeout || 300000, // 5 minutes
30
- ...options
31
- };
32
-
33
- this.currentPersona = null;
34
- this.personaHistory = [];
35
- this.availablePersonas = {};
36
- this.lastSwitchTime = null;
37
-
38
- // Initialize sub-systems
39
- this.contextEngine = new ContextEngine(this.options);
40
- this.metricsCollector = new MetricsCollector(this.options);
41
- this.taskAnalyzer = new TaskAnalyzer(this.options);
42
-
43
- // Cache for persona configurations
44
- this.personaCache = new Map();
45
- }
46
-
47
- /**
48
- * Initialize the persona system
49
- */
50
- async init() {
51
- try {
52
- // Ensure persona directory exists
53
- await fs.mkdir(this.options.personaConfigPath, { recursive: true });
54
-
55
- // Load available personas
56
- await this.loadAvailablePersonas();
57
-
58
- // Initialize sub-systems
59
- await this.contextEngine.init();
60
- if (this.options.metricsEnabled) {
61
- await this.metricsCollector.init();
62
- }
63
-
64
- // Set default persona
65
- if (!this.currentPersona) {
66
- await this.switchPersona('developer', { silent: true });
67
- }
68
-
69
- this.emit('initialized', {
70
- availablePersonas: Object.keys(this.availablePersonas),
71
- currentPersona: this.currentPersona?.name
72
- });
73
-
74
- return true;
75
- } catch (error) {
76
- this.emit('error', { error, phase: 'initialization' });
77
- throw error;
78
- }
79
- }
80
-
81
- /**
82
- * Load available persona configurations
83
- */
84
- async loadAvailablePersonas() {
85
- // Default personas
86
- const defaultPersonas = {
87
- architect: {
88
- name: 'architect',
89
- description: 'System design and architecture',
90
- behaviors: [
91
- 'Focus on big picture and overall system structure',
92
- 'Prioritize scalability and maintainability',
93
- 'Apply design patterns and architectural principles',
94
- 'Consider integration points and interfaces'
95
- ],
96
- focusAreas: ['system design', 'architecture', 'patterns', 'scalability'],
97
- communicationStyle: 'strategic and high-level',
98
- recommendedTools: ['Glob', 'LS', 'MarkdownProcessor', 'Read'],
99
- contextRules: {
100
- priority: ['*.md', '*.yml', '*.json', 'architecture/**'],
101
- exclude: ['test/**', 'node_modules/**', '*.test.*'],
102
- focus: ['interfaces', 'contracts', 'dependencies'],
103
- keywords: ['design', 'pattern', 'architecture', 'structure']
104
- },
105
- tokenAllocation: {
106
- context: 0.3,
107
- response: 0.7
108
- }
109
- },
110
-
111
- debugger: {
112
- name: 'debugger',
113
- description: 'Bug detection and problem solving',
114
- behaviors: [
115
- 'Systematic and methodical approach',
116
- 'Focus on root cause analysis',
117
- 'Consider edge cases and error scenarios',
118
- 'Trace execution flow step by step'
119
- ],
120
- focusAreas: ['error handling', 'debugging', 'testing', 'validation'],
121
- communicationStyle: 'detailed and analytical',
122
- recommendedTools: ['Grep', 'Read', 'Bash', 'MemoryProfiler'],
123
- contextRules: {
124
- priority: ['*.log', '*.test.*', 'error.**', 'debug/**'],
125
- exclude: ['docs/**', '*.md'],
126
- focus: ['errors', 'exceptions', 'stack traces', 'logs'],
127
- keywords: ['error', 'bug', 'fix', 'debug', 'trace']
128
- },
129
- tokenAllocation: {
130
- context: 0.5,
131
- response: 0.5
132
- }
133
- },
134
-
135
- reviewer: {
136
- name: 'reviewer',
137
- description: 'Code quality and standards',
138
- behaviors: [
139
- 'Verify coding standards compliance',
140
- 'Identify security vulnerabilities',
141
- 'Suggest optimizations and improvements',
142
- 'Ensure best practices are followed'
143
- ],
144
- focusAreas: ['code quality', 'security', 'standards', 'best practices'],
145
- communicationStyle: 'constructive and thorough',
146
- recommendedTools: ['Grep', 'Read', 'Bash', 'FileUtils'],
147
- contextRules: {
148
- priority: ['*.js', '*.ts', '*.py', 'src/**'],
149
- exclude: ['dist/**', 'build/**', 'coverage/**'],
150
- focus: ['functions', 'classes', 'imports', 'exports'],
151
- keywords: ['review', 'quality', 'security', 'standard']
152
- },
153
- tokenAllocation: {
154
- context: 0.4,
155
- response: 0.6
156
- }
157
- },
158
-
159
- documenter: {
160
- name: 'documenter',
161
- description: 'Documentation and guides',
162
- behaviors: [
163
- 'Write clear and understandable explanations',
164
- 'Provide practical examples',
165
- 'Ensure comprehensive coverage',
166
- 'Maintain consistent documentation style'
167
- ],
168
- focusAreas: ['documentation', 'guides', 'examples', 'tutorials'],
169
- communicationStyle: 'clear and educational',
170
- recommendedTools: ['MarkdownProcessor', 'Read', 'Write', 'TemplateEngine'],
171
- contextRules: {
172
- priority: ['*.md', 'README*', 'docs/**', 'examples/**'],
173
- exclude: ['test/**', 'node_modules/**'],
174
- focus: ['APIs', 'interfaces', 'usage', 'examples'],
175
- keywords: ['document', 'explain', 'guide', 'example']
176
- },
177
- tokenAllocation: {
178
- context: 0.2,
179
- response: 0.8
180
- }
181
- },
182
-
183
- optimizer: {
184
- name: 'optimizer',
185
- description: 'Performance optimization',
186
- behaviors: [
187
- 'Analyze performance bottlenecks',
188
- 'Focus on efficiency and resource usage',
189
- 'Measure and benchmark improvements',
190
- 'Apply optimization techniques'
191
- ],
192
- focusAreas: ['performance', 'efficiency', 'optimization', 'benchmarking'],
193
- communicationStyle: 'data-driven and precise',
194
- recommendedTools: ['PerformanceBenchmark', 'MemoryProfiler', 'TokenTracker'],
195
- contextRules: {
196
- priority: ['*.bench.*', 'benchmark/**', 'perf/**'],
197
- exclude: ['docs/**', '*.md'],
198
- focus: ['algorithms', 'loops', 'memory', 'complexity'],
199
- keywords: ['optimize', 'performance', 'speed', 'efficiency']
200
- },
201
- tokenAllocation: {
202
- context: 0.6,
203
- response: 0.4
204
- }
205
- },
206
-
207
- developer: {
208
- name: 'developer',
209
- description: 'General development (default)',
210
- behaviors: [
211
- 'Balanced approach to coding',
212
- 'Focus on functionality and correctness',
213
- 'Write clean and maintainable code',
214
- 'Follow project conventions'
215
- ],
216
- focusAreas: ['implementation', 'features', 'functionality', 'coding'],
217
- communicationStyle: 'practical and straightforward',
218
- recommendedTools: ['Read', 'Write', 'Edit', 'Bash'],
219
- contextRules: {
220
- priority: ['src/**', 'lib/**', '*.js', '*.ts'],
221
- exclude: ['node_modules/**', 'dist/**'],
222
- focus: ['implementation', 'logic', 'features'],
223
- keywords: ['implement', 'create', 'build', 'develop']
224
- },
225
- tokenAllocation: {
226
- context: 0.4,
227
- response: 0.6
228
- }
229
- }
230
- };
231
-
232
- // Store default personas
233
- this.availablePersonas = { ...defaultPersonas };
234
-
235
- // Load custom personas if they exist
236
- try {
237
- const customPath = path.join(this.options.personaConfigPath, 'custom');
238
- const files = await fs.readdir(customPath).catch(() => []);
239
-
240
- for (const file of files) {
241
- if (file.endsWith('.json')) {
242
- const content = await fs.readFile(
243
- path.join(customPath, file),
244
- 'utf-8'
245
- );
246
- const persona = JSON.parse(content);
247
- this.availablePersonas[persona.name] = persona;
248
- }
249
- }
250
- } catch (error) {
251
- // Custom personas are optional
252
- }
253
- }
254
-
255
- /**
256
- * Switch to a different persona
257
- */
258
- async switchPersona(personaName, options = {}) {
259
- try {
260
- // Validate persona
261
- if (!this.isValidPersona(personaName)) {
262
- throw new Error(`Invalid persona: ${personaName}`);
263
- }
264
-
265
- // Check if already in this persona
266
- if (this.currentPersona?.name === personaName && !options.force) {
267
- return this.currentPersona;
268
- }
269
-
270
- // Save current state to history
271
- if (this.currentPersona && !options.silent) {
272
- const metrics = this.options.metricsEnabled ?
273
- await this.metricsCollector.collectCurrentMetrics() : null;
274
-
275
- this.personaHistory.push({
276
- persona: this.currentPersona,
277
- startTime: this.lastSwitchTime,
278
- endTime: new Date(),
279
- metrics
280
- });
281
- }
282
-
283
- // Load new persona
284
- const persona = await this.loadPersona(personaName);
285
-
286
- // Apply context rules
287
- await this.contextEngine.applyPersonaRules(persona);
288
-
289
- // Update state
290
- this.currentPersona = persona;
291
- this.lastSwitchTime = new Date();
292
-
293
- // Track switch event
294
- if (this.options.metricsEnabled && !options.silent) {
295
- this.metricsCollector.trackEvent('persona_switch', {
296
- from: this.personaHistory[this.personaHistory.length - 1]?.persona?.name,
297
- to: personaName,
298
- trigger: options.manual ? 'manual' : 'auto',
299
- reason: options.reason
300
- });
301
- }
302
-
303
- // Emit event
304
- this.emit('personaSwitched', {
305
- persona: personaName,
306
- trigger: options.manual ? 'manual' : 'auto'
307
- });
308
-
309
- return persona;
310
- } catch (error) {
311
- this.emit('error', { error, phase: 'persona_switch' });
312
- throw error;
313
- }
314
- }
315
-
316
- /**
317
- * Load a specific persona configuration
318
- */
319
- async loadPersona(personaName) {
320
- // Check cache first
321
- if (this.personaCache.has(personaName)) {
322
- const cached = this.personaCache.get(personaName);
323
- if (Date.now() - cached.timestamp < this.options.cacheTimeout) {
324
- return cached.persona;
325
- }
326
- }
327
-
328
- // Load from configuration
329
- const persona = this.availablePersonas[personaName];
330
- if (!persona) {
331
- throw new Error(`Persona not found: ${personaName}`);
332
- }
333
-
334
- // Process and validate persona
335
- const processed = {
336
- ...persona,
337
- loadedAt: new Date(),
338
- isActive: true
339
- };
340
-
341
- // Cache the persona
342
- this.personaCache.set(personaName, {
343
- persona: processed,
344
- timestamp: Date.now()
345
- });
346
-
347
- return processed;
348
- }
349
-
350
- /**
351
- * Detect optimal persona for a task
352
- */
353
- async detectOptimalPersona(taskContext) {
354
- if (!this.options.autoDetectionEnabled) {
355
- return this.currentPersona?.name || 'developer';
356
- }
357
-
358
- try {
359
- // Analyze task
360
- const analysis = await this.taskAnalyzer.analyzeTask(taskContext);
361
-
362
- // Score each persona
363
- const scores = {};
364
- for (const personaName of Object.keys(this.availablePersonas)) {
365
- scores[personaName] = await this.scorePersonaFit(personaName, analysis);
366
- }
367
-
368
- // Get best match
369
- const sorted = Object.entries(scores)
370
- .sort(([,a], [,b]) => b - a);
371
-
372
- const bestMatch = sorted[0][0];
373
- const confidence = sorted[0][1];
374
-
375
- // Only switch if confidence is high enough
376
- if (confidence > 0.7 && bestMatch !== this.currentPersona?.name) {
377
- await this.switchPersona(bestMatch, {
378
- manual: false,
379
- reason: 'auto_detection',
380
- confidence
381
- });
382
- }
383
-
384
- return bestMatch;
385
- } catch (error) {
386
- this.emit('error', { error, phase: 'persona_detection' });
387
- return this.currentPersona?.name || 'developer';
388
- }
389
- }
390
-
391
- /**
392
- * Score how well a persona fits a task
393
- */
394
- async scorePersonaFit(personaName, taskAnalysis) {
395
- const persona = this.availablePersonas[personaName];
396
- if (!persona) return 0;
397
-
398
- let score = 0;
399
- const weights = {
400
- keywords: 0.4,
401
- patterns: 0.3,
402
- context: 0.2,
403
- history: 0.1
404
- };
405
-
406
- // Keyword matching
407
- const keywordScore = this.calculateKeywordScore(
408
- persona.contextRules.keywords,
409
- taskAnalysis.keywords
410
- );
411
- score += keywordScore * weights.keywords;
412
-
413
- // Pattern matching
414
- const patternScore = taskAnalysis.scores[personaName] || 0;
415
- score += (patternScore / 100) * weights.patterns;
416
-
417
- // Context matching
418
- const contextScore = this.calculateContextScore(persona, taskAnalysis);
419
- score += contextScore * weights.context;
420
-
421
- // Historical performance
422
- const historyScore = await this.calculateHistoryScore(personaName, taskAnalysis);
423
- score += historyScore * weights.history;
424
-
425
- return Math.min(score, 1);
426
- }
427
-
428
- /**
429
- * Calculate keyword matching score
430
- */
431
- calculateKeywordScore(personaKeywords, taskKeywords) {
432
- if (!personaKeywords?.length || !taskKeywords?.length) return 0;
433
-
434
- const matches = taskKeywords.filter(keyword =>
435
- personaKeywords.some(pk =>
436
- keyword.toLowerCase().includes(pk.toLowerCase())
437
- )
438
- );
439
-
440
- return matches.length / taskKeywords.length;
441
- }
442
-
443
- /**
444
- * Calculate context matching score
445
- */
446
- calculateContextScore(persona, analysis) {
447
- let score = 0;
448
- let factors = 0;
449
-
450
- // File type matching
451
- if (analysis.recentFiles?.length) {
452
- const priorityPatterns = persona.contextRules.priority || [];
453
- const matchingFiles = analysis.recentFiles.filter(file =>
454
- priorityPatterns.some(pattern =>
455
- this.matchesPattern(file, pattern)
456
- )
457
- );
458
- score += matchingFiles.length / analysis.recentFiles.length;
459
- factors++;
460
- }
461
-
462
- // Error state bonus for debugger
463
- if (persona.name === 'debugger' && analysis.errorState?.hasErrors) {
464
- score += 1;
465
- factors++;
466
- }
467
-
468
- // Git context bonus
469
- if (persona.name === 'reviewer' && analysis.gitContext?.isPullRequest) {
470
- score += 1;
471
- factors++;
472
- }
473
-
474
- return factors > 0 ? score / factors : 0;
475
- }
476
-
477
- /**
478
- * Calculate historical performance score
479
- */
480
- async calculateHistoryScore(personaName, analysis) {
481
- if (!this.options.metricsEnabled) return 0.5; // Neutral score
482
-
483
- const history = await this.metricsCollector.getPersonaHistory(personaName);
484
- if (!history || history.length === 0) return 0.5;
485
-
486
- // Find similar tasks in history
487
- const similarTasks = history.filter(session =>
488
- this.taskAnalyzer.calculateSimilarity(session.task, analysis) > 0.6
489
- );
490
-
491
- if (similarTasks.length === 0) return 0.5;
492
-
493
- // Calculate average performance
494
- const avgPerformance = similarTasks.reduce((sum, task) =>
495
- sum + (task.qualityMetrics?.overallScore || 0.5), 0
496
- ) / similarTasks.length;
497
-
498
- return avgPerformance;
499
- }
500
-
501
- /**
502
- * Get current persona
503
- */
504
- getCurrentPersona() {
505
- return this.currentPersona;
506
- }
507
-
508
- /**
509
- * Get persona context rules
510
- */
511
- getPersonaContext(personaName) {
512
- const persona = this.availablePersonas[personaName];
513
- return persona?.contextRules || null;
514
- }
515
-
516
- /**
517
- * Apply persona rules to content
518
- */
519
- async applyPersonaRules(content, personaName) {
520
- const persona = personaName ?
521
- this.availablePersonas[personaName] :
522
- this.currentPersona;
523
-
524
- if (!persona) {
525
- throw new Error('No persona specified or active');
526
- }
527
-
528
- return await this.contextEngine.filterContent(content, persona);
529
- }
530
-
531
- /**
532
- * Get available personas
533
- */
534
- getAvailablePersonas() {
535
- return Object.keys(this.availablePersonas);
536
- }
537
-
538
- /**
539
- * Check if persona is valid
540
- */
541
- isValidPersona(personaName) {
542
- return personaName in this.availablePersonas;
543
- }
544
-
545
- /**
546
- * Get persona statistics
547
- */
548
- async getPersonaStats(personaName) {
549
- if (!this.options.metricsEnabled) {
550
- return { message: 'Metrics collection is disabled' };
551
- }
552
-
553
- return await this.metricsCollector.getPersonaStats(personaName);
554
- }
555
-
556
- /**
557
- * Generate persona report
558
- */
559
- async generateReport(options = {}) {
560
- if (!this.options.metricsEnabled) {
561
- return { message: 'Metrics collection is disabled' };
562
- }
563
-
564
- const report = await this.metricsCollector.generateReport(options);
565
-
566
- // Add persona-specific insights
567
- report.personaInsights = {};
568
- for (const personaName of this.getAvailablePersonas()) {
569
- report.personaInsights[personaName] = await this.generatePersonaInsights(
570
- personaName,
571
- report.personaAnalysis[personaName]
572
- );
573
- }
574
-
575
- return report;
576
- }
577
-
578
- /**
579
- * Generate insights for a specific persona
580
- */
581
- async generatePersonaInsights(personaName, analysis) {
582
- if (!analysis) return null;
583
-
584
- const insights = {
585
- effectiveness: this.calculateEffectiveness(analysis),
586
- recommendations: [],
587
- bestPractices: []
588
- };
589
-
590
- // Generate recommendations
591
- if (analysis.tokenEfficiency < 0.5) {
592
- insights.recommendations.push(
593
- 'Consider more aggressive context filtering to improve token efficiency'
594
- );
595
- }
596
-
597
- if (analysis.averageCompletionTime > 300000) { // 5 minutes
598
- insights.recommendations.push(
599
- 'Tasks are taking longer than expected. Review task complexity or persona fit'
600
- );
601
- }
602
-
603
- // Add best practices based on persona
604
- const persona = this.availablePersonas[personaName];
605
- if (persona) {
606
- insights.bestPractices = this.generateBestPractices(persona, analysis);
607
- }
608
-
609
- return insights;
610
- }
611
-
612
- /**
613
- * Calculate persona effectiveness
614
- */
615
- calculateEffectiveness(analysis) {
616
- const weights = {
617
- completionTime: 0.3,
618
- qualityScore: 0.4,
619
- tokenEfficiency: 0.3
620
- };
621
-
622
- let score = 0;
623
-
624
- // Normalize completion time (lower is better)
625
- const timeScore = Math.max(0, 1 - (analysis.averageCompletionTime / 600000));
626
- score += timeScore * weights.completionTime;
627
-
628
- // Quality score (already normalized)
629
- score += (analysis.averageQualityScore || 0.5) * weights.qualityScore;
630
-
631
- // Token efficiency (already normalized)
632
- score += (analysis.tokenEfficiency || 0.5) * weights.tokenEfficiency;
633
-
634
- return {
635
- score,
636
- rating: score > 0.8 ? 'excellent' :
637
- score > 0.6 ? 'good' :
638
- score > 0.4 ? 'fair' : 'needs improvement'
639
- };
640
- }
641
-
642
- /**
643
- * Generate best practices for a persona
644
- */
645
- generateBestPractices(persona, analysis) {
646
- const practices = [];
647
-
648
- // General best practices
649
- practices.push(`Use ${persona.name} persona for ${persona.focusAreas.join(', ')}`);
650
- practices.push(`Recommended tools: ${persona.recommendedTools.join(', ')}`);
651
-
652
- // Specific recommendations based on analysis
653
- if (analysis.bestUseCases?.length) {
654
- practices.push(`Most effective for: ${analysis.bestUseCases.join(', ')}`);
655
- }
656
-
657
- return practices;
658
- }
659
-
660
- /**
661
- * Check if pattern matches file path
662
- */
663
- matchesPattern(filePath, pattern) {
664
- // Convert glob pattern to regex
665
- const regex = pattern
666
- .replace(/\*\*/g, '.*')
667
- .replace(/\*/g, '[^/]*')
668
- .replace(/\?/g, '.');
669
-
670
- return new RegExp(`^${regex}$`).test(filePath);
671
- }
672
-
673
- /**
674
- * Reset persona system
675
- */
676
- async reset() {
677
- this.currentPersona = null;
678
- this.personaHistory = [];
679
- this.personaCache.clear();
680
- this.lastSwitchTime = null;
681
-
682
- if (this.options.metricsEnabled) {
683
- await this.metricsCollector.reset();
684
- }
685
-
686
- await this.contextEngine.reset();
687
-
688
- // Set default persona
689
- await this.switchPersona('developer', { silent: true });
690
-
691
- this.emit('reset');
692
- }
693
-
694
- /**
695
- * Cleanup resources
696
- */
697
- async cleanup() {
698
- this.personaCache.clear();
699
-
700
- if (this.options.metricsEnabled) {
701
- await this.metricsCollector.cleanup();
702
- }
703
-
704
- await this.contextEngine.cleanup();
705
-
706
- this.removeAllListeners();
707
- }
708
- }
709
-
710
- export default AIPersonaManager;
711
- export { AIPersonaManager };