create-byan-agent 2.0.1 → 2.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/API-BYAN-V2.md +741 -0
- package/BMAD-QUICK-REFERENCE.md +370 -0
- package/CHANGELOG-v2.1.0.md +371 -0
- package/LICENSE +1 -1
- package/MIGRATION-v2.0-to-v2.1.md +430 -0
- package/README-BYAN-V2.md +446 -0
- package/README.md +264 -201
- package/install/.eslintrc.js +20 -0
- package/install/.prettierrc +7 -0
- package/install/BUGFIX-CHALK.md +173 -0
- package/install/BUGFIX-DOCUMENTATION-INDEX.md +299 -0
- package/install/BUGFIX-PATH-RESOLUTION.md +293 -0
- package/install/BUGFIX-QUICKSTART.md +184 -0
- package/install/BUGFIX-SUMMARY.txt +91 -0
- package/install/BUGFIX-VISUAL-SUMMARY.md +253 -0
- package/install/DEPLOYMENT-GUIDE-V2.md +431 -0
- package/install/DOCS-INDEX.md +261 -0
- package/install/GUIDE-INSTALLATION-BYAN-SIMPLE.md +1083 -0
- package/install/INSTALLER-V2-CHANGES.md +472 -0
- package/install/LICENSE +21 -0
- package/install/PUBLICATION-CHECKLIST.md +265 -0
- package/install/PUBLISH-GUIDE.md +190 -0
- package/install/QUICKSTART.md +311 -0
- package/install/README-NPM-PUBLISH.md +298 -0
- package/install/README-NPM-SHORT.md +298 -0
- package/install/README-NPM.md +433 -0
- package/install/README-RACHID.md +302 -0
- package/install/README-V2-INDEX.md +306 -0
- package/install/README.md +298 -0
- package/install/RESUME-EXECUTIF-YAN.md +408 -0
- package/install/UPDATE-SUMMARY.md +205 -0
- package/install/__tests__/integration/detection-flow.test.js +154 -0
- package/install/__tests__/platforms/claude-code.test.js +175 -0
- package/install/__tests__/platforms/codex.test.js +80 -0
- package/install/__tests__/platforms/copilot-cli.test.js +118 -0
- package/install/__tests__/platforms/vscode.test.js +67 -0
- package/install/__tests__/utils/file-utils.test.js +87 -0
- package/install/__tests__/utils/git-detector.test.js +80 -0
- package/install/__tests__/utils/logger.test.js +83 -0
- package/install/__tests__/utils/node-detector.test.js +71 -0
- package/install/__tests__/utils/os-detector.test.js +63 -0
- package/install/__tests__/utils/yaml-utils.test.js +85 -0
- package/install/__tests__/yanstaller/detector.test.js +210 -0
- package/install/coverage/clover.xml +219 -0
- package/install/coverage/coverage-final.json +13 -0
- package/install/coverage/lcov-report/base.css +224 -0
- package/install/coverage/lcov-report/block-navigation.js +87 -0
- package/install/coverage/lcov-report/favicon.png +0 -0
- package/install/coverage/lcov-report/index.html +146 -0
- package/install/coverage/lcov-report/lib/errors.js.html +268 -0
- package/install/coverage/lcov-report/lib/exit-codes.js.html +247 -0
- package/install/coverage/lcov-report/lib/index.html +131 -0
- package/install/coverage/lcov-report/lib/platforms/claude-code.js.html +343 -0
- package/install/coverage/lcov-report/lib/platforms/codex.js.html +361 -0
- package/install/coverage/lcov-report/lib/platforms/copilot-cli.js.html +454 -0
- package/install/coverage/lcov-report/lib/platforms/index.html +176 -0
- package/install/coverage/lcov-report/lib/platforms/index.js.html +127 -0
- package/install/coverage/lcov-report/lib/platforms/vscode.js.html +238 -0
- package/install/coverage/lcov-report/lib/utils/config-loader.js.html +322 -0
- package/install/coverage/lcov-report/lib/utils/file-utils.js.html +397 -0
- package/install/coverage/lcov-report/lib/utils/git-detector.js.html +190 -0
- package/install/coverage/lcov-report/lib/utils/index.html +206 -0
- package/install/coverage/lcov-report/lib/utils/logger.js.html +277 -0
- package/install/coverage/lcov-report/lib/utils/node-detector.js.html +259 -0
- package/install/coverage/lcov-report/lib/utils/os-detector.js.html +307 -0
- package/install/coverage/lcov-report/lib/utils/yaml-utils.js.html +346 -0
- package/install/coverage/lcov-report/lib/yanstaller/backuper.js.html +409 -0
- package/install/coverage/lcov-report/lib/yanstaller/detector.js.html +508 -0
- package/install/coverage/lcov-report/lib/yanstaller/index.html +236 -0
- package/install/coverage/lcov-report/lib/yanstaller/index.js.html +364 -0
- package/install/coverage/lcov-report/lib/yanstaller/installer.js.html +505 -0
- package/install/coverage/lcov-report/lib/yanstaller/interviewer.js.html +349 -0
- package/install/coverage/lcov-report/lib/yanstaller/recommender.js.html +379 -0
- package/install/coverage/lcov-report/lib/yanstaller/troubleshooter.js.html +352 -0
- package/install/coverage/lcov-report/lib/yanstaller/validator.js.html +679 -0
- package/install/coverage/lcov-report/lib/yanstaller/wizard.js.html +412 -0
- package/install/coverage/lcov-report/platforms/claude-code.js.html +343 -0
- package/install/coverage/lcov-report/platforms/codex.js.html +361 -0
- package/install/coverage/lcov-report/platforms/copilot-cli.js.html +454 -0
- package/install/coverage/lcov-report/platforms/index.html +176 -0
- package/install/coverage/lcov-report/platforms/index.js.html +127 -0
- package/install/coverage/lcov-report/platforms/vscode.js.html +238 -0
- package/install/coverage/lcov-report/prettify.css +1 -0
- package/install/coverage/lcov-report/prettify.js +2 -0
- package/install/coverage/lcov-report/sort-arrow-sprite.png +0 -0
- package/install/coverage/lcov-report/sorter.js +210 -0
- package/install/coverage/lcov-report/utils/file-utils.js.html +397 -0
- package/install/coverage/lcov-report/utils/git-detector.js.html +190 -0
- package/install/coverage/lcov-report/utils/index.html +191 -0
- package/install/coverage/lcov-report/utils/logger.js.html +277 -0
- package/install/coverage/lcov-report/utils/node-detector.js.html +259 -0
- package/install/coverage/lcov-report/utils/os-detector.js.html +307 -0
- package/install/coverage/lcov-report/utils/yaml-utils.js.html +346 -0
- package/install/coverage/lcov-report/yanstaller/detector.js.html +508 -0
- package/install/coverage/lcov-report/yanstaller/index.html +116 -0
- package/install/coverage/lcov.info +414 -0
- package/install/install.sh +239 -0
- package/install/jest.config.js +33 -0
- package/install/lib/errors.js +61 -0
- package/install/lib/exit-codes.js +54 -0
- package/install/lib/platforms/claude-code.js +86 -0
- package/install/lib/platforms/codex.js +92 -0
- package/install/lib/platforms/copilot-cli.js +123 -0
- package/install/lib/platforms/index.js +14 -0
- package/install/lib/platforms/vscode.js +51 -0
- package/install/lib/utils/config-loader.js +79 -0
- package/install/lib/utils/file-utils.js +104 -0
- package/install/lib/utils/git-detector.js +35 -0
- package/install/lib/utils/logger.js +64 -0
- package/install/lib/utils/node-detector.js +58 -0
- package/install/lib/utils/os-detector.js +74 -0
- package/install/lib/utils/yaml-utils.js +87 -0
- package/install/lib/yanstaller/backuper.js +108 -0
- package/install/lib/yanstaller/detector.js +141 -0
- package/install/lib/yanstaller/index.js +93 -0
- package/install/lib/yanstaller/installer.js +140 -0
- package/install/lib/yanstaller/interviewer.js +88 -0
- package/install/lib/yanstaller/recommender.js +98 -0
- package/install/lib/yanstaller/troubleshooter.js +89 -0
- package/install/lib/yanstaller/validator.js +198 -0
- package/install/lib/yanstaller/wizard.js +109 -0
- package/install/package-npm.json +55 -0
- package/install/package.json +63 -0
- package/install/src/byan-v2/context/copilot-context.js +79 -0
- package/install/src/byan-v2/context/session-state.js +98 -0
- package/install/src/byan-v2/dispatcher/complexity-scorer.js +232 -0
- package/install/src/byan-v2/dispatcher/local-executor.js +221 -0
- package/install/src/byan-v2/dispatcher/task-router.js +122 -0
- package/install/src/byan-v2/dispatcher/task-tool-interface-mock.js +134 -0
- package/install/src/byan-v2/dispatcher/task-tool-interface.js +123 -0
- package/install/src/byan-v2/generation/agent-profile-validator.js +113 -0
- package/install/src/byan-v2/generation/profile-template.js +113 -0
- package/install/src/byan-v2/generation/templates/default-agent.md +49 -0
- package/install/src/byan-v2/generation/templates/test-template.md +1 -0
- package/install/src/byan-v2/index.js +199 -0
- package/install/src/byan-v2/observability/error-tracker.js +105 -0
- package/install/src/byan-v2/observability/logger.js +154 -0
- package/install/src/byan-v2/observability/metrics-collector.js +194 -0
- package/install/src/byan-v2/orchestrator/analysis-state.js +268 -0
- package/install/src/byan-v2/orchestrator/generation-state.js +340 -0
- package/install/src/byan-v2/orchestrator/interview-state.js +271 -0
- package/install/src/byan-v2/orchestrator/state-machine.js +204 -0
- package/install/src/core/cache/cache.js +126 -0
- package/install/src/core/context/context.js +86 -0
- package/install/src/core/dispatcher/dispatcher.js +135 -0
- package/install/src/core/worker-pool/worker-pool.js +194 -0
- package/install/src/core/workflow/workflow-executor.js +220 -0
- package/install/src/index.js +139 -0
- package/install/src/observability/dashboard/dashboard.js +191 -0
- package/install/src/observability/logger/structured-logger.js +254 -0
- package/install/src/observability/metrics/metrics-collector.js +325 -0
- package/install/switch-to-v2.sh +126 -0
- package/install/test-chalk-fix.sh +210 -0
- package/install/test-installer-v2.sh +204 -0
- package/install/test-path-resolution.sh +200 -0
- package/package.json +53 -33
- package/src/byan-v2/context/copilot-context.js +79 -0
- package/src/byan-v2/context/session-state.js +98 -0
- package/src/byan-v2/data/mantras.json +852 -0
- package/src/byan-v2/dispatcher/complexity-scorer.js +232 -0
- package/src/byan-v2/dispatcher/five-whys-analyzer.js +310 -0
- package/src/byan-v2/dispatcher/local-executor.js +221 -0
- package/src/byan-v2/dispatcher/task-router.js +122 -0
- package/src/byan-v2/dispatcher/task-tool-interface-mock.js +134 -0
- package/src/byan-v2/dispatcher/task-tool-interface.js +123 -0
- package/src/byan-v2/generation/agent-profile-validator.js +113 -0
- package/src/byan-v2/generation/mantra-validator.js +416 -0
- package/src/byan-v2/generation/profile-template.js +113 -0
- package/src/byan-v2/generation/templates/default-agent.md +49 -0
- package/src/byan-v2/generation/templates/test-template.md +1 -0
- package/src/byan-v2/index.js +652 -0
- package/src/byan-v2/integration/voice-integration.js +295 -0
- package/src/byan-v2/observability/error-tracker.js +105 -0
- package/src/byan-v2/observability/logger.js +154 -0
- package/src/byan-v2/observability/metrics-collector.js +194 -0
- package/src/byan-v2/orchestrator/active-listener.js +541 -0
- package/src/byan-v2/orchestrator/analysis-state.js +268 -0
- package/src/byan-v2/orchestrator/generation-state.js +340 -0
- package/src/byan-v2/orchestrator/glossary-builder.js +431 -0
- package/src/byan-v2/orchestrator/interview-state.js +353 -0
- package/src/byan-v2/orchestrator/state-machine.js +253 -0
- package/src/core/cache/cache.js +126 -0
- package/src/core/context/context.js +86 -0
- package/src/core/dispatcher/dispatcher.js +135 -0
- package/src/core/worker-pool/worker-pool.js +194 -0
- package/src/core/workflow/workflow-executor.js +220 -0
- package/src/index.js +139 -0
- package/src/observability/dashboard/dashboard.js +191 -0
- package/src/observability/logger/structured-logger.js +254 -0
- package/src/observability/metrics/metrics-collector.js +325 -0
- package/templates/.github/agents/bmad-agent-test-dynamic.md +0 -21
- package/templates/.github/agents/franck.md +0 -379
- /package/{CHANGELOG.md → install/CHANGELOG.md} +0 -0
- /package/{bin → install/bin}/create-byan-agent-backup.js +0 -0
- /package/{bin → install/bin}/create-byan-agent-fixed.js +0 -0
- /package/{bin → install/bin}/create-byan-agent-v2.js +0 -0
- /package/{bin → install/bin}/create-byan-agent.js +0 -0
- /package/{templates → install/templates}/.github/agents/bmad-agent-bmad-master.md +0 -0
- /package/{templates → install/templates}/.github/agents/bmad-agent-bmb-agent-builder.md +0 -0
- /package/{templates → install/templates}/.github/agents/bmad-agent-bmb-module-builder.md +0 -0
- /package/{templates → install/templates}/.github/agents/bmad-agent-bmb-workflow-builder.md +0 -0
- /package/{templates → install/templates}/.github/agents/bmad-agent-bmm-analyst.md +0 -0
- /package/{templates → install/templates}/.github/agents/bmad-agent-bmm-architect.md +0 -0
- /package/{templates → install/templates}/.github/agents/bmad-agent-bmm-dev.md +0 -0
- /package/{templates → install/templates}/.github/agents/bmad-agent-bmm-pm.md +0 -0
- /package/{templates → install/templates}/.github/agents/bmad-agent-bmm-quick-flow-solo-dev.md +0 -0
- /package/{templates → install/templates}/.github/agents/bmad-agent-bmm-quinn.md +0 -0
- /package/{templates → install/templates}/.github/agents/bmad-agent-bmm-sm.md +0 -0
- /package/{templates → install/templates}/.github/agents/bmad-agent-bmm-tech-writer.md +0 -0
- /package/{templates → install/templates}/.github/agents/bmad-agent-bmm-ux-designer.md +0 -0
- /package/{templates → install/templates}/.github/agents/bmad-agent-byan-test.md +0 -0
- /package/{templates → install/templates}/.github/agents/bmad-agent-byan.md +0 -0
- /package/{templates → install/templates}/.github/agents/bmad-agent-carmack.md +0 -0
- /package/{templates → install/templates}/.github/agents/bmad-agent-cis-brainstorming-coach.md +0 -0
- /package/{templates → install/templates}/.github/agents/bmad-agent-cis-creative-problem-solver.md +0 -0
- /package/{templates → install/templates}/.github/agents/bmad-agent-cis-design-thinking-coach.md +0 -0
- /package/{templates → install/templates}/.github/agents/bmad-agent-cis-innovation-strategist.md +0 -0
- /package/{templates → install/templates}/.github/agents/bmad-agent-cis-presentation-master.md +0 -0
- /package/{templates → install/templates}/.github/agents/bmad-agent-cis-storyteller.md +0 -0
- /package/{templates → install/templates}/.github/agents/bmad-agent-marc.md +0 -0
- /package/{templates → install/templates}/.github/agents/bmad-agent-patnote.md +0 -0
- /package/{templates → install/templates}/.github/agents/bmad-agent-rachid.md +0 -0
- /package/{templates → install/templates}/.github/agents/bmad-agent-tea-tea.md +0 -0
- /package/{templates → install/templates}/_bmad/bmb/agents/agent-builder.md +0 -0
- /package/{templates → install/templates}/_bmad/bmb/agents/byan-test.md +0 -0
- /package/{templates → install/templates}/_bmad/bmb/agents/byan.md +0 -0
- /package/{templates → install/templates}/_bmad/bmb/agents/marc.md +0 -0
- /package/{templates → install/templates}/_bmad/bmb/agents/module-builder.md +0 -0
- /package/{templates → install/templates}/_bmad/bmb/agents/patnote.md +0 -0
- /package/{templates → install/templates}/_bmad/bmb/agents/rachid.md +0 -0
- /package/{templates → install/templates}/_bmad/bmb/agents/workflow-builder.md +0 -0
- /package/{templates → install/templates}/_bmad/bmb/workflows/byan/data/mantras.yaml +0 -0
- /package/{templates → install/templates}/_bmad/bmb/workflows/byan/data/templates.yaml +0 -0
- /package/{templates → install/templates}/_bmad/bmb/workflows/byan/delete-agent-workflow.md +0 -0
- /package/{templates → install/templates}/_bmad/bmb/workflows/byan/edit-agent-workflow.md +0 -0
- /package/{templates → install/templates}/_bmad/bmb/workflows/byan/interview-workflow.md +0 -0
- /package/{templates → install/templates}/_bmad/bmb/workflows/byan/quick-create-workflow.md +0 -0
- /package/{templates → install/templates}/_bmad/bmb/workflows/byan/templates/base-agent-template.md +0 -0
- /package/{templates → install/templates}/_bmad/bmb/workflows/byan/validate-agent-workflow.md +0 -0
- /package/{templates → install/templates}/_bmad/core/agents/carmack.md +0 -0
|
@@ -0,0 +1,232 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ComplexityScorer - Calculate task complexity score (0-100)
|
|
3
|
+
*
|
|
4
|
+
* Scoring factors:
|
|
5
|
+
* - Factor 1: Token count (max 30 points)
|
|
6
|
+
* - Factor 2: Task type (max 80 points)
|
|
7
|
+
* - Factor 3: Context size (max 20 points)
|
|
8
|
+
* - Factor 4: Keywords (max 25 points)
|
|
9
|
+
*
|
|
10
|
+
* Total score is capped at 100 points.
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
class ComplexityScorer {
|
|
14
|
+
constructor() {
|
|
15
|
+
// Task type patterns with base scores
|
|
16
|
+
this.taskTypePatterns = {
|
|
17
|
+
exploration: {
|
|
18
|
+
keywords: ['explore', 'find', 'list', 'show', 'search', 'get', 'read', 'view', 'display', 'check'],
|
|
19
|
+
baseScore: 15
|
|
20
|
+
},
|
|
21
|
+
implementation: {
|
|
22
|
+
keywords: ['implement', 'create', 'build', 'write', 'develop', 'code', 'add', 'generate'],
|
|
23
|
+
baseScore: 45
|
|
24
|
+
},
|
|
25
|
+
analysis: {
|
|
26
|
+
keywords: ['analyze', 'design', 'architect', 'evaluate', 'review', 'assess', 'plan', 'strategy'],
|
|
27
|
+
baseScore: 75
|
|
28
|
+
}
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
// Keyword complexity weights
|
|
32
|
+
this.keywordWeights = {
|
|
33
|
+
simple: {
|
|
34
|
+
keywords: ['list', 'show', 'find', 'get', 'read', 'basic', 'simple'],
|
|
35
|
+
score: 7
|
|
36
|
+
},
|
|
37
|
+
medium: {
|
|
38
|
+
keywords: ['refactor', 'optimize', 'implement', 'integrate', 'update', 'modify'],
|
|
39
|
+
score: 17
|
|
40
|
+
},
|
|
41
|
+
critical: {
|
|
42
|
+
keywords: ['security', 'performance', 'architecture', 'scalability', 'critical', 'mission-critical'],
|
|
43
|
+
score: 25
|
|
44
|
+
}
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Calculate overall complexity score for a task
|
|
50
|
+
* @param {Object} task - Task object with prompt and context
|
|
51
|
+
* @returns {number} - Complexity score (0-100)
|
|
52
|
+
*/
|
|
53
|
+
calculateComplexity(task) {
|
|
54
|
+
if (!task || !task.prompt || task.prompt.trim() === '') {
|
|
55
|
+
throw new Error('prompt is required');
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
const tokenScore = this._calculateTokenScore(task.prompt);
|
|
59
|
+
const taskTypeScore = this._calculateTaskTypeScore(task);
|
|
60
|
+
const contextScore = this._calculateContextScore(task.context || {});
|
|
61
|
+
const keywordScore = this._calculateKeywordScore(task.prompt);
|
|
62
|
+
|
|
63
|
+
// Combine scores (token + type + context + keyword)
|
|
64
|
+
// Note: These can theoretically exceed 100, so we cap it
|
|
65
|
+
const totalScore = tokenScore + taskTypeScore + contextScore + keywordScore;
|
|
66
|
+
|
|
67
|
+
return Math.min(100, Math.max(0, totalScore));
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Factor 1: Token count scoring (max 30 points)
|
|
72
|
+
* < 10 tokens: 0 points
|
|
73
|
+
* 10-200 tokens: scale linearly 0-30
|
|
74
|
+
* > 200 tokens: 30 points
|
|
75
|
+
*/
|
|
76
|
+
_calculateTokenScore(prompt) {
|
|
77
|
+
const tokenCount = this._estimateTokenCount(prompt);
|
|
78
|
+
|
|
79
|
+
if (tokenCount < 10) return 0;
|
|
80
|
+
if (tokenCount >= 200) return 30;
|
|
81
|
+
|
|
82
|
+
// Linear scaling between 10 and 200 tokens
|
|
83
|
+
return Math.round((tokenCount - 10) / 190 * 30);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Estimate token count (simple word-based approximation)
|
|
88
|
+
*/
|
|
89
|
+
_estimateTokenCount(text) {
|
|
90
|
+
return text.trim().split(/\s+/).length;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* Factor 2: Task type scoring (max 80 points)
|
|
95
|
+
*/
|
|
96
|
+
_calculateTaskTypeScore(task) {
|
|
97
|
+
const prompt = task.prompt.toLowerCase();
|
|
98
|
+
|
|
99
|
+
// Check explicit type if provided
|
|
100
|
+
if (task.type) {
|
|
101
|
+
const typeMap = {
|
|
102
|
+
'exploration': 15,
|
|
103
|
+
'implementation': 45,
|
|
104
|
+
'analysis': 75
|
|
105
|
+
};
|
|
106
|
+
return typeMap[task.type] || 45;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
// Infer type from keywords
|
|
110
|
+
for (const [typeName, typeData] of Object.entries(this.taskTypePatterns)) {
|
|
111
|
+
const hasKeyword = typeData.keywords.some(keyword => {
|
|
112
|
+
const regex = new RegExp(`\\b${keyword}\\b`, 'i');
|
|
113
|
+
return regex.test(prompt);
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
if (hasKeyword) {
|
|
117
|
+
return typeData.baseScore;
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
// Default to medium complexity if no pattern matches
|
|
122
|
+
return 45;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
/**
|
|
126
|
+
* Factor 3: Context size scoring (max 20 points)
|
|
127
|
+
*/
|
|
128
|
+
_calculateContextScore(context) {
|
|
129
|
+
if (!context || Object.keys(context).length === 0) {
|
|
130
|
+
return 0;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
// Calculate context complexity based on:
|
|
134
|
+
// - Number of top-level keys
|
|
135
|
+
// - Depth of nesting
|
|
136
|
+
// - Total property count
|
|
137
|
+
|
|
138
|
+
const propertyCount = this._countProperties(context);
|
|
139
|
+
const nestingDepth = this._calculateNestingDepth(context);
|
|
140
|
+
const topLevelKeys = Object.keys(context).length;
|
|
141
|
+
|
|
142
|
+
// Scoring formula:
|
|
143
|
+
// - Small context (< 5 properties): 5-10 points
|
|
144
|
+
// - Medium context (5-15 properties): 10-15 points
|
|
145
|
+
// - Large context (> 15 properties): 15-20 points
|
|
146
|
+
|
|
147
|
+
let score = 0;
|
|
148
|
+
|
|
149
|
+
if (propertyCount < 5) {
|
|
150
|
+
score = 7;
|
|
151
|
+
} else if (propertyCount < 15) {
|
|
152
|
+
score = 12;
|
|
153
|
+
} else {
|
|
154
|
+
score = 17;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
// Add bonus for deep nesting (max +3)
|
|
158
|
+
if (nestingDepth > 2) {
|
|
159
|
+
score += Math.min(3, nestingDepth - 2);
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
return Math.min(20, score);
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
/**
|
|
166
|
+
* Count total properties in an object (including nested)
|
|
167
|
+
*/
|
|
168
|
+
_countProperties(obj, visited = new Set()) {
|
|
169
|
+
if (!obj || typeof obj !== 'object' || visited.has(obj)) {
|
|
170
|
+
return 0;
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
visited.add(obj);
|
|
174
|
+
let count = 0;
|
|
175
|
+
|
|
176
|
+
for (const key in obj) {
|
|
177
|
+
if (obj.hasOwnProperty(key)) {
|
|
178
|
+
count++;
|
|
179
|
+
if (typeof obj[key] === 'object' && obj[key] !== null) {
|
|
180
|
+
count += this._countProperties(obj[key], visited);
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
return count;
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
/**
|
|
189
|
+
* Calculate maximum nesting depth of an object
|
|
190
|
+
*/
|
|
191
|
+
_calculateNestingDepth(obj, visited = new Set()) {
|
|
192
|
+
if (!obj || typeof obj !== 'object' || visited.has(obj)) {
|
|
193
|
+
return 0;
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
visited.add(obj);
|
|
197
|
+
let maxDepth = 0;
|
|
198
|
+
|
|
199
|
+
for (const key in obj) {
|
|
200
|
+
if (obj.hasOwnProperty(key) && typeof obj[key] === 'object' && obj[key] !== null) {
|
|
201
|
+
const depth = this._calculateNestingDepth(obj[key], visited);
|
|
202
|
+
maxDepth = Math.max(maxDepth, depth);
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
return maxDepth + 1;
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
/**
|
|
210
|
+
* Factor 4: Keyword scoring (max 25 points)
|
|
211
|
+
*/
|
|
212
|
+
_calculateKeywordScore(prompt) {
|
|
213
|
+
const promptLower = prompt.toLowerCase();
|
|
214
|
+
let maxScore = 0;
|
|
215
|
+
|
|
216
|
+
// Check each keyword category (take highest matching score)
|
|
217
|
+
for (const [category, data] of Object.entries(this.keywordWeights)) {
|
|
218
|
+
const hasKeyword = data.keywords.some(keyword => {
|
|
219
|
+
const regex = new RegExp(`\\b${keyword}\\b`, 'i');
|
|
220
|
+
return regex.test(promptLower);
|
|
221
|
+
});
|
|
222
|
+
|
|
223
|
+
if (hasKeyword) {
|
|
224
|
+
maxScore = Math.max(maxScore, data.score);
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
return maxScore;
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
module.exports = ComplexityScorer;
|
|
@@ -0,0 +1,310 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* FiveWhysAnalyzer - Root cause analysis through 5 WHYs technique
|
|
3
|
+
*
|
|
4
|
+
* MANTRAS: KISS, DRY, SOLID, Zero Emoji (IA-23)
|
|
5
|
+
*
|
|
6
|
+
* Features:
|
|
7
|
+
* - Pain point detection in user responses
|
|
8
|
+
* - Sequential WHY questioning (1-5 depth)
|
|
9
|
+
* - Root cause extraction
|
|
10
|
+
* - Analysis export with metadata
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
const Logger = require('../observability/logger');
|
|
14
|
+
|
|
15
|
+
class FiveWhysAnalyzer {
|
|
16
|
+
constructor(sessionState, logger) {
|
|
17
|
+
this.sessionState = sessionState;
|
|
18
|
+
this.logger = logger || new Logger({ logDir: 'logs', logFile: 'five-whys.log' });
|
|
19
|
+
|
|
20
|
+
this.depth = 0;
|
|
21
|
+
this.maxDepth = 5;
|
|
22
|
+
this.responses = [];
|
|
23
|
+
this.painPoints = [];
|
|
24
|
+
this.rootCause = null;
|
|
25
|
+
this.active = false;
|
|
26
|
+
|
|
27
|
+
this.painKeywords = [
|
|
28
|
+
'problem', 'issue', 'challenge', 'difficult', 'slow', 'complex',
|
|
29
|
+
'error', 'fail', 'break', 'bug', 'struggle', 'hard', 'confusing',
|
|
30
|
+
'frustrating', 'annoying', 'painful', 'blocking', 'stuck'
|
|
31
|
+
];
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
start(initialResponse) {
|
|
35
|
+
if (!initialResponse || typeof initialResponse !== 'string') {
|
|
36
|
+
return { needsWhys: false, reason: 'Invalid response' };
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
const detected = this._detectPainPoints(initialResponse);
|
|
40
|
+
|
|
41
|
+
if (!detected.hasPainPoints) {
|
|
42
|
+
this.logger.info('No pain points detected', { response: initialResponse.substring(0, 100) });
|
|
43
|
+
return { needsWhys: false, reason: 'No pain points detected' };
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
this.active = true;
|
|
47
|
+
this.painPoints = detected.painPoints;
|
|
48
|
+
this.responses.push({
|
|
49
|
+
depth: 0,
|
|
50
|
+
question: 'initial',
|
|
51
|
+
answer: initialResponse,
|
|
52
|
+
painPoints: detected.painPoints
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
this.logger.info('5 Whys started', { painPoints: detected.painPoints });
|
|
56
|
+
|
|
57
|
+
return {
|
|
58
|
+
needsWhys: true,
|
|
59
|
+
painPoints: detected.painPoints,
|
|
60
|
+
firstQuestion: this.askNext()
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
_detectPainPoints(text) {
|
|
65
|
+
const lowerText = text.toLowerCase();
|
|
66
|
+
const foundPoints = [];
|
|
67
|
+
|
|
68
|
+
for (const keyword of this.painKeywords) {
|
|
69
|
+
if (lowerText.includes(keyword)) {
|
|
70
|
+
const index = lowerText.indexOf(keyword);
|
|
71
|
+
const context = text.substring(Math.max(0, index - 20), Math.min(text.length, index + 50));
|
|
72
|
+
foundPoints.push({ keyword, context: context.trim() });
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
return {
|
|
77
|
+
hasPainPoints: foundPoints.length > 0,
|
|
78
|
+
painPoints: foundPoints,
|
|
79
|
+
confidence: Math.min(1.0, foundPoints.length / 3)
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
askNext() {
|
|
84
|
+
if (!this.active) {
|
|
85
|
+
return null;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
if (this.depth >= this.maxDepth) {
|
|
89
|
+
return null;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
this.depth++;
|
|
93
|
+
|
|
94
|
+
const questions = [
|
|
95
|
+
'Why is this a problem for you?',
|
|
96
|
+
'Why does this happen?',
|
|
97
|
+
'Why is that the case?',
|
|
98
|
+
'Why does that matter?',
|
|
99
|
+
'What is the underlying reason?'
|
|
100
|
+
];
|
|
101
|
+
|
|
102
|
+
const question = this.depth === 1
|
|
103
|
+
? 'Why is this a problem for you?'
|
|
104
|
+
: questions[Math.min(this.depth - 1, questions.length - 1)];
|
|
105
|
+
|
|
106
|
+
return {
|
|
107
|
+
depth: this.depth,
|
|
108
|
+
question,
|
|
109
|
+
prompt: `${question} (${this.depth}/5)`
|
|
110
|
+
};
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
processAnswer(answer) {
|
|
114
|
+
if (!this.active) {
|
|
115
|
+
return { valid: false, reason: 'Analyzer not active' };
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
if (!answer || typeof answer !== 'string' || answer.trim().length < 10) {
|
|
119
|
+
return { valid: false, reason: 'Answer too short or invalid' };
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
this.responses.push({
|
|
123
|
+
depth: this.depth,
|
|
124
|
+
question: `Why #${this.depth}`,
|
|
125
|
+
answer: answer.trim(),
|
|
126
|
+
timestamp: new Date().toISOString()
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
const rootCauseAnalysis = this._analyzeForRootCause(answer);
|
|
130
|
+
|
|
131
|
+
if (rootCauseAnalysis.isRootCause && this.depth >= 3) {
|
|
132
|
+
this.rootCause = rootCauseAnalysis;
|
|
133
|
+
this.active = false;
|
|
134
|
+
this.logger.info('Root cause identified early', {
|
|
135
|
+
depth: this.depth,
|
|
136
|
+
rootCause: rootCauseAnalysis.statement
|
|
137
|
+
});
|
|
138
|
+
|
|
139
|
+
return {
|
|
140
|
+
valid: true,
|
|
141
|
+
rootCauseFound: true,
|
|
142
|
+
analysis: rootCauseAnalysis,
|
|
143
|
+
nextQuestion: null
|
|
144
|
+
};
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
if (this.depth >= this.maxDepth) {
|
|
148
|
+
this.rootCause = this._extractRootCause();
|
|
149
|
+
this.active = false;
|
|
150
|
+
this.logger.info('5 Whys completed', {
|
|
151
|
+
depth: this.depth,
|
|
152
|
+
rootCause: this.rootCause.statement
|
|
153
|
+
});
|
|
154
|
+
|
|
155
|
+
return {
|
|
156
|
+
valid: true,
|
|
157
|
+
completed: true,
|
|
158
|
+
rootCause: this.rootCause,
|
|
159
|
+
nextQuestion: null
|
|
160
|
+
};
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
return {
|
|
164
|
+
valid: true,
|
|
165
|
+
nextQuestion: this.askNext()
|
|
166
|
+
};
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
_analyzeForRootCause(answer) {
|
|
170
|
+
const lowerAnswer = answer.toLowerCase();
|
|
171
|
+
|
|
172
|
+
const rootCauseIndicators = [
|
|
173
|
+
'because', 'fundamental', 'core', 'underlying', 'root',
|
|
174
|
+
'lack of', 'missing', 'no process', 'no system', 'unclear',
|
|
175
|
+
'not defined', 'never', 'always', 'since beginning'
|
|
176
|
+
];
|
|
177
|
+
|
|
178
|
+
let indicatorCount = 0;
|
|
179
|
+
for (const indicator of rootCauseIndicators) {
|
|
180
|
+
if (lowerAnswer.includes(indicator)) {
|
|
181
|
+
indicatorCount++;
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
const isRootCause = indicatorCount >= 2 || (indicatorCount >= 1 && answer.length > 100);
|
|
186
|
+
const confidence = Math.min(1.0, (indicatorCount * 0.3) + (answer.length / 500));
|
|
187
|
+
|
|
188
|
+
return {
|
|
189
|
+
isRootCause,
|
|
190
|
+
confidence,
|
|
191
|
+
statement: answer.trim(),
|
|
192
|
+
depth: this.depth,
|
|
193
|
+
indicators: indicatorCount
|
|
194
|
+
};
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
_extractRootCause() {
|
|
198
|
+
if (this.responses.length < 2) {
|
|
199
|
+
return {
|
|
200
|
+
statement: 'Insufficient data for root cause analysis',
|
|
201
|
+
confidence: 0.0,
|
|
202
|
+
category: 'unknown',
|
|
203
|
+
actionItems: []
|
|
204
|
+
};
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
const lastResponses = this.responses.slice(-2);
|
|
208
|
+
const deepestAnswer = lastResponses[lastResponses.length - 1].answer;
|
|
209
|
+
|
|
210
|
+
const category = this._categorizeRootCause(deepestAnswer);
|
|
211
|
+
const actionItems = this._extractActionItems(deepestAnswer);
|
|
212
|
+
const confidence = this._calculateConfidence(this.depth, deepestAnswer);
|
|
213
|
+
|
|
214
|
+
return {
|
|
215
|
+
statement: deepestAnswer,
|
|
216
|
+
confidence,
|
|
217
|
+
category,
|
|
218
|
+
actionItems,
|
|
219
|
+
depth: this.depth
|
|
220
|
+
};
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
_categorizeRootCause(statement) {
|
|
224
|
+
const lowerStatement = statement.toLowerCase();
|
|
225
|
+
|
|
226
|
+
const categories = {
|
|
227
|
+
technical: ['code', 'system', 'software', 'hardware', 'infrastructure', 'api', 'database'],
|
|
228
|
+
process: ['process', 'workflow', 'procedure', 'method', 'approach', 'way we'],
|
|
229
|
+
resource: ['time', 'money', 'budget', 'people', 'team', 'resource', 'capacity'],
|
|
230
|
+
knowledge: ['know', 'understand', 'learn', 'training', 'documentation', 'experience', 'skill']
|
|
231
|
+
};
|
|
232
|
+
|
|
233
|
+
for (const [category, keywords] of Object.entries(categories)) {
|
|
234
|
+
for (const keyword of keywords) {
|
|
235
|
+
if (lowerStatement.includes(keyword)) {
|
|
236
|
+
return category;
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
return 'general';
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
_extractActionItems(statement) {
|
|
245
|
+
const actionKeywords = [
|
|
246
|
+
'need to', 'should', 'must', 'have to', 'require',
|
|
247
|
+
'implement', 'create', 'build', 'fix', 'improve'
|
|
248
|
+
];
|
|
249
|
+
|
|
250
|
+
const sentences = statement.split(/[.!?]+/).filter(s => s.trim().length > 0);
|
|
251
|
+
const actions = [];
|
|
252
|
+
|
|
253
|
+
for (const sentence of sentences) {
|
|
254
|
+
const lowerSentence = sentence.toLowerCase();
|
|
255
|
+
for (const keyword of actionKeywords) {
|
|
256
|
+
if (lowerSentence.includes(keyword)) {
|
|
257
|
+
actions.push(sentence.trim());
|
|
258
|
+
break;
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
return actions.slice(0, 3);
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
_calculateConfidence(depth, statement) {
|
|
267
|
+
let confidence = 0.5;
|
|
268
|
+
|
|
269
|
+
confidence += (depth / this.maxDepth) * 0.3;
|
|
270
|
+
|
|
271
|
+
if (statement.length > 50) confidence += 0.1;
|
|
272
|
+
if (statement.length > 100) confidence += 0.1;
|
|
273
|
+
|
|
274
|
+
return Math.min(1.0, confidence);
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
isComplete() {
|
|
278
|
+
return !this.active;
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
getRootCause() {
|
|
282
|
+
return this.rootCause;
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
getDepth() {
|
|
286
|
+
return this.depth;
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
getResponses() {
|
|
290
|
+
return [...this.responses];
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
export() {
|
|
294
|
+
return {
|
|
295
|
+
version: '1.0.0',
|
|
296
|
+
createdAt: new Date().toISOString(),
|
|
297
|
+
painPoints: this.painPoints,
|
|
298
|
+
depth: this.depth,
|
|
299
|
+
responses: this.responses,
|
|
300
|
+
rootCause: this.rootCause,
|
|
301
|
+
metadata: {
|
|
302
|
+
completed: this.isComplete(),
|
|
303
|
+
maxDepth: this.maxDepth,
|
|
304
|
+
responseCount: this.responses.length
|
|
305
|
+
}
|
|
306
|
+
};
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
module.exports = FiveWhysAnalyzer;
|