bmm-opencode 1.4.2 → 1.4.3

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 (126) hide show
  1. package/.opencode/agents/bmad-bmad-master.md +11 -0
  2. package/.opencode/agents/bmm-analyst.md +10 -32
  3. package/.opencode/agents/bmm-architect.md +6 -34
  4. package/.opencode/agents/bmm-dev.md +6 -32
  5. package/.opencode/agents/bmm-pm.md +10 -41
  6. package/.opencode/agents/bmm-qa.md +5 -31
  7. package/.opencode/agents/bmm-quick-flow-solo-dev.md +7 -32
  8. package/.opencode/agents/bmm-sm.md +8 -32
  9. package/.opencode/agents/bmm-tech-writer.md +12 -0
  10. package/.opencode/agents/bmm-ux-designer.md +5 -37
  11. package/.opencode/commands/bmad-bmm-check-implementation-readiness.md +7 -0
  12. package/.opencode/commands/bmad-bmm-code-review.md +7 -0
  13. package/.opencode/commands/bmad-bmm-correct-course.md +7 -0
  14. package/.opencode/commands/bmad-bmm-create-architecture.md +7 -0
  15. package/.opencode/commands/bmad-bmm-create-epics-and-stories.md +7 -0
  16. package/.opencode/commands/bmad-bmm-create-prd.md +7 -0
  17. package/.opencode/commands/bmad-bmm-create-product-brief.md +7 -0
  18. package/.opencode/commands/bmad-bmm-create-story.md +7 -0
  19. package/.opencode/commands/bmad-bmm-create-ux-design.md +7 -0
  20. package/.opencode/commands/bmad-bmm-dev-story.md +7 -0
  21. package/.opencode/commands/bmad-bmm-document-project.md +7 -0
  22. package/.opencode/commands/bmad-bmm-domain-research.md +7 -0
  23. package/.opencode/commands/bmad-bmm-edit-prd.md +7 -0
  24. package/.opencode/commands/bmad-bmm-generate-project-context.md +5 -0
  25. package/.opencode/commands/bmad-bmm-market-research.md +7 -0
  26. package/.opencode/commands/bmad-bmm-quick-dev.md +7 -0
  27. package/.opencode/commands/bmad-bmm-quick-spec.md +7 -0
  28. package/.opencode/commands/bmad-bmm-retrospective.md +7 -0
  29. package/.opencode/commands/bmad-bmm-sprint-planning.md +7 -0
  30. package/.opencode/commands/bmad-bmm-sprint-status.md +5 -0
  31. package/.opencode/commands/bmad-bmm-technical-research.md +7 -0
  32. package/.opencode/commands/bmad-bmm-validate-prd.md +7 -0
  33. package/.opencode/commands/bmad-brainstorming.md +7 -0
  34. package/.opencode/commands/bmad-editorial-review-prose.md +5 -0
  35. package/.opencode/commands/bmad-editorial-review-structure.md +5 -0
  36. package/.opencode/commands/bmad-help.md +5 -0
  37. package/.opencode/commands/bmad-index-docs.md +5 -0
  38. package/.opencode/commands/bmad-review-adversarial-general.md +5 -0
  39. package/.opencode/commands/bmad-shard-doc.md +5 -0
  40. package/.opencode/skills/bmad-bmad-master/SKILL.md +56 -0
  41. package/.opencode/skills/bmad-bmm-analyst/SKILL.md +65 -38
  42. package/.opencode/skills/bmad-bmm-architect/SKILL.md +49 -38
  43. package/.opencode/skills/bmad-bmm-check-implementation-readiness/SKILL.md +1092 -24
  44. package/.opencode/skills/bmad-bmm-code-review/SKILL.md +45 -13
  45. package/.opencode/skills/bmad-bmm-correct-course/SKILL.md +56 -94
  46. package/.opencode/skills/bmad-bmm-create-architecture/SKILL.md +2391 -27
  47. package/.opencode/skills/bmad-bmm-create-epics-and-stories/SKILL.md +927 -23
  48. package/.opencode/skills/bmad-bmm-create-prd/SKILL.md +9 -26
  49. package/.opencode/skills/bmad-bmm-create-product-brief/SKILL.md +1358 -22
  50. package/.opencode/skills/bmad-bmm-create-story/SKILL.md +61 -24
  51. package/.opencode/skills/bmad-bmm-create-ux-design/SKILL.md +3275 -26
  52. package/.opencode/skills/bmad-bmm-dev/SKILL.md +57 -43
  53. package/.opencode/skills/bmad-bmm-dev-story/SKILL.md +20 -13
  54. package/.opencode/skills/bmad-bmm-document-project/SKILL.md +22 -81
  55. package/.opencode/skills/bmad-bmm-domain-research/SKILL.md +53 -37
  56. package/.opencode/skills/bmad-bmm-edit-prd/SKILL.md +10 -27
  57. package/.opencode/skills/bmad-bmm-generate-project-context/SKILL.md +797 -28
  58. package/.opencode/skills/bmad-bmm-market-research/SKILL.md +53 -37
  59. package/.opencode/skills/bmad-bmm-pm/SKILL.md +60 -39
  60. package/.opencode/skills/bmad-bmm-qa/SKILL.md +77 -35
  61. package/.opencode/skills/bmad-bmm-qa-automate/SKILL.md +47 -129
  62. package/.opencode/skills/bmad-bmm-quick-dev/SKILL.md +802 -30
  63. package/.opencode/skills/bmad-bmm-quick-flow-solo-dev/SKILL.md +57 -36
  64. package/.opencode/skills/bmad-bmm-quick-spec/SKILL.md +684 -27
  65. package/.opencode/skills/bmad-bmm-retrospective/SKILL.md +55 -200
  66. package/.opencode/skills/bmad-bmm-sm/SKILL.md +57 -36
  67. package/.opencode/skills/bmad-bmm-sprint-planning/SKILL.md +51 -52
  68. package/.opencode/skills/bmad-bmm-sprint-status/SKILL.md +30 -99
  69. package/.opencode/skills/bmad-bmm-tech-writer/SKILL.md +70 -0
  70. package/.opencode/skills/bmad-bmm-technical-research/SKILL.md +53 -37
  71. package/.opencode/skills/bmad-bmm-ux-designer/SKILL.md +48 -37
  72. package/.opencode/skills/bmad-bmm-validate-prd/SKILL.md +10 -27
  73. package/.opencode/skills/bmad-brainstorming/SKILL.md +2048 -0
  74. package/.opencode/skills/bmad-editorial-review-prose/SKILL.md +107 -0
  75. package/.opencode/skills/bmad-editorial-review-structure/SKILL.md +214 -0
  76. package/.opencode/skills/bmad-help/SKILL.md +82 -0
  77. package/.opencode/skills/bmad-index-docs/SKILL.md +70 -0
  78. package/.opencode/skills/bmad-party-mode/SKILL.md +682 -0
  79. package/.opencode/skills/bmad-review-adversarial-general/SKILL.md +53 -0
  80. package/.opencode/skills/bmad-shard-doc/SKILL.md +113 -0
  81. package/README.md +28 -4
  82. package/dist/index.d.ts.map +1 -1
  83. package/dist/index.js +350 -47
  84. package/package.json +4 -3
  85. package/.opencode/agents/bmm-tech-writer-tech-writer.md +0 -44
  86. package/.opencode/agents/cis-brainstorming-coach.md +0 -38
  87. package/.opencode/agents/cis-creative-problem-solver.md +0 -38
  88. package/.opencode/agents/cis-design-thinking-coach.md +0 -38
  89. package/.opencode/agents/cis-innovation-strategist.md +0 -38
  90. package/.opencode/agents/cis-presentation-master.md +0 -54
  91. package/.opencode/agents/cis-storyteller-storyteller.md +0 -38
  92. package/.opencode/agents/core-bmad-master.md +0 -39
  93. package/.opencode/agents/gen-subagent.md +0 -311
  94. package/.opencode/agents/party-mode.md +0 -812
  95. package/.opencode/agents/tea-tea.md +0 -48
  96. package/.opencode/skills/bmad-bmm-dev-team-mode/SKILL.md +0 -300
  97. package/.opencode/skills/bmad-bmm-tech-writer-tech-writer/SKILL.md +0 -51
  98. package/.opencode/skills/bmad-cis-brainstorming-coach/SKILL.md +0 -46
  99. package/.opencode/skills/bmad-cis-creative-problem-solver/SKILL.md +0 -46
  100. package/.opencode/skills/bmad-cis-design-thinking/SKILL.md +0 -156
  101. package/.opencode/skills/bmad-cis-design-thinking-coach/SKILL.md +0 -46
  102. package/.opencode/skills/bmad-cis-innovation-strategist/SKILL.md +0 -46
  103. package/.opencode/skills/bmad-cis-innovation-strategy/SKILL.md +0 -238
  104. package/.opencode/skills/bmad-cis-presentation-master/SKILL.md +0 -52
  105. package/.opencode/skills/bmad-cis-problem-solving/SKILL.md +0 -212
  106. package/.opencode/skills/bmad-cis-storyteller-storyteller/SKILL.md +0 -48
  107. package/.opencode/skills/bmad-cis-storytelling/SKILL.md +0 -290
  108. package/.opencode/skills/bmad-core-bmad-master/SKILL.md +0 -48
  109. package/.opencode/skills/bmad-core-brainstorming/SKILL.md +0 -74
  110. package/.opencode/skills/bmad-core-party-mode/SKILL.md +0 -241
  111. package/.opencode/skills/bmad-core-task-editorial-review-prose/SKILL.md +0 -74
  112. package/.opencode/skills/bmad-core-task-editorial-review-structure/SKILL.md +0 -151
  113. package/.opencode/skills/bmad-core-task-help/SKILL.md +0 -100
  114. package/.opencode/skills/bmad-core-task-index-docs/SKILL.md +0 -46
  115. package/.opencode/skills/bmad-core-task-review-adversarial-general/SKILL.md +0 -36
  116. package/.opencode/skills/bmad-core-task-shard-doc/SKILL.md +0 -80
  117. package/.opencode/skills/bmad-tea-tea/SKILL.md +0 -57
  118. package/.opencode/skills/bmad-tea-teach-me-testing/SKILL.md +0 -106
  119. package/.opencode/skills/bmad-tea-testarch-atdd/SKILL.md +0 -62
  120. package/.opencode/skills/bmad-tea-testarch-automate/SKILL.md +0 -67
  121. package/.opencode/skills/bmad-tea-testarch-ci/SKILL.md +0 -62
  122. package/.opencode/skills/bmad-tea-testarch-framework/SKILL.md +0 -62
  123. package/.opencode/skills/bmad-tea-testarch-nfr/SKILL.md +0 -60
  124. package/.opencode/skills/bmad-tea-testarch-test-design/SKILL.md +0 -76
  125. package/.opencode/skills/bmad-tea-testarch-test-review/SKILL.md +0 -60
  126. package/.opencode/skills/bmad-tea-testarch-trace/SKILL.md +0 -60
