bmad-method 6.11.1-next.14 → 6.11.1-next.16
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/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-build/customize.toml +4 -4
- package/src/bmm-skills/ship/bmad-build-auto/customize.toml +6 -3
- package/src/bmm-skills/ship/bmad-code-review/customize.toml +6 -3
- 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/core-skills/bmad-review/SKILL.md +2 -2
- 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 +33 -1
- package/tools/installer/core/shim-policy.js +75 -7
- package/tools/installer/prompts.js +15 -2
- package/tools/installer/ui.js +28 -8
package/package.json
CHANGED
package/src/bmm-skills/plan/bmad-sprint-planning/scripts/__pycache__/sprint_plan.cpython-311.pyc
CHANGED
|
Binary file
|
|
Binary file
|
|
@@ -105,7 +105,7 @@ If you have zero findings, re-check and keep thinking; do not stop with an empty
|
|
|
105
105
|
CONTENT:
|
|
106
106
|
{diff_output}
|
|
107
107
|
|
|
108
|
-
Do not invoke any skill. Return
|
|
108
|
+
Do not invoke any skill, and do not spawn subagents of your own — you are the reviewer. Return your findings as text in your final message; do not route them through any findings-reporting tool the host may offer.
|
|
109
109
|
|
|
110
110
|
"""
|
|
111
111
|
|
|
@@ -121,7 +121,7 @@ Review content:
|
|
|
121
121
|
|
|
122
122
|
{diff_output}
|
|
123
123
|
|
|
124
|
-
Do not invoke any skill. If the instruction file is unreadable, report that exact failure and stop. Return
|
|
124
|
+
Do not invoke any skill, and do not spawn subagents of your own — you are the reviewer. If the instruction file is unreadable, report that exact failure and stop. Return your findings as text in your final message; do not route them through any findings-reporting tool the host may offer.
|
|
125
125
|
|
|
126
126
|
"""
|
|
127
127
|
|
|
@@ -137,7 +137,7 @@ Review content:
|
|
|
137
137
|
|
|
138
138
|
{diff_output}
|
|
139
139
|
|
|
140
|
-
Do not invoke any skill. If the instruction file is unreadable, report that exact failure and stop. Return
|
|
140
|
+
Do not invoke any skill, and do not spawn subagents of your own — you are the reviewer. If the instruction file is unreadable, report that exact failure and stop. Return your findings as text in your final message; do not route them through any findings-reporting tool the host may offer.
|
|
141
141
|
|
|
142
142
|
"""
|
|
143
143
|
|
|
@@ -159,6 +159,6 @@ If you have zero findings, re-check and keep thinking; do not stop with an empty
|
|
|
159
159
|
CONTENT:
|
|
160
160
|
The changed files in the current worktree. Inspect them directly before reviewing.
|
|
161
161
|
|
|
162
|
-
Do not invoke any skill. Return
|
|
162
|
+
Do not invoke any skill, and do not spawn subagents of your own — you are the reviewer. Return your findings as text in your final message; do not route them through any findings-reporting tool the host may offer.
|
|
163
163
|
|
|
164
164
|
"""
|
|
@@ -67,7 +67,7 @@ If you have zero findings, re-check and keep thinking; do not stop with an empty
|
|
|
67
67
|
CONTENT:
|
|
68
68
|
{diff_output}
|
|
69
69
|
|
|
70
|
-
Do not invoke any skill. Return
|
|
70
|
+
Do not invoke any skill, and do not spawn subagents of your own — you are the reviewer. Return your findings as text in your final message; do not route them through any findings-reporting tool the host may offer.
|
|
71
71
|
|
|
72
72
|
"""
|
|
73
73
|
|
|
@@ -83,7 +83,7 @@ Review content:
|
|
|
83
83
|
|
|
84
84
|
{diff_output}
|
|
85
85
|
|
|
86
|
-
Do not invoke any skill. If the instruction file is unreadable, report that exact failure and stop. Return
|
|
86
|
+
Do not invoke any skill, and do not spawn subagents of your own — you are the reviewer. If the instruction file is unreadable, report that exact failure and stop. Return your findings as text in your final message; do not route them through any findings-reporting tool the host may offer.
|
|
87
87
|
|
|
88
88
|
"""
|
|
89
89
|
|
|
@@ -99,7 +99,7 @@ Review content:
|
|
|
99
99
|
|
|
100
100
|
{diff_output}
|
|
101
101
|
|
|
102
|
-
Do not invoke any skill. If the instruction file is unreadable, report that exact failure and stop. Return
|
|
102
|
+
Do not invoke any skill, and do not spawn subagents of your own — you are the reviewer. If the instruction file is unreadable, report that exact failure and stop. Return your findings as text in your final message; do not route them through any findings-reporting tool the host may offer.
|
|
103
103
|
|
|
104
104
|
"""
|
|
105
105
|
|
|
@@ -118,4 +118,7 @@ Here is the diff:
|
|
|
118
118
|
{diff_output}
|
|
119
119
|
|
|
120
120
|
Your task is strictly descriptive — do not prescribe additional work. Report: (1) the defensible readings of the intent, enumerated; (2) which reading this diff implements; (3) where the readings and the diff diverge — specifically, which surface the intent's expectations live at versus which surface the diff's changes and its tests exercise.
|
|
121
|
+
|
|
122
|
+
Do not invoke any skill, and do not spawn subagents of your own — you are the reviewer. Return your findings as text in your final message; do not route them through any findings-reporting tool the host may offer.
|
|
123
|
+
|
|
121
124
|
"""
|
|
@@ -62,7 +62,7 @@ If you have zero findings, re-check and keep thinking; do not stop with an empty
|
|
|
62
62
|
CONTENT:
|
|
63
63
|
{diff_output}
|
|
64
64
|
|
|
65
|
-
Do not invoke any skill. Return
|
|
65
|
+
Do not invoke any skill, and do not spawn subagents of your own — you are the reviewer. Return your findings as text in your final message; do not route them through any findings-reporting tool the host may offer.
|
|
66
66
|
|
|
67
67
|
"""
|
|
68
68
|
|
|
@@ -78,7 +78,7 @@ Review content:
|
|
|
78
78
|
|
|
79
79
|
{diff_output}
|
|
80
80
|
|
|
81
|
-
Do not invoke any skill. If the instruction file is unreadable, report that exact failure and stop. Return
|
|
81
|
+
Do not invoke any skill, and do not spawn subagents of your own — you are the reviewer. If the instruction file is unreadable, report that exact failure and stop. Return your findings as text in your final message; do not route them through any findings-reporting tool the host may offer.
|
|
82
82
|
|
|
83
83
|
"""
|
|
84
84
|
|
|
@@ -94,7 +94,7 @@ Review content:
|
|
|
94
94
|
|
|
95
95
|
{diff_output}
|
|
96
96
|
|
|
97
|
-
Do not invoke any skill. If the instruction file is unreadable, report that exact failure and stop. Return
|
|
97
|
+
Do not invoke any skill, and do not spawn subagents of your own — you are the reviewer. If the instruction file is unreadable, report that exact failure and stop. Return your findings as text in your final message; do not route them through any findings-reporting tool the host may offer.
|
|
98
98
|
|
|
99
99
|
"""
|
|
100
100
|
|
|
@@ -110,4 +110,7 @@ You are an Acceptance Auditor. Review the provided diff against `{spec_file}` an
|
|
|
110
110
|
Diff:
|
|
111
111
|
|
|
112
112
|
{diff_output}
|
|
113
|
+
|
|
114
|
+
Do not invoke any skill, and do not spawn subagents of your own — you are the reviewer. Return your findings as text in your final message; do not route them through any findings-reporting tool the host may offer.
|
|
115
|
+
|
|
113
116
|
"""
|
package/src/bmm-skills/ship/bmad-retrospective/scripts/__pycache__/sprint_status.cpython-311.pyc
CHANGED
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -28,8 +28,8 @@ The lens set is whatever `{workflow.lenses}` resolves to, not a fixed list — o
|
|
|
28
28
|
2. **Load the content.** If it is empty or cannot be decoded as text: when the caller expects the raw findings JSON array (e.g. the legacy edge-case forwarder), return `[{"location":"N/A","trigger_condition":"Input empty or undecodable","guard_snippet":"Provide valid content to review","potential_consequence":"Review skipped — no analysis performed"}]` (no `lens` field) and stop; otherwise say what's wrong and ask for reviewable content. Classify the content — diff, source file, function, or document — and whether it is **code** or **docs**; scope rules and lens applicability both depend on it. A document that defines behavior (spec, requirements, plan, story) is `docs` that a behavioral lens may still apply to; judge by `when`.
|
|
29
29
|
3. **Select lenses** from `{workflow.lenses}`. A lens with an empty `instruction` is disabled. If the user or caller named lenses, run exactly those only — `applies_to` and `when` do not filter an explicit request. Otherwise run every enabled lens whose `applies_to` covers the content class (`any` always covers) and whose `when` applies.
|
|
30
30
|
4. **Announce the plan** in one line before running anything: the content class, the lenses about to run, and — when any lens has `after` set — that it runs on top of the named lens's findings. Skip the announcement entirely when the caller pinned an exact output contract (the legacy forwarders that demand raw JSON or one exact line) — their contract covers everything you emit, not just the findings block. Then execute each `{workflow.activation_steps_append}` entry in order.
|
|
31
|
-
5. **Run the independent lenses** — every selected lens without `after`. Each sees the content and `also_consider`, never another lens's findings. Follow each lens's `instruction`; the shipped lenses load their reference file just-in-time, so load only what runs. When subagents are available, spawn one per lens in parallel: give it the lens `instruction` with `{skill-root}` and paths resolved absolute, the content or where to read it, any `also_consider` areas, the standing review directives, and the constraint "Return ONLY your findings — no other output." Otherwise run the lenses sequentially yourself, completing one before starting the next.
|
|
32
|
-
6. **Run the dependent lenses** — every selected lens with `after`, once the lens it names has completed, passing that lens's findings in. A lens whose `after` target was not selected or produced nothing still runs, with no prior findings. Dependent lenses that name different targets are independent of each other and may run in parallel.
|
|
31
|
+
5. **Run the independent lenses** — every selected lens without `after`. Each sees the content and `also_consider`, never another lens's findings. Follow each lens's `instruction`; the shipped lenses load their reference file just-in-time, so load only what runs. When subagents are available, spawn one per lens in parallel: give it the lens `instruction` with `{skill-root}` and paths resolved absolute, the content or where to read it, any `also_consider` areas, the standing review directives, and the constraint "Return ONLY your findings — no other output. Do not invoke any skill, and do not spawn subagents of your own — you are the reviewer. Return your findings as text in your final message; do not route them through any findings-reporting tool the host may offer." Otherwise run the lenses sequentially yourself, completing one before starting the next.
|
|
32
|
+
6. **Run the dependent lenses** — every selected lens with `after`, once the lens it names has completed, passing that lens's findings in. A lens whose `after` target was not selected or produced nothing still runs, with no prior findings. Dependent lenses that name different targets are independent of each other and may run in parallel. When subagents are available, spawn them with the same constraint as independent lenses: "Return ONLY your findings — no other output. Do not invoke any skill, and do not spawn subagents of your own — you are the reviewer. Return your findings as text in your final message; do not route them through any findings-reporting tool the host may offer."
|
|
33
33
|
7. **Assemble and present** per Output below. Keep every lens's findings — overlap between lenses is signal, not duplication; note it in the markdown report rather than deduping. Execute `{workflow.on_complete}` if set.
|
|
34
34
|
|
|
35
35
|
## Output
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -13,7 +13,14 @@ const { InstallPaths } = require('./install-paths');
|
|
|
13
13
|
const { ExternalModuleManager } = require('../modules/external-manager');
|
|
14
14
|
const { resolveModuleVersion } = require('../modules/version-resolver');
|
|
15
15
|
const { MODULE_HELP_CSV_HEADER } = require('../modules/module-help-schema');
|
|
16
|
-
const {
|
|
16
|
+
const {
|
|
17
|
+
formatRemovedShimNotice,
|
|
18
|
+
formatRetainedShimNotice,
|
|
19
|
+
inferShimPreference,
|
|
20
|
+
readInstalledShims,
|
|
21
|
+
readInstalledSkillIds,
|
|
22
|
+
selectShimOutcome,
|
|
23
|
+
} = require('./shim-policy');
|
|
17
24
|
|
|
18
25
|
const { ExistingInstall } = require('./existing-install');
|
|
19
26
|
const { warnPreNativeSkillsLegacy } = require('./legacy-warnings');
|
|
@@ -59,6 +66,24 @@ class Installer {
|
|
|
59
66
|
}),
|
|
60
67
|
};
|
|
61
68
|
|
|
69
|
+
const installedShims = existingInstall.installed ? await readInstalledShims(paths.bmadDir) : [];
|
|
70
|
+
const { retained: retainedShims, removed: removedShims } = selectShimOutcome({
|
|
71
|
+
installedShims,
|
|
72
|
+
availableShims,
|
|
73
|
+
install: shimPolicy.install,
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
// Reported here, not at the prompt, so --yes/--shims/scripted runs get it too.
|
|
77
|
+
if (retainedShims.length > 0) {
|
|
78
|
+
await prompts.note(formatRetainedShimNotice(retainedShims), 'Deprecated shim skills retained');
|
|
79
|
+
}
|
|
80
|
+
if (removedShims.length > 0) {
|
|
81
|
+
await prompts.note(formatRemovedShimNotice(removedShims, { canReinstall: shimPolicy.available }), 'Deprecated shim skills removed');
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
// The notices above scroll away on a long install; repeat them in the summary.
|
|
85
|
+
const shimStatus = { retained: retainedShims.length, removed: removedShims.length };
|
|
86
|
+
|
|
62
87
|
try {
|
|
63
88
|
await warnPreNativeSkillsLegacy({
|
|
64
89
|
projectRoot: paths.projectRoot,
|
|
@@ -132,6 +157,7 @@ class Installer {
|
|
|
132
157
|
customFiles: restoreResult.customFiles.length > 0 ? restoreResult.customFiles : undefined,
|
|
133
158
|
modifiedFiles: restoreResult.modifiedFiles.length > 0 ? restoreResult.modifiedFiles : undefined,
|
|
134
159
|
preInstallVersions,
|
|
160
|
+
shimStatus,
|
|
135
161
|
});
|
|
136
162
|
|
|
137
163
|
return {
|
|
@@ -1261,6 +1287,12 @@ class Installer {
|
|
|
1261
1287
|
if (context.modifiedFiles && context.modifiedFiles.length > 0) {
|
|
1262
1288
|
lines.push(` ${color.yellow(`Modified files backed up (.bak): ${context.modifiedFiles.length}`)}`);
|
|
1263
1289
|
}
|
|
1290
|
+
if (context.shimStatus?.retained > 0) {
|
|
1291
|
+
lines.push(` ${color.yellow(`Deprecated shim skills retained: ${context.shimStatus.retained}`)} (re-run to remove them)`);
|
|
1292
|
+
}
|
|
1293
|
+
if (context.shimStatus?.removed > 0) {
|
|
1294
|
+
lines.push(` ${color.green(`Deprecated shim skills removed: ${context.shimStatus.removed}`)}`);
|
|
1295
|
+
}
|
|
1264
1296
|
|
|
1265
1297
|
// Next steps
|
|
1266
1298
|
lines.push(
|
|
@@ -37,6 +37,7 @@ async function discoverShims(modulePath) {
|
|
|
37
37
|
if (isShimSkill(metadata)) {
|
|
38
38
|
shims.push({
|
|
39
39
|
id: metadata.name || path.basename(dir),
|
|
40
|
+
description: typeof metadata.description === 'string' ? metadata.description : '',
|
|
40
41
|
directory: dir,
|
|
41
42
|
relativeDirectory: path.relative(modulePath, dir),
|
|
42
43
|
});
|
|
@@ -54,25 +55,40 @@ async function discoverShims(modulePath) {
|
|
|
54
55
|
return shims;
|
|
55
56
|
}
|
|
56
57
|
|
|
57
|
-
async function
|
|
58
|
-
const ids = new Set();
|
|
58
|
+
async function readSkillManifest(bmadDir) {
|
|
59
59
|
const manifestPath = path.join(bmadDir, '_config', 'skill-manifest.csv');
|
|
60
|
-
if (!(await fs.pathExists(manifestPath))) return
|
|
60
|
+
if (!(await fs.pathExists(manifestPath))) return [];
|
|
61
61
|
|
|
62
62
|
try {
|
|
63
63
|
const content = await fs.readFile(manifestPath, 'utf8');
|
|
64
|
-
|
|
65
|
-
for (const record of records) {
|
|
66
|
-
if (record.canonicalId) ids.add(record.canonicalId);
|
|
67
|
-
}
|
|
64
|
+
return csv.parse(content, { columns: true, skip_empty_lines: true });
|
|
68
65
|
} catch {
|
|
69
66
|
// A missing or unreadable legacy manifest means there is no reliable
|
|
70
67
|
// evidence that compatibility shims were installed.
|
|
68
|
+
return [];
|
|
71
69
|
}
|
|
70
|
+
}
|
|
72
71
|
|
|
72
|
+
async function readInstalledSkillIds(bmadDir) {
|
|
73
|
+
const ids = new Set();
|
|
74
|
+
for (const record of await readSkillManifest(bmadDir)) {
|
|
75
|
+
if (record.canonicalId) ids.add(record.canonicalId);
|
|
76
|
+
}
|
|
73
77
|
return ids;
|
|
74
78
|
}
|
|
75
79
|
|
|
80
|
+
// The installed manifest carries no lifecycle column, so the description
|
|
81
|
+
// prefix every shim ships with is the only record of what was a shim. This
|
|
82
|
+
// is the same signal validate-skills.js uses to exempt them.
|
|
83
|
+
async function readInstalledShims(bmadDir) {
|
|
84
|
+
const shims = [];
|
|
85
|
+
for (const record of await readSkillManifest(bmadDir)) {
|
|
86
|
+
if (!record.canonicalId || !/^\s*deprecated\b/i.test(record.description || '')) continue;
|
|
87
|
+
shims.push({ id: record.canonicalId, description: record.description || '', module: record.module || '' });
|
|
88
|
+
}
|
|
89
|
+
return shims;
|
|
90
|
+
}
|
|
91
|
+
|
|
76
92
|
function inferShimPreference({ requested, persisted, availableShims = [], installedSkillIds = new Set(), existing = false }) {
|
|
77
93
|
if (availableShims.length === 0) return false;
|
|
78
94
|
if (typeof requested === 'boolean') return requested;
|
|
@@ -82,10 +98,62 @@ function inferShimPreference({ requested, persisted, availableShims = [], instal
|
|
|
82
98
|
return availableShims.some((shim) => installedSkillIds.has(shim.id));
|
|
83
99
|
}
|
|
84
100
|
|
|
101
|
+
// Removal is driven by what is installed, not by what this release ships: a
|
|
102
|
+
// shim retired from source is still deleted by the update cleanup.
|
|
103
|
+
function selectShimOutcome({ installedShims = [], availableShims = [], install = false }) {
|
|
104
|
+
const availableShimIds = new Set(availableShims.map((shim) => shim.id));
|
|
105
|
+
return {
|
|
106
|
+
retained: install ? availableShims : [],
|
|
107
|
+
removed: installedShims.filter((shim) => !(install && availableShimIds.has(shim.id))),
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
// Shim descriptions all open with "Deprecated — "; the notice heading says it once.
|
|
112
|
+
function describeShim(shim) {
|
|
113
|
+
const cleaned = (shim.description || '').replace(/^\s*deprecated\s*[-–—:]*\s*/i, '').trim();
|
|
114
|
+
const source = shim.module ? ` (${shim.module})` : '';
|
|
115
|
+
return cleaned ? ` ${shim.id}${source}: ${cleaned}` : ` ${shim.id}${source}`;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
function formatRetainedShimNotice(availableShims = []) {
|
|
119
|
+
const lines = availableShims.map((shim) => describeShim(shim)).sort();
|
|
120
|
+
|
|
121
|
+
return [
|
|
122
|
+
`${availableShims.length} deprecated shim skill(s) are still installed. Each one only forwards to the skill that replaced it:`,
|
|
123
|
+
'',
|
|
124
|
+
...lines,
|
|
125
|
+
'',
|
|
126
|
+
'Shims will be removed with v7, and anything still calling the old name stops working then.',
|
|
127
|
+
'Only keep a shim if you customized it and still need to move that customization to the replacement.',
|
|
128
|
+
'Once you have, re-run Quick Update and answer No to this question so the shims come off.',
|
|
129
|
+
].join('\n');
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
function formatRemovedShimNotice(removedShims = [], { canReinstall = true } = {}) {
|
|
133
|
+
const lines = removedShims.map((shim) => describeShim(shim)).sort();
|
|
134
|
+
const recovery = canReinstall
|
|
135
|
+
? 'these shims, move it to the replacement, or re-run with --shims to put the shims back.'
|
|
136
|
+
: 'these shims, move it to the replacement. This release no longer ships them, so --shims cannot bring them back.';
|
|
137
|
+
|
|
138
|
+
return [
|
|
139
|
+
`${removedShims.length} deprecated shim skill(s) are being removed. Invoking these names will no longer work:`,
|
|
140
|
+
'',
|
|
141
|
+
...lines,
|
|
142
|
+
'',
|
|
143
|
+
'Each replacement named above is installed and ready. If you still had a customization on one of',
|
|
144
|
+
recovery,
|
|
145
|
+
].join('\n');
|
|
146
|
+
}
|
|
147
|
+
|
|
85
148
|
module.exports = {
|
|
149
|
+
describeShim,
|
|
150
|
+
formatRemovedShimNotice,
|
|
86
151
|
discoverShims,
|
|
152
|
+
formatRetainedShimNotice,
|
|
87
153
|
inferShimPreference,
|
|
88
154
|
isShimSkill,
|
|
89
155
|
parseSkillMetadata,
|
|
156
|
+
readInstalledShims,
|
|
90
157
|
readInstalledSkillIds,
|
|
158
|
+
selectShimOutcome,
|
|
91
159
|
};
|
|
@@ -316,7 +316,9 @@ async function autocompleteMultiselect(options) {
|
|
|
316
316
|
|
|
317
317
|
switch (this.state) {
|
|
318
318
|
case 'submit': {
|
|
319
|
-
|
|
319
|
+
const count = this.selectedValues.length;
|
|
320
|
+
const emptyHint = count === 0 && options.emptyLabel ? ` (${options.emptyLabel})` : '';
|
|
321
|
+
return `${title}${color.gray(clack.S_BAR)} ${color.dim(`${count} item${count === 1 ? '' : 's'} selected${emptyHint}`)}`;
|
|
320
322
|
}
|
|
321
323
|
|
|
322
324
|
case 'cancel': {
|
|
@@ -331,7 +333,18 @@ async function autocompleteMultiselect(options) {
|
|
|
331
333
|
|
|
332
334
|
const errorLine = this.state === 'error' ? [`${bar} ${color.yellow(this.error)}`] : [];
|
|
333
335
|
|
|
334
|
-
const
|
|
336
|
+
const emptyLine =
|
|
337
|
+
this.selectedValues.length === 0 && options.emptyLabel
|
|
338
|
+
? [`${bar} ${color.dim(`Nothing selected: installs ${options.emptyLabel}`)}`]
|
|
339
|
+
: [];
|
|
340
|
+
|
|
341
|
+
const headerLines = [
|
|
342
|
+
...`${title}${bar}`.split('\n'),
|
|
343
|
+
`${bar} ${searchDisplay}${matchCount}`,
|
|
344
|
+
...noMatchesLine,
|
|
345
|
+
...errorLine,
|
|
346
|
+
...emptyLine,
|
|
347
|
+
];
|
|
335
348
|
|
|
336
349
|
const footerLines = [`${bar} ${color.dim(hints.join(' • '))}`, `${barEnd}`];
|
|
337
350
|
|
package/tools/installer/ui.js
CHANGED
|
@@ -111,7 +111,7 @@ async function getModuleVersion(moduleCode, { repoUrl = null, registryDefault =
|
|
|
111
111
|
* UI utilities for the installer
|
|
112
112
|
*/
|
|
113
113
|
class UI {
|
|
114
|
-
async _selectShimPreference({ selectedModules, bmadDir, existing, options, channelOptions }) {
|
|
114
|
+
async _selectShimPreference({ selectedModules, bmadDir, existing, options, channelOptions, quickUpdate = false }) {
|
|
115
115
|
const { OfficialModules } = require('./modules/official-modules');
|
|
116
116
|
const officialModules = new OfficialModules({ channelOptions });
|
|
117
117
|
const availableShims = await officialModules.discoverShims(selectedModules, { channelOptions });
|
|
@@ -132,10 +132,20 @@ class UI {
|
|
|
132
132
|
|
|
133
133
|
if (typeof options.shims === 'boolean' || options.yes) return currentValue;
|
|
134
134
|
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
135
|
+
// clack's confirm never resolves without a TTY: a scripted run would exit mid-install.
|
|
136
|
+
if (!process.stdin.isTTY) return currentValue;
|
|
137
|
+
|
|
138
|
+
// Nothing to give up, so nothing to ask on every single update.
|
|
139
|
+
if (quickUpdate && !currentValue) return currentValue;
|
|
140
|
+
|
|
141
|
+
const verb = currentValue ? 'Keep' : 'Install';
|
|
142
|
+
const message =
|
|
143
|
+
`${verb} ${availableShims.length} deprecated compatibility shim skill(s)? Recommended: No. ` +
|
|
144
|
+
`If you say yes, the deprecated skills will exist as a skill that forwards to its replacement skill. ` +
|
|
145
|
+
`Shims will be removed with v7. You should only retain if you customized a shimmed skill and need to ` +
|
|
146
|
+
`still transition it to the replacement.`;
|
|
147
|
+
|
|
148
|
+
return prompts.confirm({ message, default: currentValue });
|
|
139
149
|
}
|
|
140
150
|
|
|
141
151
|
/**
|
|
@@ -346,11 +356,21 @@ class UI {
|
|
|
346
356
|
// Quick update never shows the module picker, so this is the only
|
|
347
357
|
// place an existing install of a deprecated module hears about it.
|
|
348
358
|
await this._warnDeprecatedModules(existingInstall.moduleIds || []);
|
|
359
|
+
|
|
360
|
+
const installShims = await this._selectShimPreference({
|
|
361
|
+
selectedModules: existingInstall.moduleIds || [],
|
|
362
|
+
bmadDir,
|
|
363
|
+
existing: true,
|
|
364
|
+
options,
|
|
365
|
+
channelOptions,
|
|
366
|
+
quickUpdate: true,
|
|
367
|
+
});
|
|
368
|
+
|
|
349
369
|
return {
|
|
350
370
|
actionType: 'quick-update',
|
|
351
371
|
directory: confirmedDirectory,
|
|
352
372
|
skipPrompts: options.yes || false,
|
|
353
|
-
installShims: options.shims,
|
|
373
|
+
installShims: installShims === undefined ? options.shims : installShims,
|
|
354
374
|
};
|
|
355
375
|
}
|
|
356
376
|
|
|
@@ -1116,9 +1136,9 @@ class UI {
|
|
|
1116
1136
|
message: 'Select official modules to install:',
|
|
1117
1137
|
options: allOptions,
|
|
1118
1138
|
initialValues: initialValues.length > 0 ? initialValues : undefined,
|
|
1119
|
-
//
|
|
1120
|
-
// legitimate "core only" install rather than a mistake to block on.
|
|
1139
|
+
// Core installs either way and is not a row here, so empty is a valid core-only install.
|
|
1121
1140
|
required: false,
|
|
1141
|
+
emptyLabel: 'core only',
|
|
1122
1142
|
maxItems: allOptions.length,
|
|
1123
1143
|
});
|
|
1124
1144
|
|