ma-agents 3.18.0 → 3.18.1-beta.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 +4 -2
- package/lib/bmad-cache/cache-manifest.json +3 -0
- package/lib/bmad-extension/.claude-plugin/marketplace.json.template +1 -0
- package/lib/bmad-extension/skills/add-sprint/SKILL.md +12 -0
- package/lib/bmad-extension/skills/add-to-sprint/SKILL.md +12 -0
- package/lib/bmad-extension/skills/bmad-dev-story/workflow.md +12 -0
- package/lib/bmad-extension/skills/bmad-sprint-planning/workflow.md +12 -0
- package/lib/bmad-extension/skills/bmad-sprint-status/workflow.md +12 -0
- package/lib/bmad-extension/skills/cleanup-done/SKILL.md +12 -0
- package/lib/bmad-extension/skills/close-sprint/SKILL.md +12 -0
- package/lib/bmad-extension/skills/generate-backlog/SKILL.md +12 -0
- package/lib/bmad-extension/skills/modify-sprint/SKILL.md +12 -0
- package/lib/bmad-extension/skills/module-help.csv +1 -0
- package/lib/bmad-extension/skills/module.yaml +1 -1
- package/lib/bmad-extension/skills/my-next-issue/.gitkeep +0 -0
- package/lib/bmad-extension/skills/my-next-issue/SKILL.md +195 -0
- package/lib/bmad-extension/skills/my-next-issue/bmad-skill-manifest.yaml +3 -0
- package/lib/bmad-extension/skills/prioritize-backlog/SKILL.md +12 -0
- package/lib/bmad-extension/skills/remove-from-sprint/SKILL.md +12 -0
- package/lib/bmad-extension/skills/sprint-status-view/SKILL.md +12 -0
- package/lib/bmad-extension/workflows/add-sprint/workflow.md +12 -0
- package/lib/bmad-extension/workflows/add-to-sprint/workflow.md +12 -0
- package/lib/bmad-extension/workflows/modify-sprint/workflow.md +12 -0
- package/lib/bmad-extension/workflows/sprint-status-view/workflow.md +12 -0
- package/lib/bmad-extension-plugin/.claude-plugin/marketplace.json +2 -1
- package/lib/bmad-extension-plugin/skills/add-sprint/SKILL.md +12 -0
- package/lib/bmad-extension-plugin/skills/add-to-sprint/SKILL.md +12 -0
- package/lib/bmad-extension-plugin/skills/bmad-dev-story/workflow.md +12 -0
- package/lib/bmad-extension-plugin/skills/bmad-sprint-planning/workflow.md +12 -0
- package/lib/bmad-extension-plugin/skills/bmad-sprint-status/workflow.md +12 -0
- package/lib/bmad-extension-plugin/skills/cleanup-done/SKILL.md +12 -0
- package/lib/bmad-extension-plugin/skills/close-sprint/SKILL.md +12 -0
- package/lib/bmad-extension-plugin/skills/generate-backlog/SKILL.md +12 -0
- package/lib/bmad-extension-plugin/skills/modify-sprint/SKILL.md +12 -0
- package/lib/bmad-extension-plugin/skills/module-help.csv +1 -0
- package/lib/bmad-extension-plugin/skills/module.yaml +1 -1
- package/lib/bmad-extension-plugin/skills/my-next-issue/.gitkeep +0 -0
- package/lib/bmad-extension-plugin/skills/my-next-issue/SKILL.md +195 -0
- package/lib/bmad-extension-plugin/skills/my-next-issue/bmad-skill-manifest.yaml +3 -0
- package/lib/bmad-extension-plugin/skills/prioritize-backlog/SKILL.md +12 -0
- package/lib/bmad-extension-plugin/skills/remove-from-sprint/SKILL.md +12 -0
- package/lib/bmad-extension-plugin/skills/sprint-status-view/SKILL.md +12 -0
- package/lib/bmad.js +125 -6
- package/lib/knowledge-atlas/dist/atlas.cjs +14651 -14651
- package/package.json +2 -2
- package/scripts/build-bmad-cache.js +17 -0
- package/skills/add-sprint/SKILL.md +12 -0
- package/skills/add-to-sprint/SKILL.md +12 -0
- package/skills/bmad-sprint-planning/SKILL.md +12 -0
- package/skills/bmad-sprint-status/SKILL.md +12 -0
- package/skills/cleanup-done/SKILL.md +12 -0
- package/skills/close-sprint/SKILL.md +12 -0
- package/skills/generate-backlog/SKILL.md +12 -0
- package/skills/modify-sprint/SKILL.md +12 -0
- package/skills/my-next-issue/SKILL.md +184 -0
- package/skills/my-next-issue/skill.json +7 -0
- package/skills/prioritize-backlog/SKILL.md +12 -0
- package/skills/remove-from-sprint/SKILL.md +12 -0
- package/skills/sprint-status-view/SKILL.md +12 -0
- package/skills/story-status-lookup/SKILL.md +12 -0
package/lib/bmad.js
CHANGED
|
@@ -626,6 +626,46 @@ function getInstallableBmadModules() {
|
|
|
626
626
|
return [bmmEntry, ...cacheEntries];
|
|
627
627
|
}
|
|
628
628
|
|
|
629
|
+
/**
|
|
630
|
+
* Return the upstream release tag each bundled external module is pinned to,
|
|
631
|
+
* read from the `pinTag` field of `lib/bmad-cache/cache-manifest.json`.
|
|
632
|
+
*
|
|
633
|
+
* Why this exists: `bmad-method` itself is pinned exactly (package.json), but
|
|
634
|
+
* left to its defaults it resolves every external module to that module's
|
|
635
|
+
* LATEST stable tag at install time. An upstream release cut after ma-agents
|
|
636
|
+
* shipped then lands on users' machines untested — TEA v2.0.x dropped
|
|
637
|
+
* `src/module.yaml`, which bmad-method 6.10.0 requires, and broke every
|
|
638
|
+
* install that selected tea. Pinning to the tag the bundled cache was built
|
|
639
|
+
* from makes an online install resolve to the same release an offline one
|
|
640
|
+
* does.
|
|
641
|
+
*
|
|
642
|
+
* Entries without a `pinTag` are omitted (and so float, as before);
|
|
643
|
+
* test/bundled-module-pins.test.js fails the build when a bundled module
|
|
644
|
+
* ships without one.
|
|
645
|
+
*
|
|
646
|
+
* @param {string} [manifestPath] - Override the manifest path (tests only)
|
|
647
|
+
* @returns {Object<string, string>} module id → release tag (e.g. `{ tea: 'v1.19.0' }`);
|
|
648
|
+
* empty when the manifest is missing or unreadable
|
|
649
|
+
*/
|
|
650
|
+
function getBundledModulePins(manifestPath = path.join(__dirname, 'bmad-cache', 'cache-manifest.json')) {
|
|
651
|
+
let manifest;
|
|
652
|
+
try {
|
|
653
|
+
manifest = JSON.parse(fs.readFileSync(manifestPath, 'utf-8'));
|
|
654
|
+
} catch {
|
|
655
|
+
return {};
|
|
656
|
+
}
|
|
657
|
+
const pins = {};
|
|
658
|
+
for (const [id, meta] of Object.entries(manifest.modules || {})) {
|
|
659
|
+
const tag = meta && typeof meta.pinTag === 'string' ? meta.pinTag.trim() : '';
|
|
660
|
+
// The tag is interpolated into a shell command (buildBmadArgs), so
|
|
661
|
+
// accept only plain git-tag characters.
|
|
662
|
+
if (/^[A-Za-z0-9][A-Za-z0-9._-]*$/.test(tag)) {
|
|
663
|
+
pins[id] = tag;
|
|
664
|
+
}
|
|
665
|
+
}
|
|
666
|
+
return pins;
|
|
667
|
+
}
|
|
668
|
+
|
|
629
669
|
/**
|
|
630
670
|
* Detect which BMad modules are already installed under a given project
|
|
631
671
|
* root by checking for `_bmad/<id>/` directories. Used by the install
|
|
@@ -830,6 +870,10 @@ function resolveCustomContentFlag() {
|
|
|
830
870
|
* `--custom-source <path>`; when omitted no extension flag is added.
|
|
831
871
|
* The legacy fallback to `lib/bmad-extension/` was removed when the
|
|
832
872
|
* stage-and-invoke flow replaced applyCustomizations().
|
|
873
|
+
* @param {Object<string, string>} [ctx.pins] - module id → release tag to pass
|
|
874
|
+
* as `--pin <id>=<tag>`. Defaults to getBundledModulePins(). Only modules in
|
|
875
|
+
* `ctx.modules` are pinned (bmad-method warns on a pin for an unselected
|
|
876
|
+
* module).
|
|
833
877
|
* @returns {string} Complete command string ready for execSync
|
|
834
878
|
*/
|
|
835
879
|
function buildBmadArgs(ctx) {
|
|
@@ -868,6 +912,16 @@ function buildBmadArgs(ctx) {
|
|
|
868
912
|
parts.push(flag, `"${ctx.customSource}"`);
|
|
869
913
|
}
|
|
870
914
|
|
|
915
|
+
// Pin each selected external module to the release the bundled cache was
|
|
916
|
+
// built from, so upstream releases cut after this ma-agents version can't
|
|
917
|
+
// reach the install (see getBundledModulePins).
|
|
918
|
+
const pins = ctx.pins || getBundledModulePins();
|
|
919
|
+
for (const mod of ctx.modules) {
|
|
920
|
+
if (pins[mod]) {
|
|
921
|
+
parts.push('--pin', `${mod}=${pins[mod]}`);
|
|
922
|
+
}
|
|
923
|
+
}
|
|
924
|
+
|
|
871
925
|
if (ctx.action === 'update') {
|
|
872
926
|
parts.push('--action', 'update');
|
|
873
927
|
}
|
|
@@ -2118,12 +2172,20 @@ async function installCustomMarketplaceSubset({ projectRoot, modules, tools, sel
|
|
|
2118
2172
|
* `stable` because that's bmad-method's own default when a registry
|
|
2119
2173
|
* entry has no `default_channel` field.
|
|
2120
2174
|
*
|
|
2175
|
+
* When the manifest entry carries a `pinTag`, the marker is written on the
|
|
2176
|
+
* `pinned` channel at that tag instead, matching the `--pin` buildBmadArgs
|
|
2177
|
+
* passes. bmad-method compares the marker's channel to the requested one and
|
|
2178
|
+
* wipes + re-clones the cache on a mismatch, which an air-gapped host cannot
|
|
2179
|
+
* survive. A local tag ref is also created so bmad-method's
|
|
2180
|
+
* `git fetch origin tag <pinTag>` (origin = the cache itself, see
|
|
2181
|
+
* restoreGitDir) resolves without the network.
|
|
2182
|
+
*
|
|
2121
2183
|
* Best-effort: failures are swallowed. The next install attempt (online or
|
|
2122
2184
|
* offline-with-marker) will write a fresh one.
|
|
2123
2185
|
*
|
|
2124
2186
|
* @param {string} moduleDir - Cache dir for the module
|
|
2125
2187
|
* (e.g. `~/.bmad/cache/external-modules/tea`)
|
|
2126
|
-
* @param {{ branch?: string, commitSha?: string }} [manifestEntry] - Entry
|
|
2188
|
+
* @param {{ branch?: string, commitSha?: string, pinTag?: string }} [manifestEntry] - Entry
|
|
2127
2189
|
* from `lib/bmad-cache/cache-manifest.json` for this module
|
|
2128
2190
|
* @returns {Promise<boolean>} `true` if the marker was written, `false` if
|
|
2129
2191
|
* it already existed or the manifest entry is missing required fields
|
|
@@ -2132,13 +2194,15 @@ async function ensureCacheMarker(moduleDir, manifestEntry) {
|
|
|
2132
2194
|
const markerPath = path.join(moduleDir, '.bmad-channel.json');
|
|
2133
2195
|
if (await fs.pathExists(markerPath)) return false;
|
|
2134
2196
|
if (!manifestEntry || !manifestEntry.commitSha) return false;
|
|
2197
|
+
const pinTag = manifestEntry.pinTag;
|
|
2135
2198
|
try {
|
|
2199
|
+
if (pinTag) ensureLocalTag(moduleDir, pinTag);
|
|
2136
2200
|
await fs.writeFile(
|
|
2137
2201
|
markerPath,
|
|
2138
2202
|
JSON.stringify(
|
|
2139
2203
|
{
|
|
2140
|
-
channel: 'stable',
|
|
2141
|
-
version: manifestEntry.branch || 'main',
|
|
2204
|
+
channel: pinTag ? 'pinned' : 'stable',
|
|
2205
|
+
version: pinTag || manifestEntry.branch || 'main',
|
|
2142
2206
|
sha: manifestEntry.commitSha,
|
|
2143
2207
|
writtenAt: new Date().toISOString(),
|
|
2144
2208
|
},
|
|
@@ -2154,6 +2218,53 @@ async function ensureCacheMarker(moduleDir, manifestEntry) {
|
|
|
2154
2218
|
}
|
|
2155
2219
|
}
|
|
2156
2220
|
|
|
2221
|
+
/**
|
|
2222
|
+
* Create tag `tag` at HEAD in a cached module's git repo unless it already
|
|
2223
|
+
* exists. The bundled cache is a shallow clone of the commit the pin tag
|
|
2224
|
+
* names (or a metadata-only commit past it), and the clone only carries the
|
|
2225
|
+
* tag when it pointed at HEAD exactly.
|
|
2226
|
+
*
|
|
2227
|
+
* Best-effort: no `.git/` or no `git` binary is a silent no-op — bmad-method
|
|
2228
|
+
* then falls back to cloning the tag from upstream.
|
|
2229
|
+
*
|
|
2230
|
+
* @param {string} moduleDir - Cached module directory
|
|
2231
|
+
* @param {string} tag - Release tag (e.g. `v2.1.0`)
|
|
2232
|
+
*/
|
|
2233
|
+
function ensureLocalTag(moduleDir, tag) {
|
|
2234
|
+
if (!fs.existsSync(path.join(moduleDir, '.git'))) return;
|
|
2235
|
+
try {
|
|
2236
|
+
execFileSync('git', ['rev-parse', '--quiet', '--verify', `refs/tags/${tag}`], { cwd: moduleDir, stdio: 'pipe' });
|
|
2237
|
+
} catch {
|
|
2238
|
+
try {
|
|
2239
|
+
execFileSync('git', ['tag', tag, 'HEAD'], { cwd: moduleDir, stdio: 'pipe' });
|
|
2240
|
+
} catch {
|
|
2241
|
+
// Non-fatal — see above.
|
|
2242
|
+
}
|
|
2243
|
+
}
|
|
2244
|
+
}
|
|
2245
|
+
|
|
2246
|
+
/**
|
|
2247
|
+
* True when a cached module's `.bmad-channel.json` records a resolution other
|
|
2248
|
+
* than the pin the manifest asks for — e.g. a cache bmad-method cloned at a
|
|
2249
|
+
* newer upstream release before pinning existed. Such a cache must be
|
|
2250
|
+
* replaced from the bundle: left alone, bmad-method would wipe it to switch
|
|
2251
|
+
* channels and need the network to re-clone.
|
|
2252
|
+
*
|
|
2253
|
+
* @param {string} moduleDir - Cached module directory
|
|
2254
|
+
* @param {{ pinTag?: string }} [manifestEntry] - Manifest entry for the module
|
|
2255
|
+
* @returns {Promise<boolean>} `false` when the entry has no pinTag
|
|
2256
|
+
*/
|
|
2257
|
+
async function cacheDiffersFromPin(moduleDir, manifestEntry) {
|
|
2258
|
+
if (!manifestEntry || !manifestEntry.pinTag) return false;
|
|
2259
|
+
try {
|
|
2260
|
+
const marker = JSON.parse(await fs.readFile(path.join(moduleDir, '.bmad-channel.json'), 'utf8'));
|
|
2261
|
+
return marker.channel !== 'pinned' || marker.version !== manifestEntry.pinTag;
|
|
2262
|
+
} catch {
|
|
2263
|
+
// No marker or unreadable — we can't tell what this cache holds.
|
|
2264
|
+
return true;
|
|
2265
|
+
}
|
|
2266
|
+
}
|
|
2267
|
+
|
|
2157
2268
|
async function prePopulateBmadCache(force = false) {
|
|
2158
2269
|
const cacheSource = path.join(__dirname, 'bmad-cache');
|
|
2159
2270
|
if (!(await fs.pathExists(cacheSource))) {
|
|
@@ -2195,12 +2306,17 @@ async function prePopulateBmadCache(force = false) {
|
|
|
2195
2306
|
&& (await fs.pathExists(path.join(src, 'skills')))
|
|
2196
2307
|
&& !(await fs.pathExists(path.join(dst, 'skills')));
|
|
2197
2308
|
|
|
2309
|
+
const manifestEntry = manifest && manifest.modules ? manifest.modules[mod] : null;
|
|
2310
|
+
const offPin = (await fs.pathExists(dst)) && (await cacheDiffersFromPin(dst, manifestEntry));
|
|
2311
|
+
|
|
2198
2312
|
if (await fs.pathExists(dst)) {
|
|
2199
|
-
if (force || structurallyBroken) {
|
|
2313
|
+
if (force || structurallyBroken || offPin) {
|
|
2200
2314
|
await fs.remove(dst);
|
|
2201
2315
|
await fs.copy(src, dst);
|
|
2202
2316
|
restoreGitDir(dst);
|
|
2203
|
-
const reason = structurallyBroken
|
|
2317
|
+
const reason = structurallyBroken
|
|
2318
|
+
? '(structural repair)'
|
|
2319
|
+
: offPin ? `(not at pinned ${manifestEntry.pinTag})` : '';
|
|
2204
2320
|
console.log(chalk.cyan(` + Replaced cached module: ${mod} ${reason}`));
|
|
2205
2321
|
replaced++;
|
|
2206
2322
|
} else {
|
|
@@ -2218,7 +2334,7 @@ async function prePopulateBmadCache(force = false) {
|
|
|
2218
2334
|
// skip path, since prior ma-agents versions copied the module
|
|
2219
2335
|
// without the marker and left users wedged on offline installs.
|
|
2220
2336
|
// ensureCacheMarker no-ops when the marker already exists.
|
|
2221
|
-
const wrote = await ensureCacheMarker(dst,
|
|
2337
|
+
const wrote = await ensureCacheMarker(dst, manifestEntry);
|
|
2222
2338
|
if (wrote) markersWritten++;
|
|
2223
2339
|
}
|
|
2224
2340
|
|
|
@@ -3747,4 +3863,7 @@ module.exports = {
|
|
|
3747
3863
|
getDefaultBmadModules,
|
|
3748
3864
|
// 3.12.2 — offline-fallback marker for bmad-method's cloneExternalModule
|
|
3749
3865
|
ensureCacheMarker,
|
|
3866
|
+
// Bug: external modules pinned to the bundled release (--pin)
|
|
3867
|
+
getBundledModulePins,
|
|
3868
|
+
cacheDiffersFromPin,
|
|
3750
3869
|
};
|