package/dist/index.js CHANGED
@@ -1,43 +1,13 @@
1
1
  import { tool } from "@opencode-ai/plugin/tool";
2
- import { readFileSync, readdirSync, existsSync, mkdirSync, writeFileSync } from "fs";
2
+ import { readFileSync, readdirSync, existsSync, mkdirSync, writeFileSync, statSync } from "fs";
3
3
  import { join, dirname } from "path";
4
4
  import { fileURLToPath } from "url";
5
5
  import { homedir } from "os";
6
- import { convert } from "bmad-opencode-converter";
7
6
  const __dirname = dirname(fileURLToPath(import.meta.url));
8
7
  const packageRoot = join(__dirname, "..");
9
8
  const bundledAgentsDir = join(packageRoot, ".opencode", "agents");
10
9
  const bundledSkillsDir = join(packageRoot, ".opencode", "skills");
11
- const bmadSourceDir = join(packageRoot, "_bmad");
12
- let conversionCache = null;
13
- const CACHE_TTL_MS = 60000;
14
- function hasBmadSource() {
15
- return existsSync(join(bmadSourceDir, "_config", "agent-manifest.csv"));
16
- }
17
- async function getConvertedResources() {
18
- if (conversionCache && Date.now() - conversionCache.timestamp < CACHE_TTL_MS) {
19
- return { agents: conversionCache.agents, skills: conversionCache.skills };
20
- }
21
- if (hasBmadSource()) {
22
- try {
23
- const result = await convert({
24
- sourceDir: bmadSourceDir,
25
- outputDir: "",
26
- verbose: false,
27
- });
28
- conversionCache = {
29
- agents: result.agents,
30
- skills: result.skills,
31
- timestamp: Date.now(),
32
- };
33
- return { agents: result.agents, skills: result.skills };
34
- }
35
- catch (err) {
36
- console.error("Failed to convert from BMAD source:", err);
37
- }
38
- }
39
- return readBundledFiles();
40
- }
10
+ const bundledWorkflowsDir = join(packageRoot, "_bmad", "bmm", "workflows");
41
11
  function readBundledFiles() {
42
12
  const agents = [];
43
13
  const skills = [];
@@ -53,6 +23,8 @@ function readBundledFiles() {
53
23
  mode: frontmatter.mode,
54
24
  model: frontmatter.model || undefined,
55
25
  tools: frontmatter.tools,
26
+ workflows: frontmatter.workflows || extractWorkflowsFromBody(body),
27
+ permittedSkills: extractPermittedSkills(content),
56
28
  },
57
29
  prompt: body,
58
30
  });
