bmad-method-test-architecture-enterprise 1.16.0 → 1.17.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.
@@ -12,7 +12,7 @@
12
12
  "name": "bmad-method-test-architecture-enterprise",
13
13
  "source": "./",
14
14
  "description": "Master Test Architect module for quality strategy, test automation, CI/CD quality gates, and structured testing education. Part of the BMad Method ecosystem.",
15
- "version": "1.16.0",
15
+ "version": "1.17.0",
16
16
  "author": {
17
17
  "name": "Murat K Ozcan (TEA Creator) & Brian (BMad) Madison"
18
18
  },
@@ -25,14 +25,14 @@ jobs:
25
25
  runs-on: ubuntu-latest
26
26
  steps:
27
27
  - name: Checkout repository
28
- uses: actions/checkout@v4
28
+ uses: actions/checkout@v5
29
29
  with:
30
30
  fetch-depth: 0
31
31
 
32
32
  - name: Setup Node.js
33
- uses: actions/setup-node@v4
33
+ uses: actions/setup-node@v6
34
34
  with:
35
- node-version: "20"
35
+ node-version-file: ".nvmrc"
36
36
  cache: "npm"
37
37
 
38
38
  - name: Install root dependencies
@@ -43,19 +43,19 @@ jobs:
43
43
  - name: Generate GitHub App token
44
44
  id: app-token
45
45
  if: github.event_name == 'workflow_dispatch' && inputs.channel == 'latest'
46
- uses: actions/create-github-app-token@v2
46
+ uses: actions/create-github-app-token@v3
47
47
  with:
48
48
  app-id: ${{ secrets.RELEASE_APP_ID }}
49
49
  private-key: ${{ secrets.RELEASE_APP_PRIVATE_KEY }}
50
50
 
51
51
  - name: Checkout
52
- uses: actions/checkout@v4
52
+ uses: actions/checkout@v5
53
53
  with:
54
54
  fetch-depth: 0
55
55
  token: ${{ steps.app-token.outputs.token || secrets.GITHUB_TOKEN }}
56
56
 
57
57
  - name: Setup Node
58
- uses: actions/setup-node@v4
58
+ uses: actions/setup-node@v6
59
59
  with:
60
60
  node-version-file: ".nvmrc"
61
61
  cache: "npm"
@@ -150,6 +150,14 @@ jobs:
150
150
  run: |
151
151
  TAG="v$(node -p 'require("./package.json").version')"
152
152
  VERSION="${TAG#v}"
153
+ has_release_notes() {
154
+ awk '
155
+ /^[[:space:]]*$/ { next }
156
+ /^[[:space:]]*-{3,}[[:space:]]*$/ { next }
157
+ { found = 1 }
158
+ END { exit found ? 0 : 1 }
159
+ ' <<< "$1"
160
+ }
153
161
  BODY=$(awk -v ver="$VERSION" '
154
162
  /^## / {
155
163
  if (found) exit
@@ -158,7 +166,20 @@ jobs:
158
166
  }
159
167
  found { print }
160
168
  ' CHANGELOG.md)
161
- if [ -z "$BODY" ]; then
169
+ if ! has_release_notes "$BODY"; then
170
+ BODY=$(awk '
171
+ /^##[[:space:]]*\[Unreleased\]/ { found=1; next }
172
+ /^## / {
173
+ if (found) exit
174
+ next
175
+ }
176
+ found { print }
177
+ ' CHANGELOG.md)
178
+ if has_release_notes "$BODY"; then
179
+ echo "::notice::No CHANGELOG.md entry for $TAG — using [Unreleased] notes"
180
+ fi
181
+ fi
182
+ if ! has_release_notes "$BODY"; then
162
183
  echo "::warning::No CHANGELOG.md entry for $TAG — falling back to auto-generated notes"
163
184
  gh release create "$TAG" --generate-notes
164
185
  else
@@ -18,10 +18,10 @@ jobs:
18
18
  runs-on: ubuntu-latest
