bmad-method 6.12.2 → 6.12.3-next.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/.claude-plugin/marketplace.json +1 -1
- package/bmad-modules.yaml +3 -1
- package/body.md +17 -0
- package/package.json +1 -1
- package/src/bmm-skills/plan/bmad-sprint-planning/scripts/__pycache__/sprint_plan.cpython-311.pyc +0 -0
- package/src/bmm-skills/plan/bmad-sprint-planning/scripts/tests/__pycache__/test_sprint_plan.cpython-311-pytest-9.1.1.pyc +0 -0
- package/src/bmm-skills/ship/bmad-retrospective/scripts/__pycache__/sprint_status.cpython-311.pyc +0 -0
- package/src/bmm-skills/ship/bmad-retrospective/scripts/tests/__pycache__/test_git_evidence.cpython-311-pytest-9.1.1.pyc +0 -0
- package/src/bmm-skills/ship/bmad-retrospective/scripts/tests/__pycache__/test_sprint_status.cpython-311-pytest-9.1.1.pyc +0 -0
- package/src/scripts/__pycache__/config_utils.cpython-311.pyc +0 -0
- package/src/scripts/tests/__pycache__/test_config_utils.cpython-311.pyc +0 -0
- package/src/scripts/tests/__pycache__/test_resolve_config.cpython-311.pyc +0 -0
- package/src/scripts/tests/__pycache__/test_resolve_customization.cpython-311.pyc +0 -0
- package/tools/installer/core/installer.js +1 -1
- package/tools/installer/modules/channel-plan.js +14 -6
- package/tools/installer/ui.js +8 -25
- package/tools/tests/__pycache__/test_validate_skills.cpython-311.pyc +0 -0
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
"displayName": "BMad Method Analyze Plan Build",
|
|
15
15
|
"source": "./",
|
|
16
16
|
"description": "Full-lifecycle AI development framework — agents and workflows for product analysis, planning, architecture, and implementation.",
|
|
17
|
-
"version": "6.12.
|
|
17
|
+
"version": "6.12.3",
|
|
18
18
|
"author": {
|
|
19
19
|
"name": "Brian (BMad) Madison"
|
|
20
20
|
},
|
package/bmad-modules.yaml
CHANGED
|
@@ -9,7 +9,9 @@
|
|
|
9
9
|
# Omit to inherit the installer's hardcoded default (stable).
|
|
10
10
|
#
|
|
11
11
|
# pin (optional) — a git tag to install instead of the channel. Use it when
|
|
12
|
-
# newer releases no longer work with this installer.
|
|
12
|
+
# newer releases no longer work with this installer. The pin is the default for
|
|
13
|
+
# every module that gets no explicit choice. --pin, --next=CODE and a stable or
|
|
14
|
+
# next pick in the interactive picker override it; --channel and --all-* do not.
|
|
13
15
|
#
|
|
14
16
|
# deprecated (optional, default false) — when true, the module is hidden from
|
|
15
17
|
# the installer picker UNLESS it is already installed (so existing users can
|
package/body.md
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
Picking a channel in the picker is ignored when the module has a registry `pin`.
|
|
2
|
+
The `tea` pin (v1.27.2) wins, and the manifest records `channel: pinned` with no message.
|
|
3
|
+
|
|
4
|
+
`decideChannelForModule` checked `registryPin` before `--next=CODE`, and the picker never recorded a `stable` pick.
|
|
5
|
+
|
|
6
|
+
New order: `--pin` > `--next=CODE` or picker stable > registry pin > `--channel`/`--all-*` > registry default > `stable`.
|
|
7
|
+
|
|
8
|
+
- `channel-plan.js`: explicit per-module picks resolve before the registry pin. New `stableSet` holds a `stable` pick.
|
|
9
|
+
- `ui.js`: `next` is gone from the install picker and from the update flow's channel review. A stable pick fills `stableSet`. A legacy install that tracks `main` moves to stable without a prompt.
|
|
10
|
+
- Tests: "registry pin beats --next" splits into three cases. Picker-level tests drive the install and update flows, including the all-stable fast path that keeps the pin.
|
|
11
|
+
|
|
12
|
+
`--yes`, the all-stable fast path and `--channel` still get the pin.
|
|
13
|
+
|
|
14
|
+
`--next=CODE` stays for headless use.
|
|
15
|
+
On 6.12 it now installs `main` for a pinned module, which fails for TEA v2+ because that layout needs the v7 installer.
|
|
16
|
+
|
|
17
|
+
`npm run quality` passes.
|
package/package.json
CHANGED
package/src/bmm-skills/plan/bmad-sprint-planning/scripts/__pycache__/sprint_plan.cpython-311.pyc
CHANGED
|
Binary file
|
|
Binary file
|
package/src/bmm-skills/ship/bmad-retrospective/scripts/__pycache__/sprint_status.cpython-311.pyc
CHANGED
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -1474,7 +1474,7 @@ class Installer {
|
|
|
1474
1474
|
// 'pinned' would trigger a stable-channel tag lookup at config-collection
|
|
1475
1475
|
// time, burning GitHub API quota and potentially failing.
|
|
1476
1476
|
const manifestData = await this.manifest.read(bmadDir);
|
|
1477
|
-
const channelOptions = { global: null, nextSet: new Set(), pins: new Map(), warnings: [] };
|
|
1477
|
+
const channelOptions = { global: null, nextSet: new Set(), stableSet: new Set(), pins: new Map(), warnings: [] };
|
|
1478
1478
|
if (manifestData?.modulesDetailed) {
|
|
1479
1479
|
const { fetchStableTags, classifyUpgrade, parseGitHubRepo } = require('../modules/channel-resolver');
|
|
1480
1480
|
for (const entry of manifestData.modulesDetailed) {
|
|
@@ -10,7 +10,8 @@
|
|
|
10
10
|
* 3. Registry defaults (default_channel from bmad-modules.yaml)
|
|
11
11
|
* 4. Hardcoded fallback 'stable'
|
|
12
12
|
*
|
|
13
|
-
* Precedence: --pin > --next=CODE
|
|
13
|
+
* Precedence: --pin > explicit per-module choice (--next=CODE, picker next/stable) > registry pin
|
|
14
|
+
* > --channel (global) > registry default > 'stable'.
|
|
14
15
|
*
|
|
15
16
|
* This module is pure. No prompts, no git, no filesystem.
|
|
16
17
|
*/
|
|
@@ -24,6 +25,7 @@ const VALID_CHANNELS = new Set(['stable', 'next']);
|
|
|
24
25
|
* @returns {{
|
|
25
26
|
* global: 'stable'|'next'|null,
|
|
26
27
|
* nextSet: Set<string>,
|
|
28
|
+
* stableSet: Set<string>,
|
|
27
29
|
* pins: Map<string, string>,
|
|
28
30
|
* warnings: string[]
|
|
29
31
|
* }}
|
|
@@ -58,6 +60,9 @@ function parseChannelOptions(options = {}) {
|
|
|
58
60
|
nextSet.add(trimmed);
|
|
59
61
|
}
|
|
60
62
|
|
|
63
|
+
// Filled only by the interactive per-module picker (no CLI flag).
|
|
64
|
+
const stableSet = new Set();
|
|
65
|
+
|
|
61
66
|
// --pin CODE=TAG (repeatable)
|
|
62
67
|
const pins = new Map();
|
|
63
68
|
for (const spec of options.pin || []) {
|
|
@@ -76,7 +81,7 @@ function parseChannelOptions(options = {}) {
|
|
|
76
81
|
// headless installs with --next=/--pin for a community module don't hang.
|
|
77
82
|
const acceptBypass = options.yes === true || options.acceptBypass === true;
|
|
78
83
|
|
|
79
|
-
return { global, nextSet, pins, warnings, acceptBypass };
|
|
84
|
+
return { global, nextSet, stableSet, pins, warnings, acceptBypass };
|
|
80
85
|
}
|
|
81
86
|
|
|
82
87
|
function normalizeChannel(raw, warnings, flagName) {
|
|
@@ -109,17 +114,20 @@ function parsePinSpec(spec) {
|
|
|
109
114
|
* source describes where the decision came from, for logging / debugging.
|
|
110
115
|
*/
|
|
111
116
|
function decideChannelForModule({ code, channelOptions, registryDefault, registryPin }) {
|
|
112
|
-
const { global, nextSet, pins } = channelOptions || { nextSet: new Set(), pins: new Map() };
|
|
117
|
+
const { global, nextSet, stableSet, pins } = channelOptions || { nextSet: new Set(), stableSet: new Set(), pins: new Map() };
|
|
113
118
|
|
|
114
119
|
if (pins && pins.has(code)) {
|
|
115
120
|
return { channel: 'pinned', pin: pins.get(code), source: 'flag:--pin' };
|
|
116
121
|
}
|
|
117
|
-
if (registryPin) {
|
|
118
|
-
return { channel: 'pinned', pin: registryPin, source: 'registry:pin' };
|
|
119
|
-
}
|
|
120
122
|
if (nextSet && nextSet.has(code)) {
|
|
121
123
|
return { channel: 'next', source: 'flag:--next' };
|
|
122
124
|
}
|
|
125
|
+
if (stableSet && stableSet.has(code)) {
|
|
126
|
+
return { channel: 'stable', source: 'picker:stable' };
|
|
127
|
+
}
|
|
128
|
+
if (registryPin) {
|
|
129
|
+
return { channel: 'pinned', pin: registryPin, source: 'registry:pin' };
|
|
130
|
+
}
|
|
123
131
|
if (global) {
|
|
124
132
|
return { channel: global, source: 'flag:--channel' };
|
|
125
133
|
}
|
package/tools/installer/ui.js
CHANGED
|
@@ -1980,15 +1980,12 @@ class UI {
|
|
|
1980
1980
|
message: `${code}: choose a channel`,
|
|
1981
1981
|
choices: [
|
|
1982
1982
|
{ name: stableLabel, value: 'stable' },
|
|
1983
|
-
{ name: 'next (main HEAD \u2014 current development)', value: 'next' },
|
|
1984
1983
|
{ name: 'pin (specific version)', value: 'pin' },
|
|
1985
1984
|
],
|
|
1986
1985
|
default: 'stable',
|
|
1987
1986
|
});
|
|
1988
1987
|
|
|
1989
|
-
if (choice === '
|
|
1990
|
-
channelOptions.nextSet.add(code);
|
|
1991
|
-
} else if (choice === 'pin') {
|
|
1988
|
+
if (choice === 'pin') {
|
|
1992
1989
|
const pinValue = await prompts.text({
|
|
1993
1990
|
message: `Enter a version tag for '${code}' (e.g. v1.6.0):`,
|
|
1994
1991
|
validate: (value) => {
|
|
@@ -1998,8 +1995,9 @@ class UI {
|
|
|
1998
1995
|
},
|
|
1999
1996
|
});
|
|
2000
1997
|
channelOptions.pins.set(code, String(pinValue).trim());
|
|
1998
|
+
} else {
|
|
1999
|
+
channelOptions.stableSet.add(code);
|
|
2001
2000
|
}
|
|
2002
|
-
// 'stable' is the default; nothing to record.
|
|
2003
2001
|
}
|
|
2004
2002
|
}
|
|
2005
2003
|
|
|
@@ -2014,8 +2012,7 @@ class UI {
|
|
|
2014
2012
|
* frozen unless the user also passes `--pin CODE=NEW_TAG`.
|
|
2015
2013
|
* - On `next`: no prompt (pull HEAD).
|
|
2016
2014
|
* - On `pinned`: no prompt (stays pinned).
|
|
2017
|
-
* - No channel recorded and `version: null`:
|
|
2018
|
-
* ("Switch to stable / Keep on next").
|
|
2015
|
+
* - No channel recorded and `version: null`: moves to stable, no prompt.
|
|
2019
2016
|
*
|
|
2020
2017
|
* Decisions that freeze the current version are applied by adding a pin to
|
|
2021
2018
|
* `channelOptions.pins` so downstream clone logic honors them.
|
|
@@ -2050,7 +2047,7 @@ class UI {
|
|
|
2050
2047
|
});
|
|
2051
2048
|
if (existingWithChannel.length > 0) {
|
|
2052
2049
|
reviewChannels = await prompts.confirm({
|
|
2053
|
-
message: 'Review channel assignments (stable /
|
|
2050
|
+
message: 'Review channel assignments (stable / pin) for your existing modules?',
|
|
2054
2051
|
default: false,
|
|
2055
2052
|
});
|
|
2056
2053
|
}
|
|
@@ -2071,7 +2068,7 @@ class UI {
|
|
|
2071
2068
|
const parsed = repoUrl ? parseGitHubRepo(repoUrl) : null;
|
|
2072
2069
|
|
|
2073
2070
|
// Legacy migration: manifest carries no channel and a null/empty
|
|
2074
|
-
// version.
|
|
2071
|
+
// version. The next channel is gone from the picker, so move it to stable.
|
|
2075
2072
|
const recordedChannel = prev.channel || null;
|
|
2076
2073
|
const needsMigration = !recordedChannel && (prev.version == null || prev.version === '');
|
|
2077
2074
|
if (needsMigration) {
|
|
@@ -2079,15 +2076,7 @@ class UI {
|
|
|
2079
2076
|
// Conservative headless default: stable.
|
|
2080
2077
|
continue;
|
|
2081
2078
|
}
|
|
2082
|
-
|
|
2083
|
-
message: `${code}: your existing install tracks the main branch. Switch to stable releases (recommended for production), or keep on main?`,
|
|
2084
|
-
choices: [
|
|
2085
|
-
{ name: 'Switch to stable', value: 'stable' },
|
|
2086
|
-
{ name: 'Keep on main (next)', value: 'next' },
|
|
2087
|
-
],
|
|
2088
|
-
default: 'stable',
|
|
2089
|
-
});
|
|
2090
|
-
if (chosen === 'next') channelOptions.nextSet.add(code);
|
|
2079
|
+
channelOptions.stableSet.add(code);
|
|
2091
2080
|
continue;
|
|
2092
2081
|
}
|
|
2093
2082
|
|
|
@@ -2105,9 +2094,6 @@ class UI {
|
|
|
2105
2094
|
if (recordedChannel !== 'stable') {
|
|
2106
2095
|
switchChoices.push({ name: 'Switch to stable (released version)', value: 'stable' });
|
|
2107
2096
|
}
|
|
2108
|
-
if (recordedChannel !== 'next') {
|
|
2109
|
-
switchChoices.push({ name: 'Switch to next (main HEAD)', value: 'next' });
|
|
2110
|
-
}
|
|
2111
2097
|
switchChoices.push({ name: 'Pin to a specific version tag', value: 'pin' });
|
|
2112
2098
|
|
|
2113
2099
|
const choice = await prompts.select({
|
|
@@ -2116,10 +2102,6 @@ class UI {
|
|
|
2116
2102
|
default: 'keep',
|
|
2117
2103
|
});
|
|
2118
2104
|
|
|
2119
|
-
if (choice === 'next') {
|
|
2120
|
-
channelOptions.nextSet.add(code);
|
|
2121
|
-
continue;
|
|
2122
|
-
}
|
|
2123
2105
|
if (choice === 'pin') {
|
|
2124
2106
|
const pinValue = await prompts.text({
|
|
2125
2107
|
message: `Enter a version tag for '${code}' (e.g. v1.6.0):`,
|
|
@@ -2135,6 +2117,7 @@ class UI {
|
|
|
2135
2117
|
if (choice === 'stable') {
|
|
2136
2118
|
// Switch to stable: install at the top stable tag without an
|
|
2137
2119
|
// upgrade-classification prompt (the user explicitly opted in).
|
|
2120
|
+
channelOptions.stableSet.add(code);
|
|
2138
2121
|
// Also warm the tag cache here so the actual clone step doesn't
|
|
2139
2122
|
// need a second GitHub API call (can hit rate limits).
|
|
2140
2123
|
if (parsed) {
|
|
Binary file
|