@@ -127,6 +99,129 @@ function parseFrontmatter(content) {
127
99
  }
128
100
  return { frontmatter, body: match[2] };
129
101
  }
102
+ function extractPermittedSkills(content) {
103
+ const skills = [];
104
+ const lines = content.split('\n');
105
+ let inPermission = false;
106
+ let inSkill = false;
107
+ for (const line of lines) {
108
+ if (line === '---' && skills.length > 0)
109
+ break;
110
+ if (line.match(/^permission:\s*$/)) {
111
+ inPermission = true;
112
+ continue;
113
+ }
114
+ if (inPermission && line.match(/^\s+skill:\s*$/)) {
115
+ inSkill = true;
116
+ continue;
117
+ }
118
+ if (inSkill) {
119
+ const skillMatch = line.match(/^\s+"([^"]+)":\s*allow/);
120
+ if (skillMatch) {
121
+ skills.push(skillMatch[1]);
122
+ }
123
+ else if (line.match(/^\s+\w+:/) && !line.match(/^\s+"/)) {
124
+ inSkill = false;
125
+ inPermission = false;
126
+ }
127
+ else if (line.match(/^\w/)) {
128
+ inSkill = false;
129
+ inPermission = false;
130
+ }
131
+ }
132
+ }
133
+ return skills;
134
+ }
135
+ function extractWorkflowsFromBody(body) {
136
+ const workflows = [];
137
+ const lines = body.split('\n');
138
+ let inWorkflowSection = false;
139
+ for (const line of lines) {
140
+ if (line.includes('You have access to the following workflows')) {
141
+ inWorkflowSection = true;
142
+ continue;
143
+ }
144
+ if (inWorkflowSection) {
145
+ const match = line.match(/^-\s+([\w-]+)/);
146
+ if (match) {
147
+ workflows.push(match[1]);
148
+ }
149
+ else if (line.trim() && !line.startsWith('-')) {
150
+ break;
151
+ }
152
+ }
153
+ }
154
+ return workflows;
155
+ }
156
+ function readWorkflows(workflowsDir) {
157
+ const workflows = [];
158
+ const searchDir = workflowsDir || bundledWorkflowsDir;
159
+ if (!existsSync(searchDir)) {
160
+ return workflows;
161
+ }
162
+ function scanDirectory(dir) {
163
+ for (const item of readdirSync(dir)) {
164
+ const fullPath = join(dir, item);
165
+ const stat = statSync(fullPath);
166
+ if (stat.isDirectory()) {
167
+ scanDirectory(fullPath);
168
+ }
169
+ else if (item === 'workflow.yaml') {
170
+ try {
171
+ const content = readFileSync(fullPath, 'utf-8');
172
+ const lines = content.split('\n');
173
+ let name = '';
174
+ let description = '';
175
+ let author = '';
176
+ for (const line of lines) {
177
+ const nameMatch = line.match(/^name:\s*["']?([^"'\n]+)["']?/);
178
+ const descMatch = line.match(/^description:\s*["']?([^"'\n]+)["']?/);
179
+ const authorMatch = line.match(/^author:\s*["']?([^"'\n]+)["']?/);
180
+ if (nameMatch)
181
+ name = nameMatch[1];
182
+ if (descMatch)
183
+ description = descMatch[1];
184
+ if (authorMatch)
185
+ author = authorMatch[1];
186
+ }
187
+ if (name) {
188
+ workflows.push({
189
+ name,
190
+ description,
191
+ path: fullPath,
192
+ author,
193
+ });
194
+ }
195
+ }
196
+ catch (error) {
197
+ // Skip invalid YAML files
198
+ }
199
+ }
200
+ }
201
+ }
202
+ scanDirectory(searchDir);
203
+ return workflows;
204
+ }
205
+ function getAgentWorkflowMappings() {
206
+ const { agents } = readBundledFiles();
207
+ const workflows = readWorkflows();
208
+ return agents.map(agent => {
209
+ const agentName = agent.filename.replace('.md', '');
210
+ const agentWorkflows = agent.frontmatter.workflows || [];
211
+ const workflowDetails = agentWorkflows
212
+ .map(workflowName => {
213
+ const workflow = workflows.find(w => w.name === workflowName ||
214
+ w.name.endsWith(workflowName) ||
215
+ workflowName.includes(w.name));
216
+ return workflow ? `${workflowName}${workflow.description ? ` - ${workflow.description}` : ''}` : workflowName;
217
+ });
218
+ return {
219
+ agent: agentName,
220
+ workflows: agentWorkflows,
221
+ description: agent.frontmatter.description
222
+ };
223
+ }).filter(mapping => mapping.workflows.length > 0);
224
+ }
130
225
  function writeAgentFile(targetDir, agent) {
131
226
  const agentDir = join(targetDir, "agents");
132
227
  mkdirSync(agentDir, { recursive: true });
@@ -144,7 +239,15 @@ function writeAgentFile(targetDir, agent) {
144
239
  }
145
240
  }
