ma-agents 3.13.0 → 3.13.2-skillname.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/bin/cli.js +67 -13
- package/lib/.bmad-extension-plugin.build-37364-1782300865129/.claude-plugin/marketplace.json +109 -0
- package/lib/.bmad-extension-plugin.build-37364-1782300865129/skills/module-help.csv +62 -0
- package/lib/.bmad-extension-plugin.build-37364-1782300865129/skills/module.yaml +20 -0
- package/lib/bmad-extension-plugin/.claude-plugin/marketplace.json +1 -1
- package/lib/bmad.js +270 -11
- package/lib/installer.js +276 -23
- package/lib/profile.js +96 -5
- package/lib/templates/instruction-block-git.template.md +25 -25
- package/lib/templates/instruction-block-onprem.template.md +86 -86
- package/lib/templates/instruction-block-universal.template.md +29 -29
- package/package.json +2 -2
- package/skills/git-workflow-skill/skill.json +21 -21
package/lib/bmad.js
CHANGED
|
@@ -278,17 +278,34 @@ function ensurePluginStageGitignoredForProject(projectRoot) {
|
|
|
278
278
|
console.warn(chalk.yellow(` Warning: could not load installer for gitignore policy: ${err.message}`));
|
|
279
279
|
return;
|
|
280
280
|
}
|
|
281
|
-
if (typeof installer.ensurePluginStageIgnored
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
281
|
+
if (typeof installer.ensurePluginStageIgnored === 'function') {
|
|
282
|
+
try {
|
|
283
|
+
installer.ensurePluginStageIgnored(projectRoot);
|
|
284
|
+
} catch (err) {
|
|
285
|
+
// EACCES on read-only `.gitignore`, EROFS on read-only filesystem, etc.
|
|
286
|
+
// Logged so the operator can fix it manually; never fatal to the install.
|
|
287
|
+
console.warn(
|
|
288
|
+
chalk.yellow(
|
|
289
|
+
` Warning: could not update ${path.join(projectRoot, '.gitignore')} with plugin-stage entry: ${err.message}`
|
|
290
|
+
)
|
|
291
|
+
);
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
// Bug 27.11 — also ensure the regenerated, installer-managed `_bmad/` tree is
|
|
296
|
+
// gitignored. Same project-root contract and same non-fatal failure policy as
|
|
297
|
+
// the plugin-stage entry above. `_bmad-output/` is intentionally left tracked
|
|
298
|
+
// (see ensureBmadOutputTracked) and is not matched by these patterns.
|
|
299
|
+
if (typeof installer.ensureBmadDirIgnored === 'function') {
|
|
300
|
+
try {
|
|
301
|
+
installer.ensureBmadDirIgnored(projectRoot);
|
|
302
|
+
} catch (err) {
|
|
303
|
+
console.warn(
|
|
304
|
+
chalk.yellow(
|
|
305
|
+
` Warning: could not update ${path.join(projectRoot, '.gitignore')} with _bmad/ entry: ${err.message}`
|
|
306
|
+
)
|
|
307
|
+
);
|
|
308
|
+
}
|
|
292
309
|
}
|
|
293
310
|
}
|
|
294
311
|
|
|
@@ -847,6 +864,11 @@ async function installBmad(modules = ['bmm', 'bmb'], tools = [], projectRoot = p
|
|
|
847
864
|
try {
|
|
848
865
|
runCommand(command, { cwd: projectRoot, env: buildChildSpawnEnv() });
|
|
849
866
|
bmadInvokeSucceeded = true;
|
|
867
|
+
// Bug 27.14 — repair any module artifact path that upstream's
|
|
868
|
+
// suffix-match output-folder resolution contaminated (e.g. gds paths
|
|
869
|
+
// pinned to bmb's "skills" instead of the chosen output folder). Runs
|
|
870
|
+
// after bmad-method writes the config and before downstream consumers.
|
|
871
|
+
normalizeModuleOutputFolders(projectRoot);
|
|
850
872
|
// F1a — on-prem persona phase-prefix pass. Runs BEFORE
|
|
851
873
|
// deployMethodology so a methodology-deploy failure doesn't prevent
|
|
852
874
|
// the prefix from being applied (they are independent concerns).
|
|
@@ -953,6 +975,10 @@ async function runMigration(modules, tools, projectRoot, force, { userName, comm
|
|
|
953
975
|
return false;
|
|
954
976
|
}
|
|
955
977
|
|
|
978
|
+
// Bug 27.14 — repair contaminated module artifact paths on the migration
|
|
979
|
+
// path too (same upstream suffix-match resolution applies to updates).
|
|
980
|
+
normalizeModuleOutputFolders(projectRoot);
|
|
981
|
+
|
|
956
982
|
// Step 3: Merge user customizations
|
|
957
983
|
if (backedUpFiles.length > 0) {
|
|
958
984
|
console.log(chalk.cyan(' Step 3/4: Merging user customizations...'));
|
|
@@ -1808,6 +1834,237 @@ function readCanonicalBmadConfig(projectRoot) {
|
|
|
1808
1834
|
}
|
|
1809
1835
|
}
|
|
1810
1836
|
|
|
1837
|
+
// ── Bug 27.14 — output-folder propagation normalization ──────────────────────
|
|
1838
|
+
//
|
|
1839
|
+
// Upstream bmad-method's resolveConfigValue (official-modules.js) resolves the
|
|
1840
|
+
// `{output_folder}` token via a `endsWith('_output_folder')` suffix match over
|
|
1841
|
+
// all collected answers. When bmb (answer key `bmb_..._output_folder` = "skills")
|
|
1842
|
+
// and gds are co-installed, gds's `{output_folder}` resolves alphabetically to
|
|
1843
|
+
// bmb's "skills" value, so gds artifact paths become `{project-root}/skills/...`
|
|
1844
|
+
// instead of `{project-root}/_bmad-output/...`.
|
|
1845
|
+
//
|
|
1846
|
+
// ma-agents owns no part of that resolution (it lives in vendored node_modules),
|
|
1847
|
+
// so this is a post-install WORK-AROUND: after bmad-method writes the config,
|
|
1848
|
+
// re-read `[core] output_folder` and rewrite any contaminated module artifact
|
|
1849
|
+
// path back onto the canonical output folder. We deliberately scope the rewrite
|
|
1850
|
+
// to the well-known core artifact keys so we never touch a module's INTENTIONAL
|
|
1851
|
+
// own-folder values (e.g. bmb's `bmad_builder_output_folder = ".../skills"` or
|
|
1852
|
+
// wds's `design_artifacts = ".../design-artifacts"`).
|
|
1853
|
+
//
|
|
1854
|
+
// Upstream follow-up (do NOT edit node_modules here): patch resolveConfigValue
|
|
1855
|
+
// to require an exact `output_folder` / `core_output_folder` key instead of the
|
|
1856
|
+
// `endsWith` suffix match. Tracked as an upstream follow-up.
|
|
1857
|
+
|
|
1858
|
+
// Artifact keys that must always live under `[core] output_folder`. These are
|
|
1859
|
+
// the canonical bmm/gds planning+implementation+architecture artifact keys plus
|
|
1860
|
+
// tea's test_artifacts. Module-specific own-folder keys (bmb_*_output_folder,
|
|
1861
|
+
// design_artifacts, project_knowledge, *_output sub-paths) are intentionally
|
|
1862
|
+
// excluded.
|
|
1863
|
+
const OUTPUT_FOLDER_ARTIFACT_KEYS = [
|
|
1864
|
+
'planning_artifacts',
|
|
1865
|
+
'architecture_artifacts',
|
|
1866
|
+
'implementation_artifacts',
|
|
1867
|
+
'test_artifacts',
|
|
1868
|
+
];
|
|
1869
|
+
|
|
1870
|
+
/**
|
|
1871
|
+
* Given an artifact path value and the canonical output folder, return a
|
|
1872
|
+
* corrected value if the path's output-folder segment differs from the
|
|
1873
|
+
* canonical one, or `null` if no change is needed.
|
|
1874
|
+
*
|
|
1875
|
+
* Handles both conventions:
|
|
1876
|
+
* - `{project-root}/<seg>/<suffix...>` (config.toml style)
|
|
1877
|
+
* - `<seg>/<suffix...>` (config.yaml stripped style)
|
|
1878
|
+
*
|
|
1879
|
+
* The leading `<seg>` (the first path segment after an optional `{project-root}/`
|
|
1880
|
+
* prefix) is the resolved output folder; if it !== `outputFolder` it is rewritten.
|
|
1881
|
+
* Only single-segment output folders are handled (the bmad default), which covers
|
|
1882
|
+
* the observed `skills` vs `_bmad-output` contamination.
|
|
1883
|
+
*/
|
|
1884
|
+
function correctArtifactPath(value, outputFolder) {
|
|
1885
|
+
if (typeof value !== 'string' || !value) return null;
|
|
1886
|
+
const ROOT = '{project-root}/';
|
|
1887
|
+
let prefix = '';
|
|
1888
|
+
let rest = value;
|
|
1889
|
+
if (rest.startsWith(ROOT)) {
|
|
1890
|
+
prefix = ROOT;
|
|
1891
|
+
rest = rest.slice(ROOT.length);
|
|
1892
|
+
}
|
|
1893
|
+
const slash = rest.indexOf('/');
|
|
1894
|
+
if (slash === -1) return null; // no segment/suffix split — leave as-is
|
|
1895
|
+
const seg = rest.slice(0, slash);
|
|
1896
|
+
const suffix = rest.slice(slash); // includes leading '/'
|
|
1897
|
+
if (seg === outputFolder) return null; // already canonical
|
|
1898
|
+
return `${prefix}${outputFolder}${suffix}`;
|
|
1899
|
+
}
|
|
1900
|
+
|
|
1901
|
+
/**
|
|
1902
|
+
* Rewrite contaminated artifact paths inside `_bmad/config.toml`. Returns the
|
|
1903
|
+
* number of lines changed. Uses line-based editing (no TOML dependency) so we
|
|
1904
|
+
* preserve comments, ordering, and formatting exactly.
|
|
1905
|
+
*/
|
|
1906
|
+
function normalizeTomlOutputFolders(tomlPath, outputFolder) {
|
|
1907
|
+
if (!fs.existsSync(tomlPath)) return 0;
|
|
1908
|
+
let raw;
|
|
1909
|
+
try {
|
|
1910
|
+
raw = fs.readFileSync(tomlPath, 'utf-8');
|
|
1911
|
+
} catch {
|
|
1912
|
+
return 0;
|
|
1913
|
+
}
|
|
1914
|
+
const usesCrlf = /\r\n/.test(raw);
|
|
1915
|
+
const eol = usesCrlf ? '\r\n' : '\n';
|
|
1916
|
+
const lines = raw.split(/\r?\n/);
|
|
1917
|
+
let changed = 0;
|
|
1918
|
+
let inModuleSection = false;
|
|
1919
|
+
|
|
1920
|
+
for (let i = 0; i < lines.length; i++) {
|
|
1921
|
+
const line = lines[i];
|
|
1922
|
+
const sectionMatch = line.match(/^\s*\[([^\]]+)\]\s*$/);
|
|
1923
|
+
if (sectionMatch) {
|
|
1924
|
+
const section = sectionMatch[1].trim();
|
|
1925
|
+
inModuleSection = section.startsWith('modules.');
|
|
1926
|
+
continue;
|
|
1927
|
+
}
|
|
1928
|
+
if (!inModuleSection) continue;
|
|
1929
|
+
|
|
1930
|
+
// key = "value" (only quoted string values are artifact paths)
|
|
1931
|
+
const kvMatch = line.match(/^(\s*)([A-Za-z0-9_]+)(\s*=\s*)"([^"]*)"(\s*(?:#.*)?)$/);
|
|
1932
|
+
if (!kvMatch) continue;
|
|
1933
|
+
const [, indent, key, eq, val, trailer] = kvMatch;
|
|
1934
|
+
if (!OUTPUT_FOLDER_ARTIFACT_KEYS.includes(key)) continue;
|
|
1935
|
+
const corrected = correctArtifactPath(val, outputFolder);
|
|
1936
|
+
if (corrected === null) continue;
|
|
1937
|
+
lines[i] = `${indent}${key}${eq}"${corrected}"${trailer}`;
|
|
1938
|
+
changed++;
|
|
1939
|
+
}
|
|
1940
|
+
|
|
1941
|
+
if (changed > 0) {
|
|
1942
|
+
fs.writeFileSync(tomlPath, lines.join(eol), 'utf-8');
|
|
1943
|
+
}
|
|
1944
|
+
return changed;
|
|
1945
|
+
}
|
|
1946
|
+
|
|
1947
|
+
/**
|
|
1948
|
+
* Rewrite contaminated artifact paths inside a per-module `_bmad/<mod>/config.yaml`.
|
|
1949
|
+
* Returns the number of keys changed. Uses js-yaml so we keep schema fidelity.
|
|
1950
|
+
*/
|
|
1951
|
+
function normalizeYamlOutputFolders(yamlPath, outputFolder) {
|
|
1952
|
+
if (!fs.existsSync(yamlPath)) return 0;
|
|
1953
|
+
let raw;
|
|
1954
|
+
try {
|
|
1955
|
+
raw = fs.readFileSync(yamlPath, 'utf-8');
|
|
1956
|
+
} catch {
|
|
1957
|
+
return 0;
|
|
1958
|
+
}
|
|
1959
|
+
let doc;
|
|
1960
|
+
try {
|
|
1961
|
+
doc = yaml.parse(raw);
|
|
1962
|
+
} catch {
|
|
1963
|
+
return 0;
|
|
1964
|
+
}
|
|
1965
|
+
if (!doc || typeof doc !== 'object') return 0;
|
|
1966
|
+
|
|
1967
|
+
let changed = 0;
|
|
1968
|
+
for (const key of OUTPUT_FOLDER_ARTIFACT_KEYS) {
|
|
1969
|
+
if (typeof doc[key] !== 'string') continue;
|
|
1970
|
+
const corrected = correctArtifactPath(doc[key], outputFolder);
|
|
1971
|
+
if (corrected === null) continue;
|
|
1972
|
+
doc[key] = corrected;
|
|
1973
|
+
changed++;
|
|
1974
|
+
}
|
|
1975
|
+
|
|
1976
|
+
if (changed > 0) {
|
|
1977
|
+
// Preserve the leading comment header (everything up to the first
|
|
1978
|
+
// non-comment, non-blank line) so the "Generated by BMAD installer"
|
|
1979
|
+
// banner survives the rewrite.
|
|
1980
|
+
const headerLines = [];
|
|
1981
|
+
for (const l of raw.split(/\r?\n/)) {
|
|
1982
|
+
if (l.trim() === '' || l.trimStart().startsWith('#')) {
|
|
1983
|
+
headerLines.push(l);
|
|
1984
|
+
} else {
|
|
1985
|
+
break;
|
|
1986
|
+
}
|
|
1987
|
+
}
|
|
1988
|
+
const header = headerLines.length > 0 ? headerLines.join('\n') + '\n' : '';
|
|
1989
|
+
fs.writeFileSync(yamlPath, header + yaml.stringify(doc), 'utf-8');
|
|
1990
|
+
}
|
|
1991
|
+
return changed;
|
|
1992
|
+
}
|
|
1993
|
+
|
|
1994
|
+
/**
|
|
1995
|
+
* Bug 27.14 — post-install pass that re-points any contaminated module artifact
|
|
1996
|
+
* path at the canonical `[core] output_folder`. Reads the output folder from
|
|
1997
|
+
* `_bmad/config.toml` (the install-owned source of truth), then normalizes both
|
|
1998
|
+
* `_bmad/config.toml` and every `_bmad/<mod>/config.yaml`.
|
|
1999
|
+
*
|
|
2000
|
+
* Idempotent and non-fatal: a second run finds nothing to change, and any I/O
|
|
2001
|
+
* error is logged and swallowed (config normalization must never abort an
|
|
2002
|
+
* otherwise-green install).
|
|
2003
|
+
*
|
|
2004
|
+
* @param {string} projectRoot - Absolute path to the project root.
|
|
2005
|
+
* @returns {number} Total number of artifact paths rewritten (for tests/logging).
|
|
2006
|
+
*/
|
|
2007
|
+
function normalizeModuleOutputFolders(projectRoot) {
|
|
2008
|
+
if (typeof projectRoot !== 'string' || !projectRoot) return 0;
|
|
2009
|
+
const tomlPath = path.join(projectRoot, BMAD_DIR, 'config.toml');
|
|
2010
|
+
if (!fs.existsSync(tomlPath)) return 0;
|
|
2011
|
+
|
|
2012
|
+
let tomlRaw;
|
|
2013
|
+
try {
|
|
2014
|
+
tomlRaw = fs.readFileSync(tomlPath, 'utf-8');
|
|
2015
|
+
} catch {
|
|
2016
|
+
return 0;
|
|
2017
|
+
}
|
|
2018
|
+
|
|
2019
|
+
// Extract `[core] output_folder = "..."`. Only the value inside the [core]
|
|
2020
|
+
// section counts; module sections may carry their own output_folder-like keys.
|
|
2021
|
+
let outputFolder = null;
|
|
2022
|
+
let inCore = false;
|
|
2023
|
+
for (const line of tomlRaw.split(/\r?\n/)) {
|
|
2024
|
+
const section = line.match(/^\s*\[([^\]]+)\]\s*$/);
|
|
2025
|
+
if (section) {
|
|
2026
|
+
inCore = section[1].trim() === 'core';
|
|
2027
|
+
continue;
|
|
2028
|
+
}
|
|
2029
|
+
if (!inCore) continue;
|
|
2030
|
+
const kv = line.match(/^\s*output_folder\s*=\s*"([^"]*)"/);
|
|
2031
|
+
if (kv) {
|
|
2032
|
+
outputFolder = kv[1].trim();
|
|
2033
|
+
break;
|
|
2034
|
+
}
|
|
2035
|
+
}
|
|
2036
|
+
if (!outputFolder) return 0; // nothing canonical to normalize against
|
|
2037
|
+
|
|
2038
|
+
let total = 0;
|
|
2039
|
+
try {
|
|
2040
|
+
total += normalizeTomlOutputFolders(tomlPath, outputFolder);
|
|
2041
|
+
|
|
2042
|
+
// Walk each `_bmad/<mod>/config.yaml`.
|
|
2043
|
+
const bmadDir = path.join(projectRoot, BMAD_DIR);
|
|
2044
|
+
let entries = [];
|
|
2045
|
+
try {
|
|
2046
|
+
entries = fs.readdirSync(bmadDir, { withFileTypes: true });
|
|
2047
|
+
} catch {
|
|
2048
|
+
entries = [];
|
|
2049
|
+
}
|
|
2050
|
+
for (const entry of entries) {
|
|
2051
|
+
if (!entry.isDirectory()) continue;
|
|
2052
|
+
const cfg = path.join(bmadDir, entry.name, 'config.yaml');
|
|
2053
|
+
total += normalizeYamlOutputFolders(cfg, outputFolder);
|
|
2054
|
+
}
|
|
2055
|
+
} catch (err) {
|
|
2056
|
+
console.warn(chalk.yellow(` Warning: output-folder normalization skipped: ${err.message}`));
|
|
2057
|
+
return total;
|
|
2058
|
+
}
|
|
2059
|
+
|
|
2060
|
+
if (total > 0) {
|
|
2061
|
+
console.log(chalk.green(
|
|
2062
|
+
` Normalized ${total} module artifact path(s) to output folder "${outputFolder}/" (bug 27.14 work-around)`
|
|
2063
|
+
));
|
|
2064
|
+
}
|
|
2065
|
+
return total;
|
|
2066
|
+
}
|
|
2067
|
+
|
|
1811
2068
|
/**
|
|
1812
2069
|
* Migration shim: normalize the project layout so that canonical config lives
|
|
1813
2070
|
* at `_bmad/bmm/config.yaml` (v6.3.0) instead of `_bmad/_config/manifest.yaml`
|
|
@@ -2840,6 +3097,8 @@ module.exports = {
|
|
|
2840
3097
|
isGeneratedClineWrapper,
|
|
2841
3098
|
// Story 22.7 — canonical config (_bmad/bmm/config.yaml) helpers
|
|
2842
3099
|
readCanonicalBmadConfig,
|
|
3100
|
+
normalizeModuleOutputFolders,
|
|
3101
|
+
correctArtifactPath,
|
|
2843
3102
|
ensureCanonicalConfigLocation,
|
|
2844
3103
|
CANONICAL_CONFIG_REL,
|
|
2845
3104
|
LEGACY_MANIFEST_REL,
|