ma-agents 3.16.0 → 3.17.0-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/README.md +85 -4
- package/bin/cli.js +323 -6
- package/lib/agents.js +22 -15
- package/lib/bmad-cache/cache-manifest.json +2 -2
- package/lib/bmad-extension/.claude-plugin/marketplace.json.template +2 -15
- package/lib/bmad-extension/skills/module-help.csv +0 -13
- package/lib/bmad-extension-plugin/.claude-plugin/marketplace.json +3 -16
- package/lib/bmad-extension-plugin/skills/module-help.csv +0 -13
- package/lib/bmad.js +116 -1
- package/lib/custom-marketplace.js +507 -0
- package/lib/installer.js +19 -7
- package/lib/knowledge-atlas/dist/atlas.cjs +14651 -14651
- package/lib/knowledge-atlas/src/render/vendor.ts +43 -43
- package/lib/knowledge-atlas/vendor/drawio-viewer.min.js +7563 -7563
- package/lib/knowledge-atlas/vendor/mermaid.min.js +2314 -2314
- package/lib/profile.js +201 -0
- package/lib/skill-authoring.js +3 -1
- package/package.json +3 -3
- package/scripts/build-bmad-cache.js +127 -43
- package/lib/bmad-extension/skills/ma-agent-ml/.gitkeep +0 -0
- package/lib/bmad-extension/skills/ma-agent-ml/SKILL.md +0 -59
- package/lib/bmad-extension/skills/ma-agent-ml/bmad-skill-manifest.yaml +0 -11
- package/lib/bmad-extension/skills/ml-advise/.gitkeep +0 -0
- package/lib/bmad-extension/skills/ml-advise/SKILL.md +0 -76
- package/lib/bmad-extension/skills/ml-advise/bmad-skill-manifest.yaml +0 -3
- package/lib/bmad-extension/skills/ml-advise/skill.json +0 -7
- package/lib/bmad-extension/skills/ml-analysis/.gitkeep +0 -0
- package/lib/bmad-extension/skills/ml-analysis/SKILL.md +0 -60
- package/lib/bmad-extension/skills/ml-analysis/bmad-skill-manifest.yaml +0 -3
- package/lib/bmad-extension/skills/ml-analysis/skill.json +0 -7
- package/lib/bmad-extension/skills/ml-architecture/.gitkeep +0 -0
- package/lib/bmad-extension/skills/ml-architecture/SKILL.md +0 -55
- package/lib/bmad-extension/skills/ml-architecture/bmad-skill-manifest.yaml +0 -3
- package/lib/bmad-extension/skills/ml-architecture/skill.json +0 -7
- package/lib/bmad-extension/skills/ml-detailed-design/.gitkeep +0 -0
- package/lib/bmad-extension/skills/ml-detailed-design/SKILL.md +0 -67
- package/lib/bmad-extension/skills/ml-detailed-design/bmad-skill-manifest.yaml +0 -3
- package/lib/bmad-extension/skills/ml-detailed-design/skill.json +0 -7
- package/lib/bmad-extension/skills/ml-eda/.gitkeep +0 -0
- package/lib/bmad-extension/skills/ml-eda/SKILL.md +0 -56
- package/lib/bmad-extension/skills/ml-eda/bmad-skill-manifest.yaml +0 -3
- package/lib/bmad-extension/skills/ml-eda/scripts/baseline_classifier.py +0 -522
- package/lib/bmad-extension/skills/ml-eda/scripts/class_weights_calculator.py +0 -295
- package/lib/bmad-extension/skills/ml-eda/scripts/clustering_explorer.py +0 -383
- package/lib/bmad-extension/skills/ml-eda/scripts/eda_analyzer.py +0 -654
- package/lib/bmad-extension/skills/ml-eda/skill.json +0 -7
- package/lib/bmad-extension/skills/ml-experiment/.gitkeep +0 -0
- package/lib/bmad-extension/skills/ml-experiment/SKILL.md +0 -74
- package/lib/bmad-extension/skills/ml-experiment/assets/advanced_trainer_configs.py +0 -430
- package/lib/bmad-extension/skills/ml-experiment/assets/quick_trainer_setup.py +0 -233
- package/lib/bmad-extension/skills/ml-experiment/assets/template_datamodule.py +0 -219
- package/lib/bmad-extension/skills/ml-experiment/assets/template_gnn_module.py +0 -341
- package/lib/bmad-extension/skills/ml-experiment/assets/template_lightning_module.py +0 -158
- package/lib/bmad-extension/skills/ml-experiment/bmad-skill-manifest.yaml +0 -3
- package/lib/bmad-extension/skills/ml-experiment/skill.json +0 -7
- package/lib/bmad-extension/skills/ml-hparam/.gitkeep +0 -0
- package/lib/bmad-extension/skills/ml-hparam/SKILL.md +0 -81
- package/lib/bmad-extension/skills/ml-hparam/bmad-skill-manifest.yaml +0 -3
- package/lib/bmad-extension/skills/ml-hparam/skill.json +0 -7
- package/lib/bmad-extension/skills/ml-ideation/.gitkeep +0 -0
- package/lib/bmad-extension/skills/ml-ideation/SKILL.md +0 -50
- package/lib/bmad-extension/skills/ml-ideation/bmad-skill-manifest.yaml +0 -3
- package/lib/bmad-extension/skills/ml-ideation/scripts/validate_ml_prd.py +0 -287
- package/lib/bmad-extension/skills/ml-ideation/skill.json +0 -7
- package/lib/bmad-extension/skills/ml-infra/.gitkeep +0 -0
- package/lib/bmad-extension/skills/ml-infra/SKILL.md +0 -58
- package/lib/bmad-extension/skills/ml-infra/bmad-skill-manifest.yaml +0 -3
- package/lib/bmad-extension/skills/ml-infra/skill.json +0 -7
- package/lib/bmad-extension/skills/ml-retrospective/.gitkeep +0 -0
- package/lib/bmad-extension/skills/ml-retrospective/SKILL.md +0 -63
- package/lib/bmad-extension/skills/ml-retrospective/bmad-skill-manifest.yaml +0 -3
- package/lib/bmad-extension/skills/ml-retrospective/skill.json +0 -7
- package/lib/bmad-extension/skills/ml-revision/.gitkeep +0 -0
- package/lib/bmad-extension/skills/ml-revision/SKILL.md +0 -82
- package/lib/bmad-extension/skills/ml-revision/bmad-skill-manifest.yaml +0 -3
- package/lib/bmad-extension/skills/ml-revision/skill.json +0 -7
- package/lib/bmad-extension/skills/ml-techspec/.gitkeep +0 -0
- package/lib/bmad-extension/skills/ml-techspec/SKILL.md +0 -80
- package/lib/bmad-extension/skills/ml-techspec/bmad-skill-manifest.yaml +0 -3
- package/lib/bmad-extension/skills/ml-techspec/skill.json +0 -7
- package/lib/bmad-extension-plugin/skills/ma-agent-ml/.gitkeep +0 -0
- package/lib/bmad-extension-plugin/skills/ma-agent-ml/SKILL.md +0 -59
- package/lib/bmad-extension-plugin/skills/ma-agent-ml/bmad-skill-manifest.yaml +0 -11
- package/lib/bmad-extension-plugin/skills/ml-advise/.gitkeep +0 -0
- package/lib/bmad-extension-plugin/skills/ml-advise/SKILL.md +0 -76
- package/lib/bmad-extension-plugin/skills/ml-advise/bmad-skill-manifest.yaml +0 -3
- package/lib/bmad-extension-plugin/skills/ml-advise/skill.json +0 -7
- package/lib/bmad-extension-plugin/skills/ml-analysis/.gitkeep +0 -0
- package/lib/bmad-extension-plugin/skills/ml-analysis/SKILL.md +0 -60
- package/lib/bmad-extension-plugin/skills/ml-analysis/bmad-skill-manifest.yaml +0 -3
- package/lib/bmad-extension-plugin/skills/ml-analysis/skill.json +0 -7
- package/lib/bmad-extension-plugin/skills/ml-architecture/.gitkeep +0 -0
- package/lib/bmad-extension-plugin/skills/ml-architecture/SKILL.md +0 -55
- package/lib/bmad-extension-plugin/skills/ml-architecture/bmad-skill-manifest.yaml +0 -3
- package/lib/bmad-extension-plugin/skills/ml-architecture/skill.json +0 -7
- package/lib/bmad-extension-plugin/skills/ml-detailed-design/.gitkeep +0 -0
- package/lib/bmad-extension-plugin/skills/ml-detailed-design/SKILL.md +0 -67
- package/lib/bmad-extension-plugin/skills/ml-detailed-design/bmad-skill-manifest.yaml +0 -3
- package/lib/bmad-extension-plugin/skills/ml-detailed-design/skill.json +0 -7
- package/lib/bmad-extension-plugin/skills/ml-eda/.gitkeep +0 -0
- package/lib/bmad-extension-plugin/skills/ml-eda/SKILL.md +0 -56
- package/lib/bmad-extension-plugin/skills/ml-eda/bmad-skill-manifest.yaml +0 -3
- package/lib/bmad-extension-plugin/skills/ml-eda/scripts/baseline_classifier.py +0 -522
- package/lib/bmad-extension-plugin/skills/ml-eda/scripts/class_weights_calculator.py +0 -295
- package/lib/bmad-extension-plugin/skills/ml-eda/scripts/clustering_explorer.py +0 -383
- package/lib/bmad-extension-plugin/skills/ml-eda/scripts/eda_analyzer.py +0 -654
- package/lib/bmad-extension-plugin/skills/ml-eda/skill.json +0 -7
- package/lib/bmad-extension-plugin/skills/ml-experiment/.gitkeep +0 -0
- package/lib/bmad-extension-plugin/skills/ml-experiment/SKILL.md +0 -74
- package/lib/bmad-extension-plugin/skills/ml-experiment/assets/advanced_trainer_configs.py +0 -430
- package/lib/bmad-extension-plugin/skills/ml-experiment/assets/quick_trainer_setup.py +0 -233
- package/lib/bmad-extension-plugin/skills/ml-experiment/assets/template_datamodule.py +0 -219
- package/lib/bmad-extension-plugin/skills/ml-experiment/assets/template_gnn_module.py +0 -341
- package/lib/bmad-extension-plugin/skills/ml-experiment/assets/template_lightning_module.py +0 -158
- package/lib/bmad-extension-plugin/skills/ml-experiment/bmad-skill-manifest.yaml +0 -3
- package/lib/bmad-extension-plugin/skills/ml-experiment/skill.json +0 -7
- package/lib/bmad-extension-plugin/skills/ml-hparam/.gitkeep +0 -0
- package/lib/bmad-extension-plugin/skills/ml-hparam/SKILL.md +0 -81
- package/lib/bmad-extension-plugin/skills/ml-hparam/bmad-skill-manifest.yaml +0 -3
- package/lib/bmad-extension-plugin/skills/ml-hparam/skill.json +0 -7
- package/lib/bmad-extension-plugin/skills/ml-ideation/.gitkeep +0 -0
- package/lib/bmad-extension-plugin/skills/ml-ideation/SKILL.md +0 -50
- package/lib/bmad-extension-plugin/skills/ml-ideation/bmad-skill-manifest.yaml +0 -3
- package/lib/bmad-extension-plugin/skills/ml-ideation/scripts/validate_ml_prd.py +0 -287
- package/lib/bmad-extension-plugin/skills/ml-ideation/skill.json +0 -7
- package/lib/bmad-extension-plugin/skills/ml-infra/.gitkeep +0 -0
- package/lib/bmad-extension-plugin/skills/ml-infra/SKILL.md +0 -58
- package/lib/bmad-extension-plugin/skills/ml-infra/bmad-skill-manifest.yaml +0 -3
- package/lib/bmad-extension-plugin/skills/ml-infra/skill.json +0 -7
- package/lib/bmad-extension-plugin/skills/ml-retrospective/.gitkeep +0 -0
- package/lib/bmad-extension-plugin/skills/ml-retrospective/SKILL.md +0 -63
- package/lib/bmad-extension-plugin/skills/ml-retrospective/bmad-skill-manifest.yaml +0 -3
- package/lib/bmad-extension-plugin/skills/ml-retrospective/skill.json +0 -7
- package/lib/bmad-extension-plugin/skills/ml-revision/.gitkeep +0 -0
- package/lib/bmad-extension-plugin/skills/ml-revision/SKILL.md +0 -82
- package/lib/bmad-extension-plugin/skills/ml-revision/bmad-skill-manifest.yaml +0 -3
- package/lib/bmad-extension-plugin/skills/ml-revision/skill.json +0 -7
- package/lib/bmad-extension-plugin/skills/ml-techspec/.gitkeep +0 -0
- package/lib/bmad-extension-plugin/skills/ml-techspec/SKILL.md +0 -80
- package/lib/bmad-extension-plugin/skills/ml-techspec/bmad-skill-manifest.yaml +0 -3
- package/lib/bmad-extension-plugin/skills/ml-techspec/skill.json +0 -7
package/lib/profile.js
CHANGED
|
@@ -19,6 +19,7 @@
|
|
|
19
19
|
|
|
20
20
|
const fs = require('fs');
|
|
21
21
|
const path = require('path');
|
|
22
|
+
const chalk = require('chalk');
|
|
22
23
|
|
|
23
24
|
const MANIFEST_FILE = '.ma-agents.json';
|
|
24
25
|
const VALID_PROFILES = ['on-prem', 'standard'];
|
|
@@ -211,6 +212,201 @@ function setBmadModules(projectRoot, modules) {
|
|
|
211
212
|
fs.writeFileSync(manifestPath, JSON.stringify(manifest, null, 2) + '\n', 'utf-8');
|
|
212
213
|
}
|
|
213
214
|
|
|
215
|
+
/**
|
|
216
|
+
* Story 30.4 (FR245/FR246, NFR49) — generic one-time notice tracking.
|
|
217
|
+
*
|
|
218
|
+
* Notices are keyed by an arbitrary string id and persisted under a `notices`
|
|
219
|
+
* object in the project-root `.ma-agents.json` (`{ notices: { <id>: true } }`).
|
|
220
|
+
* This mirrors the `profile`/`bmadModules` field-ownership pattern above:
|
|
221
|
+
* read/write is scoped to this module, bootstrap-on-absence uses the same
|
|
222
|
+
* profile-only `bootstrapRootManifest()` shape, and no other field is
|
|
223
|
+
* disturbed. A notice is meant to be shown to the user exactly once, ever,
|
|
224
|
+
* regardless of how many times install/update subsequently runs.
|
|
225
|
+
*/
|
|
226
|
+
|
|
227
|
+
/**
|
|
228
|
+
* Returns true if the given notice id has already been recorded as shown.
|
|
229
|
+
* Missing/malformed manifest, or a manifest with no matching entry, both
|
|
230
|
+
* return false (never shown) — mirrors getProfile's non-throwing contract.
|
|
231
|
+
*/
|
|
232
|
+
function hasShownNotice(projectRoot, noticeId) {
|
|
233
|
+
const manifestPath = path.join(projectRoot, MANIFEST_FILE);
|
|
234
|
+
if (!fs.existsSync(manifestPath)) return false;
|
|
235
|
+
let manifest;
|
|
236
|
+
try {
|
|
237
|
+
manifest = JSON.parse(fs.readFileSync(manifestPath, 'utf-8'));
|
|
238
|
+
} catch {
|
|
239
|
+
return false;
|
|
240
|
+
}
|
|
241
|
+
if (!manifest || typeof manifest !== 'object') return false;
|
|
242
|
+
return !!(manifest.notices && manifest.notices[noticeId] === true);
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
/**
|
|
246
|
+
* Persists that the given notice id has been shown, preserving all other
|
|
247
|
+
* `.ma-agents.json` fields (profile, bmadModules, profileHistory, ...).
|
|
248
|
+
* Bootstraps a profile-only root manifest if none exists yet (mirrors
|
|
249
|
+
* setProfile/setBmadModules).
|
|
250
|
+
*/
|
|
251
|
+
function markNoticeShown(projectRoot, noticeId) {
|
|
252
|
+
const manifestPath = path.join(projectRoot, MANIFEST_FILE);
|
|
253
|
+
let manifest;
|
|
254
|
+
if (fs.existsSync(manifestPath)) {
|
|
255
|
+
try {
|
|
256
|
+
manifest = JSON.parse(fs.readFileSync(manifestPath, 'utf-8'));
|
|
257
|
+
} catch {
|
|
258
|
+
manifest = null;
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
if (!manifest || typeof manifest !== 'object') {
|
|
262
|
+
manifest = bootstrapRootManifest();
|
|
263
|
+
}
|
|
264
|
+
// Guard: `typeof null === 'object'` is already caught by `!manifest.notices`,
|
|
265
|
+
// but `typeof [] === 'object'` is NOT — a foreign tool that wrote
|
|
266
|
+
// `notices: []` would otherwise keep an array here, and a named property set
|
|
267
|
+
// on an array is dropped by JSON.stringify, silently defeating the
|
|
268
|
+
// show-once guarantee. Reject any non-plain-object shape.
|
|
269
|
+
if (!manifest.notices || typeof manifest.notices !== 'object' || Array.isArray(manifest.notices)) {
|
|
270
|
+
manifest.notices = {};
|
|
271
|
+
}
|
|
272
|
+
manifest.notices[noticeId] = true;
|
|
273
|
+
fs.writeFileSync(manifestPath, JSON.stringify(manifest, null, 2) + '\n', 'utf-8');
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
/**
|
|
277
|
+
* Story 30.7 (FR242) — persisted custom-marketplace source + selection.
|
|
278
|
+
*
|
|
279
|
+
* Stored under the `customMarketplace` key (a single object, NOT nested under
|
|
280
|
+
* `bmadModules`/`profile`) so a future multi-source design can introduce a
|
|
281
|
+
* sibling array field (e.g. `customMarketplaceSources`) without a breaking
|
|
282
|
+
* migration of this one. v1 supports exactly ONE marketplace source, per
|
|
283
|
+
* FR242 / architecture Decision P5-8.
|
|
284
|
+
*
|
|
285
|
+
* Shape:
|
|
286
|
+
* {
|
|
287
|
+
* source: string, // original user input (local path or Git URL)
|
|
288
|
+
* sourceUrl: string|null, // resolved clone URL (Git sources) or null (local)
|
|
289
|
+
* mode: 'discovery'|'direct',
|
|
290
|
+
* selectedCodes: string[],
|
|
291
|
+
* sha: string|null, // resolved commit SHA pin (Git-URL sources only)
|
|
292
|
+
* updatedAt: string, // ISO timestamp of the last persist
|
|
293
|
+
* }
|
|
294
|
+
*/
|
|
295
|
+
|
|
296
|
+
/**
|
|
297
|
+
* Reads the persisted custom-marketplace selection from `.ma-agents.json`.
|
|
298
|
+
* Returns undefined if the file is absent/malformed or the `customMarketplace`
|
|
299
|
+
* field is missing/malformed — mirrors getBmadModules' non-throwing contract.
|
|
300
|
+
*/
|
|
301
|
+
function getCustomMarketplaceSelection(projectRoot) {
|
|
302
|
+
const manifestPath = path.join(projectRoot, MANIFEST_FILE);
|
|
303
|
+
if (!fs.existsSync(manifestPath)) return undefined;
|
|
304
|
+
let manifest;
|
|
305
|
+
try {
|
|
306
|
+
manifest = JSON.parse(fs.readFileSync(manifestPath, 'utf-8'));
|
|
307
|
+
} catch {
|
|
308
|
+
return undefined;
|
|
309
|
+
}
|
|
310
|
+
if (!manifest || typeof manifest !== 'object') return undefined;
|
|
311
|
+
const entry = manifest.customMarketplace;
|
|
312
|
+
if (!entry || typeof entry !== 'object' || Array.isArray(entry)) return undefined;
|
|
313
|
+
if (typeof entry.source !== 'string' || !entry.source) return undefined;
|
|
314
|
+
if (!Array.isArray(entry.selectedCodes)) return undefined;
|
|
315
|
+
return entry;
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
/**
|
|
319
|
+
* Persists the custom-marketplace source + selection into `.ma-agents.json`,
|
|
320
|
+
* preserving all other fields (profile, bmadModules, notices, ...). Creates
|
|
321
|
+
* the file via the standard profile-only bootstrap path if absent (mirrors
|
|
322
|
+
* setProfile/setBmadModules). Stamps `updatedAt` with the current time.
|
|
323
|
+
*
|
|
324
|
+
* @param {string} projectRoot
|
|
325
|
+
* @param {Object} entry
|
|
326
|
+
* @param {string} entry.source - Original source string (local path or Git URL).
|
|
327
|
+
* @param {string|null} [entry.sourceUrl] - Resolved clone URL (Git sources) or null.
|
|
328
|
+
* @param {'discovery'|'direct'} entry.mode
|
|
329
|
+
* @param {string[]} entry.selectedCodes
|
|
330
|
+
* @param {string|null} [entry.sha] - Commit SHA of the LAST-INSTALLED marketplace
|
|
331
|
+
* state (Git-URL sources only; null for local paths). This is INFORMATIONAL —
|
|
332
|
+
* it records what was installed, not a lock. Per FR242/NFR72, `update`
|
|
333
|
+
* deliberately re-enumerates the source ref and floats to remote HEAD to offer
|
|
334
|
+
* newly-published extensions; it does NOT check out this SHA. reconcile surfaces
|
|
335
|
+
* this last-installed SHA and the float-to-HEAD behavior (see
|
|
336
|
+
* reconcileCustomMarketplaceOnUpdate) but never pins/reverts to it.
|
|
337
|
+
*/
|
|
338
|
+
function setCustomMarketplaceSelection(projectRoot, entry) {
|
|
339
|
+
if (!entry || typeof entry !== 'object') {
|
|
340
|
+
throw new Error('setCustomMarketplaceSelection expects an entry object');
|
|
341
|
+
}
|
|
342
|
+
if (typeof entry.source !== 'string' || !entry.source) {
|
|
343
|
+
throw new Error('setCustomMarketplaceSelection requires a non-empty "source" string');
|
|
344
|
+
}
|
|
345
|
+
if (entry.mode !== 'discovery' && entry.mode !== 'direct') {
|
|
346
|
+
throw new Error(`setCustomMarketplaceSelection requires mode 'discovery' or 'direct' (got ${JSON.stringify(entry.mode)})`);
|
|
347
|
+
}
|
|
348
|
+
if (!Array.isArray(entry.selectedCodes)) {
|
|
349
|
+
throw new Error('setCustomMarketplaceSelection requires "selectedCodes" to be an array');
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
const manifestPath = path.join(projectRoot, MANIFEST_FILE);
|
|
353
|
+
let manifest;
|
|
354
|
+
if (fs.existsSync(manifestPath)) {
|
|
355
|
+
try {
|
|
356
|
+
manifest = JSON.parse(fs.readFileSync(manifestPath, 'utf-8'));
|
|
357
|
+
} catch {
|
|
358
|
+
manifest = null;
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
if (!manifest || typeof manifest !== 'object') {
|
|
362
|
+
manifest = bootstrapRootManifest();
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
manifest.customMarketplace = {
|
|
366
|
+
source: entry.source,
|
|
367
|
+
sourceUrl: entry.sourceUrl ?? null,
|
|
368
|
+
mode: entry.mode,
|
|
369
|
+
selectedCodes: [...new Set(entry.selectedCodes.filter(c => typeof c === 'string' && c.length > 0))],
|
|
370
|
+
sha: entry.sha ?? null,
|
|
371
|
+
updatedAt: new Date().toISOString(),
|
|
372
|
+
};
|
|
373
|
+
fs.writeFileSync(manifestPath, JSON.stringify(manifest, null, 2) + '\n', 'utf-8');
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
const DEMERZEL_DEPRECATION_NOTICE_ID = 'demerzel-deprecation';
|
|
377
|
+
|
|
378
|
+
/**
|
|
379
|
+
* FR245/FR246 — idempotent one-time deprecation notice for the Demerzel
|
|
380
|
+
* (ML Scientist) agent. Prints an informational message the first time it is
|
|
381
|
+
* called for a given project root, then persists a `shown` flag so every
|
|
382
|
+
* subsequent call (any future install/update run) is a silent no-op.
|
|
383
|
+
*
|
|
384
|
+
* Deliberately does NOT touch any already-installed `ma-agent-ml`/`ml-*`
|
|
385
|
+
* content — that is the job of `migrateRetiredSkills()` for genuinely
|
|
386
|
+
* retired/renamed skills, and `ma-agent-ml`/`ml-*` are intentionally excluded
|
|
387
|
+
* from that sweep (NFR49 — existing installs are non-destructively preserved).
|
|
388
|
+
* Names no replacement target (FR246 — no in-tool migration).
|
|
389
|
+
*
|
|
390
|
+
* @param {string} projectRoot
|
|
391
|
+
* @returns {boolean} true if the notice was printed on this call, false if
|
|
392
|
+
* it had already been shown previously (no-op).
|
|
393
|
+
*/
|
|
394
|
+
function showDemerzelDeprecationNoticeOnce(projectRoot) {
|
|
395
|
+
if (hasShownNotice(projectRoot, DEMERZEL_DEPRECATION_NOTICE_ID)) {
|
|
396
|
+
return false;
|
|
397
|
+
}
|
|
398
|
+
console.log(chalk.yellow(
|
|
399
|
+
'\n Notice: the Demerzel (ML Scientist) agent - ma-agent-ml plus the 12 ml-*\n' +
|
|
400
|
+
' workflow skills - is deprecated and is no longer installed by default for\n' +
|
|
401
|
+
' new projects (FR244-FR247). Already-installed content on this or any other\n' +
|
|
402
|
+
' project is left untouched; no action is required. Teams that still need ML\n' +
|
|
403
|
+
' workflows can install a replacement from a custom BMAD marketplace source\n' +
|
|
404
|
+
' (see --bmad-custom-source). This message is shown once.\n'
|
|
405
|
+
));
|
|
406
|
+
markNoticeShown(projectRoot, DEMERZEL_DEPRECATION_NOTICE_ID);
|
|
407
|
+
return true;
|
|
408
|
+
}
|
|
409
|
+
|
|
214
410
|
module.exports = {
|
|
215
411
|
getProfile,
|
|
216
412
|
setProfile,
|
|
@@ -218,4 +414,9 @@ module.exports = {
|
|
|
218
414
|
clearProfile,
|
|
219
415
|
getBmadModules,
|
|
220
416
|
setBmadModules,
|
|
417
|
+
hasShownNotice,
|
|
418
|
+
markNoticeShown,
|
|
419
|
+
showDemerzelDeprecationNoticeOnce,
|
|
420
|
+
getCustomMarketplaceSelection,
|
|
421
|
+
setCustomMarketplaceSelection,
|
|
221
422
|
};
|
package/lib/skill-authoring.js
CHANGED
|
@@ -405,7 +405,9 @@ async function handleSetMandatory(args) {
|
|
|
405
405
|
|
|
406
406
|
// ─── Story 3.4: BMAD Persona Customization Tooling ───────────────────────────
|
|
407
407
|
|
|
408
|
-
|
|
408
|
+
// Story 30.4 / FR244-FR247: 'bmm-demerzel' removed — Demerzel is deprecated for
|
|
409
|
+
// new installs (see lib/agents.js for the full rationale).
|
|
410
|
+
const CUSTOM_AGENTS = ['bmm-sre', 'bmm-devops', 'bmm-cyber', 'bmm-qa'];
|
|
409
411
|
const BUILTIN_AGENTS = ['bmm-pm', 'bmm-architect', 'bmm-dev', 'bmm-sm', 'bmm-tech-writer', 'bmm-ux-designer'];
|
|
410
412
|
|
|
411
413
|
const MANDATORY_CRITICAL_ACTIONS = {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ma-agents",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.17.0-beta.0",
|
|
4
4
|
"description": "NPX tool to install skills for AI coding agents (Claude Code, Gemini, Copilot, Kilocode, Cline, Cursor, Roo Code)",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"bin": {
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
},
|
|
9
9
|
"scripts": {
|
|
10
10
|
"start": "node bin/cli.js",
|
|
11
|
-
"test": "node test/yes-flag.test.js && node test/skill-authoring.test.js && node test/skill-validation.test.js && node test/skill-mandatory.test.js && node test/skill-customize-agent.test.js && node test/create-agent.test.js && node test/generate-project-context.test.js && node test/build-bmad-args.test.js && node test/build-bmad-cache-reader.test.js && node test/bmad-version-bump.test.js && node test/uv-transition-resilience.test.js && node test/passthrough-reconciliation-6-9-0.test.js && node test/extension-module-restructure.test.js && node test/convert-agents-to-skills.test.js && node test/migration.test.js && node test/migration-validation.test.js && node test/story-15-5-workflow-skills.test.js && node test/repo-layout.test.js && node test/config-storage.test.js && node test/cross-repo-validation.test.js && node test/config-lost-on-update.test.js && node test/portable-paths.test.js && node test/cicd-remote-mode.test.js && node test/config-layout.test.js && node test/roo-code-agent.test.js && node test/roo-code-injection.test.js && node test/profile.test.js && node test/instruction-block.test.js && node test/instruction-injection.test.js && node test/agents-md.test.js && node test/instruction-block-git.test.js && node test/onprem-injection.test.js && node test/onprem-layer.test.js && node test/copilot-instructions-path.test.js && node test/roomodes.test.js && node test/clinerules.test.js && node test/cline-workflow-reconciliation.test.js && node test/reconfigure.test.js && node test/experimental-warning.test.js && node test/bmad-persona-phase-prefix.test.js && node test/f1a-on-prem-prefix-post-install.test.js && node test/retired-skills-migration.test.js && node test/rename-migration.test.js && node test/uninstall.test.js && node test/offline-recompile.test.js && node test/plugin-manifests.test.js && node test/build-plugin.test.js && node test/config-path-migration.test.js && node test/gitignore-plugin-stage.test.js && node test/customizations-translation.test.js && node test/routing-parity.test.js && node test/bmad-extension.test.js && node test/integration-verification.test.js && node test/agent-scope.test.js && node test/obsolete-tool-dirs.test.js && node test/bmad-empty-tools-guard.test.js && node test/v68-pluginresolver-enumeration-passthrough.test.js && node test/agents.test.js && node test/installer.test.js && node test/bmad.test.js && node test/cli.test.js && node test/knowledge-atlas-smoke.test.js && node test/knowledge-atlas-manifest.test.js && node test/knowledge-atlas-render.test.js && node test/knowledge-atlas-graph.test.js && node test/knowledge-atlas-packaging.test.js && node test/knowledge-atlas-offline-safety.test.js && node test/knowledge-atlas-reconcile.test.js && node test/knowledge-atlas-determinism.test.js && node test/knowledge-atlas-degradation.test.js && node test/knowledge-atlas-realproject.test.js && node test/knowledge-atlas-link-integrity.test.js && node test/knowledge-atlas-config-scan.test.js && node test/knowledge-atlas-references.test.js",
|
|
11
|
+
"test": "node test/yes-flag.test.js && node test/skill-authoring.test.js && node test/skill-validation.test.js && node test/skill-mandatory.test.js && node test/skill-customize-agent.test.js && node test/create-agent.test.js && node test/generate-project-context.test.js && node test/build-bmad-args.test.js && node test/build-bmad-cache-reader.test.js && node test/bundle-filter-set-equality.test.js && node test/bmad-version-bump.test.js && node test/staging-6-10-0-regression.test.js && node test/uv-transition-resilience.test.js && node test/passthrough-reconciliation-6-9-0.test.js && node test/extension-module-restructure.test.js && node test/convert-agents-to-skills.test.js && node test/migration.test.js && node test/migration-validation.test.js && node test/story-15-5-workflow-skills.test.js && node test/repo-layout.test.js && node test/config-storage.test.js && node test/cross-repo-validation.test.js && node test/config-lost-on-update.test.js && node test/portable-paths.test.js && node test/cicd-remote-mode.test.js && node test/config-layout.test.js && node test/roo-code-agent.test.js && node test/roo-code-injection.test.js && node test/profile.test.js && node test/instruction-block.test.js && node test/instruction-injection.test.js && node test/agents-md.test.js && node test/instruction-block-git.test.js && node test/onprem-injection.test.js && node test/onprem-layer.test.js && node test/copilot-instructions-path.test.js && node test/roomodes.test.js && node test/clinerules.test.js && node test/cline-workflow-reconciliation.test.js && node test/reconfigure.test.js && node test/experimental-warning.test.js && node test/bmad-persona-phase-prefix.test.js && node test/f1a-on-prem-prefix-post-install.test.js && node test/retired-skills-migration.test.js && node test/rename-migration.test.js && node test/uninstall.test.js && node test/offline-recompile.test.js && node test/plugin-manifests.test.js && node test/demerzel-ml-removal-drift.test.js && node test/demerzel-deprecation-notice.test.js && node test/build-plugin.test.js && node test/config-path-migration.test.js && node test/gitignore-plugin-stage.test.js && node test/customizations-translation.test.js && node test/routing-parity.test.js && node test/bmad-extension.test.js && node test/integration-verification.test.js && node test/agent-scope.test.js && node test/obsolete-tool-dirs.test.js && node test/bmad-empty-tools-guard.test.js && node test/v68-pluginresolver-enumeration-passthrough.test.js && node test/agents.test.js && node test/installer.test.js && node test/bmad.test.js && node test/cli.test.js && node test/knowledge-atlas-smoke.test.js && node test/knowledge-atlas-manifest.test.js && node test/knowledge-atlas-render.test.js && node test/knowledge-atlas-graph.test.js && node test/knowledge-atlas-packaging.test.js && node test/knowledge-atlas-offline-safety.test.js && node test/knowledge-atlas-reconcile.test.js && node test/knowledge-atlas-determinism.test.js && node test/knowledge-atlas-degradation.test.js && node test/knowledge-atlas-realproject.test.js && node test/knowledge-atlas-link-integrity.test.js && node test/knowledge-atlas-config-scan.test.js && node test/knowledge-atlas-references.test.js && node test/agent-injection-strategy.test.js && node test/bmad-module-selection.test.js && node test/custom-marketplace-surface-drift.test.js && node test/custom-marketplace-wizard.test.js && node test/custom-marketplace-live-clone.test.js && node test/custom-marketplace-stage-install.test.js && node test/custom-marketplace-persist-reconcile.test.js && node test/demerzel-nondestructive-invariant.test.js && node test/fr243-custom-source-allowlist-nonleak.test.js",
|
|
12
12
|
"build:bmad-cache": "node scripts/build-bmad-cache.js",
|
|
13
13
|
"build:plugin": "node scripts/build-plugin.js",
|
|
14
14
|
"build:atlas": "node scripts/build-atlas.js",
|
|
@@ -32,7 +32,7 @@
|
|
|
32
32
|
"author": "",
|
|
33
33
|
"license": "MIT",
|
|
34
34
|
"dependencies": {
|
|
35
|
-
"bmad-method": "6.
|
|
35
|
+
"bmad-method": "6.10.0",
|
|
36
36
|
"chalk": "^4.1.2",
|
|
37
37
|
"fs-extra": "^11.1.1",
|
|
38
38
|
"js-yaml": "^4.1.1",
|
|
@@ -47,18 +47,44 @@ const REGISTRY_CANDIDATES = [
|
|
|
47
47
|
{ parts: ['tools', 'cli', 'external-official-modules.yaml'], schema: 'legacy' },
|
|
48
48
|
];
|
|
49
49
|
|
|
50
|
-
// The set of modules ma-agents bundles for offline installs
|
|
51
|
-
//
|
|
52
|
-
//
|
|
53
|
-
//
|
|
54
|
-
//
|
|
50
|
+
// The set of modules ma-agents bundles for offline installs — the CLOSED
|
|
51
|
+
// ALLOWLIST. `normalizeModules()` includes ONLY these codes; every other
|
|
52
|
+
// registry entry is dropped, regardless of its `type`. This is the load-bearing
|
|
53
|
+
// safety posture (P5-8 / FR235): at v6.10.0 the registry gained `bmad-loop`
|
|
54
|
+
// (`type: bmad-org`, `marketplace-plugin: true`, air-gap-hostile) and marked
|
|
55
|
+
// `bmad-automator` `deprecated: true`. An open-by-default "keep every
|
|
56
|
+
// `type: bmad-org`" filter would silently force-bundle `bmad-loop` (and any
|
|
57
|
+
// FUTURE plain `bmad-org` module) onto air-gapped machines. Closing to this
|
|
58
|
+
// allowlist means new/renamed/re-flagged upstream modules FAIL CLOSED (excluded)
|
|
59
|
+
// rather than fail open.
|
|
55
60
|
const KNOWN_BUNDLED_MODULES = ['tea', 'bmb', 'cis', 'gds', 'wds'];
|
|
56
61
|
|
|
57
|
-
//
|
|
58
|
-
//
|
|
59
|
-
// is
|
|
62
|
+
// The registry `type` first-party expansions carry. Retained for diagnostics
|
|
63
|
+
// and for the shape-flip assertion below (an allowlisted module is expected to
|
|
64
|
+
// stay a plain `bmad-org` module). It is NO LONGER the include criterion — the
|
|
65
|
+
// allowlist above is. `experimental` (automator) and `marketplace-plugin`
|
|
66
|
+
// modules (bmad-loop) are excluded simply by not being on the allowlist.
|
|
60
67
|
const BUNDLED_MODULE_TYPE = 'bmad-org';
|
|
61
68
|
|
|
69
|
+
// Registry traits that DISQUALIFY a module from the offline bundle. If a module
|
|
70
|
+
// that IS on the allowlist ever starts carrying one of these (an upstream
|
|
71
|
+
// shape/status flip on a module we bundle), the build HALTS rather than silently
|
|
72
|
+
// shipping it — see the assertion in normalizeModules(). `bmad-loop` carries
|
|
73
|
+
// `marketplace-plugin: true`; deprecated modules carry `deprecated: true`.
|
|
74
|
+
const DISQUALIFYING_FLAGS = ['marketplace-plugin', 'deprecated'];
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* True when a parsed registry flag reads as boolean-true. The line parser
|
|
78
|
+
* stores YAML scalars as strings (`'true'`), but unit callers may pass a real
|
|
79
|
+
* boolean, so accept both. Anything else (absent, `'false'`, other) is false.
|
|
80
|
+
*
|
|
81
|
+
* @param {*} value Raw flag value off a parsed module entry.
|
|
82
|
+
* @returns {boolean}
|
|
83
|
+
*/
|
|
84
|
+
function isFlagTrue(value) {
|
|
85
|
+
return value === true || String(value).trim().toLowerCase() === 'true';
|
|
86
|
+
}
|
|
87
|
+
|
|
62
88
|
/**
|
|
63
89
|
* Locate the bmad-method package on disk. Abort cleanly if missing so the
|
|
64
90
|
* caller gets an actionable "run npm install" message instead of a MODULE_NOT_FOUND
|
|
@@ -179,20 +205,29 @@ function parseModulesYaml(content) {
|
|
|
179
205
|
* Normalize parsed module entries into a uniform cache-ready shape:
|
|
180
206
|
* { code, url, name, branch }
|
|
181
207
|
*
|
|
208
|
+
* CLOSED-BY-DEFAULT (FR235). The filter is an ALLOWLIST: an entry survives ONLY
|
|
209
|
+
* if its `code` is in KNOWN_BUNDLED_MODULES (tea, bmb, cis, gds, wds). Every
|
|
210
|
+
* other registry entry is dropped no matter its `type` — so a NEW upstream
|
|
211
|
+
* module (even a plain `type: bmad-org` one carrying neither disqualifying
|
|
212
|
+
* flag), `bmad-loop` (`marketplace-plugin: true`), the deprecated
|
|
213
|
+
* `bmad-automator`, `experimental` modules, and the built-in `bmm`/`core` are
|
|
214
|
+
* ALL excluded by default. This replaces the prior open-by-default posture
|
|
215
|
+
* ("keep every `type: bmad-org`, subtract known-bad"), which would silently
|
|
216
|
+
* bundle any future first-party module the moment it appeared upstream.
|
|
217
|
+
*
|
|
218
|
+
* SHAPE-FLIP HALT. For each entry that IS on the allowlist, assert it carries
|
|
219
|
+
* NONE of DISQUALIFYING_FLAGS (`marketplace-plugin: true` / `deprecated: true`).
|
|
220
|
+
* If a bundled module ever flips shape/status upstream, THROW — a bundled
|
|
221
|
+
* module turning into a marketplace-plugin or getting deprecated must be
|
|
222
|
+
* re-reviewed by a maintainer, never shipped silently.
|
|
223
|
+
*
|
|
182
224
|
* - Requires both `code` and `url`.
|
|
183
|
-
* -
|
|
184
|
-
* everything else. This replaces the pre-6.8.0 `built_in` exclusion: the
|
|
185
|
-
* relocated registry no longer carries a `built_in` flag and instead tags
|
|
186
|
-
* each module with a `type`. `type: experimental` (e.g. `automator`) is
|
|
187
|
-
* excluded from the offline bundle; `bmm`/`core` are first-party modules
|
|
188
|
-
* that ship inside the npm package and are absent from the registry, so they
|
|
189
|
-
* are dropped here too (no `bmad-org` type → filtered out). There is NO
|
|
190
|
-
* `wds`-retired/skip path — `wds` is an active `bmad-org` clone at 6.8.0.
|
|
191
|
-
* - Defaults `branch` to `main` when absent (the 6.8.0 schema omits it).
|
|
225
|
+
* - Defaults `branch` to `main` when absent (the 6.8.0+ schema omits it).
|
|
192
226
|
* - Passes the URL through verbatim (git accepts both `repo` and `repo.git`).
|
|
193
227
|
*
|
|
194
228
|
* @param {Array<Object>} raw Entries from parseModulesYaml().
|
|
195
229
|
* @returns {Array<{code: string, url: string, name: string, branch: string}>}
|
|
230
|
+
* @throws {Error} if an allowlisted entry carries a disqualifying flag.
|
|
196
231
|
*/
|
|
197
232
|
// Module `code` values are used as directory names under lib/bmad-cache.
|
|
198
233
|
// Reject anything that could escape the cache dir or inject shell characters;
|
|
@@ -200,25 +235,65 @@ function parseModulesYaml(content) {
|
|
|
200
235
|
const MODULE_CODE_PATTERN = /^[a-zA-Z0-9_-]+$/;
|
|
201
236
|
|
|
202
237
|
function normalizeModules(raw) {
|
|
238
|
+
const allowlist = new Set(KNOWN_BUNDLED_MODULES);
|
|
203
239
|
return raw
|
|
204
240
|
.filter(m => m.code && m.url)
|
|
205
|
-
.
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
const type = String(m.type || '').trim().toLowerCase();
|
|
209
|
-
return type === BUNDLED_MODULE_TYPE;
|
|
210
|
-
})
|
|
241
|
+
// CLOSED allowlist: include ONLY the known bundled codes. Anything not on
|
|
242
|
+
// the allowlist fails closed (excluded) — the safety-critical inversion.
|
|
243
|
+
.filter(m => allowlist.has(m.code))
|
|
211
244
|
.filter(m => {
|
|
212
245
|
if (MODULE_CODE_PATTERN.test(m.code)) return true;
|
|
213
246
|
console.warn(` ⚠ Skipping module with invalid code "${m.code}" (must match [a-zA-Z0-9_-]+)`);
|
|
214
247
|
return false;
|
|
215
248
|
})
|
|
216
|
-
.map(m =>
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
249
|
+
.map(m => {
|
|
250
|
+
// Shape-flip halt: a module we DO bundle must not have turned into a
|
|
251
|
+
// marketplace-plugin or been deprecated upstream. Fail loud, don't ship.
|
|
252
|
+
const tripped = DISQUALIFYING_FLAGS.filter(flag => isFlagTrue(m[flag]));
|
|
253
|
+
if (tripped.length > 0) {
|
|
254
|
+
throw new Error(
|
|
255
|
+
`Allowlisted bundled module "${m.code}" now carries disqualifying flag(s): ` +
|
|
256
|
+
`${tripped.map(f => `${f}: true`).join(', ')}. A bundled module changing shape/status ` +
|
|
257
|
+
`upstream must be re-reviewed before shipping (FR235) — refusing to build. ` +
|
|
258
|
+
`Remove it from KNOWN_BUNDLED_MODULES in scripts/build-bmad-cache.js, or coordinate ` +
|
|
259
|
+
`the upstream change, then rebuild.`
|
|
260
|
+
);
|
|
261
|
+
}
|
|
262
|
+
return {
|
|
263
|
+
code: m.code,
|
|
264
|
+
url: m.url,
|
|
265
|
+
name: m.name || m.key,
|
|
266
|
+
branch: m.branch || 'main',
|
|
267
|
+
};
|
|
268
|
+
});
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
/**
|
|
272
|
+
* Compare a RESOLVED bundle set (the codes normalizeModules() kept) against the
|
|
273
|
+
* closed allowlist and report both directions of drift (NFR73 two-sided
|
|
274
|
+
* set-EQUALITY). The resolved set must EQUAL the allowlist exactly.
|
|
275
|
+
*
|
|
276
|
+
* - `missing`: allowlisted codes the registry did NOT resolve — the thin-cache
|
|
277
|
+
* case (a bundled module vanished / the registry relocated / a downgrade).
|
|
278
|
+
* - `extra`: resolved codes NOT on the allowlist — a silent upstream addition
|
|
279
|
+
* (e.g. `bmad-loop`) that must never be force-bundled. Under the closed
|
|
280
|
+
* allowlist filter this is normally empty; the check is defense-in-depth so a
|
|
281
|
+
* future loosening of the filter can never ship an over-broad cache silently.
|
|
282
|
+
*
|
|
283
|
+
* Computed on the resolved/filtered set — NOT the final manifest keys, which
|
|
284
|
+
* the incremental-retention path deliberately augments with retired-upstream
|
|
285
|
+
* modules that are not on the allowlist (see AC #7 retention in main()).
|
|
286
|
+
*
|
|
287
|
+
* @param {Iterable<string>|Set<string>} resolvedCodes Codes kept by normalize.
|
|
288
|
+
* @param {Array<string>} [allowlist=KNOWN_BUNDLED_MODULES]
|
|
289
|
+
* @returns {{ missing: string[], extra: string[] }} Sorted; both empty = equal.
|
|
290
|
+
*/
|
|
291
|
+
function diffBundleSet(resolvedCodes, allowlist = KNOWN_BUNDLED_MODULES) {
|
|
292
|
+
const allow = new Set(allowlist);
|
|
293
|
+
const resolved = resolvedCodes instanceof Set ? resolvedCodes : new Set(resolvedCodes);
|
|
294
|
+
const missing = [...allow].filter(code => !resolved.has(code)).sort();
|
|
295
|
+
const extra = [...resolved].filter(code => !allow.has(code)).sort();
|
|
296
|
+
return { missing, extra };
|
|
222
297
|
}
|
|
223
298
|
|
|
224
299
|
function loadModuleDefinitions() {
|
|
@@ -371,12 +446,15 @@ function main() {
|
|
|
371
446
|
|
|
372
447
|
const { modules, schema } = loadModuleDefinitions();
|
|
373
448
|
|
|
374
|
-
//
|
|
375
|
-
//
|
|
376
|
-
//
|
|
377
|
-
//
|
|
378
|
-
//
|
|
379
|
-
//
|
|
449
|
+
// Two-sided set-EQUALITY fail-loud guard (NFR73, strengthening NFR56). The
|
|
450
|
+
// resolved bundle set must EQUAL the known allowlist — abort on a set that is
|
|
451
|
+
// either SMALLER (thin cache: a bundled module vanished / the registry moved /
|
|
452
|
+
// a downgrade below 6.8.0) OR LARGER (a silent upstream addition such as
|
|
453
|
+
// bmad-loop that must never be force-bundled). Abort BEFORE writing any
|
|
454
|
+
// manifest — a partial or over-broad cache-manifest.json would otherwise ship
|
|
455
|
+
// a broken/air-gap-hostile offline bundle that "looks" successful. Computed on
|
|
456
|
+
// the RESOLVED set (not the final manifest keys — the retention path below
|
|
457
|
+
// augments the manifest with non-allowlist retired modules by design).
|
|
380
458
|
const resolvedCodes = new Set(modules.map(m => m.code));
|
|
381
459
|
|
|
382
460
|
// Duplicate-code guard. Two registry entries sharing a `code` would clone
|
|
@@ -395,15 +473,18 @@ function main() {
|
|
|
395
473
|
process.exit(1);
|
|
396
474
|
}
|
|
397
475
|
|
|
398
|
-
const missing =
|
|
399
|
-
if (missing.length > 0) {
|
|
400
|
-
console.error('Error:
|
|
401
|
-
console.error(
|
|
402
|
-
console.error(`
|
|
403
|
-
console.error(`
|
|
476
|
+
const { missing, extra } = diffBundleSet(resolvedCodes);
|
|
477
|
+
if (missing.length > 0 || extra.length > 0) {
|
|
478
|
+
console.error('Error: resolved bundle set does not EQUAL the known allowlist — refusing to build a');
|
|
479
|
+
console.error(' partial or over-broad cache (thin module set / silent upstream addition).');
|
|
480
|
+
console.error(` Allowlist (KNOWN_BUNDLED_MODULES): ${KNOWN_BUNDLED_MODULES.join(', ')}`);
|
|
481
|
+
console.error(` Resolved: ${[...resolvedCodes].sort().join(', ') || '(none)'}`);
|
|
482
|
+
console.error(` Missing: ${missing.join(', ') || '(none)'} (thin cache — a bundled module vanished/relocated)`);
|
|
483
|
+
console.error(` Extra: ${extra.join(', ') || '(none)'} (silent upstream addition — must not be force-bundled)`);
|
|
404
484
|
console.error(' Likely cause: bmad-method was downgraded below 6.8.0, the registry layout moved');
|
|
405
|
-
console.error(' again, or a bundled module was renamed/retired upstream. Update
|
|
406
|
-
console.error('
|
|
485
|
+
console.error(' again, or a bundled module was added/renamed/retired upstream. Update');
|
|
486
|
+
console.error(' REGISTRY_CANDIDATES or KNOWN_BUNDLED_MODULES in scripts/build-bmad-cache.js to match —');
|
|
487
|
+
console.error(' and, for an EXTRA module, confirm it is safe to bundle offline before allowlisting it.');
|
|
407
488
|
process.exit(1);
|
|
408
489
|
}
|
|
409
490
|
console.log(`Found ${modules.length} modules: ${modules.map(m => m.code).join(', ')}`);
|
|
@@ -587,9 +668,12 @@ if (require.main === module) {
|
|
|
587
668
|
module.exports = {
|
|
588
669
|
parseModulesYaml,
|
|
589
670
|
normalizeModules,
|
|
671
|
+
diffBundleSet,
|
|
672
|
+
isFlagTrue,
|
|
590
673
|
locateRegistry,
|
|
591
674
|
KNOWN_BUNDLED_MODULES,
|
|
592
675
|
BUNDLED_MODULE_TYPE,
|
|
676
|
+
DISQUALIFYING_FLAGS,
|
|
593
677
|
REGISTRY_CANDIDATES,
|
|
594
678
|
};
|
|
595
679
|
}
|
|
File without changes
|
|
@@ -1,59 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: ma-agent-ml
|
|
3
|
-
description: Demerzel (ML Scientist) — Machine Learning Scientist specializing in falsifiable hypothesis validation and failure-cost analysis
|
|
4
|
-
---
|
|
5
|
-
|
|
6
|
-
# Agent: Demerzel — ML Scientist
|
|
7
|
-
|
|
8
|
-
You must fully embody this agent's persona and follow all activation instructions exactly as specified. NEVER break character until given an exit command.
|
|
9
|
-
|
|
10
|
-
## Persona
|
|
11
|
-
- **Role:** Machine Learning Scientist specializing in falsifiable hypothesis validation and failure-cost analysis.
|
|
12
|
-
- **Identity:** Named after Eto Demerzel from Isaac Asimov's Foundation series. Senior AI/ML Architect and Data Scientist committed to the scientific method. She refuses to skip to modelling before high-quality EDA and a locked TechSpec are in place.
|
|
13
|
-
- **Communication Style:** Professional, precise, and hypothesis-driven. Uses statistical terminology correctly. Prioritizes failure modes and their domain costs.
|
|
14
|
-
- **Principles:**
|
|
15
|
-
- Scientific Rigor: No modelling without EDA. No modelling without a locked TechSpec.
|
|
16
|
-
- Dependency Integrity: Always use uv for project reproducibility.
|
|
17
|
-
- Failure Focus: Capture every failure mode and its domain cost.
|
|
18
|
-
|
|
19
|
-
## Activation Sequence
|
|
20
|
-
1. Load persona from this agent skill (already in context)
|
|
21
|
-
2. Load and read {project-root}/_bmad/bmm/config.yaml — store ALL fields as session variables: {user_name}, {communication_language}, {output_folder}. If config not loaded, STOP and report error to user.
|
|
22
|
-
3. Remember: user's name is {user_name}
|
|
23
|
-
4. Show greeting as Demerzel using {user_name} from config, communicate in {communication_language}, then display the ML Lifecycle stage menu.
|
|
24
|
-
5. Let {user_name} know they can type `/ml-advise` at any time to consult previous findings.
|
|
25
|
-
6. STOP and WAIT for user input — do NOT execute menu items automatically — accept number or cmd trigger or fuzzy command match
|
|
26
|
-
7. On user input: Number -> process menu item[n] | Text -> case-insensitive substring match | Multiple matches -> ask user to clarify | No match -> show "Not recognized"
|
|
27
|
-
8. When processing a menu item: load the referenced skill and follow its instructions
|
|
28
|
-
|
|
29
|
-
### Rules
|
|
30
|
-
- ALWAYS communicate in {communication_language} UNLESS contradicted by communication_style.
|
|
31
|
-
- Stay in character until exit selected.
|
|
32
|
-
- After each stage approval, commit all new/modified files under `_bmad-output/` with: `git add _bmad-output/ && git commit -m "feat(ml): stage [N] complete - [stage-name]"`
|
|
33
|
-
- Never commit before explicit user approval — the commit is the confirmation receipt.
|
|
34
|
-
- Display menu items as the item dictates and in the order given.
|
|
35
|
-
|
|
36
|
-
## Menu
|
|
37
|
-
| # | Cmd | Action | Trigger | Skill |
|
|
38
|
-
|---|-----|--------|---------|-------|
|
|
39
|
-
| 1 | MH | Redisplay Menu Help | "menu", "help" | _(built-in)_ |
|
|
40
|
-
| 2 | CH | Chat with Demerzel about ML | "chat", "ml" | _(built-in)_ |
|
|
41
|
-
| 3 | MLI | ML Ideation & PRD | "ideation", "prd" | ml-ideation |
|
|
42
|
-
| 4 | MLE | ML EDA & Research Thesis | "eda", "thesis" | ml-eda |
|
|
43
|
-
| 5 | MLA | ML Architecture Design | "architecture", "design" | ml-architecture |
|
|
44
|
-
| 6 | MLD | ML Detailed Design | "detailed", "breakdown" | ml-detailed-design |
|
|
45
|
-
| 7 | MLS | ML TechSpec (Lock Params) | "techspec", "lock" | ml-techspec |
|
|
46
|
-
| 8 | MLNF| ML Infra & Smoke Test | "infra", "smoke" | ml-infra |
|
|
47
|
-
| 9 | MLX | ML Experiment Execution | "experiment", "train" | ml-experiment |
|
|
48
|
-
| 10 | MLAN| ML Analysis (vs TechSpec) | "analysis", "results" | ml-analysis |
|
|
49
|
-
| 11 | MLH | ML HPO (Tuning) | "hpo", "tuning", "hyperparameter" | ml-hparam |
|
|
50
|
-
| 12 | MLR | ML Iterative Revision | "revision", "iterate" | ml-revision |
|
|
51
|
-
| 13 | MLAD| ML Advise & Search | "advise", "search", "findings" | ml-advise |
|
|
52
|
-
| 14 | MLRT| ML Retrospective | "retro", "learnings" | ml-retrospective |
|
|
53
|
-
| 15 | DA | Dismiss Demerzel | "dismiss", "exit" | _(built-in)_ |
|
|
54
|
-
|
|
55
|
-
## Critical Actions
|
|
56
|
-
1. Read the skills MANIFEST at {project-root}/_bmad/skills/demerzel/MANIFEST.yaml
|
|
57
|
-
2. For each skill marked always_load: true, read the skill file completely
|
|
58
|
-
3. If _bmad-output/project-context.md exists, read it completely
|
|
59
|
-
4. Follow all skill directives and project-context rules during this session
|
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
type: agent
|
|
2
|
-
name: ma-agent-ml
|
|
3
|
-
displayName: Demerzel
|
|
4
|
-
title: ML Scientist
|
|
5
|
-
icon: "\U0001F9EA"
|
|
6
|
-
capabilities: "Machine Learning Ideation, EDA, Architecture, Training, Analysis, Retrospective"
|
|
7
|
-
role: "Machine Learning Scientist specializing in falsifiable hypothesis validation and failure-cost analysis."
|
|
8
|
-
identity: "Named after Eto Demerzel from Isaac Asimov's Foundation series. Senior AI/ML Architect and Data Scientist committed to the scientific method. She refuses to skip to modelling before high-quality EDA and a locked TechSpec are in place."
|
|
9
|
-
communicationStyle: "Professional, precise, and hypothesis-driven. Uses statistical terminology correctly. Prioritizes failure modes and their domain costs."
|
|
10
|
-
principles: "No modelling without EDA. Lock params in TechSpec before training. Focus on failure-cost attribution. Use uv for reproducibility."
|
|
11
|
-
module: ma-skills
|
|
File without changes
|