146
241
  frontmatterLines.push("---");
147
- const content = frontmatterLines.join("\n") + "\n\n" + agent.prompt;
242
+ let promptContent = agent.prompt;
243
+ if (agent.frontmatter.workflows && agent.frontmatter.workflows.length > 0) {
244
+ const workflows = readWorkflows();
245
+ const workflowSection = buildWorkflowSection(agent.frontmatter.workflows, workflows);
246
+ if (!promptContent.includes("You have access to the following workflows")) {
247
+ promptContent = promptContent.trim() + "\n\n" + workflowSection;
248
+ }
249
+ }
250
+ const content = frontmatterLines.join("\n") + "\n\n" + promptContent;
148
251
  writeFileSync(join(agentDir, agent.filename), content);
149
252
  }
150
253
  function writeSkillFile(targetDir, skill) {
@@ -167,7 +270,7 @@ function writeSkillFile(targetDir, skill) {
167
270
  const content = frontmatterLines.join("\n") + "\n\n" + skill.content;
168
271
  writeFileSync(join(skillDir, "SKILL.md"), content);
169
272
  }
170
- function formatAgentContent(agent) {
273
+ function formatAgentContent(agent, injectWorkflows = true) {
171
274
  const frontmatterLines = ["---"];
172
275
  frontmatterLines.push(`description: ${JSON.stringify(agent.frontmatter.description)}`);
173
276
  if (agent.frontmatter.mode)
@@ -181,8 +284,112 @@ function formatAgentContent(agent) {
181
284
  frontmatterLines.push(` ${toolName}: ${enabled}`);
182
285
  }
183
286
  }
287
+ if (agent.frontmatter.workflows && agent.frontmatter.workflows.length > 0) {
288
+ frontmatterLines.push("workflows:");
289
+ for (const workflow of agent.frontmatter.workflows) {
290
+ frontmatterLines.push(` - ${workflow}`);
291
+ }
292
+ }
293
+ frontmatterLines.push("---");
294
+ let promptContent = agent.prompt;
295
+ if (injectWorkflows && agent.frontmatter.workflows && agent.frontmatter.workflows.length > 0) {
296
+ const workflows = readWorkflows();
297
+ const workflowSection = buildWorkflowSection(agent.frontmatter.workflows, workflows);
298
+ if (!promptContent.includes("You have access to the following workflows")) {
299
+ promptContent = promptContent.trim() + "\n\n" + workflowSection;
300
+ }
301
+ }
302
+ return frontmatterLines.join("\n") + "\n\n" + promptContent;
303
+ }
304
+ function buildWorkflowSection(agentWorkflows, allWorkflows) {
305
+ const lines = ["You have access to the following workflows and tasks:"];
306
+ for (const workflowName of agentWorkflows) {
307
+ const workflow = allWorkflows.find(w => w.name === workflowName ||
308
+ w.name.endsWith(workflowName) ||
309
+ workflowName.includes(w.name));
310
+ if (workflow && workflow.description) {
311
+ lines.push(`- **${workflowName}**: ${workflow.description}`);
312
+ }
313
+ else {
314
+ lines.push(`- ${workflowName}`);
315
+ }
316
+ }
317
+ return lines.join("\n");
318
+ }
319
+ function getCommandMappings() {
320
+ const { agents, skills } = readBundledFiles();
321
+ const mappings = [];
322
+ const mappedSkills = new Set();
323
+ const agentBaseSkills = new Set();
324
+ for (const a of agents) {
325
+ const name = a.filename.replace('.md', '');
326
+ agentBaseSkills.add(`bmad-${name}`);
327
+ agentBaseSkills.add(name);
328
+ }
329
+ const skipSkills = new Set(['bmad-party-mode']);
330
+ for (const agent of agents) {
331
+ const agentName = agent.filename.replace('.md', '');
332
+ const permitted = agent.frontmatter.permittedSkills || [];
333
+ const workflows = agent.frontmatter.workflows || [];
334
+ const allSkillNames = [...new Set([...permitted, ...workflows])];
335
+ for (const skillName of allSkillNames) {
336
+ if (agentBaseSkills.has(skillName) || skipSkills.has(skillName))
337
+ continue;
338
+ if (mappedSkills.has(skillName))
339
+ continue;
340
+ const skill = skills.find(s => s.name === skillName || s.folder === skillName);
341
+ if (!skill)
342
+ continue;
343
+ mappings.push({
344
+ commandName: skillName,
345
+ skillName: skillName,
346
+ agentName: agentName,
347
+ description: skill.frontmatter.description,
348
+ });
349
+ mappedSkills.add(skillName);
350
+ }
351
+ }
352
+ const standaloneSkills = [
353
+ 'bmad-help',
354
+ 'bmad-index-docs',
355
+ 'bmad-shard-doc',
356
+ 'bmad-editorial-review-prose',
357
+ 'bmad-editorial-review-structure',
358
+ 'bmad-review-adversarial-general',
359
+ 'bmad-bmm-generate-project-context',
360
+ 'bmad-bmm-sprint-status',
361
+ ];
362
+ for (const skillName of standaloneSkills) {
363
+ if (mappedSkills.has(skillName))
364
+ continue;
365
+ const skill = skills.find(s => s.name === skillName || s.folder === skillName);
366
+ if (!skill)
367
+ continue;
368
+ mappings.push({
369
+ commandName: skillName,
370
+ skillName: skillName,
371
+ agentName: '',
372
+ description: skill.frontmatter.description,
373
+ });
374
+ mappedSkills.add(skillName);
375
+ }
376
+ return mappings;
377
+ }
378
+ function writeCommandFile(targetDir, mapping) {
379
+ const commandsDir = join(targetDir, "commands");
380
+ mkdirSync(commandsDir, { recursive: true });
381
+ const frontmatterLines = ["---"];
382
+ frontmatterLines.push(`description: ${JSON.stringify(mapping.description)}`);
383
+ if (mapping.agentName) {
384
+ frontmatterLines.push(`agent: ${mapping.agentName}`);
385
+ frontmatterLines.push(`subtask: true`);
386
+ }
184
387
  frontmatterLines.push("---");
185
- return frontmatterLines.join("\n") + "\n\n" + agent.prompt;
388
+ const prompt = mapping.agentName
389
+ ? `Load the skill "${mapping.skillName}" and follow its instructions. $ARGUMENTS`
390
+ : `Load the skill "${mapping.skillName}" and follow its instructions. $ARGUMENTS`;
391
+ const content = frontmatterLines.join("\n") + "\n\n" + prompt + "\n";
392
+ writeFileSync(join(commandsDir, `${mapping.commandName}.md`), content);
186
393
  }
187
394
  function formatSkillContent(skill) {
188
395
  const frontmatterLines = ["---"];
@@ -205,13 +412,14 @@ export const BMMPlugin = async () => {
205
412
  return {
206
413
  tool: {
207
414
  bmm_list: tool({
208
- description: "List all available BMAD-METHOD agents and skills from bmm-opencode",
415
+ description: "List all available BMAD-METHOD agents, skills, and commands from bmm-opencode",
209
416
  args: {},
210
417
  async execute() {
211
- const { agents, skills } = await getConvertedResources();
212
- const source = hasBmadSource() ? "BMAD source (_bmad/)" : "bundled files (.opencode/)";
418
+ const { agents, skills } = readBundledFiles();
419
+ const commands = getCommandMappings();
420
+ const agentCommands = commands.filter(c => c.agentName);
421
+ const standaloneCommands = commands.filter(c => !c.agentName);
213
422
  return `# BMM-OpenCode Resources
214
- Source: ${source}
215
423
 
216
424
  ## Agents (${agents.length})
217
425
  ${agents.map((a) => `- ${a.filename.replace(".md", "")}: ${a.frontmatter.description}`).join("\n")}
@@ -219,11 +427,20 @@ ${agents.map((a) => `- ${a.filename.replace(".md", "")}: ${a.frontmatter.descrip
219
427
  ## Skills (${skills.length})
220
428
  ${skills.map((s) => `- ${s.name}: ${s.frontmatter.description}`).join("\n")}
221
429
 
430
+ ## Commands (${commands.length})
431
+ After \`bmm_install\`, type \`/\` in the TUI to see these workflow commands:
432
+
433
+ ### Agent Workflows (${agentCommands.length})
434
+ ${agentCommands.map((c) => `- \`/${c.commandName}\` → @${c.agentName}: ${c.description}`).join("\n")}
435
+
436
+ ### Standalone Utilities (${standaloneCommands.length})
437
+ ${standaloneCommands.map((c) => `- \`/${c.commandName}\`: ${c.description}`).join("\n")}
438
+
222
439
  ## Usage
223
440
  - Use \`bmm_agent\` tool to get agent definition
224
441
  - Use \`bmm_skill\` tool to get skill instructions
225
- - Use \`bmm_install\` with \`global=true\` to install globally (~/.config/opencode/)
226
- - Use \`bmm_install\` to install to current project (.opencode/)`;
442
+ - Use \`bmm_install\` to install agents, skills, and commands
443
+ - After install, use \`/command-name\` to invoke workflows directly`;
227
444
  },
228
445
  }),
229
446
  bmm_agent: tool({
@@ -232,14 +449,32 @@ ${skills.map((s) => `- ${s.name}: ${s.frontmatter.description}`).join("\n")}
232
449
  name: tool.schema.string().describe("Agent name (e.g., bmm-dev, bmm-pm)"),
233
450
  },
234
451
  async execute(args) {
235
- const { agents } = await getConvertedResources();
452
+ const { agents } = readBundledFiles();
236
453
  const agent = agents.find((a) => a.filename === `${args.name}.md` ||
237
454
  a.filename.replace(".md", "") === args.name);
238
455
  if (!agent) {
239
456
  const available = agents.map((a) => a.filename.replace(".md", "")).join(", ");
240
457
  return `Agent "${args.name}" not found.\n\nAvailable agents: ${available}`;
241
458
  }
242
- return formatAgentContent(agent);
459
+ let output = formatAgentContent(agent);
460
+ if (agent.frontmatter.workflows && agent.frontmatter.workflows.length > 0) {
461
+ const workflows = readWorkflows();
462
+ output += `\n\n## Available Workflows\n\n`;
463
+ output += `This agent has access to ${agent.frontmatter.workflows.length} workflow(s):\n\n`;
464
+ for (const workflowName of agent.frontmatter.workflows) {
465
+ const workflow = workflows.find(w => w.name === workflowName ||
466
+ w.name.endsWith(workflowName) ||
467
+ workflowName.includes(w.name));
468
+ if (workflow) {
469
+ output += `- **${workflowName}**: ${workflow.description}\n`;
470
+ }
471
+ else {
472
+ output += `- ${workflowName}\n`;
473
+ }
474
+ }
475
+ output += `\n**Tip**: Use \`bmm_suggest_workflows({ agent: "${args.name}" })\` for detailed workflow information.\n`;
476
+ }
477
+ return output;
243
478
  },
244
479
  }),
245
480
  bmm_skill: tool({
@@ -248,7 +483,7 @@ ${skills.map((s) => `- ${s.name}: ${s.frontmatter.description}`).join("\n")}
248
483
  name: tool.schema.string().describe("Skill name (e.g., bmad-bmm-create-prd)"),
249
484
  },
250
485
  async execute(args) {
251
- const { skills } = await getConvertedResources();
486
+ const { skills } = readBundledFiles();
252
487
  const skill = skills.find((s) => s.name === args.name || s.folder === args.name);
253
488
  if (!skill) {
254
489
  const available = skills.map((s) => s.name).join(", ");
@@ -330,7 +565,7 @@ To avoid confusion, consider removing one installation.`;
330
565
 
331
566
  Use \`force=true\` to overwrite, or remove existing files first.`;
332
567
  }
333
- const { agents, skills } = await getConvertedResources();
568
+ const { agents, skills } = readBundledFiles();
334
569
  let agentsCopied = 0;
335
570
  for (const agent of agents) {
336
571
  writeAgentFile(targetBase, agent);
@@ -341,23 +576,91 @@ Use \`force=true\` to overwrite, or remove existing files first.`;
341
576
  writeSkillFile(targetBase, skill);
342
577
  skillsCopied++;
343
578
  }
579
+ const commandMappings = getCommandMappings();
580
+ let commandsCopied = 0;
581
+ for (const mapping of commandMappings) {
582
+ writeCommandFile(targetBase, mapping);
583
+ commandsCopied++;
584
+ }
344
585
  const isGlobal = targetBase === globalConfigDir;
345
586
  const installType = isGlobal ? "globally" : "to project";
346
- const source = hasBmadSource() ? "converted from BMAD source" : "from bundled files";
587
+ const source = "from bundled files";
588
+ const targetCommands = join(targetBase, "commands");
347
589
  const autoNote = autoDetected ? `\n\nNote: Auto-detected existing global installation at ${globalConfigDir}` : "";
348
590
  return `Successfully installed BMM-OpenCode ${installType} (${targetBase}):
349
591
  - ${agentsCopied} agents copied to ${targetAgents}
350
592
  - ${skillsCopied} skills copied to ${targetSkills}
593
+ - ${commandsCopied} commands copied to ${targetCommands}
351
594
 
352
595
  Source: ${source}${autoNote}
353
596
 
354
- Restart OpenCode to use the new agents and skills.`;
597
+ After restart, type \`/\` to see all available workflow commands (e.g. \`/bmad-bmm-create-prd\`, \`/bmad-bmm-dev-story\`).
598
+ Each command auto-routes to the correct agent and loads the workflow skill.
599
+
600
+ Restart OpenCode to use the new agents, skills, and commands.`;
355
601
  }
356
602
  catch (error) {
357
603
  return `Installation failed: ${error instanceof Error ? error.message : String(error)}`;
358
604
  }
359
605
  },
360
606
  }),
607
+ bmm_agent_workflows: tool({
608
+ description: "List all BMM agents with their available workflows for @agent autocomplete suggestions",
609
+ args: {},
610
+ async execute() {
611
+ const mappings = getAgentWorkflowMappings();
612
+ if (mappings.length === 0) {
613
+ return "No agent-workflow mappings found. Make sure BMM agents are properly configured.";
614
+ }
615
+ let output = "# BMM Agent Workflow Mappings\n\n";
616
+ output += "Use this information to suggest workflows when users @mention an agent.\n\n";
617
+ for (const mapping of mappings) {
618
+ output += `## @${mapping.agent}\n`;
619
+ output += `**Role**: ${mapping.description}\n\n`;
620
+ output += `**Available Workflows**:\n`;
621
+ for (const workflow of mapping.workflows) {
622
+ output += `- ${workflow}\n`;
623
+ }
624
+ output += '\n';
625
+ }
626
+ return output;
627
+ },
628
+ }),
629
+ bmm_suggest_workflows: tool({
630
+ description: "Get workflow suggestions for a specific BMM agent (useful for @agent autocomplete)",
631
+ args: {
632
+ agent: tool.schema.string().describe("Agent name (e.g., bmm-dev, bmm-pm, bmm-qa)"),
633
+ },
634
+ async execute(args) {
635
+ const mappings = getAgentWorkflowMappings();
636
+ const agentName = args.agent.replace(/^@/, '').replace(/\.md$/, '');
637
+ const mapping = mappings.find(m => m.agent === agentName ||
638
+ m.agent === `bmm-${agentName}` ||
639
+ m.agent === `bmad-${agentName}`);
640
+ if (!mapping) {
641
+ const available = mappings.map(m => m.agent).join(", ");
642
+ return `Agent "${args.agent}" not found or has no workflows configured.\n\nAvailable agents with workflows: ${available}`;
643
+ }
644
+ let output = `# Workflows for @${mapping.agent}\n\n`;
645
+ output += `**Role**: ${mapping.description}\n\n`;
646
+ output += `**Available Workflows** (${mapping.workflows.length}):\n`;
647
+ const workflows = readWorkflows();
648
+ for (const workflowName of mapping.workflows) {
649
+ const workflow = workflows.find(w => w.name === workflowName ||
650
+ w.name.endsWith(workflowName) ||
651
+ workflowName.includes(w.name));
652
+ if (workflow) {
653
+ output += `- **${workflowName}**: ${workflow.description}\n`;
654
+ }
655
+ else {
656
+ output += `- ${workflowName}\n`;
657
+ }
658
+ }
659
+ output += `\n## Usage\n`;
660
+ output += `\`\`\`\n@${mapping.agent} [use workflow: ${mapping.workflows[0] || 'workflow-name'}]\n\`\`\`\n`;
661
+ return output;
662
+ },
663
+ }),
361
664
  },
