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,268 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AnalysisState - Story 4.3
|
|
3
|
+
* Analyzes interview responses to extract structured requirements
|
|
4
|
+
*
|
|
5
|
+
* Integrates:
|
|
6
|
+
* - TaskRouter: Route tasks based on complexity
|
|
7
|
+
* - LocalExecutor: Execute high-complexity analysis
|
|
8
|
+
* - Logger: Log analysis steps
|
|
9
|
+
* - SessionState: Store analysis results
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
const TaskRouter = require('../dispatcher/task-router');
|
|
13
|
+
const LocalExecutor = require('../dispatcher/local-executor');
|
|
14
|
+
const Logger = require('../observability/logger');
|
|
15
|
+
|
|
16
|
+
class AnalysisState {
|
|
17
|
+
constructor(sessionState) {
|
|
18
|
+
this.sessionState = sessionState;
|
|
19
|
+
this.taskRouter = new TaskRouter();
|
|
20
|
+
this.localExecutor = new LocalExecutor();
|
|
21
|
+
this.logger = new Logger();
|
|
22
|
+
|
|
23
|
+
this.analysisComplete = false;
|
|
24
|
+
this.requirements = null;
|
|
25
|
+
this.patterns = null;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* AC2: Extract requirements from user responses
|
|
30
|
+
* Identifies: purpose, capabilities, knowledgeAreas, constraints
|
|
31
|
+
*
|
|
32
|
+
* @returns {Promise<Object>} Extracted requirements
|
|
33
|
+
*/
|
|
34
|
+
async extractRequirements() {
|
|
35
|
+
this.logger.info('Analysis started: extracting requirements', {
|
|
36
|
+
responseCount: this.sessionState.userResponses.length
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
// Prepare analysis task
|
|
40
|
+
const responsesText = this.sessionState.userResponses
|
|
41
|
+
.map((r, i) => `Response ${i + 1}: ${r.response}`)
|
|
42
|
+
.join('\n');
|
|
43
|
+
|
|
44
|
+
const analysisTask = {
|
|
45
|
+
type: 'analysis',
|
|
46
|
+
prompt: `Extract structured requirements from these user responses:
|
|
47
|
+
|
|
48
|
+
${responsesText}
|
|
49
|
+
|
|
50
|
+
Extract and return JSON with:
|
|
51
|
+
- purpose: Main goal/purpose of the agent
|
|
52
|
+
- capabilities: Array of specific capabilities needed
|
|
53
|
+
- knowledgeAreas: Array of knowledge domains required
|
|
54
|
+
- constraints: Array of constraints or limitations`,
|
|
55
|
+
metadata: {
|
|
56
|
+
requiresReasoning: true,
|
|
57
|
+
requiresMultipleSteps: true,
|
|
58
|
+
estimatedDuration: 'medium'
|
|
59
|
+
}
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
// AC6: Route through TaskRouter (complexity-based delegation)
|
|
63
|
+
const routing = this.taskRouter.routeTask(analysisTask);
|
|
64
|
+
|
|
65
|
+
this.logger.info('Task routed', {
|
|
66
|
+
executor: routing.executor,
|
|
67
|
+
complexity: routing.complexity
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
// Execute analysis (typically routed to LocalExecutor due to high complexity)
|
|
71
|
+
let result;
|
|
72
|
+
if (routing.executor === 'local') {
|
|
73
|
+
result = await this.localExecutor.execute(analysisTask);
|
|
74
|
+
} else {
|
|
75
|
+
// Fallback to local if task-tool routing (shouldn't happen for analysis)
|
|
76
|
+
result = await this.localExecutor.execute(analysisTask);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
// Parse requirements
|
|
80
|
+
try {
|
|
81
|
+
this.requirements = JSON.parse(result.output);
|
|
82
|
+
} catch (error) {
|
|
83
|
+
this.logger.error('Failed to parse analysis output', { error: error.message });
|
|
84
|
+
throw new Error('Invalid analysis output format');
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
// Store in SessionState
|
|
88
|
+
this.sessionState.setAnalysisResults({
|
|
89
|
+
requirements: this.requirements,
|
|
90
|
+
timestamp: Date.now(),
|
|
91
|
+
tokens: result.tokens,
|
|
92
|
+
duration: result.duration
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
this.logger.info('Requirements extraction complete', {
|
|
96
|
+
purpose: this.requirements.purpose,
|
|
97
|
+
capabilitiesCount: this.requirements.capabilities?.length || 0,
|
|
98
|
+
knowledgeAreasCount: this.requirements.knowledgeAreas?.length || 0
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
return this.requirements;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* AC3: Identify patterns and common themes across responses
|
|
106
|
+
* @returns {Promise<Array>} Patterns found
|
|
107
|
+
*/
|
|
108
|
+
async identifyPatterns() {
|
|
109
|
+
this.logger.info('Identifying patterns across responses');
|
|
110
|
+
|
|
111
|
+
if (!this.sessionState.userResponses || this.sessionState.userResponses.length === 0) {
|
|
112
|
+
this.logger.warn('No responses to analyze for patterns');
|
|
113
|
+
this.patterns = [];
|
|
114
|
+
return this.patterns;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
// Simple pattern detection based on keyword frequency
|
|
118
|
+
const keywordCounts = {};
|
|
119
|
+
const responses = this.sessionState.userResponses
|
|
120
|
+
.map(r => (r.response || '').toLowerCase())
|
|
121
|
+
.join(' ');
|
|
122
|
+
|
|
123
|
+
// Extract words (simple tokenization)
|
|
124
|
+
const words = responses.split(/\s+/).filter(w => w.length > 3);
|
|
125
|
+
|
|
126
|
+
// Count occurrences
|
|
127
|
+
words.forEach(word => {
|
|
128
|
+
keywordCounts[word] = (keywordCounts[word] || 0) + 1;
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
// Find patterns (words appearing >= 2 times)
|
|
132
|
+
this.patterns = Object.entries(keywordCounts)
|
|
133
|
+
.filter(([word, count]) => count >= 2)
|
|
134
|
+
.map(([word, count]) => ({
|
|
135
|
+
theme: word,
|
|
136
|
+
occurrences: count,
|
|
137
|
+
relevance: count / words.length
|
|
138
|
+
}))
|
|
139
|
+
.sort((a, b) => b.occurrences - a.occurrences)
|
|
140
|
+
.slice(0, 10); // Top 10 patterns
|
|
141
|
+
|
|
142
|
+
// Update SessionState
|
|
143
|
+
if (this.sessionState.analysisResults) {
|
|
144
|
+
this.sessionState.analysisResults.patterns = this.patterns;
|
|
145
|
+
} else {
|
|
146
|
+
this.sessionState.setAnalysisResults({ patterns: this.patterns });
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
this.logger.info('Pattern identification complete', {
|
|
150
|
+
patternsFound: this.patterns.length
|
|
151
|
+
});
|
|
152
|
+
|
|
153
|
+
return this.patterns;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
/**
|
|
157
|
+
* AC4: Validate that all required fields are present and complete
|
|
158
|
+
* @param {Object} requirements - Requirements object to validate
|
|
159
|
+
* @returns {boolean} True if complete
|
|
160
|
+
*/
|
|
161
|
+
validateCompleteness(requirements) {
|
|
162
|
+
if (!requirements || typeof requirements !== 'object') {
|
|
163
|
+
this.logger.warn('Requirements validation failed: invalid input');
|
|
164
|
+
return false;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
// Check required fields exist
|
|
168
|
+
const requiredFields = ['purpose', 'capabilities', 'knowledgeAreas', 'constraints'];
|
|
169
|
+
|
|
170
|
+
for (const field of requiredFields) {
|
|
171
|
+
if (!requirements[field]) {
|
|
172
|
+
this.logger.warn(`Requirements validation failed: missing ${field}`);
|
|
173
|
+
return false;
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
// Validate purpose is not empty
|
|
178
|
+
if (typeof requirements.purpose !== 'string' || requirements.purpose.trim().length === 0) {
|
|
179
|
+
this.logger.warn('Requirements validation failed: empty purpose');
|
|
180
|
+
return false;
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
// Validate arrays are not empty
|
|
184
|
+
const arrayFields = ['capabilities', 'knowledgeAreas'];
|
|
185
|
+
|
|
186
|
+
for (const field of arrayFields) {
|
|
187
|
+
if (!Array.isArray(requirements[field]) || requirements[field].length === 0) {
|
|
188
|
+
this.logger.warn(`Requirements validation failed: empty ${field}`);
|
|
189
|
+
return false;
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
// Constraints can be empty array (optional)
|
|
194
|
+
if (!Array.isArray(requirements.constraints)) {
|
|
195
|
+
this.logger.warn('Requirements validation failed: constraints must be array');
|
|
196
|
+
return false;
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
this.logger.info('Requirements validation passed', {
|
|
200
|
+
purpose: requirements.purpose.substring(0, 50),
|
|
201
|
+
capabilitiesCount: requirements.capabilities.length,
|
|
202
|
+
knowledgeAreasCount: requirements.knowledgeAreas.length
|
|
203
|
+
});
|
|
204
|
+
|
|
205
|
+
return true;
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
/**
|
|
209
|
+
* AC5: Check if analysis is complete and can transition to GENERATION
|
|
210
|
+
* @returns {boolean} True if ready to transition
|
|
211
|
+
*/
|
|
212
|
+
canTransitionToGeneration() {
|
|
213
|
+
// Check if requirements have been extracted
|
|
214
|
+
if (!this.requirements) {
|
|
215
|
+
this.logger.warn('Cannot transition: requirements not extracted');
|
|
216
|
+
return false;
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
// Validate completeness
|
|
220
|
+
if (!this.validateCompleteness(this.requirements)) {
|
|
221
|
+
this.logger.warn('Cannot transition: requirements incomplete');
|
|
222
|
+
return false;
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
// Check SessionState has analysis results
|
|
226
|
+
if (!this.sessionState.analysisResults ||
|
|
227
|
+
!this.sessionState.analysisResults.requirements) {
|
|
228
|
+
this.logger.warn('Cannot transition: SessionState missing analysis results');
|
|
229
|
+
return false;
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
this.logger.info('Analysis complete - ready to transition to GENERATION');
|
|
233
|
+
this.analysisComplete = true;
|
|
234
|
+
return true;
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
/**
|
|
238
|
+
* Get current analysis results
|
|
239
|
+
* @returns {Object} Analysis results
|
|
240
|
+
*/
|
|
241
|
+
getAnalysisResults() {
|
|
242
|
+
return {
|
|
243
|
+
requirements: this.requirements,
|
|
244
|
+
patterns: this.patterns,
|
|
245
|
+
complete: this.analysisComplete
|
|
246
|
+
};
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
/**
|
|
250
|
+
* Get requirements summary
|
|
251
|
+
* @returns {Object} Requirements summary
|
|
252
|
+
*/
|
|
253
|
+
getRequirementsSummary() {
|
|
254
|
+
if (!this.requirements) {
|
|
255
|
+
return { summary: 'No requirements extracted yet' };
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
return {
|
|
259
|
+
purpose: this.requirements.purpose,
|
|
260
|
+
capabilitiesCount: this.requirements.capabilities?.length || 0,
|
|
261
|
+
knowledgeAreasCount: this.requirements.knowledgeAreas?.length || 0,
|
|
262
|
+
constraintsCount: this.requirements.constraints?.length || 0,
|
|
263
|
+
isComplete: this.validateCompleteness(this.requirements)
|
|
264
|
+
};
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
module.exports = AnalysisState;
|
|
@@ -0,0 +1,340 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* GenerationState - Story 4.4
|
|
3
|
+
* Generates agent profile in BMAD/Copilot format
|
|
4
|
+
*
|
|
5
|
+
* Format:
|
|
6
|
+
* - YAML frontmatter (name, description)
|
|
7
|
+
* - XML structure (<agent>, <persona>, <menu>, <capabilities>)
|
|
8
|
+
* - Compliant with .github/copilot/agents/ standard
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
const Logger = require('../observability/logger');
|
|
12
|
+
const fs = require('fs');
|
|
13
|
+
const path = require('path');
|
|
14
|
+
|
|
15
|
+
class GenerationState {
|
|
16
|
+
constructor(sessionState) {
|
|
17
|
+
if (!sessionState) {
|
|
18
|
+
throw new Error('SessionState is required');
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
this.sessionState = sessionState;
|
|
22
|
+
this.logger = new Logger();
|
|
23
|
+
this.profileGenerated = false;
|
|
24
|
+
this.generatedProfile = null;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* AC2: Generate agent profile from analysis results
|
|
29
|
+
* Creates: name, description, persona, menu, capabilities
|
|
30
|
+
*
|
|
31
|
+
* @returns {Promise<string>} Agent profile content
|
|
32
|
+
*/
|
|
33
|
+
async generateProfile() {
|
|
34
|
+
this.logger.info('Starting agent profile generation');
|
|
35
|
+
|
|
36
|
+
// AC6: Try to retrieve analysis results, fallback to user responses
|
|
37
|
+
let requirements;
|
|
38
|
+
|
|
39
|
+
if (this.sessionState.analysisResults && this.sessionState.analysisResults.requirements) {
|
|
40
|
+
requirements = this.sessionState.analysisResults.requirements;
|
|
41
|
+
} else {
|
|
42
|
+
// Fallback: Generate minimal requirements from user responses
|
|
43
|
+
this.logger.warn('No analysis results, generating from user responses');
|
|
44
|
+
requirements = this._extractRequirementsFromResponses();
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
// AC2: Extract components from requirements
|
|
48
|
+
const agentName = this._deriveAgentName(requirements.purpose || 'custom-agent');
|
|
49
|
+
const description = this._deriveDescription(requirements.purpose || 'Custom agent');
|
|
50
|
+
const persona = this._generatePersona(requirements);
|
|
51
|
+
const menu = this._generateMenu(requirements.capabilities || []);
|
|
52
|
+
const capabilities = this._generateCapabilities(requirements);
|
|
53
|
+
|
|
54
|
+
// AC1 & AC3: Build profile with YAML frontmatter + XML
|
|
55
|
+
this.generatedProfile = this._buildProfile({
|
|
56
|
+
name: agentName,
|
|
57
|
+
description,
|
|
58
|
+
persona,
|
|
59
|
+
menu,
|
|
60
|
+
capabilities,
|
|
61
|
+
requirements
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
// AC6: Store in SessionState
|
|
65
|
+
this.sessionState.agentProfileDraft = {
|
|
66
|
+
content: this.generatedProfile,
|
|
67
|
+
name: agentName,
|
|
68
|
+
timestamp: Date.now()
|
|
69
|
+
};
|
|
70
|
+
|
|
71
|
+
this.profileGenerated = true;
|
|
72
|
+
|
|
73
|
+
this.logger.info('Agent profile generated', {
|
|
74
|
+
name: agentName,
|
|
75
|
+
length: this.generatedProfile.length
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
return this.generatedProfile;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* AC4: Validate profile format and compliance
|
|
83
|
+
* Checks: YAML frontmatter, XML well-formed, required fields, no emojis in code
|
|
84
|
+
*
|
|
85
|
+
* @param {string} profile - Profile content to validate
|
|
86
|
+
* @returns {boolean} True if valid
|
|
87
|
+
*/
|
|
88
|
+
validateProfile(profile) {
|
|
89
|
+
if (!profile || typeof profile !== 'string') {
|
|
90
|
+
this.logger.warn('Validation failed: invalid profile');
|
|
91
|
+
return false;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
try {
|
|
95
|
+
// AC4: Validate YAML frontmatter
|
|
96
|
+
const frontmatterMatch = profile.match(/^---([\s\S]*?)---/);
|
|
97
|
+
if (!frontmatterMatch) {
|
|
98
|
+
this.logger.warn('Validation failed: missing YAML frontmatter');
|
|
99
|
+
return false;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
const frontmatter = frontmatterMatch[1];
|
|
103
|
+
|
|
104
|
+
// Check required YAML fields
|
|
105
|
+
if (!frontmatter.includes('name:')) {
|
|
106
|
+
this.logger.warn('Validation failed: missing name in frontmatter');
|
|
107
|
+
return false;
|
|
108
|
+
}
|
|
109
|
+
if (!frontmatter.includes('description:')) {
|
|
110
|
+
this.logger.warn('Validation failed: missing description in frontmatter');
|
|
111
|
+
return false;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
// AC4: Validate XML block
|
|
115
|
+
const xmlMatch = profile.match(/```xml\s*([\s\S]*?)\s*```/);
|
|
116
|
+
if (!xmlMatch) {
|
|
117
|
+
this.logger.warn('Validation failed: missing XML block');
|
|
118
|
+
return false;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
const xml = xmlMatch[1];
|
|
122
|
+
|
|
123
|
+
// AC4: Check XML well-formedness (basic)
|
|
124
|
+
if (!xml.includes('<agent') || !xml.includes('</agent>')) {
|
|
125
|
+
this.logger.warn('Validation failed: malformed XML');
|
|
126
|
+
return false;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
// AC4: Validate no emojis in XML code sections
|
|
130
|
+
const emojiRegex = /[\u{1F300}-\u{1F9FF}]/u;
|
|
131
|
+
if (emojiRegex.test(xml)) {
|
|
132
|
+
this.logger.warn('Validation failed: emojis found in XML');
|
|
133
|
+
return false;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
this.logger.info('Profile validation passed');
|
|
137
|
+
return true;
|
|
138
|
+
|
|
139
|
+
} catch (error) {
|
|
140
|
+
this.logger.error('Validation error', { error: error.message });
|
|
141
|
+
return false;
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
/**
|
|
146
|
+
* AC5: Save profile to disk
|
|
147
|
+
* @param {string} filePath - Path to save profile
|
|
148
|
+
*/
|
|
149
|
+
saveProfile(filePath) {
|
|
150
|
+
if (!this.generatedProfile) {
|
|
151
|
+
throw new Error('No profile to save - generate profile first');
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
try {
|
|
155
|
+
// Ensure directory exists
|
|
156
|
+
const dir = path.dirname(filePath);
|
|
157
|
+
if (!fs.existsSync(dir)) {
|
|
158
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
// Write profile
|
|
162
|
+
fs.writeFileSync(filePath, this.generatedProfile, 'utf-8');
|
|
163
|
+
|
|
164
|
+
this.logger.info('Profile saved', {
|
|
165
|
+
path: filePath,
|
|
166
|
+
size: this.generatedProfile.length
|
|
167
|
+
});
|
|
168
|
+
|
|
169
|
+
} catch (error) {
|
|
170
|
+
this.logger.error('Save failed', { error: error.message, path: filePath });
|
|
171
|
+
throw error;
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
/**
|
|
176
|
+
* Get default save path
|
|
177
|
+
* @returns {string} Default path
|
|
178
|
+
*/
|
|
179
|
+
getDefaultSavePath() {
|
|
180
|
+
const name = this.sessionState.agentProfileDraft?.name || 'agent';
|
|
181
|
+
return `.github/copilot/agents/${name}.md`;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
/**
|
|
185
|
+
* Extract requirements from user responses (fallback)
|
|
186
|
+
* @private
|
|
187
|
+
*/
|
|
188
|
+
_extractRequirementsFromResponses() {
|
|
189
|
+
const responseData = this.sessionState.userResponses || [];
|
|
190
|
+
|
|
191
|
+
// Extract response text from response objects
|
|
192
|
+
const responses = responseData.map(r => typeof r === 'string' ? r : (r.response || ''));
|
|
193
|
+
|
|
194
|
+
return {
|
|
195
|
+
purpose: responses[0] || 'Custom agent',
|
|
196
|
+
domain: responses[3] || 'General',
|
|
197
|
+
capabilities: responses[7] ? responses[7].split(',').map(c => c.trim()) : ['General capability'],
|
|
198
|
+
knowledgeAreas: responses[2] ? responses[2].split(',').map(k => k.trim()) : ['General'],
|
|
199
|
+
users: responses[4] ? responses[4].split(',').map(u => u.trim()) : ['Users'],
|
|
200
|
+
constraints: responses.length > 10 ? [responses[10]] : []
|
|
201
|
+
};
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
/**
|
|
205
|
+
* Derive agent name from purpose
|
|
206
|
+
* @private
|
|
207
|
+
*/
|
|
208
|
+
_deriveAgentName(purpose) {
|
|
209
|
+
// Extract key words, sanitize, hyphenate
|
|
210
|
+
const name = purpose
|
|
211
|
+
.toLowerCase()
|
|
212
|
+
.replace(/[^a-z0-9\s-]/g, '')
|
|
213
|
+
.trim()
|
|
214
|
+
.split(/\s+/)
|
|
215
|
+
.slice(0, 3) // Max 3 words
|
|
216
|
+
.join('-');
|
|
217
|
+
|
|
218
|
+
return name || 'custom-agent';
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
/**
|
|
222
|
+
* Derive description from purpose
|
|
223
|
+
* @private
|
|
224
|
+
*/
|
|
225
|
+
_deriveDescription(purpose) {
|
|
226
|
+
// Use first sentence or truncate
|
|
227
|
+
const firstSentence = purpose.split(/[.!?]/)[0].trim();
|
|
228
|
+
return firstSentence.length > 100
|
|
229
|
+
? firstSentence.substring(0, 97) + '...'
|
|
230
|
+
: firstSentence;
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
/**
|
|
234
|
+
* Generate persona from requirements
|
|
235
|
+
* @private
|
|
236
|
+
*/
|
|
237
|
+
_generatePersona(requirements) {
|
|
238
|
+
const { purpose, capabilities, knowledgeAreas } = requirements;
|
|
239
|
+
|
|
240
|
+
return `<persona>
|
|
241
|
+
<role>Specialized Agent</role>
|
|
242
|
+
<identity>${purpose}</identity>
|
|
243
|
+
<expertise>Expert in ${knowledgeAreas.slice(0, 3).join(', ')}</expertise>
|
|
244
|
+
<communication_style>Professional, clear, and focused on delivering results</communication_style>
|
|
245
|
+
<capabilities>
|
|
246
|
+
${capabilities.slice(0, 5).map(cap => ` <capability>${this._escapeXml(cap)}</capability>`).join('\n')}
|
|
247
|
+
</capabilities>
|
|
248
|
+
</persona>`;
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
/**
|
|
252
|
+
* Generate menu from capabilities
|
|
253
|
+
* @private
|
|
254
|
+
*/
|
|
255
|
+
_generateMenu(capabilities) {
|
|
256
|
+
const menuItems = capabilities.slice(0, 5).map((cap, index) => {
|
|
257
|
+
const cmdKey = `C${index + 1}`;
|
|
258
|
+
return ` <item cmd="${cmdKey}">[${cmdKey}] ${this._escapeXml(cap)}</item>`;
|
|
259
|
+
});
|
|
260
|
+
|
|
261
|
+
return `<menu>
|
|
262
|
+
${menuItems.join('\n')}
|
|
263
|
+
<item cmd="MH">[MH] Menu Help</item>
|
|
264
|
+
</menu>`;
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
/**
|
|
268
|
+
* Generate capabilities section
|
|
269
|
+
* @private
|
|
270
|
+
*/
|
|
271
|
+
_generateCapabilities(requirements) {
|
|
272
|
+
const { capabilities, knowledgeAreas, constraints } = requirements;
|
|
273
|
+
|
|
274
|
+
return `<capabilities>
|
|
275
|
+
<primary>
|
|
276
|
+
${capabilities.map(cap => ` <capability>${this._escapeXml(cap)}</capability>`).join('\n')}
|
|
277
|
+
</primary>
|
|
278
|
+
<knowledge>
|
|
279
|
+
${knowledgeAreas.map(area => ` <domain>${this._escapeXml(area)}</domain>`).join('\n')}
|
|
280
|
+
</knowledge>
|
|
281
|
+
<constraints>
|
|
282
|
+
${(constraints || []).map(c => ` <constraint>${this._escapeXml(c)}</constraint>`).join('\n')}
|
|
283
|
+
</constraints>
|
|
284
|
+
</capabilities>`;
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
/**
|
|
288
|
+
* Build complete profile
|
|
289
|
+
* @private
|
|
290
|
+
*/
|
|
291
|
+
_buildProfile({ name, description, persona, menu, capabilities, requirements }) {
|
|
292
|
+
const agentId = `${name}.agent.yaml`;
|
|
293
|
+
|
|
294
|
+
return `---
|
|
295
|
+
name: "${name}"
|
|
296
|
+
description: "${description}"
|
|
297
|
+
---
|
|
298
|
+
|
|
299
|
+
\`\`\`xml
|
|
300
|
+
<agent id="${agentId}" name="${name}" title="${description}">
|
|
301
|
+
<activation>
|
|
302
|
+
<step n="1">Load agent context and requirements</step>
|
|
303
|
+
<step n="2">Initialize with user's project context</step>
|
|
304
|
+
<step n="3">Display greeting and menu</step>
|
|
305
|
+
<step n="4">Await user input</step>
|
|
306
|
+
</activation>
|
|
307
|
+
|
|
308
|
+
${persona}
|
|
309
|
+
|
|
310
|
+
${menu}
|
|
311
|
+
|
|
312
|
+
${capabilities}
|
|
313
|
+
|
|
314
|
+
<guidelines>
|
|
315
|
+
<guideline>Follow user requirements precisely</guideline>
|
|
316
|
+
<guideline>Maintain professional communication</guideline>
|
|
317
|
+
<guideline>Provide actionable, clear responses</guideline>
|
|
318
|
+
<guideline>Leverage knowledge domains effectively</guideline>
|
|
319
|
+
</guidelines>
|
|
320
|
+
</agent>
|
|
321
|
+
\`\`\`
|
|
322
|
+
`;
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
/**
|
|
326
|
+
* Escape XML special characters
|
|
327
|
+
* @private
|
|
328
|
+
*/
|
|
329
|
+
_escapeXml(str) {
|
|
330
|
+
if (!str) return '';
|
|
331
|
+
return String(str)
|
|
332
|
+
.replace(/&/g, '&')
|
|
333
|
+
.replace(/</g, '<')
|
|
334
|
+
.replace(/>/g, '>')
|
|
335
|
+
.replace(/"/g, '"')
|
|
336
|
+
.replace(/'/g, ''');
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
module.exports = GenerationState;
|