11const path = require ( 'node:path' ) ;
22const { BaseIdeSetup } = require ( './_base-ide' ) ;
33const chalk = require ( 'chalk' ) ;
4+ const { getAgentsFromBmad, getTasksFromBmad } = require ( './shared/bmad-artifacts' ) ;
45
56/**
67 * Qwen Code setup handler
@@ -11,7 +12,7 @@ class QwenSetup extends BaseIdeSetup {
1112 super ( 'qwen' , 'Qwen Code' ) ;
1213 this . configDir = '.qwen' ;
1314 this . commandsDir = 'commands' ;
14- this . bmadDir = 'BMad ' ;
15+ this . bmadDir = 'bmad ' ;
1516 }
1617
1718 /**
@@ -27,11 +28,8 @@ class QwenSetup extends BaseIdeSetup {
2728 const qwenDir = path . join ( projectDir , this . configDir ) ;
2829 const commandsDir = path . join ( qwenDir , this . commandsDir ) ;
2930 const bmadCommandsDir = path . join ( commandsDir , this . bmadDir ) ;
30- const agentsDir = path . join ( bmadCommandsDir , 'agents' ) ;
31- const tasksDir = path . join ( bmadCommandsDir , 'tasks' ) ;
3231
33- await this . ensureDir ( agentsDir ) ;
34- await this . ensureDir ( tasksDir ) ;
32+ await this . ensureDir ( bmadCommandsDir ) ;
3533
3634 // Update existing settings.json if present
3735 await this . updateSettings ( qwenDir ) ;
@@ -40,68 +38,55 @@ class QwenSetup extends BaseIdeSetup {
4038 await this . cleanupOldConfig ( qwenDir ) ;
4139
4240 // Get agents and tasks
43- const agents = await this . getAgents ( bmadDir ) ;
44- const tasks = await this . getTasks ( bmadDir ) ;
41+ const agents = await getAgentsFromBmad ( bmadDir , options . selectedModules || [ ] ) ;
42+ const tasks = await getTasksFromBmad ( bmadDir , options . selectedModules || [ ] ) ;
43+
44+ // Create directories for each module (including standalone)
45+ const modules = new Set ( ) ;
46+ for ( const item of [ ...agents , ...tasks ] ) modules . add ( item . module ) ;
47+
48+ for ( const module of modules ) {
49+ await this . ensureDir ( path . join ( bmadCommandsDir , module ) ) ;
50+ await this . ensureDir ( path . join ( bmadCommandsDir , module , 'agents' ) ) ;
51+ await this . ensureDir ( path . join ( bmadCommandsDir , module , 'tasks' ) ) ;
52+ }
4553
4654 // Create TOML files for each agent
4755 let agentCount = 0 ;
4856 for ( const agent of agents ) {
49- const content = await this . readFile ( agent . path ) ;
50- const tomlContent = this . createAgentToml ( agent , content , projectDir ) ;
51- const tomlPath = path . join ( agentsDir , `${ agent . name } .toml` ) ;
52- await this . writeFile ( tomlPath , tomlContent ) ;
57+ const content = await this . readAndProcess ( agent . path , {
58+ module : agent . module ,
59+ name : agent . name ,
60+ } ) ;
61+
62+ const targetPath = path . join ( bmadCommandsDir , agent . module , 'agents' , `${ agent . name } .toml` ) ;
63+
64+ await this . writeFile ( targetPath , content ) ;
65+
5366 agentCount ++ ;
54- console . log ( chalk . green ( ` ✓ Added agent: /BMad :agents:${ agent . name } ` ) ) ;
67+ console . log ( chalk . green ( ` ✓ Added agent: /bmad: ${ agent . module } :agents:${ agent . name } ` ) ) ;
5568 }
5669
5770 // Create TOML files for each task
5871 let taskCount = 0 ;
5972 for ( const task of tasks ) {
60- const content = await this . readFile ( task . path ) ;
61- const tomlContent = this . createTaskToml ( task , content , projectDir ) ;
62- const tomlPath = path . join ( tasksDir , `${ task . name } .toml` ) ;
63- await this . writeFile ( tomlPath , tomlContent ) ;
64- taskCount ++ ;
65- console . log ( chalk . green ( ` ✓ Added task: /BMad:tasks:${ task . name } ` ) ) ;
66- }
73+ const content = await this . readAndProcess ( task . path , {
74+ module : task . module ,
75+ name : task . name ,
76+ } ) ;
6777
68- // Create concatenated QWEN.md for reference
69- let concatenatedContent = `# BMAD Method - Qwen Code Configuration
78+ const targetPath = path . join ( bmadCommandsDir , task . module , 'agents' , `${ agent . name } .toml` ) ;
7079
71- This file contains all BMAD agents and tasks configured for use with Qwen Code.
80+ await this . writeFile ( targetPath , content ) ;
7281
73- ## Agents
74- Agents can be activated using: \`/BMad:agents:<agent-name>\`
75-
76- ## Tasks
77- Tasks can be executed using: \`/BMad:tasks:<task-name>\`
78-
79- ---
80-
81- ` ;
82-
83- for ( const agent of agents ) {
84- const content = await this . readFile ( agent . path ) ;
85- const agentSection = this . createAgentSection ( agent , content , projectDir ) ;
86- concatenatedContent += agentSection ;
87- concatenatedContent += '\n\n---\n\n' ;
88- }
89-
90- for ( const task of tasks ) {
91- const content = await this . readFile ( task . path ) ;
92- const taskSection = this . createTaskSection ( task , content , projectDir ) ;
93- concatenatedContent += taskSection ;
94- concatenatedContent += '\n\n---\n\n' ;
82+ taskCount ++ ;
83+ console . log ( chalk . green ( ` ✓ Added task: /bmad:${ task . module } :tasks:${ task . name } ` ) ) ;
9584 }
9685
97- const qwenMdPath = path . join ( bmadCommandsDir , 'QWEN.md' ) ;
98- await this . writeFile ( qwenMdPath , concatenatedContent ) ;
99-
10086 console . log ( chalk . green ( `✓ ${ this . name } configured:` ) ) ;
10187 console . log ( chalk . dim ( ` - ${ agentCount } agents configured` ) ) ;
10288 console . log ( chalk . dim ( ` - ${ taskCount } tasks configured` ) ) ;
103- console . log ( chalk . dim ( ` - Agents activated with: /BMad:agents:<agent-name>` ) ) ;
104- console . log ( chalk . dim ( ` - Tasks activated with: /BMad:tasks:<task-name>` ) ) ;
89+ console . log ( chalk . dim ( ` - Commands directory: ${ path . relative ( projectDir , bmadCommandsDir ) } ` ) ) ;
10590
10691 return {
10792 success : true ,
@@ -152,6 +137,7 @@ Tasks can be executed using: \`/BMad:tasks:<task-name>\`
152137 const fs = require ( 'fs-extra' ) ;
153138 const agentsDir = path . join ( qwenDir , 'agents' ) ;
154139 const bmadMethodDir = path . join ( qwenDir , 'bmad-method' ) ;
140+ const bmadDir = path . join ( qwenDir , 'bmadDir' ) ;
155141
156142 if ( await fs . pathExists ( agentsDir ) ) {
157143 await fs . remove ( agentsDir ) ;
@@ -162,135 +148,57 @@ Tasks can be executed using: \`/BMad:tasks:<task-name>\`
162148 await fs . remove ( bmadMethodDir ) ;
163149 console . log ( chalk . green ( ' ✓ Removed old bmad-method directory' ) ) ;
164150 }
165- }
166-
167- /**
168- * Create TOML file for agent
169- */
170- createAgentToml ( agent , content , projectDir ) {
171- const titleMatch = content . match ( / t i t l e = " ( [ ^ " ] + ) " / ) ;
172- const title = titleMatch ? titleMatch [ 1 ] : this . formatTitle ( agent . name ) ;
173- const yamlMatch = content . match ( / ` ` ` y a ? m l \r ? \n ( [ \s \S ] * ?) ` ` ` / ) ;
174- const yamlContent = yamlMatch ? yamlMatch [ 1 ] : content ;
175- const relativePath = path . relative ( projectDir , agent . path ) . replaceAll ( '\\' , '/' ) ;
176-
177- return `# ${ title } Agent
178- name = "${ agent . name } "
179- description = """
180- ${ title } agent from BMAD ${ agent . module . toUpperCase ( ) } module.
181-
182- CRITICAL: Read the full YAML, start activation to alter your state of being, follow startup section instructions, stay in this being until told to exit this mode:
183-
184- \`\`\`yaml
185- ${ yamlContent }
186- \`\`\`
187-
188- File: ${ relativePath }
189- """` ;
190- }
191151
192- /**
193- * Create TOML file for task
194- */
195- createTaskToml ( task , content , projectDir ) {
196- const titleMatch = content . match ( / t i t l e = " ( [ ^ " ] + ) " / ) ;
197- const title = titleMatch ? titleMatch [ 1 ] : this . formatTitle ( task . name ) ;
198- const yamlMatch = content . match ( / ` ` ` y a ? m l \r ? \n ( [ \s \S ] * ?) ` ` ` / ) ;
199- const yamlContent = yamlMatch ? yamlMatch [ 1 ] : content ;
200- const relativePath = path . relative ( projectDir , task . path ) . replaceAll ( '\\' , '/' ) ;
201-
202- return `# ${ title } Task
203- name = "${ task . name } "
204- description = """
205- ${ title } task from BMAD ${ task . module . toUpperCase ( ) } module.
206-
207- Execute this task by following the instructions in the YAML configuration:
208-
209- \`\`\`yaml
210- ${ yamlContent }
211- \`\`\`
212-
213- File: ${ relativePath }
214- """` ;
152+ if ( await fs . pathExists ( bmadDir ) ) {
153+ await fs . remove ( bmadDir ) ;
154+ console . log ( chalk . green ( ' ✓ Removed old BMad directory' ) ) ;
155+ }
215156 }
216157
217158 /**
218- * Create agent section for concatenated file
159+ * Read and process file content
219160 */
220- createAgentSection ( agent , content , projectDir ) {
221- // Extract metadata
222- const titleMatch = content . match ( / t i t l e = " ( [ ^ " ] + ) " / ) ;
223- const title = titleMatch ? titleMatch [ 1 ] : this . formatTitle ( agent . name ) ;
224-
225- // Extract YAML content
226- const yamlMatch = content . match ( / ` ` ` y a ? m l \r ? \n ( [ \s \S ] * ?) ` ` ` / ) ;
227- const yamlContent = yamlMatch ? yamlMatch [ 1 ] : content ;
228-
229- // Get relative path
230- const relativePath = path . relative ( projectDir , agent . path ) . replaceAll ( '\\' , '/' ) ;
231-
232- let section = `# ${ agent . name . toUpperCase ( ) } Agent Rule
233-
234- This rule is triggered when the user types \`/BMad:agents:${ agent . name } \` and activates the ${ title } agent persona.
235-
236- ## Agent Activation
237-
238- CRITICAL: Read the full YAML, start activation to alter your state of being, follow startup section instructions, stay in this being until told to exit this mode:
239-
240- \`\`\`yaml
241- ${ yamlContent }
242- \`\`\`
243-
244- ## File Reference
245-
246- The complete agent definition is available in [${ relativePath } ](${ relativePath } ).
247-
248- ## Usage
249-
250- When the user types \`/BMad:agents:${ agent . name } \`, activate this ${ title } persona and follow all instructions defined in the YAML configuration above.
251-
252- ## Module
253-
254- Part of the BMAD ${ agent . module . toUpperCase ( ) } module.` ;
255-
256- return section ;
161+ async readAndProcess ( filePath , metadata ) {
162+ const fs = require ( 'fs-extra' ) ;
163+ const content = await fs . readFile ( filePath , 'utf8' ) ;
164+ return this . processContent ( content , metadata ) ;
257165 }
258166
259167 /**
260- * Create task section for concatenated file
168+ * Override processContent to add TOML metadata header for Qwen
169+ * @param {string } content - File content
170+ * @param {Object } metadata - File metadata
171+ * @returns {string } Processed content with Qwen template
261172 */
262- createTaskSection ( task , content , projectDir ) {
263- const titleMatch = content . match ( / t i t l e = " ( [ ^ " ] + ) " / ) ;
264- const title = titleMatch ? titleMatch [ 1 ] : this . formatTitle ( task . name ) ;
265- const yamlMatch = content . match ( / ` ` ` y a ? m l \r ? \n ( [ \s \S ] * ?) ` ` ` / ) ;
266- const yamlContent = yamlMatch ? yamlMatch [ 1 ] : content ;
267- const relativePath = path . relative ( projectDir , task . path ) . replaceAll ( '\\' , '/' ) ;
268-
269- let section = `# ${ task . name . toUpperCase ( ) } Task
270-
271- This task is triggered when the user types \`/BMad:tasks:${ task . name } \` and executes the ${ title } task.
272-
273- ## Task Execution
274-
275- Execute this task by following the instructions in the YAML configuration:
276-
277- \`\`\`yaml
278- ${ yamlContent }
279- \`\`\`
280-
281- ## File Reference
282-
283- The complete task definition is available in [${ relativePath } ](${ relativePath } ).
284-
285- ## Usage
286-
287- When the user types \`/BMad:tasks:${ task . name } \`, execute this ${ title } task and follow all instructions defined in the YAML configuration above.
288-
289- ## Module
290-
291- Part of the BMAD ${ task . module . toUpperCase ( ) } module.` ;
173+ processContent ( content , metadata = { } ) {
174+ // First apply base processing (includes activation injection for agents)
175+ let prompt = super . processContent ( content , metadata ) ;
176+
177+ // Determine the type and description based on content
178+ const isAgent = content . includes ( '<agent' ) ;
179+ const isTask = content . includes ( '<task' ) ;
180+
181+ let description = '' ;
182+
183+ if ( isAgent ) {
184+ // Extract agent title if available
185+ const titleMatch = content . match ( / t i t l e = " ( [ ^ " ] + ) " / ) ;
186+ const title = titleMatch ? titleMatch [ 1 ] : metadata . name ;
187+ description = `BMAD ${ metadata . module . toUpperCase ( ) } Agent: ${ title } ` ;
188+ } else if ( isTask ) {
189+ // Extract task name if available
190+ const nameMatch = content . match ( / < n a m e > ( [ ^ < ] + ) < \/ n a m e > / ) ;
191+ const taskName = nameMatch ? nameMatch [ 1 ] : metadata . name ;
192+ description = `BMAD ${ metadata . module . toUpperCase ( ) } Task: ${ taskName } ` ;
193+ } else {
194+ description = `BMAD ${ metadata . module . toUpperCase ( ) } : ${ metadata . name } ` ;
195+ }
292196
293- return section ;
197+ return `description = "${ description } "
198+ prompt = """
199+ ${ prompt }
200+ """
201+ ` ;
294202 }
295203
296204 /**
@@ -310,6 +218,7 @@ Part of the BMAD ${task.module.toUpperCase()} module.`;
310218 const fs = require ( 'fs-extra' ) ;
311219 const bmadCommandsDir = path . join ( projectDir , this . configDir , this . commandsDir , this . bmadDir ) ;
312220 const oldBmadMethodDir = path . join ( projectDir , this . configDir , 'bmad-method' ) ;
221+ const oldBMadDir = path . join ( projectDir , this . configDir , 'BMad' ) ;
313222
314223 if ( await fs . pathExists ( bmadCommandsDir ) ) {
315224 await fs . remove ( bmadCommandsDir ) ;
@@ -320,6 +229,11 @@ Part of the BMAD ${task.module.toUpperCase()} module.`;
320229 await fs . remove ( oldBmadMethodDir ) ;
321230 console . log ( chalk . dim ( `Removed old BMAD configuration from Qwen Code` ) ) ;
322231 }
232+
233+ if ( await fs . pathExists ( oldBMadDir ) ) {
234+ await fs . remove ( oldBMadDir ) ;
235+ console . log ( chalk . dim ( `Removed old BMAD configuration from Qwen Code` ) ) ;
236+ }
323237 }
324238}
325239
0 commit comments