19
19
  steps:
20
20
  - name: Checkout
21
- uses: actions/checkout@v4
21
+ uses: actions/checkout@v5
22
22
 
23
23
  - name: Setup Node
24
- uses: actions/setup-node@v4
24
+ uses: actions/setup-node@v6
25
25
  with:
26
26
  node-version-file: ".nvmrc"
27
27
  cache: "npm"
@@ -36,10 +36,10 @@ jobs:
36
36
  runs-on: ubuntu-latest
37
37
  steps:
38
38
  - name: Checkout
39
- uses: actions/checkout@v4
39
+ uses: actions/checkout@v5
40
40
 
41
41
  - name: Setup Node
42
- uses: actions/setup-node@v4
42
+ uses: actions/setup-node@v6
43
43
  with:
44
44
  node-version-file: ".nvmrc"
45
45
  cache: "npm"
@@ -54,10 +54,10 @@ jobs:
54
54
  runs-on: ubuntu-latest
55
55
  steps:
56
56
  - name: Checkout
57
- uses: actions/checkout@v4
57
+ uses: actions/checkout@v5
58
58
 
59
59
  - name: Setup Node
60
- uses: actions/setup-node@v4
60
+ uses: actions/setup-node@v6
61
61
  with:
62
62
  node-version-file: ".nvmrc"
63
63
  cache: "npm"
@@ -72,10 +72,10 @@ jobs:
72
72
  runs-on: ubuntu-latest
73
73
  steps:
74
74
  - name: Checkout
75
- uses: actions/checkout@v4
75
+ uses: actions/checkout@v5
76
76
 
77
77
  - name: Setup Node
78
- uses: actions/setup-node@v4
78
+ uses: actions/setup-node@v6
79
79
  with:
80
80
  node-version-file: ".nvmrc"
81
81
  cache: "npm"
@@ -93,10 +93,10 @@ jobs:
93
93
  runs-on: ubuntu-latest
94
94
  steps:
95
95
  - name: Checkout
96
- uses: actions/checkout@v4
96
+ uses: actions/checkout@v5
97
97
 
98
98
  - name: Setup Node
99
- uses: actions/setup-node@v4
99
+ uses: actions/setup-node@v6
100
100
  with:
101
101
  node-version-file: ".nvmrc"
102
102
  cache: "npm"
@@ -115,6 +115,3 @@ jobs:
115
115
 
116
116
  - name: Test agent compilation components
117
117
  run: npm run test:install