362
665
  };
363
666
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "bmm-opencode",
3
- "version": "1.4.2",
3
+ "version": "1.4.3",
4
4
  "description": "BMAD-METHOD agents and skills for OpenCode - AI agent framework with 19 specialized agents and 62 workflow skills",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -32,14 +32,15 @@
32
32
  "scripts": {
33
33
  "build": "tsc",
34
34
  "dev": "tsc --watch",
35
+ "dev:test": "bash scripts/dev-test.sh",
35
36
  "test": "node --experimental-vm-modules --test tests/*.test.js",
36
37
  "prepublishOnly": "npm run build && npm test"
37
38
  },
38
39
  "dependencies": {
39
- "@opencode-ai/plugin": "^1.1.51",
40
- "bmad-opencode-converter": "^1.0.0"
40
+ "@opencode-ai/plugin": "^1.1.51"
41
41
  },
42
42
  "devDependencies": {
43
+ "bmad-opencode-converter": "^1.3.0",
43
44
  "@types/node": "^22.0.0",
44
45
  "typescript": "^5.0.0"
45
46
  },
@@ -1,44 +0,0 @@
1
- ---
2
- description: "Technical Writer"
3
- mode: subagent
4
- model: "google/gemini-2.5-flash"
5
- tools:
6
- write: true
7
- edit: true
8
- bash: true
9
- read: true
10
- glob: true
11
- grep: true
12
- ---
13
-
14
- 📚 **Technical Writer** - Paige
15
-
16
- ## Role
17
- Technical Documentation Specialist + Knowledge Curator
18
-
19
- ## Identity
20
- Experienced technical writer expert in CommonMark, DITA, OpenAPI. Master of clarity - transforms complex concepts into accessible structured documentation.
21
-
22
- ## Communication Style
23
- Patient educator who explains like teaching a friend. Uses analogies that make complex simple, celebrates clarity when it shines.
24
-
25
- ## Principles
26
- - Every Technical Document I touch helps someone accomplish a task. Thus I strive for Clarity above all, and every word and phrase serves a purpose without being overly wordy.
27
- - I believe a picture/diagram is worth 1000s works and will include diagrams over drawn out text.
28
- - I understand the intended audience or will clarify with the user so I know when to simplify vs when to be detailed.
29
- - I will always strive to follow `_bmad/_memory/tech
30
- - writer
31
- - sidecar/documentation
32
- - standards.md` best practices.
33
-
34
- ## Rules
35
- - ALWAYS communicate in {communication_language} UNLESS contradicted by communication_style.
36
- - Stay in character until exit selected
37
- - Display Menu items as the item dictates and in the order given.
38
- - Load files ONLY when executing a user chosen workflow or a command requires it, EXCEPTION: agent activation step 2 config.yaml
39
-
40
- ---
41
-
42
- ## Model Configuration
43
- - **Default**: `google/gemini-2.5-flash`
44
- - **Alternatives**: `anthropic/claude-haiku-3-5-20241022`, `openai/gpt-4o-mini`
@@ -1,38 +0,0 @@
1
- ---
2
- description: "Elite Brainstorming Specialist"
3
- mode: subagent
4
- model: "openai/gpt-4o"
5
- tools:
6
- write: true
7
- edit: true
8
- bash: true
9
- read: true
10
- glob: true
11
- grep: true
12
- ---
13
-
14
- 🧠 **Elite Brainstorming Specialist** - Carson
15
-
16
- ## Role
17
- Master Brainstorming Facilitator + Innovation Catalyst
18
-
19
- ## Identity
20
- Elite facilitator with 20+ years leading breakthrough sessions. Expert in creative techniques, group dynamics, and systematic innovation.
21
-
22
- ## Communication Style
23
- Talks like an enthusiastic improv coach - high energy, builds on ideas with YES AND, celebrates wild thinking
24
-
25
- ## Principles
26
- - Psychological safety unlocks breakthroughs. Wild ideas today become innovations tomorrow. Humor and play are serious innovation tools.
27
-
28
- ## Rules
29
- - ALWAYS communicate in {communication_language} UNLESS contradicted by communication_style.
30
- - Stay in character until exit selected
31
- - Display Menu items as the item dictates and in the order given.
32
- - Load files ONLY when executing a user chosen workflow or a command requires it, EXCEPTION: agent activation step 2 config.yaml
33
-
34
- ---
35
-
36
- ## Model Configuration
37
- - **Default**: `openai/gpt-4o`
38
- - **Alternatives**: `anthropic/claude-sonnet-4-20250514`, `google/gemini-2.5-flash`
@@ -1,38 +0,0 @@
1
- ---
2
- description: "Master Problem Solver"
3
- mode: subagent
4
- model: "anthropic/claude-opus-4-20250514"
5
- tools:
6
- write: true
7
- edit: true
8
- bash: true
9
- read: true
10
- glob: true
11
- grep: true
12
- ---
13
-
14
- 🔬 **Master Problem Solver** - Dr. Quinn
15
-
16
- ## Role
17
- Systematic Problem-Solving Expert + Solutions Architect
18
-
19
- ## Identity
20
- Renowned problem-solver who cracks impossible challenges. Expert in TRIZ, Theory of Constraints, Systems Thinking. Former aerospace engineer turned puzzle master.
21
-
22
- ## Communication Style
23
- Speaks like Sherlock Holmes mixed with a playful scientist - deductive, curious, punctuates breakthroughs with AHA moments
24
-
25
- ## Principles
26
- - Every problem is a system revealing weaknesses. Hunt for root causes relentlessly. The right question beats a fast answer.
27
-
28
- ## Rules
29
- - ALWAYS communicate in {communication_language} UNLESS contradicted by communication_style.
30
- - Stay in character until exit selected
31
- - Display Menu items as the item dictates and in the order given.
32
- - Load files ONLY when executing a user chosen workflow or a command requires it, EXCEPTION: agent activation step 2 config.yaml
33
-
34
- ---
35
-
36
- ## Model Configuration
37
- - **Default**: `anthropic/claude-opus-4-20250514`
38
- - **Alternatives**: `openai/o3`, `google/gemini-2.5-pro`