bmad-fh 6.0.0-alpha.23.50b728f9 → 6.0.0-alpha.23.599980af
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/README.md +116 -13
- package/package.json +1 -1
- package/src/core/lib/scope/scope-manager.js +37 -4
- package/test/test-scope-cli.js +1306 -0
- package/test/test-scope-e2e.js +13 -17
- package/test/test-scope-system.js +115 -95
- package/tools/cli/commands/scope.js +1135 -43
package/README.md
CHANGED
|
@@ -66,31 +66,134 @@ BMad supports running multiple workflows in parallel across different terminal s
|
|
|
66
66
|
- **Multi-team projects** — Each team works in their own scope
|
|
67
67
|
- **Parallel feature development** — Develop auth, payments, and catalog simultaneously
|
|
68
68
|
- **Microservices** — One scope per service with shared contracts
|
|
69
|
+
- **Experimentation** — Create isolated scopes for spikes and prototypes
|
|
70
|
+
|
|
71
|
+
### Quick Start
|
|
69
72
|
|
|
70
73
|
```bash
|
|
71
74
|
# Initialize scope system
|
|
72
|
-
bmad scope init
|
|
75
|
+
npx bmad-fh@multi-artifact scope init
|
|
73
76
|
|
|
74
77
|
# Create scopes for different services
|
|
75
|
-
bmad scope create auth --name "Authentication"
|
|
76
|
-
bmad scope create payments --name "
|
|
78
|
+
npx bmad-fh@multi-artifact scope create auth --name "Authentication Service"
|
|
79
|
+
npx bmad-fh@multi-artifact scope create payments --name "Payment Processing" --deps auth
|
|
80
|
+
|
|
81
|
+
# Set the active scope for your session
|
|
82
|
+
npx bmad-fh@multi-artifact scope set auth
|
|
77
83
|
|
|
78
84
|
# Run workflows in parallel (different terminals)
|
|
79
|
-
|
|
80
|
-
|
|
85
|
+
# Terminal 1: Set scope to auth, run agent workflows
|
|
86
|
+
# Terminal 2: Set scope to payments, run agent workflows
|
|
81
87
|
|
|
82
88
|
# Share artifacts between scopes
|
|
83
|
-
bmad scope sync-up auth # Promote to shared layer
|
|
84
|
-
bmad scope sync-down payments # Pull shared updates
|
|
89
|
+
npx bmad-fh@multi-artifact scope sync-up auth # Promote to shared layer
|
|
90
|
+
npx bmad-fh@multi-artifact scope sync-down payments # Pull shared updates
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
### CLI Reference
|
|
94
|
+
|
|
95
|
+
| Command | Description |
|
|
96
|
+
| ------------------------------------------------- | ------------------------------------------- |
|
|
97
|
+
| `npx bmad-fh@multi-artifact scope init` | Initialize the scope system in your project |
|
|
98
|
+
| `npx bmad-fh@multi-artifact scope list` | List all scopes (alias: `ls`) |
|
|
99
|
+
| `npx bmad-fh@multi-artifact scope create <id>` | Create a new scope (alias: `new`) |
|
|
100
|
+
| `npx bmad-fh@multi-artifact scope info <id>` | Show scope details (alias: `show`) |
|
|
101
|
+
| `npx bmad-fh@multi-artifact scope set [id]` | Set active scope for session (alias: `use`) |
|
|
102
|
+
| `npx bmad-fh@multi-artifact scope unset` | Clear active scope (alias: `clear`) |
|
|
103
|
+
| `npx bmad-fh@multi-artifact scope remove <id>` | Remove a scope (aliases: `rm`, `delete`) |
|
|
104
|
+
| `npx bmad-fh@multi-artifact scope archive <id>` | Archive a completed scope |
|
|
105
|
+
| `npx bmad-fh@multi-artifact scope activate <id>` | Reactivate an archived scope |
|
|
106
|
+
| `npx bmad-fh@multi-artifact scope sync-up <id>` | Promote artifacts to shared layer |
|
|
107
|
+
| `npx bmad-fh@multi-artifact scope sync-down <id>` | Pull shared updates into scope |
|
|
108
|
+
| `npx bmad-fh@multi-artifact scope help [cmd]` | Show help (add command for detailed help) |
|
|
109
|
+
|
|
110
|
+
### Create Options
|
|
111
|
+
|
|
112
|
+
```bash
|
|
113
|
+
npx bmad-fh@multi-artifact scope create auth \
|
|
114
|
+
--name "Authentication Service" \
|
|
115
|
+
--description "User auth, SSO, and session management" \
|
|
116
|
+
--deps users,notifications \
|
|
117
|
+
--context # Create scope-specific project-context.md
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
### Directory Structure
|
|
121
|
+
|
|
122
|
+
After initialization and scope creation:
|
|
123
|
+
|
|
124
|
+
```
|
|
125
|
+
project-root/
|
|
126
|
+
├── _bmad/
|
|
127
|
+
│ ├── _config/
|
|
128
|
+
│ │ └── scopes.yaml # Scope registry and settings
|
|
129
|
+
│ └── _events/
|
|
130
|
+
│ ├── event-log.yaml # Event history
|
|
131
|
+
│ └── subscriptions.yaml # Cross-scope subscriptions
|
|
132
|
+
│
|
|
133
|
+
├── _bmad-output/
|
|
134
|
+
│ ├── _shared/ # Shared knowledge layer
|
|
135
|
+
│ │ ├── project-context.md # Global project context
|
|
136
|
+
│ │ ├── contracts/ # Integration contracts
|
|
137
|
+
│ │ └── principles/ # Architecture principles
|
|
138
|
+
│ │
|
|
139
|
+
│ ├── auth/ # Auth scope artifacts
|
|
140
|
+
│ │ ├── planning-artifacts/
|
|
141
|
+
│ │ ├── implementation-artifacts/
|
|
142
|
+
│ │ └── tests/
|
|
143
|
+
│ │
|
|
144
|
+
│ └── payments/ # Payments scope artifacts
|
|
145
|
+
│ └── ...
|
|
146
|
+
│
|
|
147
|
+
└── .bmad-scope # Session-sticky active scope (gitignored)
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
### Access Model
|
|
151
|
+
|
|
152
|
+
Scopes follow a "read-any, write-own" isolation model:
|
|
153
|
+
|
|
154
|
+
| Operation | Own Scope | Other Scopes | \_shared/ |
|
|
155
|
+
| --------- | --------- | ------------ | ----------- |
|
|
156
|
+
| **Read** | Allowed | Allowed | Allowed |
|
|
157
|
+
| **Write** | Allowed | Blocked | via sync-up |
|
|
158
|
+
|
|
159
|
+
### Workflow Integration
|
|
160
|
+
|
|
161
|
+
Workflows (run via agent menus like `CP` for Create PRD, `DS` for Dev Story) automatically detect and use scope context. Resolution order:
|
|
162
|
+
|
|
163
|
+
1. Session context from `.bmad-scope` file (set via `scope set`)
|
|
164
|
+
2. `BMAD_SCOPE` environment variable
|
|
165
|
+
3. Prompt user to select or create scope
|
|
166
|
+
|
|
167
|
+
**Setting your active scope:**
|
|
168
|
+
|
|
169
|
+
```bash
|
|
170
|
+
# Set scope for your terminal session
|
|
171
|
+
npx bmad-fh@multi-artifact scope set auth
|
|
172
|
+
|
|
173
|
+
# Or use environment variable (useful for CI/CD)
|
|
174
|
+
export BMAD_SCOPE=auth
|
|
85
175
|
```
|
|
86
176
|
|
|
87
|
-
**
|
|
88
|
-
|
|
89
|
-
-
|
|
90
|
-
-
|
|
91
|
-
-
|
|
177
|
+
**Scope-aware path variables in workflows:**
|
|
178
|
+
|
|
179
|
+
- `{scope}` → Scope ID (e.g., "auth")
|
|
180
|
+
- `{scope_path}` → `_bmad-output/auth`
|
|
181
|
+
- `{scope_planning}` → `_bmad-output/auth/planning-artifacts`
|
|
182
|
+
- `{scope_implementation}` → `_bmad-output/auth/implementation-artifacts`
|
|
183
|
+
- `{scope_tests}` → `_bmad-output/auth/tests`
|
|
184
|
+
|
|
185
|
+
### Getting Help
|
|
186
|
+
|
|
187
|
+
```bash
|
|
188
|
+
# Show comprehensive help for all scope commands
|
|
189
|
+
npx bmad-fh@multi-artifact scope help
|
|
190
|
+
|
|
191
|
+
# Get detailed help for a specific command
|
|
192
|
+
npx bmad-fh@multi-artifact scope help create
|
|
193
|
+
npx bmad-fh@multi-artifact scope help sync-up
|
|
194
|
+
```
|
|
92
195
|
|
|
93
|
-
See [Multi-Scope Guide](docs/multi-scope-guide.md) for
|
|
196
|
+
See [Multi-Scope Guide](docs/multi-scope-guide.md) for complete documentation.
|
|
94
197
|
|
|
95
198
|
## Community
|
|
96
199
|
|
package/package.json
CHANGED
|
@@ -2,6 +2,7 @@ const path = require('node:path');
|
|
|
2
2
|
const fs = require('fs-extra');
|
|
3
3
|
const yaml = require('yaml');
|
|
4
4
|
const { ScopeValidator } = require('./scope-validator');
|
|
5
|
+
const { ScopeInitializer } = require('./scope-initializer');
|
|
5
6
|
|
|
6
7
|
/**
|
|
7
8
|
* Manages scope lifecycle and CRUD operations
|
|
@@ -25,6 +26,7 @@ class ScopeManager {
|
|
|
25
26
|
this.scopesFilePath = options.scopesFilePath || path.join(this.configPath, 'scopes.yaml');
|
|
26
27
|
|
|
27
28
|
this.validator = new ScopeValidator();
|
|
29
|
+
this.initializer = new ScopeInitializer({ projectRoot: this.projectRoot });
|
|
28
30
|
this._config = null; // Cached configuration
|
|
29
31
|
}
|
|
30
32
|
|
|
@@ -38,6 +40,7 @@ class ScopeManager {
|
|
|
38
40
|
this.configPath = path.join(this.bmadPath, '_config');
|
|
39
41
|
this.scopesFilePath = path.join(this.configPath, 'scopes.yaml');
|
|
40
42
|
this._config = null; // Clear cache
|
|
43
|
+
this.initializer.setProjectRoot(projectRoot);
|
|
41
44
|
}
|
|
42
45
|
|
|
43
46
|
/**
|
|
@@ -59,6 +62,9 @@ class ScopeManager {
|
|
|
59
62
|
await this.saveConfig(defaultConfig);
|
|
60
63
|
}
|
|
61
64
|
|
|
65
|
+
// Initialize scope system directories (_shared, _events)
|
|
66
|
+
await this.initializer.initializeScopeSystem();
|
|
67
|
+
|
|
62
68
|
// Load and validate configuration
|
|
63
69
|
const config = await this.loadConfig();
|
|
64
70
|
return config !== null;
|
|
@@ -239,6 +245,9 @@ class ScopeManager {
|
|
|
239
245
|
// Save configuration
|
|
240
246
|
await this.saveConfig(config);
|
|
241
247
|
|
|
248
|
+
// Create scope directory structure
|
|
249
|
+
await this.initializer.initializeScope(scopeId, options);
|
|
250
|
+
|
|
242
251
|
return scope;
|
|
243
252
|
} catch (error) {
|
|
244
253
|
throw new Error(`Failed to create scope '${scopeId}': ${error.message}`);
|
|
@@ -311,7 +320,7 @@ class ScopeManager {
|
|
|
311
320
|
}
|
|
312
321
|
|
|
313
322
|
// Check if other scopes depend on this one
|
|
314
|
-
const dependentScopes = this.
|
|
323
|
+
const dependentScopes = this.findDependentScopesSync(scopeId, config.scopes);
|
|
315
324
|
if (dependentScopes.length > 0 && !options.force) {
|
|
316
325
|
throw new Error(
|
|
317
326
|
`Cannot remove scope '${scopeId}'. The following scopes depend on it: ${dependentScopes.join(', ')}. Use force option to remove anyway.`,
|
|
@@ -396,7 +405,7 @@ class ScopeManager {
|
|
|
396
405
|
const tree = {
|
|
397
406
|
scope: scopeId,
|
|
398
407
|
dependencies: [],
|
|
399
|
-
dependents: this.
|
|
408
|
+
dependents: this.findDependentScopesSync(scopeId, config.scopes),
|
|
400
409
|
};
|
|
401
410
|
|
|
402
411
|
// Build dependency tree recursively
|
|
@@ -422,10 +431,34 @@ class ScopeManager {
|
|
|
422
431
|
/**
|
|
423
432
|
* Find scopes that depend on a given scope
|
|
424
433
|
* @param {string} scopeId - The scope ID
|
|
425
|
-
* @param {object} allScopes - All scopes object
|
|
434
|
+
* @param {object} allScopes - All scopes object (optional, will load if not provided)
|
|
435
|
+
* @returns {Promise<string[]>|string[]} Array of dependent scope IDs
|
|
436
|
+
*/
|
|
437
|
+
async findDependentScopes(scopeId, allScopes = null) {
|
|
438
|
+
// If allScopes not provided, load from config
|
|
439
|
+
if (!allScopes) {
|
|
440
|
+
const config = await this.loadConfig();
|
|
441
|
+
allScopes = config.scopes || {};
|
|
442
|
+
}
|
|
443
|
+
|
|
444
|
+
const dependents = [];
|
|
445
|
+
|
|
446
|
+
for (const [sid, scope] of Object.entries(allScopes)) {
|
|
447
|
+
if (scope.dependencies && scope.dependencies.includes(scopeId)) {
|
|
448
|
+
dependents.push(sid);
|
|
449
|
+
}
|
|
450
|
+
}
|
|
451
|
+
|
|
452
|
+
return dependents;
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
/**
|
|
456
|
+
* Find scopes that depend on a given scope (synchronous version)
|
|
457
|
+
* @param {string} scopeId - The scope ID
|
|
458
|
+
* @param {object} allScopes - All scopes object (required)
|
|
426
459
|
* @returns {string[]} Array of dependent scope IDs
|
|
427
460
|
*/
|
|
428
|
-
|
|
461
|
+
findDependentScopesSync(scopeId, allScopes) {
|
|
429
462
|
const dependents = [];
|
|
430
463
|
|
|
431
464
|
for (const [sid, scope] of Object.entries(allScopes)) {
|