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.
Files changed (240) hide show
  1. package/API-BYAN-V2.md +741 -0
  2. package/BMAD-QUICK-REFERENCE.md +370 -0
  3. package/CHANGELOG-v2.1.0.md +371 -0
  4. package/LICENSE +1 -1
  5. package/MIGRATION-v2.0-to-v2.1.md +430 -0
  6. package/README-BYAN-V2.md +446 -0
  7. package/README.md +264 -201
  8. package/install/.eslintrc.js +20 -0
  9. package/install/.prettierrc +7 -0
  10. package/install/BUGFIX-CHALK.md +173 -0
  11. package/install/BUGFIX-DOCUMENTATION-INDEX.md +299 -0
  12. package/install/BUGFIX-PATH-RESOLUTION.md +293 -0
  13. package/install/BUGFIX-QUICKSTART.md +184 -0
  14. package/install/BUGFIX-SUMMARY.txt +91 -0
  15. package/install/BUGFIX-VISUAL-SUMMARY.md +253 -0
  16. package/install/DEPLOYMENT-GUIDE-V2.md +431 -0
  17. package/install/DOCS-INDEX.md +261 -0
  18. package/install/GUIDE-INSTALLATION-BYAN-SIMPLE.md +1083 -0
  19. package/install/INSTALLER-V2-CHANGES.md +472 -0
  20. package/install/LICENSE +21 -0
  21. package/install/PUBLICATION-CHECKLIST.md +265 -0
  22. package/install/PUBLISH-GUIDE.md +190 -0
  23. package/install/QUICKSTART.md +311 -0
  24. package/install/README-NPM-PUBLISH.md +298 -0
  25. package/install/README-NPM-SHORT.md +298 -0
  26. package/install/README-NPM.md +433 -0
  27. package/install/README-RACHID.md +302 -0
  28. package/install/README-V2-INDEX.md +306 -0
  29. package/install/README.md +298 -0
  30. package/install/RESUME-EXECUTIF-YAN.md +408 -0
  31. package/install/UPDATE-SUMMARY.md +205 -0
  32. package/install/__tests__/integration/detection-flow.test.js +154 -0
  33. package/install/__tests__/platforms/claude-code.test.js +175 -0
  34. package/install/__tests__/platforms/codex.test.js +80 -0
  35. package/install/__tests__/platforms/copilot-cli.test.js +118 -0
  36. package/install/__tests__/platforms/vscode.test.js +67 -0
  37. package/install/__tests__/utils/file-utils.test.js +87 -0
  38. package/install/__tests__/utils/git-detector.test.js +80 -0
  39. package/install/__tests__/utils/logger.test.js +83 -0
  40. package/install/__tests__/utils/node-detector.test.js +71 -0
  41. package/install/__tests__/utils/os-detector.test.js +63 -0
  42. package/install/__tests__/utils/yaml-utils.test.js +85 -0
  43. package/install/__tests__/yanstaller/detector.test.js +210 -0
  44. package/install/coverage/clover.xml +219 -0
  45. package/install/coverage/coverage-final.json +13 -0
  46. package/install/coverage/lcov-report/base.css +224 -0
  47. package/install/coverage/lcov-report/block-navigation.js +87 -0
  48. package/install/coverage/lcov-report/favicon.png +0 -0
  49. package/install/coverage/lcov-report/index.html +146 -0
  50. package/install/coverage/lcov-report/lib/errors.js.html +268 -0
  51. package/install/coverage/lcov-report/lib/exit-codes.js.html +247 -0
  52. package/install/coverage/lcov-report/lib/index.html +131 -0
  53. package/install/coverage/lcov-report/lib/platforms/claude-code.js.html +343 -0
  54. package/install/coverage/lcov-report/lib/platforms/codex.js.html +361 -0
  55. package/install/coverage/lcov-report/lib/platforms/copilot-cli.js.html +454 -0
  56. package/install/coverage/lcov-report/lib/platforms/index.html +176 -0
  57. package/install/coverage/lcov-report/lib/platforms/index.js.html +127 -0
  58. package/install/coverage/lcov-report/lib/platforms/vscode.js.html +238 -0
  59. package/install/coverage/lcov-report/lib/utils/config-loader.js.html +322 -0
  60. package/install/coverage/lcov-report/lib/utils/file-utils.js.html +397 -0
  61. package/install/coverage/lcov-report/lib/utils/git-detector.js.html +190 -0
  62. package/install/coverage/lcov-report/lib/utils/index.html +206 -0
  63. package/install/coverage/lcov-report/lib/utils/logger.js.html +277 -0
  64. package/install/coverage/lcov-report/lib/utils/node-detector.js.html +259 -0
  65. package/install/coverage/lcov-report/lib/utils/os-detector.js.html +307 -0
  66. package/install/coverage/lcov-report/lib/utils/yaml-utils.js.html +346 -0
  67. package/install/coverage/lcov-report/lib/yanstaller/backuper.js.html +409 -0
  68. package/install/coverage/lcov-report/lib/yanstaller/detector.js.html +508 -0
  69. package/install/coverage/lcov-report/lib/yanstaller/index.html +236 -0
  70. package/install/coverage/lcov-report/lib/yanstaller/index.js.html +364 -0
  71. package/install/coverage/lcov-report/lib/yanstaller/installer.js.html +505 -0
  72. package/install/coverage/lcov-report/lib/yanstaller/interviewer.js.html +349 -0
  73. package/install/coverage/lcov-report/lib/yanstaller/recommender.js.html +379 -0
  74. package/install/coverage/lcov-report/lib/yanstaller/troubleshooter.js.html +352 -0
  75. package/install/coverage/lcov-report/lib/yanstaller/validator.js.html +679 -0
  76. package/install/coverage/lcov-report/lib/yanstaller/wizard.js.html +412 -0
  77. package/install/coverage/lcov-report/platforms/claude-code.js.html +343 -0
  78. package/install/coverage/lcov-report/platforms/codex.js.html +361 -0
  79. package/install/coverage/lcov-report/platforms/copilot-cli.js.html +454 -0
  80. package/install/coverage/lcov-report/platforms/index.html +176 -0
  81. package/install/coverage/lcov-report/platforms/index.js.html +127 -0
  82. package/install/coverage/lcov-report/platforms/vscode.js.html +238 -0
  83. package/install/coverage/lcov-report/prettify.css +1 -0
  84. package/install/coverage/lcov-report/prettify.js +2 -0
  85. package/install/coverage/lcov-report/sort-arrow-sprite.png +0 -0
  86. package/install/coverage/lcov-report/sorter.js +210 -0
  87. package/install/coverage/lcov-report/utils/file-utils.js.html +397 -0
  88. package/install/coverage/lcov-report/utils/git-detector.js.html +190 -0
  89. package/install/coverage/lcov-report/utils/index.html +191 -0
  90. package/install/coverage/lcov-report/utils/logger.js.html +277 -0
  91. package/install/coverage/lcov-report/utils/node-detector.js.html +259 -0
  92. package/install/coverage/lcov-report/utils/os-detector.js.html +307 -0
  93. package/install/coverage/lcov-report/utils/yaml-utils.js.html +346 -0
  94. package/install/coverage/lcov-report/yanstaller/detector.js.html +508 -0
  95. package/install/coverage/lcov-report/yanstaller/index.html +116 -0
  96. package/install/coverage/lcov.info +414 -0
  97. package/install/install.sh +239 -0
  98. package/install/jest.config.js +33 -0
  99. package/install/lib/errors.js +61 -0
  100. package/install/lib/exit-codes.js +54 -0
  101. package/install/lib/platforms/claude-code.js +86 -0
  102. package/install/lib/platforms/codex.js +92 -0
  103. package/install/lib/platforms/copilot-cli.js +123 -0
  104. package/install/lib/platforms/index.js +14 -0
  105. package/install/lib/platforms/vscode.js +51 -0
  106. package/install/lib/utils/config-loader.js +79 -0
  107. package/install/lib/utils/file-utils.js +104 -0
  108. package/install/lib/utils/git-detector.js +35 -0
  109. package/install/lib/utils/logger.js +64 -0
  110. package/install/lib/utils/node-detector.js +58 -0
  111. package/install/lib/utils/os-detector.js +74 -0
  112. package/install/lib/utils/yaml-utils.js +87 -0
  113. package/install/lib/yanstaller/backuper.js +108 -0
  114. package/install/lib/yanstaller/detector.js +141 -0
  115. package/install/lib/yanstaller/index.js +93 -0
  116. package/install/lib/yanstaller/installer.js +140 -0
  117. package/install/lib/yanstaller/interviewer.js +88 -0
  118. package/install/lib/yanstaller/recommender.js +98 -0
  119. package/install/lib/yanstaller/troubleshooter.js +89 -0
  120. package/install/lib/yanstaller/validator.js +198 -0
  121. package/install/lib/yanstaller/wizard.js +109 -0
  122. package/install/package-npm.json +55 -0
  123. package/install/package.json +63 -0
  124. package/install/src/byan-v2/context/copilot-context.js +79 -0
  125. package/install/src/byan-v2/context/session-state.js +98 -0
  126. package/install/src/byan-v2/dispatcher/complexity-scorer.js +232 -0
  127. package/install/src/byan-v2/dispatcher/local-executor.js +221 -0
  128. package/install/src/byan-v2/dispatcher/task-router.js +122 -0
  129. package/install/src/byan-v2/dispatcher/task-tool-interface-mock.js +134 -0
  130. package/install/src/byan-v2/dispatcher/task-tool-interface.js +123 -0
  131. package/install/src/byan-v2/generation/agent-profile-validator.js +113 -0
  132. package/install/src/byan-v2/generation/profile-template.js +113 -0
  133. package/install/src/byan-v2/generation/templates/default-agent.md +49 -0
  134. package/install/src/byan-v2/generation/templates/test-template.md +1 -0
  135. package/install/src/byan-v2/index.js +199 -0
  136. package/install/src/byan-v2/observability/error-tracker.js +105 -0
  137. package/install/src/byan-v2/observability/logger.js +154 -0
  138. package/install/src/byan-v2/observability/metrics-collector.js +194 -0
  139. package/install/src/byan-v2/orchestrator/analysis-state.js +268 -0
  140. package/install/src/byan-v2/orchestrator/generation-state.js +340 -0
  141. package/install/src/byan-v2/orchestrator/interview-state.js +271 -0
  142. package/install/src/byan-v2/orchestrator/state-machine.js +204 -0
  143. package/install/src/core/cache/cache.js +126 -0
  144. package/install/src/core/context/context.js +86 -0
  145. package/install/src/core/dispatcher/dispatcher.js +135 -0
  146. package/install/src/core/worker-pool/worker-pool.js +194 -0
  147. package/install/src/core/workflow/workflow-executor.js +220 -0
  148. package/install/src/index.js +139 -0
  149. package/install/src/observability/dashboard/dashboard.js +191 -0
  150. package/install/src/observability/logger/structured-logger.js +254 -0
  151. package/install/src/observability/metrics/metrics-collector.js +325 -0
  152. package/install/switch-to-v2.sh +126 -0
  153. package/install/test-chalk-fix.sh +210 -0
  154. package/install/test-installer-v2.sh +204 -0
  155. package/install/test-path-resolution.sh +200 -0
  156. package/package.json +53 -33
  157. package/src/byan-v2/context/copilot-context.js +79 -0
  158. package/src/byan-v2/context/session-state.js +98 -0
  159. package/src/byan-v2/data/mantras.json +852 -0
  160. package/src/byan-v2/dispatcher/complexity-scorer.js +232 -0
  161. package/src/byan-v2/dispatcher/five-whys-analyzer.js +310 -0
  162. package/src/byan-v2/dispatcher/local-executor.js +221 -0
  163. package/src/byan-v2/dispatcher/task-router.js +122 -0
  164. package/src/byan-v2/dispatcher/task-tool-interface-mock.js +134 -0
  165. package/src/byan-v2/dispatcher/task-tool-interface.js +123 -0
  166. package/src/byan-v2/generation/agent-profile-validator.js +113 -0
  167. package/src/byan-v2/generation/mantra-validator.js +416 -0
  168. package/src/byan-v2/generation/profile-template.js +113 -0
  169. package/src/byan-v2/generation/templates/default-agent.md +49 -0
  170. package/src/byan-v2/generation/templates/test-template.md +1 -0
  171. package/src/byan-v2/index.js +652 -0
  172. package/src/byan-v2/integration/voice-integration.js +295 -0
  173. package/src/byan-v2/observability/error-tracker.js +105 -0
  174. package/src/byan-v2/observability/logger.js +154 -0
  175. package/src/byan-v2/observability/metrics-collector.js +194 -0
  176. package/src/byan-v2/orchestrator/active-listener.js +541 -0
  177. package/src/byan-v2/orchestrator/analysis-state.js +268 -0
  178. package/src/byan-v2/orchestrator/generation-state.js +340 -0
  179. package/src/byan-v2/orchestrator/glossary-builder.js +431 -0
  180. package/src/byan-v2/orchestrator/interview-state.js +353 -0
  181. package/src/byan-v2/orchestrator/state-machine.js +253 -0
  182. package/src/core/cache/cache.js +126 -0
  183. package/src/core/context/context.js +86 -0
  184. package/src/core/dispatcher/dispatcher.js +135 -0
  185. package/src/core/worker-pool/worker-pool.js +194 -0
  186. package/src/core/workflow/workflow-executor.js +220 -0
  187. package/src/index.js +139 -0
  188. package/src/observability/dashboard/dashboard.js +191 -0
  189. package/src/observability/logger/structured-logger.js +254 -0
  190. package/src/observability/metrics/metrics-collector.js +325 -0
  191. package/templates/.github/agents/bmad-agent-test-dynamic.md +0 -21
  192. package/templates/.github/agents/franck.md +0 -379
  193. /package/{CHANGELOG.md → install/CHANGELOG.md} +0 -0
  194. /package/{bin → install/bin}/create-byan-agent-backup.js +0 -0
  195. /package/{bin → install/bin}/create-byan-agent-fixed.js +0 -0
  196. /package/{bin → install/bin}/create-byan-agent-v2.js +0 -0
  197. /package/{bin → install/bin}/create-byan-agent.js +0 -0
  198. /package/{templates → install/templates}/.github/agents/bmad-agent-bmad-master.md +0 -0
  199. /package/{templates → install/templates}/.github/agents/bmad-agent-bmb-agent-builder.md +0 -0
  200. /package/{templates → install/templates}/.github/agents/bmad-agent-bmb-module-builder.md +0 -0
  201. /package/{templates → install/templates}/.github/agents/bmad-agent-bmb-workflow-builder.md +0 -0
  202. /package/{templates → install/templates}/.github/agents/bmad-agent-bmm-analyst.md +0 -0
  203. /package/{templates → install/templates}/.github/agents/bmad-agent-bmm-architect.md +0 -0
  204. /package/{templates → install/templates}/.github/agents/bmad-agent-bmm-dev.md +0 -0
  205. /package/{templates → install/templates}/.github/agents/bmad-agent-bmm-pm.md +0 -0
  206. /package/{templates → install/templates}/.github/agents/bmad-agent-bmm-quick-flow-solo-dev.md +0 -0
  207. /package/{templates → install/templates}/.github/agents/bmad-agent-bmm-quinn.md +0 -0
  208. /package/{templates → install/templates}/.github/agents/bmad-agent-bmm-sm.md +0 -0
  209. /package/{templates → install/templates}/.github/agents/bmad-agent-bmm-tech-writer.md +0 -0
  210. /package/{templates → install/templates}/.github/agents/bmad-agent-bmm-ux-designer.md +0 -0
  211. /package/{templates → install/templates}/.github/agents/bmad-agent-byan-test.md +0 -0
  212. /package/{templates → install/templates}/.github/agents/bmad-agent-byan.md +0 -0
  213. /package/{templates → install/templates}/.github/agents/bmad-agent-carmack.md +0 -0
  214. /package/{templates → install/templates}/.github/agents/bmad-agent-cis-brainstorming-coach.md +0 -0
  215. /package/{templates → install/templates}/.github/agents/bmad-agent-cis-creative-problem-solver.md +0 -0
  216. /package/{templates → install/templates}/.github/agents/bmad-agent-cis-design-thinking-coach.md +0 -0
  217. /package/{templates → install/templates}/.github/agents/bmad-agent-cis-innovation-strategist.md +0 -0
  218. /package/{templates → install/templates}/.github/agents/bmad-agent-cis-presentation-master.md +0 -0
  219. /package/{templates → install/templates}/.github/agents/bmad-agent-cis-storyteller.md +0 -0
  220. /package/{templates → install/templates}/.github/agents/bmad-agent-marc.md +0 -0
  221. /package/{templates → install/templates}/.github/agents/bmad-agent-patnote.md +0 -0
  222. /package/{templates → install/templates}/.github/agents/bmad-agent-rachid.md +0 -0
  223. /package/{templates → install/templates}/.github/agents/bmad-agent-tea-tea.md +0 -0
  224. /package/{templates → install/templates}/_bmad/bmb/agents/agent-builder.md +0 -0
  225. /package/{templates → install/templates}/_bmad/bmb/agents/byan-test.md +0 -0
  226. /package/{templates → install/templates}/_bmad/bmb/agents/byan.md +0 -0
  227. /package/{templates → install/templates}/_bmad/bmb/agents/marc.md +0 -0
  228. /package/{templates → install/templates}/_bmad/bmb/agents/module-builder.md +0 -0
  229. /package/{templates → install/templates}/_bmad/bmb/agents/patnote.md +0 -0
  230. /package/{templates → install/templates}/_bmad/bmb/agents/rachid.md +0 -0
  231. /package/{templates → install/templates}/_bmad/bmb/agents/workflow-builder.md +0 -0
  232. /package/{templates → install/templates}/_bmad/bmb/workflows/byan/data/mantras.yaml +0 -0
  233. /package/{templates → install/templates}/_bmad/bmb/workflows/byan/data/templates.yaml +0 -0
  234. /package/{templates → install/templates}/_bmad/bmb/workflows/byan/delete-agent-workflow.md +0 -0
  235. /package/{templates → install/templates}/_bmad/bmb/workflows/byan/edit-agent-workflow.md +0 -0
  236. /package/{templates → install/templates}/_bmad/bmb/workflows/byan/interview-workflow.md +0 -0
  237. /package/{templates → install/templates}/_bmad/bmb/workflows/byan/quick-create-workflow.md +0 -0
  238. /package/{templates → install/templates}/_bmad/bmb/workflows/byan/templates/base-agent-template.md +0 -0
  239. /package/{templates → install/templates}/_bmad/bmb/workflows/byan/validate-agent-workflow.md +0 -0
  240. /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, '&amp;')
333
+ .replace(/</g, '&lt;')
334
+ .replace(/>/g, '&gt;')
335
+ .replace(/"/g, '&quot;')
336
+ .replace(/'/g, '&apos;');
337
+ }
338
+ }
339
+
340
+ module.exports = GenerationState;