telos-framework 0.1.4 → 0.3.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.
- package/.claude/agents/behavioral-transformation-agent.md +144 -0
- package/.claude/agents/command-system-agent.md +335 -0
- package/.claude/agents/completion-gate.md +71 -0
- package/.claude/agents/component-implementation-agent.md +174 -0
- package/.claude/agents/devops-agent.md +128 -0
- package/.claude/agents/dynamic-agent-creator.md +103 -0
- package/.claude/agents/enhanced-project-manager-agent.md +145 -0
- package/.claude/agents/enhanced-quality-gate.md +54 -0
- package/.claude/agents/feature-implementation-agent.md +148 -0
- package/.claude/agents/functional-testing-agent.md +51 -0
- package/.claude/agents/hook-integration-agent.md +204 -0
- package/.claude/agents/infrastructure-implementation-agent.md +175 -0
- package/.claude/agents/lib/research-analyzer.js +470 -0
- package/.claude/agents/metrics-collection-agent.md +374 -0
- package/.claude/agents/npx-package-agent.md +246 -0
- package/.claude/agents/polish-implementation-agent.md +151 -0
- package/.claude/agents/prd-agent.md +76 -0
- package/.claude/agents/prd-mvp.md +101 -0
- package/.claude/agents/prd-research-agent.md +482 -0
- package/.claude/agents/quality-agent.md +128 -0
- package/.claude/agents/readiness-gate.md +104 -0
- package/.claude/agents/research-agent.md +173 -0
- package/.claude/agents/routing-agent.md +108 -0
- package/.claude/agents/task-checker.md +163 -0
- package/.claude/agents/task-executor.md +107 -0
- package/.claude/agents/task-orchestrator.md +343 -0
- package/.claude/agents/tdd-validation-agent.md +187 -0
- package/.claude/agents/testing-implementation-agent.md +151 -0
- package/.claude/agents/van-maintenance-agent.md +64 -0
- package/.claude/agents/workflow-agent.md +87 -0
- package/.claude/commands/autocompact.md +41 -0
- package/.claude/commands/continue-handoff.md +98 -0
- package/.claude/commands/mock.md +45 -0
- package/.claude/commands/reset-handoff.md +59 -0
- package/.claude/commands/telos/init.md +326 -0
- package/.claude/commands/telos/quick.md +90 -0
- package/.claude/commands/telos/reset.md +100 -0
- package/.claude/commands/telos/status.md +170 -0
- package/.claude/commands/telos/validate.md +143 -0
- package/.claude/commands/tm/add-dependency/add-dependency.md +55 -0
- package/.claude/commands/tm/add-subtask/add-subtask.md +76 -0
- package/.claude/commands/tm/add-subtask/convert-task-to-subtask.md +71 -0
- package/.claude/commands/tm/add-task/add-task.md +78 -0
- package/.claude/commands/tm/analyze-complexity/analyze-complexity.md +121 -0
- package/.claude/commands/tm/clear-subtasks/clear-all-subtasks.md +93 -0
- package/.claude/commands/tm/clear-subtasks/clear-subtasks.md +86 -0
- package/.claude/commands/tm/complexity-report/complexity-report.md +117 -0
- package/.claude/commands/tm/expand/expand-all-tasks.md +51 -0
- package/.claude/commands/tm/expand/expand-task.md +49 -0
- package/.claude/commands/tm/fix-dependencies/fix-dependencies.md +81 -0
- package/.claude/commands/tm/generate/generate-tasks.md +121 -0
- package/.claude/commands/tm/help.md +81 -0
- package/.claude/commands/tm/init/init-project-quick.md +46 -0
- package/.claude/commands/tm/init/init-project.md +50 -0
- package/.claude/commands/tm/learn.md +103 -0
- package/.claude/commands/tm/list/list-tasks-by-status.md +39 -0
- package/.claude/commands/tm/list/list-tasks-with-subtasks.md +29 -0
- package/.claude/commands/tm/list/list-tasks.md +43 -0
- package/.claude/commands/tm/models/setup-models.md +51 -0
- package/.claude/commands/tm/models/view-models.md +51 -0
- package/.claude/commands/tm/next/next-task.md +66 -0
- package/.claude/commands/tm/parse-prd/parse-prd-with-research.md +48 -0
- package/.claude/commands/tm/parse-prd/parse-prd.md +49 -0
- package/.claude/commands/tm/remove-dependency/remove-dependency.md +62 -0
- package/.claude/commands/tm/remove-subtask/remove-subtask.md +84 -0
- package/.claude/commands/tm/remove-task/remove-task.md +107 -0
- package/.claude/commands/tm/set-status/to-cancelled.md +55 -0
- package/.claude/commands/tm/set-status/to-deferred.md +47 -0
- package/.claude/commands/tm/set-status/to-done.md +44 -0
- package/.claude/commands/tm/set-status/to-in-progress.md +36 -0
- package/.claude/commands/tm/set-status/to-pending.md +32 -0
- package/.claude/commands/tm/set-status/to-review.md +40 -0
- package/.claude/commands/tm/setup/install-taskmaster.md +117 -0
- package/.claude/commands/tm/setup/quick-install-taskmaster.md +22 -0
- package/.claude/commands/tm/show/show-task.md +82 -0
- package/.claude/commands/tm/status/project-status.md +64 -0
- package/.claude/commands/tm/sync-readme/sync-readme.md +117 -0
- package/.claude/commands/tm/tm-main.md +146 -0
- package/.claude/commands/tm/update/update-single-task.md +119 -0
- package/.claude/commands/tm/update/update-task.md +72 -0
- package/.claude/commands/tm/update/update-tasks-from-id.md +108 -0
- package/.claude/commands/tm/utils/analyze-project.md +97 -0
- package/.claude/commands/tm/validate-dependencies/validate-dependencies.md +71 -0
- package/.claude/commands/tm/workflows/auto-implement-tasks.md +97 -0
- package/.claude/commands/tm/workflows/command-pipeline.md +77 -0
- package/.claude/commands/tm/workflows/smart-workflow.md +55 -0
- package/.claude/commands/van.md +150 -0
- package/.claude/docs/README.md +214 -0
- package/.claude/docs/TROUBLESHOOTING.md +126 -0
- package/.claude/hooks/block-destructive-commands.sh +243 -0
- package/.claude/hooks/collective-metrics.sh +291 -0
- package/.claude/hooks/directive-enforcer.sh +117 -0
- package/.claude/hooks/load-behavioral-system.sh +49 -0
- package/.claude/hooks/routing-executor.sh +4 -0
- package/.claude/hooks/test-driven-handoff.sh +653 -0
- package/.claude/settings.json +125 -0
- package/README.md +39 -15
- package/lib/commands/init-state.js +102 -0
- package/lib/commands/init.js +58 -95
- package/lib/installers/memory-files.js +77 -0
- package/lib/installers/slash-commands.js +77 -0
- package/package.json +7 -2
- package/templates/AGENTS.md +79 -0
- package/templates/CLAUDE.md +54 -0
|
@@ -0,0 +1,470 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ResearchDrivenAnalyzer - Autonomous complexity analysis using Context7 research cache
|
|
3
|
+
*
|
|
4
|
+
* This class replaces task-master delegation with research-informed decision making.
|
|
5
|
+
* It analyzes tasks against cached Context7 documentation to make autonomous complexity scoring
|
|
6
|
+
* and selective expansion decisions.
|
|
7
|
+
*/
|
|
8
|
+
class ResearchDrivenAnalyzer {
|
|
9
|
+
constructor(projectRoot, cacheDirectory = '.taskmaster/docs/research/') {
|
|
10
|
+
this.projectRoot = projectRoot;
|
|
11
|
+
this.cacheDir = cacheDirectory;
|
|
12
|
+
this.researchCache = {};
|
|
13
|
+
this.complexityFactors = {
|
|
14
|
+
// React patterns from Context7
|
|
15
|
+
'custom-hooks': { weight: 3, patterns: ['useState', 'useEffect', 'useCallback', 'useMemo'] },
|
|
16
|
+
'context-api': { weight: 2, patterns: ['createContext', 'useContext', 'Provider'] },
|
|
17
|
+
'react-router': { weight: 2, patterns: ['Routes', 'Route', 'useNavigate', 'useParams'] },
|
|
18
|
+
'react-query': { weight: 3, patterns: ['useQuery', 'useMutation', 'QueryClient'] },
|
|
19
|
+
|
|
20
|
+
// TypeScript complexity from Context7
|
|
21
|
+
'typescript-generics': { weight: 4, patterns: ['<T>', 'extends', 'keyof', 'Pick', 'Omit'] },
|
|
22
|
+
'typescript-interfaces': { weight: 2, patterns: ['interface', 'type', 'Record'] },
|
|
23
|
+
'typescript-decorators': { weight: 4, patterns: ['@Component', '@Injectable', 'reflect-metadata'] },
|
|
24
|
+
|
|
25
|
+
// Build/tooling complexity from Context7
|
|
26
|
+
'vite-plugins': { weight: 3, patterns: ['defineConfig', 'plugins', 'rollupOptions'] },
|
|
27
|
+
'webpack-config': { weight: 4, patterns: ['webpack.config', 'loaders', 'plugins'] },
|
|
28
|
+
'babel-config': { weight: 3, patterns: ['.babelrc', 'babel.config', 'presets'] },
|
|
29
|
+
|
|
30
|
+
// Testing complexity from Context7
|
|
31
|
+
'vitest-mocking': { weight: 2, patterns: ['vi.mock', 'vi.spyOn', 'mockImplementation'] },
|
|
32
|
+
'jest-config': { weight: 3, patterns: ['jest.config', 'setupTests', 'testEnvironment'] },
|
|
33
|
+
'playwright-e2e': { weight: 4, patterns: ['test.describe', 'page.goto', 'expect.toHaveText'] },
|
|
34
|
+
|
|
35
|
+
// Data/state complexity from Context7
|
|
36
|
+
'state-management': { weight: 3, patterns: ['redux', 'zustand', 'jotai', 'recoil'] },
|
|
37
|
+
'database-integration': { weight: 4, patterns: ['prisma', 'typeorm', 'mongoose', 'supabase'] },
|
|
38
|
+
'api-integration': { weight: 3, patterns: ['axios', 'fetch', 'graphql', 'tRPC'] },
|
|
39
|
+
|
|
40
|
+
// Common utilities from Context7
|
|
41
|
+
'localStorage': { weight: 1, patterns: ['localStorage.setItem', 'localStorage.getItem'] },
|
|
42
|
+
'responsive-design': { weight: 2, patterns: ['@media', 'flexbox', 'grid', 'mobile-first'] },
|
|
43
|
+
'authentication': { weight: 4, patterns: ['jwt', 'oauth', 'passport', 'auth0'] },
|
|
44
|
+
'deployment': { weight: 3, patterns: ['docker', 'vercel', 'netlify', 'aws'] }
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
this.expansionThreshold = 5; // Tasks scoring > 5 need subtasks
|
|
48
|
+
this.maxSubtasks = 8; // Limit subtask explosion
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Load all research cache files into memory for analysis
|
|
53
|
+
*/
|
|
54
|
+
async loadResearchCache() {
|
|
55
|
+
try {
|
|
56
|
+
// Use LS tool to get research files
|
|
57
|
+
const researchFiles = await this.listFiles(this.cacheDir);
|
|
58
|
+
|
|
59
|
+
for (const file of researchFiles) {
|
|
60
|
+
if (file.endsWith('.md')) {
|
|
61
|
+
const content = await this.readFile(`${this.cacheDir}${file}`);
|
|
62
|
+
const technology = this.extractTechnologyFromFilename(file);
|
|
63
|
+
|
|
64
|
+
this.researchCache[technology] = {
|
|
65
|
+
file: file,
|
|
66
|
+
content: content,
|
|
67
|
+
patterns: this.extractPatternsFromResearch(content),
|
|
68
|
+
examples: this.extractCodeExamples(content),
|
|
69
|
+
lastUpdated: this.extractDateFromFilename(file)
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
console.log(`✅ Loaded research cache: ${Object.keys(this.researchCache).length} technologies`);
|
|
75
|
+
return this.researchCache;
|
|
76
|
+
} catch (error) {
|
|
77
|
+
console.error('❌ Failed to load research cache:', error);
|
|
78
|
+
return {};
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Analyze a task's complexity using loaded research cache
|
|
84
|
+
*/
|
|
85
|
+
analyzeTaskComplexity(task) {
|
|
86
|
+
let score = 0;
|
|
87
|
+
const detectedFactors = [];
|
|
88
|
+
const researchHints = [];
|
|
89
|
+
|
|
90
|
+
// Analyze task description against complexity factors
|
|
91
|
+
const taskText = `${task.title} ${task.description}`.toLowerCase();
|
|
92
|
+
|
|
93
|
+
for (const [factorName, factor] of Object.entries(this.complexityFactors)) {
|
|
94
|
+
if (this.taskInvolvesPattern(taskText, factor.patterns)) {
|
|
95
|
+
score += factor.weight;
|
|
96
|
+
detectedFactors.push({
|
|
97
|
+
factor: factorName,
|
|
98
|
+
weight: factor.weight,
|
|
99
|
+
patterns: factor.patterns.filter(p => taskText.includes(p.toLowerCase()))
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
// Add research-specific hints if we have cache for this technology
|
|
103
|
+
const relatedResearch = this.findRelatedResearch(factorName);
|
|
104
|
+
if (relatedResearch) {
|
|
105
|
+
researchHints.push({
|
|
106
|
+
factor: factorName,
|
|
107
|
+
researchFile: relatedResearch.file,
|
|
108
|
+
keyPatterns: relatedResearch.patterns.slice(0, 3) // Top 3 patterns
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
return {
|
|
115
|
+
taskId: task.id,
|
|
116
|
+
title: task.title,
|
|
117
|
+
complexityScore: score,
|
|
118
|
+
detectedFactors,
|
|
119
|
+
researchHints,
|
|
120
|
+
needsExpansion: score > this.expansionThreshold,
|
|
121
|
+
suggestedSubtasks: this.generateResearchBasedSubtasks(task, detectedFactors, researchHints),
|
|
122
|
+
researchContext: this.buildResearchContext(detectedFactors, researchHints)
|
|
123
|
+
};
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
/**
|
|
127
|
+
* Analyze all tasks and create complexity report
|
|
128
|
+
*/
|
|
129
|
+
analyzeAllTasks(tasks) {
|
|
130
|
+
const analyses = [];
|
|
131
|
+
let totalScore = 0;
|
|
132
|
+
let tasksNeedingExpansion = 0;
|
|
133
|
+
|
|
134
|
+
for (const task of tasks) {
|
|
135
|
+
const analysis = this.analyzeTaskComplexity(task);
|
|
136
|
+
analyses.push(analysis);
|
|
137
|
+
totalScore += analysis.complexityScore;
|
|
138
|
+
|
|
139
|
+
if (analysis.needsExpansion) {
|
|
140
|
+
tasksNeedingExpansion++;
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
return {
|
|
145
|
+
totalTasks: tasks.length,
|
|
146
|
+
totalComplexityScore: totalScore,
|
|
147
|
+
averageComplexity: totalScore / tasks.length,
|
|
148
|
+
tasksNeedingExpansion,
|
|
149
|
+
expansionPercentage: (tasksNeedingExpansion / tasks.length) * 100,
|
|
150
|
+
taskAnalyses: analyses,
|
|
151
|
+
researchUtilization: this.calculateResearchUtilization(analyses),
|
|
152
|
+
recommendations: this.generateRecommendations(analyses)
|
|
153
|
+
};
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
/**
|
|
157
|
+
* Generate subtasks based on research patterns
|
|
158
|
+
*/
|
|
159
|
+
generateResearchBasedSubtasks(task, detectedFactors, researchHints) {
|
|
160
|
+
const subtasks = [];
|
|
161
|
+
const maxSubtasks = Math.min(this.maxSubtasks, Math.ceil(detectedFactors.length * 1.5));
|
|
162
|
+
|
|
163
|
+
// Group factors by category for logical subtask structure
|
|
164
|
+
const categories = this.groupFactorsByCategory(detectedFactors);
|
|
165
|
+
|
|
166
|
+
for (const [category, factors] of Object.entries(categories)) {
|
|
167
|
+
const categorySubtasks = this.generateCategorySubtasks(category, factors, researchHints);
|
|
168
|
+
subtasks.push(...categorySubtasks.slice(0, 2)); // Max 2 per category
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
// Always include TDD subtasks based on research
|
|
172
|
+
if (researchHints.length > 0) {
|
|
173
|
+
subtasks.unshift({
|
|
174
|
+
type: 'testing',
|
|
175
|
+
title: `Write tests first using ${this.getTestingFrameworkFromResearch(researchHints)}`,
|
|
176
|
+
researchReference: this.getTestingResearchFile(researchHints)
|
|
177
|
+
});
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
return subtasks.slice(0, maxSubtasks);
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
/**
|
|
184
|
+
* Check if task involves specific patterns
|
|
185
|
+
*/
|
|
186
|
+
taskInvolvesPattern(taskText, patterns) {
|
|
187
|
+
return patterns.some(pattern =>
|
|
188
|
+
taskText.includes(pattern.toLowerCase()) ||
|
|
189
|
+
taskText.includes(pattern.replace(/([A-Z])/g, '-$1').toLowerCase()) ||
|
|
190
|
+
taskText.includes(pattern.replace(/([A-Z])/g, ' $1').toLowerCase())
|
|
191
|
+
);
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
/**
|
|
195
|
+
* Find related research cache for a complexity factor
|
|
196
|
+
*/
|
|
197
|
+
findRelatedResearch(factorName) {
|
|
198
|
+
// Map complexity factors to research cache
|
|
199
|
+
const researchMappings = {
|
|
200
|
+
'custom-hooks': ['react', 'react-18', 'react-hooks'],
|
|
201
|
+
'context-api': ['react', 'react-18', 'react-context'],
|
|
202
|
+
'typescript-generics': ['typescript', 'typescript-config'],
|
|
203
|
+
'vite-plugins': ['vite', 'vite-config'],
|
|
204
|
+
'vitest-mocking': ['vitest', 'vitest-testing'],
|
|
205
|
+
// Add more mappings as needed
|
|
206
|
+
};
|
|
207
|
+
|
|
208
|
+
const possibleKeys = researchMappings[factorName] || [factorName];
|
|
209
|
+
|
|
210
|
+
for (const key of possibleKeys) {
|
|
211
|
+
if (this.researchCache[key]) {
|
|
212
|
+
return this.researchCache[key];
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
return null;
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
/**
|
|
220
|
+
* Build research context object for task enhancement
|
|
221
|
+
*/
|
|
222
|
+
buildResearchContext(detectedFactors, researchHints) {
|
|
223
|
+
const requiredResearch = [...new Set(researchHints.map(hint => hint.factor))];
|
|
224
|
+
const researchFiles = [...new Set(researchHints.map(hint => hint.researchFile))];
|
|
225
|
+
const keyFindings = researchHints.flatMap(hint => hint.keyPatterns).slice(0, 5);
|
|
226
|
+
|
|
227
|
+
return {
|
|
228
|
+
required_research: requiredResearch,
|
|
229
|
+
research_files: researchFiles.map(f => `.taskmaster/docs/research/${f}`),
|
|
230
|
+
key_findings: keyFindings,
|
|
231
|
+
complexity_factors: detectedFactors.map(f => ({ factor: f.factor, weight: f.weight }))
|
|
232
|
+
};
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
/**
|
|
236
|
+
* Utility methods for file operations (would use MCP tools in practice)
|
|
237
|
+
*/
|
|
238
|
+
async listFiles(directory) {
|
|
239
|
+
// In practice, this would use LS tool
|
|
240
|
+
// For now, return mock data
|
|
241
|
+
return ['2025-01-13_react-18-patterns.md', '2025-01-13_typescript-config.md'];
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
async readFile(filePath) {
|
|
245
|
+
// In practice, this would use Read tool
|
|
246
|
+
// For now, return mock content
|
|
247
|
+
return 'Mock research content with patterns and examples';
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
extractTechnologyFromFilename(filename) {
|
|
251
|
+
// Extract technology name from filename pattern: YYYY-MM-DD_{tech}-*.md
|
|
252
|
+
const match = filename.match(/\d{4}-\d{2}-\d{2}_(.+?)-/);
|
|
253
|
+
return match ? match[1] : filename.replace('.md', '');
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
extractDateFromFilename(filename) {
|
|
257
|
+
const match = filename.match(/(\d{4}-\d{2}-\d{2})/);
|
|
258
|
+
return match ? new Date(match[1]) : new Date();
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
extractPatternsFromResearch(content) {
|
|
262
|
+
// Extract code patterns, configurations, and examples from research
|
|
263
|
+
const patterns = [];
|
|
264
|
+
|
|
265
|
+
// Extract JavaScript/TypeScript patterns
|
|
266
|
+
const codeBlocks = content.match(/```(?:javascript|typescript|jsx|tsx)\n([\s\S]*?)\n```/g) || [];
|
|
267
|
+
patterns.push(...codeBlocks);
|
|
268
|
+
|
|
269
|
+
// Extract configuration patterns
|
|
270
|
+
const configs = content.match(/```(?:json|yaml|toml)\n([\s\S]*?)\n```/g) || [];
|
|
271
|
+
patterns.push(...configs);
|
|
272
|
+
|
|
273
|
+
return patterns;
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
extractCodeExamples(content) {
|
|
277
|
+
// Extract working code examples from research
|
|
278
|
+
return this.extractPatternsFromResearch(content);
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
groupFactorsByCategory(factors) {
|
|
282
|
+
const categories = {
|
|
283
|
+
frontend: [],
|
|
284
|
+
backend: [],
|
|
285
|
+
testing: [],
|
|
286
|
+
tooling: [],
|
|
287
|
+
deployment: []
|
|
288
|
+
};
|
|
289
|
+
|
|
290
|
+
const categoryMap = {
|
|
291
|
+
'custom-hooks': 'frontend',
|
|
292
|
+
'context-api': 'frontend',
|
|
293
|
+
'react-router': 'frontend',
|
|
294
|
+
'typescript-generics': 'frontend',
|
|
295
|
+
'vitest-mocking': 'testing',
|
|
296
|
+
'jest-config': 'testing',
|
|
297
|
+
'vite-plugins': 'tooling',
|
|
298
|
+
'webpack-config': 'tooling',
|
|
299
|
+
'api-integration': 'backend',
|
|
300
|
+
'database-integration': 'backend',
|
|
301
|
+
'deployment': 'deployment'
|
|
302
|
+
};
|
|
303
|
+
|
|
304
|
+
for (const factor of factors) {
|
|
305
|
+
const category = categoryMap[factor.factor] || 'tooling';
|
|
306
|
+
categories[category].push(factor);
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
// Remove empty categories
|
|
310
|
+
Object.keys(categories).forEach(key => {
|
|
311
|
+
if (categories[key].length === 0) {
|
|
312
|
+
delete categories[key];
|
|
313
|
+
}
|
|
314
|
+
});
|
|
315
|
+
|
|
316
|
+
return categories;
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
generateCategorySubtasks(category, factors, researchHints) {
|
|
320
|
+
const subtasks = [];
|
|
321
|
+
|
|
322
|
+
switch (category) {
|
|
323
|
+
case 'frontend':
|
|
324
|
+
subtasks.push({
|
|
325
|
+
type: 'implementation',
|
|
326
|
+
title: `Implement ${factors.map(f => f.factor).join(' and ')} components`,
|
|
327
|
+
researchReference: this.getResearchFileForCategory(category, researchHints)
|
|
328
|
+
});
|
|
329
|
+
break;
|
|
330
|
+
|
|
331
|
+
case 'testing':
|
|
332
|
+
subtasks.push({
|
|
333
|
+
type: 'testing',
|
|
334
|
+
title: `Set up testing infrastructure for ${factors.map(f => f.factor).join(' and ')}`,
|
|
335
|
+
researchReference: this.getResearchFileForCategory(category, researchHints)
|
|
336
|
+
});
|
|
337
|
+
break;
|
|
338
|
+
|
|
339
|
+
case 'tooling':
|
|
340
|
+
subtasks.push({
|
|
341
|
+
type: 'configuration',
|
|
342
|
+
title: `Configure ${factors.map(f => f.factor).join(' and ')} build tools`,
|
|
343
|
+
researchReference: this.getResearchFileForCategory(category, researchHints)
|
|
344
|
+
});
|
|
345
|
+
break;
|
|
346
|
+
|
|
347
|
+
default:
|
|
348
|
+
subtasks.push({
|
|
349
|
+
type: 'implementation',
|
|
350
|
+
title: `Implement ${factors.map(f => f.factor).join(' and ')}`,
|
|
351
|
+
researchReference: this.getResearchFileForCategory(category, researchHints)
|
|
352
|
+
});
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
return subtasks;
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
getTestingFrameworkFromResearch(researchHints) {
|
|
359
|
+
const testingFrameworks = ['vitest', 'jest', 'playwright', 'cypress'];
|
|
360
|
+
|
|
361
|
+
for (const hint of researchHints) {
|
|
362
|
+
for (const framework of testingFrameworks) {
|
|
363
|
+
if (hint.factor.includes(framework)) {
|
|
364
|
+
return framework;
|
|
365
|
+
}
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
return 'vitest'; // Default
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
getTestingResearchFile(researchHints) {
|
|
373
|
+
for (const hint of researchHints) {
|
|
374
|
+
if (hint.factor.includes('test') || hint.factor.includes('mock')) {
|
|
375
|
+
return hint.researchFile;
|
|
376
|
+
}
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
return null;
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
getResearchFileForCategory(category, researchHints) {
|
|
383
|
+
// Return the most relevant research file for the category
|
|
384
|
+
return researchHints.length > 0 ? researchHints[0].researchFile : null;
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
calculateResearchUtilization(analyses) {
|
|
388
|
+
let totalFactors = 0;
|
|
389
|
+
let researchBackedFactors = 0;
|
|
390
|
+
|
|
391
|
+
for (const analysis of analyses) {
|
|
392
|
+
totalFactors += analysis.detectedFactors.length;
|
|
393
|
+
researchBackedFactors += analysis.researchHints.length;
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
return {
|
|
397
|
+
totalFactors,
|
|
398
|
+
researchBackedFactors,
|
|
399
|
+
utilizationPercentage: totalFactors > 0 ? (researchBackedFactors / totalFactors) * 100 : 0
|
|
400
|
+
};
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
generateRecommendations(analyses) {
|
|
404
|
+
const recommendations = [];
|
|
405
|
+
|
|
406
|
+
// High complexity tasks
|
|
407
|
+
const highComplexityTasks = analyses.filter(a => a.complexityScore > 8);
|
|
408
|
+
if (highComplexityTasks.length > 0) {
|
|
409
|
+
recommendations.push({
|
|
410
|
+
type: 'high_complexity',
|
|
411
|
+
message: `${highComplexityTasks.length} tasks have high complexity (>8). Consider breaking them down further.`,
|
|
412
|
+
tasks: highComplexityTasks.map(t => ({ id: t.taskId, score: t.complexityScore }))
|
|
413
|
+
});
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
// Missing research coverage
|
|
417
|
+
const lowResearchCoverage = analyses.filter(a => a.detectedFactors.length > a.researchHints.length);
|
|
418
|
+
if (lowResearchCoverage.length > 0) {
|
|
419
|
+
recommendations.push({
|
|
420
|
+
type: 'missing_research',
|
|
421
|
+
message: `${lowResearchCoverage.length} tasks could benefit from additional Context7 research.`,
|
|
422
|
+
tasks: lowResearchCoverage.map(t => t.taskId)
|
|
423
|
+
});
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
// Expansion recommendations
|
|
427
|
+
const expansionCandidates = analyses.filter(a => a.needsExpansion);
|
|
428
|
+
if (expansionCandidates.length > 0) {
|
|
429
|
+
recommendations.push({
|
|
430
|
+
type: 'expansion_needed',
|
|
431
|
+
message: `${expansionCandidates.length} tasks need subtask expansion based on complexity.`,
|
|
432
|
+
tasks: expansionCandidates.map(t => ({
|
|
433
|
+
id: t.taskId,
|
|
434
|
+
score: t.complexityScore,
|
|
435
|
+
subtaskCount: t.suggestedSubtasks.length
|
|
436
|
+
}))
|
|
437
|
+
});
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
return recommendations;
|
|
441
|
+
}
|
|
442
|
+
}
|
|
443
|
+
|
|
444
|
+
// Export for use in agent
|
|
445
|
+
if (typeof module !== 'undefined' && module.exports) {
|
|
446
|
+
module.exports = ResearchDrivenAnalyzer;
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
/**
|
|
450
|
+
* USAGE EXAMPLE:
|
|
451
|
+
*
|
|
452
|
+
* const analyzer = new ResearchDrivenAnalyzer('/project/root');
|
|
453
|
+
* await analyzer.loadResearchCache();
|
|
454
|
+
*
|
|
455
|
+
* const tasks = [
|
|
456
|
+
* { id: "1", title: "Create React hooks", description: "Build custom hooks with useState and useEffect" },
|
|
457
|
+
* { id: "2", title: "Setup TypeScript", description: "Configure TypeScript with generics and interfaces" }
|
|
458
|
+
* ];
|
|
459
|
+
*
|
|
460
|
+
* const report = analyzer.analyzeAllTasks(tasks);
|
|
461
|
+
* console.log('Complexity Report:', report);
|
|
462
|
+
*
|
|
463
|
+
* // Use results to enhance tasks with research context
|
|
464
|
+
* for (const analysis of report.taskAnalyses) {
|
|
465
|
+
* if (analysis.needsExpansion) {
|
|
466
|
+
* // Expand task using analysis.suggestedSubtasks
|
|
467
|
+
* // Update task with analysis.researchContext
|
|
468
|
+
* }
|
|
469
|
+
* }
|
|
470
|
+
*/
|