118
-
119
- - name: Validate marketplace manifest
120
- run: npm run validate:marketplace
package/AGENTS.md ADDED
@@ -0,0 +1,31 @@
1
+ # Repository Guidelines
2
+
3
+ ## Project Shape
4
+
5
+ - Core TEA module content lives in `src/`.
6
+ - Public documentation lives in `docs/`; the Starlight site consumes it through `website/`.
7
+ - GitHub Actions workflows live in `.github/workflows/`.
8
+ - Release metadata must stay synchronized across `package.json`, `package-lock.json`, and `.claude-plugin/marketplace.json`.
9
+
10
+ ## Common Commands
11
+
12
+ - `npm test`: full quality gate used before release.
13
+ - `npm run format:check`: Prettier check.
14
+ - `npm run lint`: ESLint check.
15
+ - `npm run lint:md`: markdownlint check.
16
+ - `npm run docs:validate-links`: docs link validation.
17
+ - `npm run docs:build`: full docs and site build.
18
+ - `npm run test:release-metadata`: package/lockfile/marketplace version sync check.
19
+
20
+ ## Changelog Discipline
21
+
22
+ - For any user-facing change, documentation change, workflow/CI change, release behavior change, or bug fix, update `CHANGELOG.md` in the same PR.
23
+ - Put unreleased work under the top `## [Unreleased]` section using Keep a Changelog headings such as `Added`, `Changed`, `Fixed`, `Deprecated`, or `Removed`.
24
+ - When preparing or repairing a stable release, convert the relevant `[Unreleased]` notes into an exact version section like `## [1.16.0] - YYYY-MM-DD`.
25
+ - Do not leave release-worthy changes only in GitHub auto-generated notes. The publish workflow can fall back to `[Unreleased]`, but an exact version entry is preferred for stable releases.
26
+
27
+ ## PR Notes
28
+
29
+ - Mention validation commands actually run.
30
+ - For docs-only changes, at minimum run `npm run docs:validate-links`, `npm run lint:md`, and `npm run format:check`.
31
+ - For workflow or release changes, run `npm run format:check`, `npm run lint:md`, `npm run lint`, and `npm run test:release-metadata`.
package/CHANGELOG.md CHANGED
@@ -5,6 +5,39 @@ All notable changes to the Test Architect (TEA) module will be documented in thi
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## [Unreleased]
9
+
10
+ ### Changed
11
+
12
+ - GitHub Actions workflow dependencies upgraded to Node 24-compatible major versions:
13
+ - `actions/checkout@v5`
14
+ - `actions/setup-node@v6`
15
+ - `actions/create-github-app-token@v3`
16
+ - Publish releases now use `[Unreleased]` changelog notes before falling back to generated GitHub release notes when an exact version section is missing.
17
+
18
+ ---
19
+
20
+ ## [1.16.0] - 2026-05-08
21
+
22
+ ### Added
23
+
24
+ - Claude Cowork marketplace plugin support.
25
+ - TEA Phase 3 command examples in the overview docs, including direct slash commands and Codex skill invocations.
26
+ - System-level and per-epic `test-design` usage examples in the TEA overview docs.
27
+
28
+ ### Changed
29
+
30
+ - Catalog dependency metadata now uses `preceded-by` and `followed-by` column names.
31
+ - TEA overview command guidance now distinguishes workflow names, TEA menu codes, slash commands, and Codex skills.
32
+
33
+ ### Fixed
34
+
35
+ - Normalized `module-help.csv` to the documented 13-column schema.
36
+ - Clarified the exact `/bmad:tea:ci` command path for Phase 3 CI setup.
37
+ - Clarified the difference between Phase 3 system-level `test-design` and Phase 4 per-epic `test-design`.
38
+
39
+ ---
40
+
8
41
  ## [1.2.4] - 2026-02-22
9
42
 
10
43
  ### Changed
@@ -15,7 +48,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
15
48
  - Affected workflows: `atdd`, `automate`, `ci`, `framework`, `nfr-assess`, `teach-me-testing`, `test-design`, `test-review`, `trace`
16
49
  - Removed redundant `web_bundle: false` from workflow.yaml files
17
50
 
18
- ## [Unreleased]
51
+ ## [Historical Unreleased Notes]
19
52
 
20
53
  ### Added
21
54
 
package/README.md CHANGED
@@ -108,32 +108,12 @@ npx bmad-method install
108
108
 
109
109
  **Note:** TEA is automatically added to party mode after installation. Use `/party` to collaborate with TEA alongside other BMad agents.
110
110
 
