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.
- package/package.json +3 -2
- package/src/cli/index.js +39 -336
- package/src/lib/installer.js +310 -90
- package/src/utils/messages.js +24 -0
- package/src/DEPENDENCY_MAP.md +0 -90
- package/src/cli/cache-cli.js +0 -459
- package/src/cli/checkpoint-cli.js +0 -417
- package/src/cli/language-cli.js +0 -286
- package/src/cli/sprint-cli.js +0 -287
- package/src/commands/ai-tool.js +0 -383
- package/src/commands/compress.js +0 -60
- package/src/commands/create-project.js +0 -160
- package/src/commands/evaluate.js +0 -459
- package/src/commands/persona.js +0 -309
- package/src/commands/sprint-task.js +0 -262
- package/src/commands/token.js +0 -312
- package/src/lib/ai-persona-manager.js +0 -711
- package/src/lib/cache-system.js +0 -332
- package/src/lib/context-engine.js +0 -568
- package/src/lib/github-integration.js +0 -402
- package/src/lib/memory-profiler.js +0 -471
- package/src/lib/metrics-collector.js +0 -885
- package/src/lib/offline-detector.js +0 -386
- package/src/lib/resource-loader-enhanced.js +0 -399
- package/src/lib/resource-loader.js +0 -250
- package/src/lib/resources/commands/ai-persona.js +0 -602
- package/src/lib/resources/commands/compress-context.js +0 -389
- package/src/lib/resources/commands/evaluate.js +0 -246
- package/src/lib/resources/commands/persona-context-apply.js +0 -562
- package/src/lib/resources/commands/token-tracking.js +0 -443
- package/src/lib/resources/config/commit-patterns.js +0 -103
- package/src/lib/resources/config/language.json +0 -6
- package/src/lib/resources/personas/PERSONA_INDEX.md +0 -57
- package/src/lib/resources/personas/analyst.json +0 -44
- package/src/lib/resources/personas/architect/best_practices.md +0 -136
- package/src/lib/resources/personas/architect/knowledge_base.md +0 -377
- package/src/lib/resources/personas/architect.json +0 -44
- package/src/lib/resources/personas/backend/best_practices.md +0 -766
- package/src/lib/resources/personas/backend/knowledge_base.md +0 -1070
- package/src/lib/resources/personas/data_analyst/best_practices.md +0 -594
- package/src/lib/resources/personas/data_analyst/knowledge_base.md +0 -1057
- package/src/lib/resources/personas/developer.json +0 -44
- package/src/lib/resources/personas/developer.md +0 -37
- package/src/lib/resources/personas/evaluation_criteria.json +0 -137
- package/src/lib/resources/personas/frontend/best_practices.md +0 -445
- package/src/lib/resources/personas/frontend/knowledge_base.md +0 -729
- package/src/lib/resources/personas/persona-index.json +0 -31
- package/src/lib/resources/personas/reviewer.json +0 -44
- package/src/lib/resources/personas/security/best_practices.md +0 -307
- package/src/lib/resources/personas/security/knowledge_base.md +0 -498
- package/src/lib/resources/personas/tester.json +0 -44
- package/src/lib/resources/templates/README.md +0 -78
- package/src/lib/resources/templates/api-server/config.json +0 -64
- package/src/lib/resources/templates/api-server/template/.aiwf/config.json +0 -56
- package/src/lib/resources/templates/api-server/template/.aiwf/feature-ledger.json +0 -42
- package/src/lib/resources/templates/api-server/template/.aiwf/personas/backend-engineer.json +0 -40
- package/src/lib/resources/templates/api-server/template/.aiwf/scripts/cli.js +0 -111
- package/src/lib/resources/templates/api-server/template/.env.example +0 -29
- package/src/lib/resources/templates/api-server/template/.eslintrc.json +0 -23
- package/src/lib/resources/templates/api-server/template/README.md +0 -171
- package/src/lib/resources/templates/api-server/template/jest.config.js +0 -26
- package/src/lib/resources/templates/api-server/template/nodemon.json +0 -9
- package/src/lib/resources/templates/api-server/template/package.json +0 -61
- package/src/lib/resources/templates/api-server/template/src/app.ts +0 -60
- package/src/lib/resources/templates/api-server/template/src/config/swagger.ts +0 -38
- package/src/lib/resources/templates/api-server/template/src/controllers/aiwfController.ts +0 -54
- package/src/lib/resources/templates/api-server/template/src/controllers/authController.ts +0 -128
- package/src/lib/resources/templates/api-server/template/src/controllers/statusController.ts +0 -28
- package/src/lib/resources/templates/api-server/template/src/index.ts +0 -28
- package/src/lib/resources/templates/api-server/template/src/middleware/aiwfMiddleware.ts +0 -50
- package/src/lib/resources/templates/api-server/template/src/middleware/authMiddleware.ts +0 -41
- package/src/lib/resources/templates/api-server/template/src/middleware/errorHandler.ts +0 -42
- package/src/lib/resources/templates/api-server/template/src/middleware/notFoundHandler.ts +0 -14
- package/src/lib/resources/templates/api-server/template/src/middleware/requestLogger.ts +0 -20
- package/src/lib/resources/templates/api-server/template/src/routes/aiwf.ts +0 -31
- package/src/lib/resources/templates/api-server/template/src/routes/index.ts +0 -13
- package/src/lib/resources/templates/api-server/template/src/routes/v1/index.ts +0 -67
- package/src/lib/resources/templates/api-server/template/src/utils/logger.ts +0 -37
- package/src/lib/resources/templates/api-server/template/tests/app.test.ts +0 -40
- package/src/lib/resources/templates/api-server/template/tsconfig.json +0 -43
- package/src/lib/resources/templates/npm-library/config.json +0 -61
- package/src/lib/resources/templates/npm-library/template/LICENSE +0 -21
- package/src/lib/resources/templates/npm-library/template/README.md +0 -201
- package/src/lib/resources/templates/npm-library/template/package.json +0 -78
- package/src/lib/resources/templates/web-app/config.json +0 -53
- package/src/lib/resources/templates/web-app/template/.aiwf/config.json +0 -54
- package/src/lib/resources/templates/web-app/template/.aiwf/feature-ledger.json +0 -37
- package/src/lib/resources/templates/web-app/template/.aiwf/personas/fullstack-developer.json +0 -40
- package/src/lib/resources/templates/web-app/template/.aiwf/scripts/cli.js +0 -110
- package/src/lib/resources/templates/web-app/template/.eslintrc.cjs +0 -20
- package/src/lib/resources/templates/web-app/template/README.md +0 -151
- package/src/lib/resources/templates/web-app/template/index.html +0 -14
- package/src/lib/resources/templates/web-app/template/package.json +0 -44
- package/src/lib/resources/templates/web-app/template/postcss.config.js +0 -6
- package/src/lib/resources/templates/web-app/template/public/vite.svg +0 -1
- package/src/lib/resources/templates/web-app/template/src/App.tsx +0 -21
- package/src/lib/resources/templates/web-app/template/src/components/Layout.tsx +0 -57
- package/src/lib/resources/templates/web-app/template/src/components/aiwf/ContextStatus.tsx +0 -107
- package/src/lib/resources/templates/web-app/template/src/components/aiwf/TokenUsage.tsx +0 -71
- package/src/lib/resources/templates/web-app/template/src/index.css +0 -60
- package/src/lib/resources/templates/web-app/template/src/main.tsx +0 -10
- package/src/lib/resources/templates/web-app/template/src/pages/AiwfDashboard.tsx +0 -57
- package/src/lib/resources/templates/web-app/template/src/pages/HomePage.tsx +0 -89
- package/src/lib/resources/templates/web-app/template/src/pages/NotFound.tsx +0 -25
- package/src/lib/resources/templates/web-app/template/src/stores/aiwfStore.ts +0 -126
- package/src/lib/resources/templates/web-app/template/src/types/global.d.ts +0 -9
- package/src/lib/resources/templates/web-app/template/src/vite-env.d.ts +0 -1
- package/src/lib/resources/templates/web-app/template/tailwind.config.js +0 -30
- package/src/lib/resources/templates/web-app/template/tsconfig.json +0 -37
- package/src/lib/resources/templates/web-app/template/tsconfig.node.json +0 -10
- package/src/lib/resources/templates/web-app/template/vite.config.ts +0 -23
- package/src/lib/resources/utils/background-monitor.js +0 -223
- package/src/lib/resources/utils/compression-metrics.js +0 -1031
- package/src/lib/resources/utils/compression-strategies.js +0 -557
- package/src/lib/resources/utils/content-normalizer.js +0 -455
- package/src/lib/resources/utils/context-compressor.js +0 -583
- package/src/lib/resources/utils/context-rule-parser.js +0 -180
- package/src/lib/resources/utils/context-token-monitor.js +0 -463
- package/src/lib/resources/utils/context-update-manager.js +0 -502
- package/src/lib/resources/utils/git-utils.js +0 -220
- package/src/lib/resources/utils/importance-classifier.js +0 -645
- package/src/lib/resources/utils/information-filter.js +0 -710
- package/src/lib/resources/utils/persona-aware-compressor.js +0 -598
- package/src/lib/resources/utils/prompt-injector.js +0 -242
- package/src/lib/resources/utils/simplified-evaluator.js +0 -119
- package/src/lib/resources/utils/text-summarizer.js +0 -492
- package/src/lib/resources/utils/token-counter.js +0 -177
- package/src/lib/resources/utils/token-monitor.js +0 -484
- package/src/lib/resources/utils/token-reporter.js +0 -452
- package/src/lib/resources/utils/token-storage.js +0 -433
- package/src/lib/resources/utils/token-tracker.js +0 -283
- package/src/lib/state/priority-calculator.js +0 -217
- package/src/lib/state/state-index.js +0 -155
- package/src/lib/state/task-scanner.js +0 -328
- package/src/lib/task-analyzer.js +0 -599
- package/src/lib/template-cache-system.js +0 -559
- package/src/lib/template-downloader.js +0 -467
- package/src/lib/template-version-manager.js +0 -491
- package/src/lib/token-optimizer.js +0 -517
- 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 };
|