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,541 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ActiveListener - Reformulates and validates user understanding
|
|
3
|
+
* Mantra IA-23: Zero emojis
|
|
4
|
+
*
|
|
5
|
+
* Principles: KISS, DRY, SOLID
|
|
6
|
+
* Performance target: < 100ms per reformulation
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
const Logger = require('../observability/logger');
|
|
10
|
+
|
|
11
|
+
class ActiveListener {
|
|
12
|
+
constructor(sessionState, logger = null) {
|
|
13
|
+
this.sessionState = sessionState;
|
|
14
|
+
this.logger = logger || new Logger('active-listener');
|
|
15
|
+
this.history = [];
|
|
16
|
+
this.validationFrequency = 3; // Ask for validation every N responses
|
|
17
|
+
this.responseCount = 0;
|
|
18
|
+
this.clarityThresholdMin = 0.0;
|
|
19
|
+
this.clarityThresholdMax = 1.0;
|
|
20
|
+
|
|
21
|
+
// Filler words to remove
|
|
22
|
+
this.fillerWords = [
|
|
23
|
+
'um', 'uh', 'like', 'you know', 'i mean', 'sort of', 'kind of',
|
|
24
|
+
'basically', 'actually', 'literally', 'really', 'very', 'just',
|
|
25
|
+
'maybe', 'probably', 'perhaps', 'i guess', 'i think'
|
|
26
|
+
];
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Process user response through active listening workflow
|
|
31
|
+
* @param {string} userResponse - Raw user input
|
|
32
|
+
* @returns {Object} Listening result with reformulation and summary
|
|
33
|
+
*/
|
|
34
|
+
listen(userResponse) {
|
|
35
|
+
const startTime = Date.now();
|
|
36
|
+
|
|
37
|
+
if (!userResponse || typeof userResponse !== 'string') {
|
|
38
|
+
return {
|
|
39
|
+
valid: false,
|
|
40
|
+
error: 'Invalid input: response must be a non-empty string'
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
this.logger.info('Processing user response', { length: userResponse.length });
|
|
45
|
+
|
|
46
|
+
const trimmed = userResponse.trim();
|
|
47
|
+
if (trimmed.length === 0) {
|
|
48
|
+
return {
|
|
49
|
+
valid: false,
|
|
50
|
+
error: 'Invalid input: response cannot be empty'
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
// Reformulate the response
|
|
55
|
+
const reformulated = this.reformulate(trimmed);
|
|
56
|
+
|
|
57
|
+
// Extract key points
|
|
58
|
+
const keyPoints = this.extractKeyPoints(reformulated.text);
|
|
59
|
+
|
|
60
|
+
// Generate summary
|
|
61
|
+
const summary = this.generateSummary(keyPoints);
|
|
62
|
+
|
|
63
|
+
// Track in history
|
|
64
|
+
this.responseCount++;
|
|
65
|
+
const record = {
|
|
66
|
+
original: trimmed,
|
|
67
|
+
reformulated: reformulated.text,
|
|
68
|
+
clarityScore: reformulated.clarityScore,
|
|
69
|
+
keyPoints: keyPoints,
|
|
70
|
+
summary: summary,
|
|
71
|
+
timestamp: Date.now(),
|
|
72
|
+
needsValidation: this.needsValidation()
|
|
73
|
+
};
|
|
74
|
+
this.history.push(record);
|
|
75
|
+
|
|
76
|
+
const duration = Date.now() - startTime;
|
|
77
|
+
this.logger.info('Response processed', {
|
|
78
|
+
duration: duration,
|
|
79
|
+
clarityScore: reformulated.clarityScore,
|
|
80
|
+
keyPointsCount: keyPoints.length
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
return {
|
|
84
|
+
valid: true,
|
|
85
|
+
reformulated: reformulated.text,
|
|
86
|
+
clarityScore: reformulated.clarityScore,
|
|
87
|
+
keyPoints: keyPoints,
|
|
88
|
+
summary: summary,
|
|
89
|
+
needsValidation: record.needsValidation,
|
|
90
|
+
processingTime: duration
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* Reformulate text in clear, simple language
|
|
96
|
+
* @param {string} text - Text to reformulate
|
|
97
|
+
* @returns {Object} Reformulated text with clarity score
|
|
98
|
+
*/
|
|
99
|
+
reformulate(text) {
|
|
100
|
+
if (!text || typeof text !== 'string') {
|
|
101
|
+
return { text: '', clarityScore: 0.0 };
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
let improved = text.trim();
|
|
105
|
+
let improvementScore = 0;
|
|
106
|
+
const maxImprovements = 5;
|
|
107
|
+
|
|
108
|
+
// 1. Remove filler words
|
|
109
|
+
const beforeFillers = improved;
|
|
110
|
+
improved = this._removeFiller(improved);
|
|
111
|
+
if (improved !== beforeFillers) improvementScore++;
|
|
112
|
+
|
|
113
|
+
// 2. Convert to active voice (basic patterns)
|
|
114
|
+
const beforeVoice = improved;
|
|
115
|
+
improved = this._toActiveVoice(improved);
|
|
116
|
+
if (improved !== beforeVoice) improvementScore++;
|
|
117
|
+
|
|
118
|
+
// 3. Simplify complex sentences
|
|
119
|
+
const beforeSimplify = improved;
|
|
120
|
+
improved = this._simplifyComplexSentences(improved);
|
|
121
|
+
if (improved !== beforeSimplify) improvementScore++;
|
|
122
|
+
|
|
123
|
+
// 4. Remove redundancy
|
|
124
|
+
const beforeRedundancy = improved;
|
|
125
|
+
improved = this._removeRedundancy(improved);
|
|
126
|
+
if (improved !== beforeRedundancy) improvementScore++;
|
|
127
|
+
|
|
128
|
+
// 5. Normalize whitespace
|
|
129
|
+
const beforeWhitespace = improved;
|
|
130
|
+
improved = this._normalizeWhitespace(improved);
|
|
131
|
+
if (improved !== beforeWhitespace) improvementScore++;
|
|
132
|
+
|
|
133
|
+
// Calculate clarity score
|
|
134
|
+
const clarityScore = this._calculateClarityScore(text, improved, improvementScore, maxImprovements);
|
|
135
|
+
|
|
136
|
+
return {
|
|
137
|
+
text: improved,
|
|
138
|
+
clarityScore: clarityScore
|
|
139
|
+
};
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
* Extract 3-5 key points from text
|
|
144
|
+
* @param {string} text - Text to analyze
|
|
145
|
+
* @returns {Array<string>} Key points (3-5 items)
|
|
146
|
+
*/
|
|
147
|
+
extractKeyPoints(text) {
|
|
148
|
+
if (!text || typeof text !== 'string' || text.trim().length === 0) {
|
|
149
|
+
return [];
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
// Split into sentences
|
|
153
|
+
const sentences = this._splitIntoSentences(text);
|
|
154
|
+
|
|
155
|
+
if (sentences.length === 0) {
|
|
156
|
+
return [];
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
// For short texts, return all sentences (max 5)
|
|
160
|
+
if (sentences.length <= 5) {
|
|
161
|
+
return sentences.slice(0, 5);
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
// For longer texts, score and select top sentences
|
|
165
|
+
const scoredSentences = sentences.map(sentence => ({
|
|
166
|
+
text: sentence,
|
|
167
|
+
score: this._scoreSentenceImportance(sentence, sentences)
|
|
168
|
+
}));
|
|
169
|
+
|
|
170
|
+
// Sort by score and take top 5
|
|
171
|
+
scoredSentences.sort((a, b) => b.score - a.score);
|
|
172
|
+
|
|
173
|
+
// Return 3-5 points based on content density
|
|
174
|
+
const pointCount = Math.min(5, Math.max(3, Math.ceil(sentences.length / 3)));
|
|
175
|
+
return scoredSentences.slice(0, pointCount).map(s => s.text);
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
/**
|
|
179
|
+
* Generate "So if I understand correctly..." summary
|
|
180
|
+
* @param {Array<string>} keyPoints - Key points to summarize
|
|
181
|
+
* @returns {string} Summary with validation question
|
|
182
|
+
*/
|
|
183
|
+
generateSummary(keyPoints) {
|
|
184
|
+
if (!Array.isArray(keyPoints) || keyPoints.length === 0) {
|
|
185
|
+
return 'So if I understand correctly, you have not provided enough information yet. Could you elaborate?';
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
// Combine key points into cohesive narrative
|
|
189
|
+
let narrative = '';
|
|
190
|
+
|
|
191
|
+
if (keyPoints.length === 1) {
|
|
192
|
+
narrative = keyPoints[0];
|
|
193
|
+
} else if (keyPoints.length === 2) {
|
|
194
|
+
narrative = `${keyPoints[0]} Additionally, ${this._lowercaseFirst(keyPoints[1])}`;
|
|
195
|
+
} else {
|
|
196
|
+
// First point
|
|
197
|
+
narrative = keyPoints[0];
|
|
198
|
+
|
|
199
|
+
// Middle points
|
|
200
|
+
for (let i = 1; i < keyPoints.length - 1; i++) {
|
|
201
|
+
narrative += ` ${this._lowercaseFirst(keyPoints[i])}`;
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
// Last point
|
|
205
|
+
narrative += ` Finally, ${this._lowercaseFirst(keyPoints[keyPoints.length - 1])}`;
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
return `So if I understand correctly, ${this._lowercaseFirst(narrative)} Is that accurate?`;
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
/**
|
|
212
|
+
* Check if validation is needed based on frequency
|
|
213
|
+
* @returns {boolean} True if validation should be requested
|
|
214
|
+
*/
|
|
215
|
+
needsValidation() {
|
|
216
|
+
return this.responseCount % this.validationFrequency === 0;
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
/**
|
|
220
|
+
* Process user's validation response
|
|
221
|
+
* @param {boolean|string} userConfirmation - User's yes/no response
|
|
222
|
+
* @param {string} summary - The summary being validated
|
|
223
|
+
* @returns {Object} Validation result
|
|
224
|
+
*/
|
|
225
|
+
validateUnderstanding(userConfirmation, summary) {
|
|
226
|
+
const confirmed = this._parseConfirmation(userConfirmation);
|
|
227
|
+
const needsCorrection = !confirmed && userConfirmation !== true && userConfirmation !== false;
|
|
228
|
+
|
|
229
|
+
const result = {
|
|
230
|
+
validated: confirmed,
|
|
231
|
+
needsCorrection: needsCorrection && !confirmed,
|
|
232
|
+
ambiguous: !confirmed && !needsCorrection,
|
|
233
|
+
timestamp: Date.now(),
|
|
234
|
+
summary: summary,
|
|
235
|
+
clarificationPrompt: needsCorrection ? 'Please clarify what I misunderstood so I can correct my understanding.' : null
|
|
236
|
+
};
|
|
237
|
+
|
|
238
|
+
// Update last history entry with validation result
|
|
239
|
+
if (this.history.length > 0) {
|
|
240
|
+
this.history[this.history.length - 1].validationResult = result;
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
this.logger.info('Understanding validated', { validated: confirmed, needsCorrection: needsCorrection });
|
|
244
|
+
|
|
245
|
+
return result;
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
/**
|
|
249
|
+
* Process correction from user when understanding was wrong
|
|
250
|
+
* @param {string} correction - User's correction text
|
|
251
|
+
* @returns {Object} Correction result with updated summary
|
|
252
|
+
*/
|
|
253
|
+
processCorrection(correction) {
|
|
254
|
+
if (!correction || typeof correction !== 'string') {
|
|
255
|
+
return { updated: false, error: 'Invalid correction' };
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
const reformulated = this.reformulate(correction);
|
|
259
|
+
const keyPoints = this.extractKeyPoints(reformulated.text);
|
|
260
|
+
const newSummary = this.generateSummary(keyPoints);
|
|
261
|
+
|
|
262
|
+
this.history.push({
|
|
263
|
+
original: correction,
|
|
264
|
+
reformulated: reformulated.text,
|
|
265
|
+
clarityScore: reformulated.clarityScore,
|
|
266
|
+
keyPoints: keyPoints,
|
|
267
|
+
summary: newSummary,
|
|
268
|
+
timestamp: Date.now(),
|
|
269
|
+
isCorrection: true
|
|
270
|
+
});
|
|
271
|
+
|
|
272
|
+
this.logger.info('Correction processed', { correctionLength: correction.length });
|
|
273
|
+
|
|
274
|
+
return {
|
|
275
|
+
updated: true,
|
|
276
|
+
reformulated: reformulated.text,
|
|
277
|
+
newSummary: newSummary,
|
|
278
|
+
keyPoints: keyPoints
|
|
279
|
+
};
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
/**
|
|
283
|
+
* Get consolidated summary from all responses
|
|
284
|
+
* @returns {string} Comprehensive summary
|
|
285
|
+
*/
|
|
286
|
+
generateConsolidatedSummary() {
|
|
287
|
+
if (this.history.length === 0) {
|
|
288
|
+
return 'No information collected yet.';
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
const allKeyPoints = [];
|
|
292
|
+
this.history.forEach(record => {
|
|
293
|
+
if (record.keyPoints && record.keyPoints.length > 0) {
|
|
294
|
+
allKeyPoints.push(...record.keyPoints);
|
|
295
|
+
}
|
|
296
|
+
});
|
|
297
|
+
|
|
298
|
+
// Remove duplicates and keep most relevant
|
|
299
|
+
const uniquePoints = [...new Set(allKeyPoints)].slice(0, 5);
|
|
300
|
+
|
|
301
|
+
return this.generateSummary(uniquePoints);
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
/**
|
|
305
|
+
* Get specific history record by index
|
|
306
|
+
* @param {number} index - Index of the record
|
|
307
|
+
* @returns {Object} History record
|
|
308
|
+
*/
|
|
309
|
+
getHistoryRecord(index) {
|
|
310
|
+
if (index < 0 || index >= this.history.length) {
|
|
311
|
+
return null;
|
|
312
|
+
}
|
|
313
|
+
return this.history[index];
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
/**
|
|
317
|
+
* Export listening session data
|
|
318
|
+
* @returns {Object} Complete session export
|
|
319
|
+
*/
|
|
320
|
+
export() {
|
|
321
|
+
return {
|
|
322
|
+
totalResponses: this.responseCount,
|
|
323
|
+
history: this.history,
|
|
324
|
+
summary: this.generateConsolidatedSummary(),
|
|
325
|
+
averageClarityScore: this._calculateAverageClarityScore(),
|
|
326
|
+
validationFrequency: this.validationFrequency,
|
|
327
|
+
exportTimestamp: Date.now(),
|
|
328
|
+
metadata: {
|
|
329
|
+
sessionId: this.sessionState?.sessionId || 'unknown',
|
|
330
|
+
totalResponses: this.responseCount,
|
|
331
|
+
validationFrequency: this.validationFrequency,
|
|
332
|
+
exportedAt: new Date().toISOString()
|
|
333
|
+
}
|
|
334
|
+
};
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
/**
|
|
338
|
+
* Export as markdown format
|
|
339
|
+
* @returns {string} Markdown formatted export
|
|
340
|
+
*/
|
|
341
|
+
exportAsMarkdown() {
|
|
342
|
+
const lines = [
|
|
343
|
+
'# Active Listening Session',
|
|
344
|
+
'',
|
|
345
|
+
`**Total Responses:** ${this.responseCount}`,
|
|
346
|
+
`**Average Clarity Score:** ${(this._calculateAverageClarityScore() * 100).toFixed(1)}%`,
|
|
347
|
+
'',
|
|
348
|
+
'## Summary',
|
|
349
|
+
'',
|
|
350
|
+
this.generateConsolidatedSummary(),
|
|
351
|
+
'',
|
|
352
|
+
'## Responses',
|
|
353
|
+
''
|
|
354
|
+
];
|
|
355
|
+
|
|
356
|
+
this.history.forEach((record, index) => {
|
|
357
|
+
lines.push(`### Response ${index + 1}`);
|
|
358
|
+
lines.push('');
|
|
359
|
+
lines.push(`**Original:** ${record.original}`);
|
|
360
|
+
lines.push('');
|
|
361
|
+
lines.push(`**Reformulated:** ${record.reformulated}`);
|
|
362
|
+
lines.push('');
|
|
363
|
+
lines.push(`**Clarity Score:** ${(record.clarityScore * 100).toFixed(1)}%`);
|
|
364
|
+
lines.push('');
|
|
365
|
+
if (record.keyPoints && record.keyPoints.length > 0) {
|
|
366
|
+
lines.push('**Key Points:**');
|
|
367
|
+
record.keyPoints.forEach(kp => lines.push(`- ${kp}`));
|
|
368
|
+
lines.push('');
|
|
369
|
+
}
|
|
370
|
+
});
|
|
371
|
+
|
|
372
|
+
return lines.join('\n');
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
/**
|
|
376
|
+
* Export as JSON format
|
|
377
|
+
* @returns {string} JSON formatted export
|
|
378
|
+
*/
|
|
379
|
+
exportAsJSON() {
|
|
380
|
+
return JSON.stringify(this.export(), null, 2);
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
// Private helper methods
|
|
384
|
+
|
|
385
|
+
_removeFiller(text) {
|
|
386
|
+
let result = text;
|
|
387
|
+
|
|
388
|
+
this.fillerWords.forEach(filler => {
|
|
389
|
+
const pattern = new RegExp(`\\b${filler}\\b,?\\s*`, 'gi');
|
|
390
|
+
result = result.replace(pattern, '');
|
|
391
|
+
});
|
|
392
|
+
|
|
393
|
+
return result;
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
_toActiveVoice(text) {
|
|
397
|
+
// Basic passive to active voice conversions
|
|
398
|
+
const patterns = [
|
|
399
|
+
{ passive: /was (\w+ed) by/gi, active: (match, verb) => verb },
|
|
400
|
+
{ passive: /were (\w+ed) by/gi, active: (match, verb) => verb },
|
|
401
|
+
{ passive: /is being (\w+ed)/gi, active: (match, verb) => verb },
|
|
402
|
+
{ passive: /has been (\w+ed)/gi, active: (match, verb) => verb }
|
|
403
|
+
];
|
|
404
|
+
|
|
405
|
+
let result = text;
|
|
406
|
+
patterns.forEach(({ passive }) => {
|
|
407
|
+
result = result.replace(passive, '');
|
|
408
|
+
});
|
|
409
|
+
|
|
410
|
+
return result;
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
_simplifyComplexSentences(text) {
|
|
414
|
+
// Replace complex conjunctions with simpler ones
|
|
415
|
+
let result = text;
|
|
416
|
+
|
|
417
|
+
const replacements = {
|
|
418
|
+
'in order to': 'to',
|
|
419
|
+
'due to the fact that': 'because',
|
|
420
|
+
'in the event that': 'if',
|
|
421
|
+
'at this point in time': 'now',
|
|
422
|
+
'for the purpose of': 'for',
|
|
423
|
+
'in spite of': 'despite',
|
|
424
|
+
'on the basis of': 'based on'
|
|
425
|
+
};
|
|
426
|
+
|
|
427
|
+
Object.entries(replacements).forEach(([complex, simple]) => {
|
|
428
|
+
const pattern = new RegExp(complex, 'gi');
|
|
429
|
+
result = result.replace(pattern, simple);
|
|
430
|
+
});
|
|
431
|
+
|
|
432
|
+
return result;
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
_removeRedundancy(text) {
|
|
436
|
+
// Remove repeated words
|
|
437
|
+
const words = text.split(/\s+/);
|
|
438
|
+
const filtered = [];
|
|
439
|
+
let previous = null;
|
|
440
|
+
|
|
441
|
+
words.forEach(word => {
|
|
442
|
+
const normalized = word.toLowerCase().replace(/[.,!?;:]$/, '');
|
|
443
|
+
if (normalized !== previous) {
|
|
444
|
+
filtered.push(word);
|
|
445
|
+
previous = normalized;
|
|
446
|
+
}
|
|
447
|
+
});
|
|
448
|
+
|
|
449
|
+
return filtered.join(' ');
|
|
450
|
+
}
|
|
451
|
+
|
|
452
|
+
_normalizeWhitespace(text) {
|
|
453
|
+
return text
|
|
454
|
+
.replace(/\s+/g, ' ')
|
|
455
|
+
.replace(/\s+([.,!?;:])/g, '$1')
|
|
456
|
+
.trim();
|
|
457
|
+
}
|
|
458
|
+
|
|
459
|
+
_calculateClarityScore(original, improved, improvementScore, maxImprovements) {
|
|
460
|
+
// Base score from improvements made
|
|
461
|
+
const improvementRatio = improvementScore / maxImprovements;
|
|
462
|
+
|
|
463
|
+
// Length reduction bonus (shorter is often clearer)
|
|
464
|
+
const lengthReduction = Math.max(0, (original.length - improved.length) / original.length);
|
|
465
|
+
|
|
466
|
+
// Combined score
|
|
467
|
+
const score = (improvementRatio * 0.7) + (lengthReduction * 0.3);
|
|
468
|
+
|
|
469
|
+
// Normalize to 0.0-1.0 range
|
|
470
|
+
return Math.max(this.clarityThresholdMin, Math.min(this.clarityThresholdMax, score));
|
|
471
|
+
}
|
|
472
|
+
|
|
473
|
+
_splitIntoSentences(text) {
|
|
474
|
+
// Split on sentence boundaries
|
|
475
|
+
const sentences = text
|
|
476
|
+
.split(/[.!?]+/)
|
|
477
|
+
.map(s => s.trim())
|
|
478
|
+
.filter(s => s.length > 0);
|
|
479
|
+
|
|
480
|
+
return sentences;
|
|
481
|
+
}
|
|
482
|
+
|
|
483
|
+
_scoreSentenceImportance(sentence, allSentences) {
|
|
484
|
+
let score = 0;
|
|
485
|
+
|
|
486
|
+
// Longer sentences often contain more information
|
|
487
|
+
score += Math.min(10, sentence.length / 10);
|
|
488
|
+
|
|
489
|
+
// First and last sentences are often important
|
|
490
|
+
const index = allSentences.indexOf(sentence);
|
|
491
|
+
if (index === 0 || index === allSentences.length - 1) {
|
|
492
|
+
score += 5;
|
|
493
|
+
}
|
|
494
|
+
|
|
495
|
+
// Sentences with numbers or specific terms
|
|
496
|
+
if (/\d+/.test(sentence)) {
|
|
497
|
+
score += 3;
|
|
498
|
+
}
|
|
499
|
+
|
|
500
|
+
// Sentences with key business terms
|
|
501
|
+
const keyTerms = ['need', 'want', 'require', 'must', 'should', 'important', 'critical', 'essential'];
|
|
502
|
+
keyTerms.forEach(term => {
|
|
503
|
+
if (sentence.toLowerCase().includes(term)) {
|
|
504
|
+
score += 2;
|
|
505
|
+
}
|
|
506
|
+
});
|
|
507
|
+
|
|
508
|
+
return score;
|
|
509
|
+
}
|
|
510
|
+
|
|
511
|
+
_lowercaseFirst(text) {
|
|
512
|
+
if (!text || text.length === 0) return text;
|
|
513
|
+
return text.charAt(0).toLowerCase() + text.slice(1);
|
|
514
|
+
}
|
|
515
|
+
|
|
516
|
+
_parseConfirmation(input) {
|
|
517
|
+
if (typeof input === 'boolean') {
|
|
518
|
+
return input;
|
|
519
|
+
}
|
|
520
|
+
|
|
521
|
+
if (typeof input === 'string') {
|
|
522
|
+
const normalized = input.toLowerCase().trim();
|
|
523
|
+
const positive = ['yes', 'y', 'yeah', 'yep', 'correct', 'right', 'true', 'ok', 'okay'];
|
|
524
|
+
const negative = ['no', 'n', 'nope', 'incorrect', 'wrong', 'false'];
|
|
525
|
+
|
|
526
|
+
if (positive.includes(normalized)) return true;
|
|
527
|
+
if (negative.includes(normalized)) return false;
|
|
528
|
+
}
|
|
529
|
+
|
|
530
|
+
return false;
|
|
531
|
+
}
|
|
532
|
+
|
|
533
|
+
_calculateAverageClarityScore() {
|
|
534
|
+
if (this.history.length === 0) return 0.0;
|
|
535
|
+
|
|
536
|
+
const sum = this.history.reduce((acc, record) => acc + record.clarityScore, 0);
|
|
537
|
+
return sum / this.history.length;
|
|
538
|
+
}
|
|
539
|
+
}
|
|
540
|
+
|
|
541
|
+
module.exports = ActiveListener;
|