convoke-agents 3.0.4 → 3.2.0
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/CHANGELOG.md +60 -0
- package/README.md +14 -13
- package/_bmad/bme/_artifacts/config.yaml +15 -0
- package/_bmad/bme/_artifacts/workflows/bmad-migrate-artifacts/SKILL.md +6 -0
- package/_bmad/bme/_artifacts/workflows/bmad-migrate-artifacts/steps/step-01-scope.md +138 -0
- package/_bmad/bme/_artifacts/workflows/bmad-migrate-artifacts/steps/step-02-dryrun.md +199 -0
- package/_bmad/bme/_artifacts/workflows/bmad-migrate-artifacts/steps/step-03-resolve.md +174 -0
- package/_bmad/bme/_artifacts/workflows/bmad-migrate-artifacts/steps/step-04-execute.md +213 -0
- package/_bmad/bme/_artifacts/workflows/bmad-migrate-artifacts/workflow.md +85 -0
- package/_bmad/bme/_artifacts/workflows/bmad-portfolio-status/SKILL.md +6 -0
- package/_bmad/bme/_artifacts/workflows/bmad-portfolio-status/steps/step-01-scan.md +131 -0
- package/_bmad/bme/_artifacts/workflows/bmad-portfolio-status/steps/step-02-explore.md +131 -0
- package/_bmad/bme/_artifacts/workflows/bmad-portfolio-status/steps/step-03-recommend.md +149 -0
- package/_bmad/bme/_artifacts/workflows/bmad-portfolio-status/workflow.md +78 -0
- package/_bmad/bme/_gyre/guides/GYRE-TEAM-GUIDE.md +506 -0
- package/_bmad/bme/_portability/skills/bmad-export-skill/SKILL.md +6 -0
- package/_bmad/bme/_portability/skills/bmad-export-skill/workflow.md +74 -0
- package/_bmad/bme/_portability/skills/bmad-generate-catalog/SKILL.md +6 -0
- package/_bmad/bme/_portability/skills/bmad-generate-catalog/workflow.md +42 -0
- package/_bmad/bme/_portability/skills/bmad-seed-catalog/SKILL.md +6 -0
- package/_bmad/bme/_portability/skills/bmad-seed-catalog/workflow.md +61 -0
- package/_bmad/bme/_portability/skills/bmad-validate-exports/SKILL.md +6 -0
- package/_bmad/bme/_portability/skills/bmad-validate-exports/workflow.md +43 -0
- package/_bmad/bme/_team-factory/agents/team-factory.md +128 -0
- package/_bmad/bme/_team-factory/config.yaml +13 -0
- package/_bmad/bme/_team-factory/lib/cascade-logic.js +184 -0
- package/_bmad/bme/_team-factory/lib/collision-detector.js +228 -0
- package/_bmad/bme/_team-factory/lib/manifest-tracker.js +214 -0
- package/_bmad/bme/_team-factory/lib/spec-differ.js +176 -0
- package/_bmad/bme/_team-factory/lib/spec-parser.js +201 -0
- package/_bmad/bme/_team-factory/lib/spec-writer.js +128 -0
- package/_bmad/bme/_team-factory/lib/types/factory-types.js +193 -0
- package/_bmad/bme/_team-factory/lib/utils/csv-utils.js +62 -0
- package/_bmad/bme/_team-factory/lib/utils/naming-utils.js +45 -0
- package/_bmad/bme/_team-factory/lib/validators/end-to-end-validator.js +898 -0
- package/_bmad/bme/_team-factory/lib/writers/activation-validator.js +175 -0
- package/_bmad/bme/_team-factory/lib/writers/config-appender.js +192 -0
- package/_bmad/bme/_team-factory/lib/writers/config-creator.js +215 -0
- package/_bmad/bme/_team-factory/lib/writers/csv-appender.js +118 -0
- package/_bmad/bme/_team-factory/lib/writers/csv-creator.js +190 -0
- package/_bmad/bme/_team-factory/lib/writers/registry-appender.js +372 -0
- package/_bmad/bme/_team-factory/lib/writers/registry-writer.js +409 -0
- package/_bmad/bme/_team-factory/module-help.csv +3 -0
- package/_bmad/bme/_team-factory/schemas/schema-independent.json +147 -0
- package/_bmad/bme/_team-factory/schemas/schema-sequential.json +242 -0
- package/_bmad/bme/_team-factory/templates/team-spec-template.yaml +86 -0
- package/_bmad/bme/_team-factory/workflows/add-team/step-01-scope.md +105 -0
- package/_bmad/bme/_team-factory/workflows/add-team/step-02-connect.md +110 -0
- package/_bmad/bme/_team-factory/workflows/add-team/step-03-review.md +116 -0
- package/_bmad/bme/_team-factory/workflows/add-team/step-04-generate.md +160 -0
- package/_bmad/bme/_team-factory/workflows/add-team/step-05-validate.md +146 -0
- package/_bmad/bme/_team-factory/workflows/step-00-route.md +76 -0
- package/_bmad/bme/_vortex/config.yaml +4 -4
- package/_bmad/bme/_vortex/guides/VORTEX-TEAM-GUIDE.md +441 -0
- package/package.json +17 -8
- package/scripts/archive.js +26 -45
- package/scripts/convoke-check.js +88 -0
- package/scripts/convoke-doctor.js +303 -4
- package/scripts/install-gyre-agents.js +0 -0
- package/scripts/lib/artifact-utils.js +2182 -0
- package/scripts/lib/portfolio/formatters/markdown-formatter.js +40 -0
- package/scripts/lib/portfolio/formatters/terminal-formatter.js +56 -0
- package/scripts/lib/portfolio/portfolio-engine.js +572 -0
- package/scripts/lib/portfolio/rules/artifact-chain-rule.js +156 -0
- package/scripts/lib/portfolio/rules/conflict-resolver.js +99 -0
- package/scripts/lib/portfolio/rules/frontmatter-rule.js +42 -0
- package/scripts/lib/portfolio/rules/git-recency-rule.js +69 -0
- package/scripts/lib/types.js +122 -0
- package/scripts/migrate-artifacts.js +439 -0
- package/scripts/portability/catalog-generator.js +353 -0
- package/scripts/portability/classify-skills.js +646 -0
- package/scripts/portability/convoke-export.js +522 -0
- package/scripts/portability/export-engine.js +1133 -0
- package/scripts/portability/generate-adapters.js +79 -0
- package/scripts/portability/manifest-csv.js +147 -0
- package/scripts/portability/seed-catalog-repo.js +427 -0
- package/scripts/portability/templates/canonical-example.md +102 -0
- package/scripts/portability/templates/canonical-format.md +218 -0
- package/scripts/portability/templates/readme-template.md +72 -0
- package/scripts/portability/test-constants.js +42 -0
- package/scripts/portability/validate-classification.js +529 -0
- package/scripts/portability/validate-exports.js +348 -0
- package/scripts/update/lib/agent-registry.js +35 -0
- package/scripts/update/lib/config-merger.js +140 -10
- package/scripts/update/lib/migration-runner.js +1 -1
- package/scripts/update/lib/refresh-installation.js +293 -8
- package/scripts/update/lib/taxonomy-merger.js +138 -0
- package/scripts/update/lib/utils.js +27 -1
- package/scripts/update/lib/validator.js +114 -4
- package/scripts/update/migrations/2.0.x-to-3.1.0.js +50 -0
- package/scripts/update/migrations/3.0.x-to-3.1.0.js +41 -0
- package/scripts/update/migrations/registry.js +14 -0
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
# Seed Catalog Workflow
|
|
2
|
+
|
|
3
|
+
**Goal:** Generate the complete catalog repository staging directory with all exportable skills, adapters, and catalog README.
|
|
4
|
+
|
|
5
|
+
**Your Role:** You are a catalog seeding assistant. Guide the user through the seeding process, run the generator, and present results with next steps. Never dump raw output.
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## EXECUTION
|
|
10
|
+
|
|
11
|
+
### 1. Get output path (REQUIRED — no default)
|
|
12
|
+
|
|
13
|
+
If the user provided a path in their invocation, use it. Otherwise ask:
|
|
14
|
+
|
|
15
|
+
> This will generate a complete catalog repository staging directory with all exportable skills (Tier 1 + Tier 2), platform adapters, and the catalog README.
|
|
16
|
+
>
|
|
17
|
+
> **Where should I create the staging directory?** (e.g., `/tmp/convoke-catalog` or `./catalog-staging`)
|
|
18
|
+
>
|
|
19
|
+
> Note: The directory must not already exist or must be empty.
|
|
20
|
+
|
|
21
|
+
**Validate inputs:** Path must only contain `[a-zA-Z0-9_./-]`. Reject paths with shell metacharacters (`;`, `|`, `&`, `$`, `` ` ``).
|
|
22
|
+
|
|
23
|
+
**HALT** — wait for the user to provide a path before proceeding.
|
|
24
|
+
|
|
25
|
+
### 2. Run the seed script
|
|
26
|
+
|
|
27
|
+
Inform the user: "Seeding the catalog — exporting all skills with adapters. This takes a few seconds..."
|
|
28
|
+
|
|
29
|
+
Run via Bash tool:
|
|
30
|
+
|
|
31
|
+
```
|
|
32
|
+
node scripts/portability/seed-catalog-repo.js --output <path>
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
### 3. Present results
|
|
36
|
+
|
|
37
|
+
**Exit 0 — Success:**
|
|
38
|
+
- Parse stdout for skill count and file count
|
|
39
|
+
- Report: "Catalog staging complete! **N** skills exported with platform adapters (Claude Code, Copilot, Cursor). Verification passed — zero violations."
|
|
40
|
+
- Show next steps:
|
|
41
|
+
|
|
42
|
+
> **To create the GitHub repo:**
|
|
43
|
+
> ```
|
|
44
|
+
> cd <path>
|
|
45
|
+
> git init && git add -A && git commit -m "Initial catalog seed"
|
|
46
|
+
> gh repo create convoke-skills-catalog --public --source=. --push
|
|
47
|
+
> ```
|
|
48
|
+
>
|
|
49
|
+
> Or run `/bmad-validate-exports` to verify the output first.
|
|
50
|
+
|
|
51
|
+
**Exit 1 — Usage error:**
|
|
52
|
+
- Report: "Invalid arguments. The `--output` path is required."
|
|
53
|
+
|
|
54
|
+
**Exit 2 — Generation failure:**
|
|
55
|
+
- Report the error message from stderr.
|
|
56
|
+
- Suggest: "Some skills may have failed to export. Check the error details above."
|
|
57
|
+
|
|
58
|
+
**Exit 3 — Verification failure:**
|
|
59
|
+
- Report: "The export completed but verification found issues:"
|
|
60
|
+
- Show the specific failures from stderr.
|
|
61
|
+
- Suggest: "Fix the issues and re-run, or run `/bmad-validate-exports` for a detailed report."
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: bmad-validate-exports
|
|
3
|
+
description: 'Validate an exported skill staging directory for structural correctness and BMAD-internal leaks. Use when the user says "validate exports", "check exports", or "verify exports".'
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
Follow the instructions in [workflow.md](workflow.md).
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
# Validate Exports Workflow
|
|
2
|
+
|
|
3
|
+
**Goal:** Validate an exported skill staging directory for structural correctness, forbidden strings, and platform adapter completeness.
|
|
4
|
+
|
|
5
|
+
**Your Role:** You are a quality checker. Run the validator, present results clearly, and offer to generate a detailed report. Never dump raw output.
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## EXECUTION
|
|
10
|
+
|
|
11
|
+
### 1. Get staging directory path (REQUIRED)
|
|
12
|
+
|
|
13
|
+
If the user provided a path in their invocation, use it. Otherwise ask:
|
|
14
|
+
|
|
15
|
+
> Which staging directory should I validate? Provide the path to the exported skills directory (e.g., the output from `/bmad-seed-catalog` or `/bmad-export-skill --all`).
|
|
16
|
+
|
|
17
|
+
**Validate inputs:** Path must only contain `[a-zA-Z0-9_./-]`. Must be an existing directory.
|
|
18
|
+
|
|
19
|
+
**HALT** — wait for the user to provide a path.
|
|
20
|
+
|
|
21
|
+
### 2. Run the validator
|
|
22
|
+
|
|
23
|
+
Run via Bash tool:
|
|
24
|
+
|
|
25
|
+
```
|
|
26
|
+
node scripts/portability/validate-exports.js --input <path>
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
### 3. Present results
|
|
30
|
+
|
|
31
|
+
**Exit 0 — All checks passed:**
|
|
32
|
+
- Report: "All checks passed — **N** skills validated. No forbidden strings, all persona sections present, all READMEs under 80 lines, all platform adapters present."
|
|
33
|
+
- Ask: "Want me to generate a detailed VALIDATION-REPORT.md with manual smoke test checklists?"
|
|
34
|
+
- If yes: run `node scripts/portability/validate-exports.js --input <path> --report <path>/VALIDATION-REPORT.md` and report the file location.
|
|
35
|
+
|
|
36
|
+
**Exit 1 — Validation failures found:**
|
|
37
|
+
- Report: "Validation found **F** issue(s) across **N** skills:"
|
|
38
|
+
- Show each issue from stdout (skill name + file + issue description)
|
|
39
|
+
- Group by skill if there are many
|
|
40
|
+
- Suggest: "Fix the issues in the export pipeline, then re-run `/bmad-validate-exports`."
|
|
41
|
+
|
|
42
|
+
**Exit 2 — Usage error:**
|
|
43
|
+
- Report: "Could not validate — the path may not exist or may not be a directory."
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: "team factory"
|
|
3
|
+
description: "Team Factory - Guided creation of BMAD-compliant teams, agents, and skills"
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
You must fully embody this agent's persona and follow all activation instructions exactly as specified. NEVER break character until given an exit command.
|
|
7
|
+
|
|
8
|
+
```xml
|
|
9
|
+
<agent id="team-factory.agent.yaml" name="Loom Master" title="Team Factory" icon="🏭">
|
|
10
|
+
<activation critical="MANDATORY">
|
|
11
|
+
<step n="1">Load persona from this current agent file (already in context)</step>
|
|
12
|
+
<step n="2">🚨 IMMEDIATE ACTION REQUIRED - BEFORE ANY OUTPUT:
|
|
13
|
+
- Load and read {project-root}/_bmad/bme/_team-factory/config.yaml NOW
|
|
14
|
+
- ERROR HANDLING: If config file not found or cannot be read, IMMEDIATELY display:
|
|
15
|
+
"❌ Configuration Error: Cannot load config file at {project-root}/_bmad/bme/_team-factory/config.yaml
|
|
16
|
+
|
|
17
|
+
This file is required for Team Factory to operate. Please verify:
|
|
18
|
+
1. File exists at the path above
|
|
19
|
+
2. File has valid YAML syntax
|
|
20
|
+
3. File contains: user_name, communication_language, output_folder
|
|
21
|
+
|
|
22
|
+
If you just installed Team Factory, the config file may be missing. Please reinstall or contact support."
|
|
23
|
+
|
|
24
|
+
Then STOP - do NOT proceed to step 3.
|
|
25
|
+
- If config loaded successfully: Store ALL fields as session variables: {user_name}, {communication_language}, {output_folder}
|
|
26
|
+
- VERIFY all 3 required fields are present. If any missing, display:
|
|
27
|
+
"❌ Configuration Error: Missing required field(s) in config.yaml
|
|
28
|
+
|
|
29
|
+
Required fields: user_name, communication_language, output_folder
|
|
30
|
+
Found: [list only fields that were found]
|
|
31
|
+
|
|
32
|
+
Please update {project-root}/_bmad/bme/_team-factory/config.yaml with all required fields."
|
|
33
|
+
|
|
34
|
+
Then STOP - do NOT proceed to step 3.
|
|
35
|
+
- DO NOT PROCEED to step 3 until config is successfully loaded and all variables stored
|
|
36
|
+
</step>
|
|
37
|
+
<step n="3">Remember: user's name is {user_name}</step>
|
|
38
|
+
|
|
39
|
+
<step n="4">Show greeting using {user_name} from config, communicate in {communication_language}, then display numbered list of ALL menu items from menu section</step>
|
|
40
|
+
<step n="{HELP_STEP}">Let {user_name} know they can type command `/bmad-help` at any time to get advice on what to do next, and that they can combine that with what they need help with <example>`/bmad-help I want to create a new BMAD team`</example></step>
|
|
41
|
+
<step n="5">STOP and WAIT for user input - do NOT execute menu items automatically - accept number or cmd trigger or fuzzy command match</step>
|
|
42
|
+
<step n="6">On user input: Number → process menu item[n] | Text → case-insensitive substring match | Multiple matches → ask user to clarify | No match → show "Not recognized"</step>
|
|
43
|
+
<step n="7">When processing a menu item: Check menu-handlers section below - extract any attributes from the selected menu item (workflow, exec, tmpl, data, action, validate-workflow) and follow the corresponding handler instructions</step>
|
|
44
|
+
|
|
45
|
+
<menu-handlers>
|
|
46
|
+
<handlers>
|
|
47
|
+
<handler type="exec">
|
|
48
|
+
When menu item or handler has: exec="path/to/file.md":
|
|
49
|
+
|
|
50
|
+
1. CRITICAL: Check if file exists at path
|
|
51
|
+
2. If file NOT found, IMMEDIATELY display:
|
|
52
|
+
"❌ Workflow Error: Cannot load workflow
|
|
53
|
+
|
|
54
|
+
Expected file: {path}
|
|
55
|
+
|
|
56
|
+
This workflow is required for Team Factory to operate.
|
|
57
|
+
|
|
58
|
+
Possible causes:
|
|
59
|
+
1. Files missing from installation
|
|
60
|
+
2. Incorrect path configuration
|
|
61
|
+
3. Files moved or deleted
|
|
62
|
+
|
|
63
|
+
Please verify Team Factory installation or reinstall bme module."
|
|
64
|
+
|
|
65
|
+
Then STOP - do NOT proceed
|
|
66
|
+
3. If file exists: Read fully and follow the file at that path
|
|
67
|
+
4. Process the complete file and follow all instructions within it
|
|
68
|
+
5. If there is data="some/path/data-foo.md" with the same item, pass that data path to the executed file as context.
|
|
69
|
+
</handler>
|
|
70
|
+
<handler type="data">
|
|
71
|
+
When menu item has: data="path/to/file.json|yaml|yml|csv|xml"
|
|
72
|
+
Load the file first, parse according to extension
|
|
73
|
+
Make available as {data} variable to subsequent handler operations
|
|
74
|
+
</handler>
|
|
75
|
+
|
|
76
|
+
<handler type="workflow">
|
|
77
|
+
When menu item has: workflow="path/to/workflow.yaml":
|
|
78
|
+
|
|
79
|
+
1. CRITICAL: Always LOAD {project-root}/_bmad/core/tasks/workflow.xml
|
|
80
|
+
2. Read the complete file - this is the CORE OS for processing BMAD workflows
|
|
81
|
+
3. Pass the yaml path as 'workflow-config' parameter to those instructions
|
|
82
|
+
4. Follow workflow.xml instructions precisely following all steps
|
|
83
|
+
5. Save outputs after completing EACH workflow step (never batch multiple steps together)
|
|
84
|
+
6. If workflow.yaml path is "todo", inform user the workflow hasn't been implemented yet
|
|
85
|
+
</handler>
|
|
86
|
+
</handlers>
|
|
87
|
+
</menu-handlers>
|
|
88
|
+
|
|
89
|
+
<rules>
|
|
90
|
+
<r>ALWAYS communicate in {communication_language} UNLESS contradicted by communication_style.</r>
|
|
91
|
+
<r>Stay in character until exit selected</r>
|
|
92
|
+
<r>Display Menu items as the item dictates and in the order given.</r>
|
|
93
|
+
<r>Load files ONLY when executing a user chosen workflow or a command requires it, EXCEPTION: agent activation step 2 config.yaml</r>
|
|
94
|
+
<r>Every factory output must be validated before write — this is the governing principle.</r>
|
|
95
|
+
<r>Present decisions one at a time. Never overwhelm — max 3 new concepts per step (NFR2).</r>
|
|
96
|
+
<r>Always explain WHY a decision matters before asking the contributor to choose.</r>
|
|
97
|
+
<r>For Sequential teams, contracts are non-negotiable. For Independent teams, contracts are eliminated from the flow.</r>
|
|
98
|
+
</rules>
|
|
99
|
+
</activation>
|
|
100
|
+
<persona>
|
|
101
|
+
<role>Team Architecture Specialist + BMAD Compliance Expert</role>
|
|
102
|
+
<identity>Master team architect who guides framework contributors through creating fully-wired, BMAD-compliant teams. Specializes in architectural thinking before artifact generation — ensures every team creation goes through structured discovery before any file is produced.
|
|
103
|
+
|
|
104
|
+
Core expertise:
|
|
105
|
+
- Composition pattern selection (Independent vs Sequential)
|
|
106
|
+
- Agent scope definition and overlap detection
|
|
107
|
+
- Contract design and pipeline orchestration
|
|
108
|
+
- Integration wiring (registry, config, manifest, activation)
|
|
109
|
+
- Naming convention enforcement
|
|
110
|
+
- End-to-end validation
|
|
111
|
+
|
|
112
|
+
Philosophy: "The quality of a BMAD team isn't in the files — it's in the thinking that precedes them." Every team creation is a discovery process, not just file generation.</identity>
|
|
113
|
+
<communication_style>Methodical yet encouraging — like a senior architect pair-programming with a colleague. Asks focused questions, explains trade-offs clearly, and celebrates good decisions. Uses concrete examples from Vortex and Gyre to illustrate patterns. Never dumps all decisions at once — progressive disclosure, one step at a time.</communication_style>
|
|
114
|
+
<principles>- Thinking before files — every team creation goes through discovery before generation - BMAD compliance is non-negotiable — output must be indistinguishable from native teams - No orphaned artifacts — if a file is created, it must be registered, wired, and discoverable - Delegate to BMB for artifact generation — factory owns integration wiring only - Validate continuously — don't wait until the end to check</principles>
|
|
115
|
+
</persona>
|
|
116
|
+
<menu>
|
|
117
|
+
<item cmd="MH or fuzzy match on menu or help">[MH] Redisplay Menu Help</item>
|
|
118
|
+
<item cmd="CH or fuzzy match on chat">[CH] Chat about team architecture, composition patterns, or BMAD compliance</item>
|
|
119
|
+
<item cmd="CT or fuzzy match on create-team or new-team or add-team" exec="{project-root}/_bmad/bme/_team-factory/workflows/step-00-route.md">[CT] Create Team: Build a new BMAD-compliant team from scratch</item>
|
|
120
|
+
<item cmd="RS or fuzzy match on resume" exec="{project-root}/_bmad/bme/_team-factory/workflows/step-00-route.md" data="resume">[RS] Resume: Continue a previously started team creation</item>
|
|
121
|
+
<item cmd="EX or fuzzy match on express" exec="{project-root}/_bmad/bme/_team-factory/workflows/step-00-route.md" data="express">[EX] Express Mode: Create team from an existing spec file</item>
|
|
122
|
+
<item cmd="VT or fuzzy match on validate-team or check-team" exec="{project-root}/_bmad/bme/_team-factory/workflows/add-team/step-05-validate.md">[VT] Validate Team: Run end-to-end validation on an existing team</item>
|
|
123
|
+
<item cmd="AR or fuzzy match on architecture-reference or reference" data="{project-root}/_bmad-output/planning-artifacts/architecture-reference-teams.md">[AR] Architecture Reference: Browse the team validity blueprint</item>
|
|
124
|
+
<item cmd="PM or fuzzy match on party-mode" exec="{project-root}/_bmad/core/workflows/party-mode/workflow.md">[PM] Start Party Mode</item>
|
|
125
|
+
<item cmd="DA or fuzzy match on exit, leave, goodbye or dismiss agent">[DA] Dismiss Agent</item>
|
|
126
|
+
</menu>
|
|
127
|
+
</agent>
|
|
128
|
+
```
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
submodule_name: _team-factory
|
|
2
|
+
description: Team Factory - Guided creation of BMAD-compliant teams through architectural discovery and automated wiring
|
|
3
|
+
module: bme
|
|
4
|
+
output_folder: '{project-root}/_bmad-output/planning-artifacts'
|
|
5
|
+
agents:
|
|
6
|
+
- team-factory
|
|
7
|
+
workflows:
|
|
8
|
+
- add-team
|
|
9
|
+
version: 1.0.0
|
|
10
|
+
user_name: '{user}'
|
|
11
|
+
communication_language: en
|
|
12
|
+
party_mode_enabled: true
|
|
13
|
+
core_module: bme
|
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Pattern-aware decision elimination for the Team Factory.
|
|
5
|
+
* A6'-coupled — adding a third composition pattern = adding a third column to DECISION_CATALOGUE.
|
|
6
|
+
*
|
|
7
|
+
* @module cascade-logic
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
const KNOWN_PATTERNS = ['Independent', 'Sequential'];
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Master catalogue of factory decisions with per-pattern relevance.
|
|
14
|
+
* Each entry defines whether the decision is active for a given pattern
|
|
15
|
+
* and whether it's required or optional.
|
|
16
|
+
*
|
|
17
|
+
* @type {Array<{id: string, step: string, description: string, patterns: Object}>}
|
|
18
|
+
*/
|
|
19
|
+
const DECISION_CATALOGUE = [
|
|
20
|
+
{
|
|
21
|
+
id: 'agent-scope',
|
|
22
|
+
step: 'scope',
|
|
23
|
+
description: 'Define agent roles and capabilities',
|
|
24
|
+
patterns: {
|
|
25
|
+
Independent: { active: true, required: true },
|
|
26
|
+
Sequential: { active: true, required: true },
|
|
27
|
+
},
|
|
28
|
+
},
|
|
29
|
+
{
|
|
30
|
+
id: 'pipeline-order',
|
|
31
|
+
step: 'scope',
|
|
32
|
+
description: 'Define agent execution sequence (pipeline positions)',
|
|
33
|
+
patterns: {
|
|
34
|
+
Independent: { active: false, required: false },
|
|
35
|
+
Sequential: { active: true, required: true },
|
|
36
|
+
},
|
|
37
|
+
},
|
|
38
|
+
{
|
|
39
|
+
id: 'handoff-contracts',
|
|
40
|
+
step: 'connect',
|
|
41
|
+
description: 'Design inter-agent handoff contracts',
|
|
42
|
+
patterns: {
|
|
43
|
+
Independent: { active: false, required: false },
|
|
44
|
+
Sequential: { active: true, required: true },
|
|
45
|
+
},
|
|
46
|
+
},
|
|
47
|
+
{
|
|
48
|
+
id: 'feedback-contracts',
|
|
49
|
+
step: 'connect',
|
|
50
|
+
description: 'Design feedback routing contracts (downstream → upstream)',
|
|
51
|
+
patterns: {
|
|
52
|
+
Independent: { active: false, required: false },
|
|
53
|
+
Sequential: { active: true, required: false },
|
|
54
|
+
},
|
|
55
|
+
},
|
|
56
|
+
{
|
|
57
|
+
id: 'contract-prefix',
|
|
58
|
+
step: 'connect',
|
|
59
|
+
description: 'Define naming prefix for contracts (e.g., HC, GC)',
|
|
60
|
+
patterns: {
|
|
61
|
+
Independent: { active: false, required: false },
|
|
62
|
+
Sequential: { active: true, required: true },
|
|
63
|
+
},
|
|
64
|
+
},
|
|
65
|
+
{
|
|
66
|
+
id: 'compass-routing',
|
|
67
|
+
step: 'connect',
|
|
68
|
+
description: 'Create compass routing reference for workflow navigation',
|
|
69
|
+
patterns: {
|
|
70
|
+
Independent: { active: true, required: false, defaultValue: 'per-agent' },
|
|
71
|
+
Sequential: { active: true, required: true, defaultValue: 'shared-reference' },
|
|
72
|
+
},
|
|
73
|
+
},
|
|
74
|
+
{
|
|
75
|
+
id: 'orchestration-workflow',
|
|
76
|
+
step: 'connect',
|
|
77
|
+
description: 'Create pipeline orchestration workflow',
|
|
78
|
+
patterns: {
|
|
79
|
+
Independent: { active: false, required: false },
|
|
80
|
+
Sequential: { active: true, required: true },
|
|
81
|
+
},
|
|
82
|
+
},
|
|
83
|
+
{
|
|
84
|
+
id: 'output-directory',
|
|
85
|
+
step: 'connect',
|
|
86
|
+
description: 'Define artifact output location',
|
|
87
|
+
patterns: {
|
|
88
|
+
Independent: { active: true, required: true, defaultValue: '_bmad-output/{team}-artifacts' },
|
|
89
|
+
Sequential: { active: true, required: true, defaultValue: '_bmad-output/{team}-artifacts' },
|
|
90
|
+
},
|
|
91
|
+
},
|
|
92
|
+
{
|
|
93
|
+
id: 'naming-enforcement',
|
|
94
|
+
step: 'scope',
|
|
95
|
+
description: 'Validate all naming conventions (agent IDs, file names, module directory)',
|
|
96
|
+
patterns: {
|
|
97
|
+
Independent: { active: true, required: true },
|
|
98
|
+
Sequential: { active: true, required: true },
|
|
99
|
+
},
|
|
100
|
+
},
|
|
101
|
+
{
|
|
102
|
+
id: 'overlap-detection',
|
|
103
|
+
step: 'scope',
|
|
104
|
+
description: 'Check proposed agents against existing agent manifest for collisions',
|
|
105
|
+
patterns: {
|
|
106
|
+
Independent: { active: true, required: true },
|
|
107
|
+
Sequential: { active: true, required: true },
|
|
108
|
+
},
|
|
109
|
+
},
|
|
110
|
+
];
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* Given a composition pattern, return which factory decisions are relevant
|
|
114
|
+
* and which are eliminated.
|
|
115
|
+
*
|
|
116
|
+
* @param {string} pattern - "Independent" or "Sequential"
|
|
117
|
+
* @returns {{ decisions: CascadeDecision[], eliminated: CascadeDecision[], error?: string }}
|
|
118
|
+
*/
|
|
119
|
+
function getCascadeForPattern(pattern) {
|
|
120
|
+
const validation = validatePattern(pattern);
|
|
121
|
+
if (!validation.valid) {
|
|
122
|
+
return { decisions: [], eliminated: [], error: validation.error };
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
const decisions = [];
|
|
126
|
+
const eliminated = [];
|
|
127
|
+
|
|
128
|
+
for (const entry of DECISION_CATALOGUE) {
|
|
129
|
+
const patternConfig = entry.patterns[pattern];
|
|
130
|
+
const decision = {
|
|
131
|
+
id: entry.id,
|
|
132
|
+
step: entry.step,
|
|
133
|
+
description: entry.description,
|
|
134
|
+
required: patternConfig.required,
|
|
135
|
+
defaultValue: patternConfig.defaultValue || undefined,
|
|
136
|
+
};
|
|
137
|
+
|
|
138
|
+
if (patternConfig.active) {
|
|
139
|
+
decisions.push(decision);
|
|
140
|
+
} else {
|
|
141
|
+
eliminated.push(decision);
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
return { decisions, eliminated };
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
/**
|
|
149
|
+
* Validate that a pattern string is recognized.
|
|
150
|
+
* @param {string} pattern
|
|
151
|
+
* @returns {{ valid: boolean, error?: string }}
|
|
152
|
+
*/
|
|
153
|
+
function validatePattern(pattern) {
|
|
154
|
+
if (!pattern || typeof pattern !== 'string') {
|
|
155
|
+
return { valid: false, error: 'Pattern must be a non-empty string' };
|
|
156
|
+
}
|
|
157
|
+
if (!KNOWN_PATTERNS.includes(pattern)) {
|
|
158
|
+
return { valid: false, error: `Unknown pattern "${pattern}". Expected one of: ${KNOWN_PATTERNS.join(', ')}` };
|
|
159
|
+
}
|
|
160
|
+
return { valid: true };
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
/**
|
|
164
|
+
* Get the list of known composition patterns.
|
|
165
|
+
* @returns {string[]}
|
|
166
|
+
*/
|
|
167
|
+
function getKnownPatterns() {
|
|
168
|
+
return [...KNOWN_PATTERNS];
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
/**
|
|
172
|
+
* @typedef {Object} CascadeDecision
|
|
173
|
+
* @property {string} id - Decision identifier
|
|
174
|
+
* @property {string} step - Factory step this belongs to (scope, connect, generate, validate)
|
|
175
|
+
* @property {string} description - Human-readable description
|
|
176
|
+
* @property {boolean} required - Whether mandatory for the pattern
|
|
177
|
+
* @property {string} [defaultValue] - Default if applicable
|
|
178
|
+
*/
|
|
179
|
+
|
|
180
|
+
module.exports = {
|
|
181
|
+
getCascadeForPattern,
|
|
182
|
+
validatePattern,
|
|
183
|
+
getKnownPatterns,
|
|
184
|
+
};
|
|
@@ -0,0 +1,228 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const fs = require('fs-extra');
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Detect collisions between a new team spec and existing framework state.
|
|
7
|
+
* Handles Level 1 (exact ID match) and Level 2 (name similarity).
|
|
8
|
+
* Level 3 (capability overlap) is LLM reasoning in the workflow step.
|
|
9
|
+
*
|
|
10
|
+
* @param {Object} specData - Parsed team spec
|
|
11
|
+
* @param {string} manifestPath - Absolute path to agent-manifest.csv
|
|
12
|
+
* @param {string} [bmeDir] - Path to _bmad/bme/ directory for submodule name checks
|
|
13
|
+
* @returns {Promise<CollisionResult>}
|
|
14
|
+
*/
|
|
15
|
+
async function detectCollisions(specData, manifestPath, bmeDir) {
|
|
16
|
+
const blocks = [];
|
|
17
|
+
const warnings = [];
|
|
18
|
+
|
|
19
|
+
const dataWarnings = [];
|
|
20
|
+
|
|
21
|
+
// Parse existing agent manifest
|
|
22
|
+
const { agents: existingAgents, warning: manifestWarning } = await parseManifest(manifestPath);
|
|
23
|
+
if (manifestWarning) dataWarnings.push(manifestWarning);
|
|
24
|
+
|
|
25
|
+
// Parse existing submodule directories
|
|
26
|
+
const { modules: existingModules, warning: modulesWarning } = bmeDir
|
|
27
|
+
? await listSubmodules(bmeDir)
|
|
28
|
+
: { modules: [], warning: null };
|
|
29
|
+
if (modulesWarning) dataWarnings.push(modulesWarning);
|
|
30
|
+
|
|
31
|
+
const proposedTeam = specData.team_name_kebab || '';
|
|
32
|
+
const proposedAgents = (specData.agents || []).map(a => a.id).filter(Boolean);
|
|
33
|
+
|
|
34
|
+
// --- Level 1: Exact submodule name collision ---
|
|
35
|
+
if (proposedTeam && existingModules.includes(`_${proposedTeam}`)) {
|
|
36
|
+
blocks.push({
|
|
37
|
+
level: 'exact',
|
|
38
|
+
field: 'submodule_name',
|
|
39
|
+
newValue: `_${proposedTeam}`,
|
|
40
|
+
existingValue: `_${proposedTeam}`,
|
|
41
|
+
existingModule: proposedTeam,
|
|
42
|
+
suggestion: `Module directory _bmad/bme/_${proposedTeam}/ already exists. Choose a different team name.`,
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
// --- Level 1: Exact agent ID collision ---
|
|
47
|
+
for (const agentId of proposedAgents) {
|
|
48
|
+
const match = existingAgents.find(a => a.id === agentId);
|
|
49
|
+
if (match) {
|
|
50
|
+
blocks.push({
|
|
51
|
+
level: 'exact',
|
|
52
|
+
field: 'agent_id',
|
|
53
|
+
newValue: agentId,
|
|
54
|
+
existingValue: match.id,
|
|
55
|
+
existingModule: match.module,
|
|
56
|
+
suggestion: `Agent ID "${agentId}" already exists in module "${match.module}". Rename your agent.`,
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
// --- Level 2: Similar agent name detection ---
|
|
62
|
+
for (const agentId of proposedAgents) {
|
|
63
|
+
for (const existing of existingAgents) {
|
|
64
|
+
if (existing.id === agentId) continue; // Already caught by Level 1
|
|
65
|
+
|
|
66
|
+
const dist = levenshtein(agentId, existing.id);
|
|
67
|
+
const sharePrefix = sharedPrefix(agentId, existing.id);
|
|
68
|
+
|
|
69
|
+
if (dist <= 2 || (sharePrefix >= 4 && dist <= 3)) {
|
|
70
|
+
warnings.push({
|
|
71
|
+
level: 'similar',
|
|
72
|
+
field: 'agent_id',
|
|
73
|
+
newValue: agentId,
|
|
74
|
+
existingValue: existing.id,
|
|
75
|
+
existingModule: existing.module,
|
|
76
|
+
suggestion: `"${agentId}" is similar to existing "${existing.id}" (${existing.module}). Intentional?`,
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
return {
|
|
83
|
+
blocks,
|
|
84
|
+
warnings,
|
|
85
|
+
dataWarnings,
|
|
86
|
+
hasBlocking: blocks.length > 0,
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* Parse agent-manifest.csv to extract agent IDs and their modules.
|
|
92
|
+
* @param {string} manifestPath
|
|
93
|
+
* @returns {Promise<{agents: Array<{id: string, module: string}>, warning: string|null}>}
|
|
94
|
+
*/
|
|
95
|
+
async function parseManifest(manifestPath) {
|
|
96
|
+
try {
|
|
97
|
+
const content = await fs.readFile(manifestPath, 'utf8');
|
|
98
|
+
const lines = content.split('\n').filter(l => l.trim());
|
|
99
|
+
if (lines.length < 2) return { agents: [], warning: null };
|
|
100
|
+
|
|
101
|
+
const results = [];
|
|
102
|
+
// Skip header (line 0), parse data rows
|
|
103
|
+
for (let i = 1; i < lines.length; i++) {
|
|
104
|
+
const fields = parseCSVLine(lines[i]);
|
|
105
|
+
if (fields.length >= 10) {
|
|
106
|
+
const id = fields[0].replace(/^"|"$/g, '').trim();
|
|
107
|
+
const module = fields[9].replace(/^"|"$/g, '').trim();
|
|
108
|
+
if (id) results.push({ id, module });
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
return { agents: results, warning: null };
|
|
112
|
+
} catch (err) {
|
|
113
|
+
return { agents: [], warning: `Could not read agent manifest at ${manifestPath}: ${err.message}. Collision detection may be incomplete.` };
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* Parse a single CSV line handling quoted fields.
|
|
119
|
+
* @param {string} line
|
|
120
|
+
* @returns {string[]}
|
|
121
|
+
*/
|
|
122
|
+
function parseCSVLine(line) {
|
|
123
|
+
const fields = [];
|
|
124
|
+
let current = '';
|
|
125
|
+
let inQuotes = false;
|
|
126
|
+
|
|
127
|
+
for (let i = 0; i < line.length; i++) {
|
|
128
|
+
const ch = line[i];
|
|
129
|
+
if (inQuotes) {
|
|
130
|
+
if (ch === '"' && line[i + 1] === '"') {
|
|
131
|
+
current += '"';
|
|
132
|
+
i++; // skip escaped quote
|
|
133
|
+
} else if (ch === '"') {
|
|
134
|
+
inQuotes = false;
|
|
135
|
+
} else {
|
|
136
|
+
current += ch;
|
|
137
|
+
}
|
|
138
|
+
} else {
|
|
139
|
+
if (ch === '"') {
|
|
140
|
+
inQuotes = true;
|
|
141
|
+
} else if (ch === ',') {
|
|
142
|
+
fields.push(current);
|
|
143
|
+
current = '';
|
|
144
|
+
} else {
|
|
145
|
+
current += ch;
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
fields.push(current);
|
|
150
|
+
return fields;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
/**
|
|
154
|
+
* List existing submodule directory names under _bmad/bme/.
|
|
155
|
+
* @param {string} bmeDir
|
|
156
|
+
* @returns {Promise<{modules: string[], warning: string|null}>}
|
|
157
|
+
*/
|
|
158
|
+
async function listSubmodules(bmeDir) {
|
|
159
|
+
try {
|
|
160
|
+
const entries = await fs.readdir(bmeDir, { withFileTypes: true });
|
|
161
|
+
const modules = entries
|
|
162
|
+
.filter(e => e.isDirectory() && e.name.startsWith('_'))
|
|
163
|
+
.map(e => e.name);
|
|
164
|
+
return { modules, warning: null };
|
|
165
|
+
} catch (err) {
|
|
166
|
+
return { modules: [], warning: `Could not read bme directory at ${bmeDir}: ${err.message}. Submodule collision detection skipped.` };
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
/**
|
|
171
|
+
* Compute Levenshtein edit distance between two strings.
|
|
172
|
+
* @param {string} a
|
|
173
|
+
* @param {string} b
|
|
174
|
+
* @returns {number}
|
|
175
|
+
*/
|
|
176
|
+
function levenshtein(a, b) {
|
|
177
|
+
if (a.length === 0) return b.length;
|
|
178
|
+
if (b.length === 0) return a.length;
|
|
179
|
+
|
|
180
|
+
const matrix = Array.from({ length: b.length + 1 }, (_, i) => [i]);
|
|
181
|
+
for (let j = 0; j <= a.length; j++) matrix[0][j] = j;
|
|
182
|
+
|
|
183
|
+
for (let i = 1; i <= b.length; i++) {
|
|
184
|
+
for (let j = 1; j <= a.length; j++) {
|
|
185
|
+
const cost = a[j - 1] === b[i - 1] ? 0 : 1;
|
|
186
|
+
matrix[i][j] = Math.min(
|
|
187
|
+
matrix[i - 1][j] + 1,
|
|
188
|
+
matrix[i][j - 1] + 1,
|
|
189
|
+
matrix[i - 1][j - 1] + cost,
|
|
190
|
+
);
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
return matrix[b.length][a.length];
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
/**
|
|
198
|
+
* Count shared prefix length between two strings.
|
|
199
|
+
* @param {string} a
|
|
200
|
+
* @param {string} b
|
|
201
|
+
* @returns {number}
|
|
202
|
+
*/
|
|
203
|
+
function sharedPrefix(a, b) {
|
|
204
|
+
let i = 0;
|
|
205
|
+
while (i < a.length && i < b.length && a[i] === b[i]) i++;
|
|
206
|
+
return i;
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
/**
|
|
210
|
+
* @typedef {Object} CollisionResult
|
|
211
|
+
* @property {CollisionEntry[]} blocks - Level 1: exact matches, must be resolved
|
|
212
|
+
* @property {CollisionEntry[]} warnings - Level 2: similar names, review recommended
|
|
213
|
+
* @property {boolean} hasBlocking - true if any blocks exist
|
|
214
|
+
*/
|
|
215
|
+
|
|
216
|
+
/**
|
|
217
|
+
* @typedef {Object} CollisionEntry
|
|
218
|
+
* @property {string} level - "exact" or "similar"
|
|
219
|
+
* @property {string} field - "agent_id", "submodule_name", or "workflow_name"
|
|
220
|
+
* @property {string} newValue
|
|
221
|
+
* @property {string} existingValue
|
|
222
|
+
* @property {string} existingModule
|
|
223
|
+
* @property {string} suggestion
|
|
224
|
+
*/
|
|
225
|
+
|
|
226
|
+
module.exports = {
|
|
227
|
+
detectCollisions,
|
|
228
|
+
};
|