111
- ### Claude Cowork
112
-
113
- Claude.ai web and the Claude desktop chat have no access to your project files, so the `npx` installer's writes can't reach them. [Claude Cowork](https://www.claude.com/product/claude-code) does — it sandboxes your project in a VM and exposes a plugin manager. The `npx` installer still can't write into that sandbox, but Cowork accepts plugins via its marketplace API, which TEA's `.claude-plugin/marketplace.json` ships with.
114
-
115
- **Install** (two steps — register the marketplace, then install the plugin):
116
-
117
- ```
118
- /plugin marketplace add bmad-code-org/bmad-method-test-architecture-enterprise
119
- /plugin install bmad-method-test-architecture-enterprise@bmad-method-test-architecture-enterprise
120
- ```
121
-
122
- Restart the Cowork session, then `/bmad-method-test-architecture-enterprise:*` slash commands appear.
123
-
124
- **Update**: `/plugin marketplace update bmad-method-test-architecture-enterprise`
125
-
126
- **Uninstall**: `/plugin uninstall bmad-method-test-architecture-enterprise@bmad-method-test-architecture-enterprise`
127
-
128
- **Known issue**: Cowork's plugin reconciler currently has open bugs ([anthropics/claude-code#38429](https://github.com/anthropics/claude-code/issues/38429), [#39274](https://github.com/anthropics/claude-code/issues/39274)) that can purge third-party marketplace plugins on session sync. If your slash commands disappear, re-run the `/plugin install` line.
129
-
130
111
  ### Tool-specific invocation
131
112
 
132
- | Tool | Invocation style | Example |
133
- | ------------------------------- | -------------------------------- | ------------------------------------------------------------------ |
134
- | Claude Code / Cursor / Windsurf | Slash command | `/bmad:tea:automate` |
135
- | Codex | `$` skill from `.agents/skills` | `$bmad-tea` or `$bmad-tea-testarch-automate` |
136
- | Claude Cowork | Marketplace plugin slash command | `/bmad-method-test-architecture-enterprise:bmad-testarch-automate` |
113
+ | Tool | Invocation style | Example |
114
+ | ------------------------------- | ------------------------------- | -------------------------------------------- |
115
+ | Claude Code / Cursor / Windsurf | Slash command | `/bmad:tea:automate` |
116
+ | Codex | `$` skill from `.agents/skills` | `$bmad-tea` or `$bmad-tea-testarch-automate` |
137
117
 
138
118
  ## Quickstart
139
119
 
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "$schema": "https://json.schemastore.org/package.json",
3
3
  "name": "bmad-method-test-architecture-enterprise",
4
- "version": "1.16.0",
4
+ "version": "1.17.0",
5
5
  "description": "Master Test Architect for quality strategy, test automation, and release gates",
6
6
  "keywords": [
7
7
  "bmad",
@@ -37,14 +37,13 @@
37
37
  "release:minor": "gh workflow run publish.yaml -f channel=latest -f bump=minor",
38
38
  "release:next": "gh workflow run publish.yaml -f channel=next",
39
39
  "release:patch": "gh workflow run publish.yaml -f channel=latest -f bump=patch",
40
- "test": "npm run test:schemas && npm run test:install && npm run test:knowledge && npm run test:release-metadata && npm run test:tea-workflow-descriptions && npm run validate:schemas && npm run validate:marketplace && npm run lint && npm run lint:md && npm run format:check",
40
+ "test": "npm run test:schemas && npm run test:install && npm run test:knowledge && npm run test:release-metadata && npm run test:tea-workflow-descriptions && npm run validate:schemas && npm run lint && npm run lint:md && npm run format:check",
41
41
  "test:coverage": "c8 npm test",
42
42
  "test:install": "node test/test-installation-components.js",
43
43
  "test:knowledge": "node test/test-knowledge-base.js",
44
44
  "test:release-metadata": "node test/test-release-metadata.js",
45
45
  "test:schemas": "node test/test-agent-schema.js",
46
46
  "test:tea-workflow-descriptions": "node tools/validate-tea-workflow-descriptions.js",
47
- "validate:marketplace": "node tools/validate-marketplace.js --strict",
48
47
  "validate:schemas": "node tools/validate-agent-schema.js",
49
48
  "validate:tea-workflow-descriptions": "node tools/validate-tea-workflow-descriptions.js"
50
49
  },
@@ -1,186 +0,0 @@
1
- 'use strict';
2
-
3
- /**
4
- * Marketplace Drift Validator
5
- *
6
- * Verifies .claude-plugin/marketplace.json stays in sync with src/**\/SKILL.md.
7
- * The marketplace.json is what Claude Code (and Claude Cowork) consume when a
8
- * user runs `/plugin marketplace add bmad-code-org/bmad-method-test-architecture-enterprise` — every skill
9
- * shipped to other IDEs through the regular installer must also be reachable
10
- * through the marketplace, or Cowork users silently miss skills.
11
- *
12
- * Checks:
13
- * - Every src/**\/SKILL.md path is declared in some plugin's `skills` array.
14
- * - Every declared skill path resolves to an existing src/.../SKILL.md.
15
- * - No skill path is declared by more than one plugin.
16
- *
17
- * Usage:
18
- * node tools/validate-marketplace.js human-readable report
19
- * node tools/validate-marketplace.js --strict exit 1 on any drift (CI)
20
- * node tools/validate-marketplace.js --json JSON output
21
- */
22
-
23
- const fs = require('node:fs');
24
- const path = require('node:path');
25
-
26
- const PROJECT_ROOT = path.resolve(__dirname, '..');
27
- const SRC_DIR = path.join(PROJECT_ROOT, 'src');
28
- const MARKETPLACE_PATH = path.join(PROJECT_ROOT, '.claude-plugin', 'marketplace.json');
29
-
30
- const args = new Set(process.argv.slice(2));
31
- const STRICT = args.has('--strict');
32
- const JSON_OUTPUT = args.has('--json');
33
-
34
- function findSkillPaths(dir, acc = []) {
35
- for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {
36
- const full = path.join(dir, entry.name);
37
- if (entry.isDirectory()) {
38
- findSkillPaths(full, acc);
39
- } else if (entry.name === 'SKILL.md') {
40
- // Normalize to forward slashes so the string-equal comparison against
41
- // marketplace.json paths works on Windows (where path.relative uses '\').
42
- const rel = path.relative(PROJECT_ROOT, path.dirname(full)).split(path.sep).join('/');
43
- acc.push('./' + rel);
44
- }
45
- }
46
- return acc;
47
- }
48
-
49
- function suggestPlugin(skillPath, plugins) {
50
- // Score by shared path-segment depth (not raw character prefix), so a new
51
- // module like ./src/cis-skills/foo doesn't get falsely suggested under
52
- // bmad-pro-skills just because both share './src/'.
53
- // Suggest only when the match goes beyond the './src/<family>/' boundary.
54
- const skillSegments = skillPath.split('/');
55
- let best = null;
56
- let bestScore = 0;
57
- for (const plugin of plugins) {
58
- for (const declared of plugin.skills || []) {
59
- const declaredSegments = declared.split('/');
60
- let i = 0;
61
- while (i < skillSegments.length && i < declaredSegments.length && skillSegments[i] === declaredSegments[i]) {
62
- i++;
63
- }
64
- if (i > bestScore) {
65
- bestScore = i;
66
- best = plugin.name;
67
- }
68
- }
69
- }
70
- // Two skills in the same module family (e.g., both under ./src/core-skills/)
71
- // share exactly 3 segments: '.', 'src', '<family>'. A skill in a brand-new
72
- // family (e.g., ./src/cis-skills/) only shares 2 segments. Require >= 3
73
- // so suggestions stay within the same family and don't leak across modules.
74
- return bestScore >= 3 ? best : null;
75
- }
76
-
77
- function validate() {
78
- if (!fs.existsSync(MARKETPLACE_PATH)) {
79
- return { ok: false, fatal: `marketplace.json not found at ${MARKETPLACE_PATH}` };
80
- }
81
-
82
- let marketplace;
83
- try {
84
- marketplace = JSON.parse(fs.readFileSync(MARKETPLACE_PATH, 'utf8'));
85
- } catch (error) {
86
- return { ok: false, fatal: `marketplace.json is not valid JSON: ${error.message}` };
87
- }
88
-
89
- if (!fs.existsSync(SRC_DIR)) {
90
- return { ok: false, fatal: `src directory not found at ${SRC_DIR}` };
91
- }
92
-
93
- const plugins = Array.isArray(marketplace.plugins) ? marketplace.plugins : [];
94
- const declaredBy = new Map(); // skillPath -> [pluginName]
95
- for (const plugin of plugins) {
96
- const skills = Array.isArray(plugin.skills) ? plugin.skills : [];
97
- for (const skillPath of skills) {
98
- if (!declaredBy.has(skillPath)) declaredBy.set(skillPath, []);
99
- declaredBy.get(skillPath).push(plugin.name);
100
- }
101
- }
102
-
103
- const onDisk = new Set(findSkillPaths(SRC_DIR));
104
-
105
- const missing = []; // SKILL.md exists in src/ but no plugin declares it
106
- for (const skillPath of [...onDisk].sort()) {
107
- if (!declaredBy.has(skillPath)) {
108
- missing.push({ path: skillPath, suggestedPlugin: suggestPlugin(skillPath, plugins) });
109
- }
110
- }
111
-
112
- const orphans = []; // plugin declares a path that has no SKILL.md
113
- for (const skillPath of declaredBy.keys()) {
114
- if (!onDisk.has(skillPath)) {
115
- orphans.push({ path: skillPath, declaredBy: declaredBy.get(skillPath) });
116
- }
117
- }
118
-
119
- const duplicates = []; // same path declared more than once (within or across plugins)
120
- for (const [skillPath, names] of declaredBy) {
121
- if (names.length > 1) {
122
- const uniquePlugins = [...new Set(names)];
123
- duplicates.push({
124
- path: skillPath,
125
- declaredBy: uniquePlugins,
126
- withinSamePlugin: uniquePlugins.length === 1,
127
- });
128
- }
129
- }
130
-
131
- return {
132
- ok: missing.length === 0 && orphans.length === 0 && duplicates.length === 0,
133
- totals: { onDisk: onDisk.size, declared: declaredBy.size, plugins: plugins.length },
134
- missing,
135
- orphans,
136
- duplicates,
137
- };
138
- }
139
-
140
- function reportHuman(result) {
141
- if (result.fatal) {
142
- console.error(`✗ ${result.fatal}`);
143
- return;
144
- }
145
- const { totals, missing, orphans, duplicates, ok } = result;
146
- console.log(`Marketplace coverage: ${totals.declared} declared / ${totals.onDisk} on disk across ${totals.plugins} plugin(s)`);
147
-
148
- if (missing.length > 0) {
149
- console.log(`\n✗ ${missing.length} skill(s) on disk are not declared in marketplace.json:`);
150
- for (const m of missing) {
151
- const hint = m.suggestedPlugin ? ` → likely belongs in "${m.suggestedPlugin}"` : '';
152
- console.log(` ${m.path}${hint}`);
153
- }
154
- }
155
-
156
- if (orphans.length > 0) {
157
- console.log(`\n✗ ${orphans.length} declared skill path(s) do not exist on disk:`);
158
- for (const o of orphans) {
159
- console.log(` ${o.path} (declared by: ${o.declaredBy.join(', ')})`);
160
- }
161
- }
162
-
163
- if (duplicates.length > 0) {
164
- console.log(`\n✗ ${duplicates.length} skill path(s) declared more than once:`);
165
- for (const d of duplicates) {
166
- const where = d.withinSamePlugin
167
- ? `listed multiple times in "${d.declaredBy[0]}"`
168
- : `in multiple plugins: ${d.declaredBy.join(', ')}`;
169
- console.log(` ${d.path} (${where})`);
170
- }
171
- }
172
-
173
- if (ok) console.log('\n✓ marketplace.json is in sync with src/');
174
- }
175
-
176
- const result = validate();
177
-
178
- if (JSON_OUTPUT) {
179
- console.log(JSON.stringify(result, null, 2));
180
- } else {
181
- reportHuman(result);
182
- }
183
-
184
- if (!result.ok && (STRICT || result.fatal)) {
185
- process.exit(1);
186
- }