bmad-plus 0.12.0 → 0.12.1
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/CHANGELOG.md +26 -0
- package/README.md +582 -577
- package/package.json +5 -5
- package/readme-international/README.de.md +9 -4
- package/readme-international/README.es.md +9 -4
- package/readme-international/README.fr.md +9 -4
- package/src/bmad-plus/packs/pack-memory/shared/memory-protocol.md +14 -0
- package/tools/build/generated-adapters/.codex/AGENTS.md +1 -1
- package/tools/build/generated-adapters/.cursor/rules/bmad-plus.mdc +1 -1
- package/tools/build/generated-adapters/.opencode/AGENTS.md +1 -1
- package/tools/build/generated-adapters/AGENTS.md +1 -1
- package/tools/build/generated-adapters/CLAUDE.md +1 -1
- package/tools/build/generated-adapters/CONVENTIONS.md +1 -1
- package/tools/build/generated-adapters/GEMINI.md +1 -1
- package/tools/cli/commands/autoconfig.js +1 -3
- package/tools/cli/commands/install.js +8 -2
- package/tools/cli/commands/scan.js +2 -18
- package/tools/cli/lib/memory-init.js +204 -113
- package/tools/cli/lib/packs.js +209 -209
- package/tools/cli/lib/path-hash.js +39 -0
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"$schema": "https://json.schemastore.org/package.json",
|
|
3
3
|
"name": "bmad-plus",
|
|
4
|
-
"version": "0.12.
|
|
4
|
+
"version": "0.12.1",
|
|
5
5
|
"description": "BMAD+ — Augmented AI-Driven Development Framework with multi-role agents, autopilot, and parallel execution",
|
|
6
6
|
"keywords": [
|
|
7
7
|
"bmad",
|
|
@@ -45,10 +45,9 @@
|
|
|
45
45
|
},
|
|
46
46
|
"dependencies": {
|
|
47
47
|
"@clack/prompts": "^1.4.0",
|
|
48
|
-
"chalk": "^4.1.2",
|
|
49
48
|
"commander": "^14.0.0",
|
|
50
|
-
"fs-extra": "^11.3.
|
|
51
|
-
"js-yaml": "^
|
|
49
|
+
"fs-extra": "^11.3.6",
|
|
50
|
+
"js-yaml": "^5.2.1",
|
|
52
51
|
"picocolors": "^1.1.1"
|
|
53
52
|
},
|
|
54
53
|
"engines": {
|
|
@@ -83,7 +82,8 @@
|
|
|
83
82
|
"testEnvironment": "node"
|
|
84
83
|
},
|
|
85
84
|
"devDependencies": {
|
|
86
|
-
"eslint": "^
|
|
85
|
+
"@eslint/js": "^10.0.1",
|
|
86
|
+
"eslint": "^10.6.0",
|
|
87
87
|
"husky": "^9.0.0",
|
|
88
88
|
"jest": "^30.4.2",
|
|
89
89
|
"prettier": "^3.4.0"
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# 🚀 BMAD+ — Erweitertes Multi-Agent KI-Framework
|
|
2
2
|
|
|
3
|
-
[](../CHANGELOG.md)
|
|
4
4
|
[](https://github.com/bmad-code-org/BMAD-METHOD)
|
|
5
5
|
[](../LICENSE)
|
|
6
6
|
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
<a href="../README.md">English</a> | <a href="README.fr.md">Français</a> | <a href="README.es.md">Español</a> | 🌐 <b>Deutsch</b>
|
|
9
9
|
</div>
|
|
10
10
|
|
|
11
|
-
> **56+ Multirole-Agenten · 9 modulare Packs · Autopilot-Modus · Parallele Ausführung ·
|
|
11
|
+
> **56+ Multirole-Agenten · 9 modulare Packs · Autopilot-Modus · Parallele Ausführung · 333 Tests**
|
|
12
12
|
> Intelligenter Fork von [BMAD-METHOD](https://github.com/bmad-code-org/BMAD-METHOD) — Selbstaktivierende Agenten mit 3-Stufen-Kontexterkennung, GRC-Compliance (Shield), vollständige SDLC-Pipeline (Dev Studio), OSINT-Intelligence, SEO-Audit, persistentes Cross-Session-Gedächtnis und 10-Sprachen CLI-Installer.
|
|
13
13
|
|
|
14
14
|
---
|
|
@@ -556,8 +556,13 @@ BMAD+/
|
|
|
556
556
|
| **0.4.4** | 2026-05-17 | 🔧 UTF-8-Kodierungsfix, vollständige i18n 10 Sprachen, 62 Unit-Tests |
|
|
557
557
|
| **0.5.0** | 2026-05-17 | 🛡️ **Pack Shield** — 38 GRC-Compliance-Agenten, 7 Kategorien, 25+ Frameworks (DSGVO, ISO 27001, SOC 2, EU AI Act...) |
|
|
558
558
|
| **0.6.0** | 2026-05-17 | 🏗️ **Pack Dev Studio** — 6 SDLC-Agenten (Miriam, Yosef, Bezalel...) + 30 SDLC-Workflows, BWML DSL |
|
|
559
|
-
| **0.
|
|
560
|
-
| **0.
|
|
559
|
+
| **0.8.0** | 2026-06-24 | 🚀 **Erweitert** — 3 neue Packs (animated, backup, seo), Sicherheits-Remediation, i18n-Sync |
|
|
560
|
+
| **0.9.0** | 2026-06-24 | 🔒 **Sicher** — Audit-Remediation-Zyklus, npm audit sauber, gemeinsames Pack-Registry (`lib/packs.js`) |
|
|
561
|
+
| **0.9.1** | 2026-07-01 | ✅ **Glaubwürdigkeit** — echte CI bei Push/PR, Jest-ESM-Harness repariert, ESLint-Flat-Config, falsche Badges entfernt |
|
|
562
|
+
| **0.9.2** | 2026-07-01 | 🔐 **Sicherheit** — RCE (ci_cd-Allowlist), SSRF, Stored/DOM-XSS, XXE, Python-CVE-Bumps (~30 Findings) |
|
|
563
|
+
| **0.10.0** | 2026-07-02 | 🧭 **Plattform-Rückgrat** — SSOT `registry.yaml` (generiertes `packs.js` + CI-Drift-Gate), Python-Provisioning, Eval- + Memory-Fundament |
|
|
564
|
+
| **0.11.0** | 2026-07-02 | 🧠 **Karpathy-Schleife** — `bmad mem` recall/write/reinforce, Multi-CLI-Adapter-Generator, OSINT-Rechtsgrundlagen-Gate (CG-02) |
|
|
565
|
+
| **0.12.0** | 2026-07-02 | 🏛️ **Load-bearing** — Root-Adapter aus dem Registry adoptiert, Memory über MCP, provider-neutrales Eval-Gateway; 333 Tests |
|
|
561
566
|
|
|
562
567
|
Siehe [CHANGELOG.md](../CHANGELOG.md) für vollständige Details.
|
|
563
568
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# 🚀 BMAD+ — Framework Multi-Agente IA Aumentado
|
|
2
2
|
|
|
3
|
-
[](../CHANGELOG.md)
|
|
4
4
|
[](https://github.com/bmad-code-org/BMAD-METHOD)
|
|
5
5
|
[](../LICENSE)
|
|
6
6
|
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
<a href="../README.md">English</a> | <a href="README.fr.md">Français</a> | 🌐 <b>Español</b> | <a href="README.de.md">Deutsch</a>
|
|
9
9
|
</div>
|
|
10
10
|
|
|
11
|
-
> **56+ agentes multirrol · 9 packs modulares · Modo Autopilot · Ejecución paralela ·
|
|
11
|
+
> **56+ agentes multirrol · 9 packs modulares · Modo Autopilot · Ejecución paralela · 333 tests**
|
|
12
12
|
> Fork inteligente de [BMAD-METHOD](https://github.com/bmad-code-org/BMAD-METHOD) — Agentes auto-activables con detección contextual en 3 niveles, cumplimiento GRC (Shield), pipeline SDLC completo (Dev Studio), inteligencia OSINT, auditoría SEO, memoria persistente cross-session e instalador CLI en 10 idiomas.
|
|
13
13
|
|
|
14
14
|
---
|
|
@@ -571,8 +571,13 @@ BMAD+/
|
|
|
571
571
|
| **0.4.4** | 2026-05-17 | 🔧 Corrección codificación UTF-8, i18n completa 10 idiomas, 62 tests unitarios |
|
|
572
572
|
| **0.5.0** | 2026-05-17 | 🛡️ **Pack Shield** — 38 agentes de cumplimiento GRC, 7 categorías, 25+ frameworks (GDPR, ISO 27001, SOC 2, EU AI Act...) |
|
|
573
573
|
| **0.6.0** | 2026-05-17 | 🏗️ **Pack Dev Studio** — 6 agentes SDLC (Miriam, Yosef, Bezalel...) + 30 flujos de trabajo SDLC, BWML DSL |
|
|
574
|
-
| **0.
|
|
575
|
-
| **0.
|
|
574
|
+
| **0.8.0** | 2026-06-24 | 🚀 **Aumentado** — 3 nuevos packs (animated, backup, seo), pase de remediación de seguridad, sync i18n |
|
|
575
|
+
| **0.9.0** | 2026-06-24 | 🔒 **Seguro** — ciclo de remediación de auditoría, npm audit limpio, registro de packs compartido (`lib/packs.js`) |
|
|
576
|
+
| **0.9.1** | 2026-07-01 | ✅ **Credibilidad** — CI real en push/PR, arnés Jest ESM reparado, config ESLint flat, badges falsos retirados |
|
|
577
|
+
| **0.9.2** | 2026-07-01 | 🔐 **Seguridad** — RCE (allowlist ci_cd), SSRF, XSS almacenado/DOM, XXE, bumps CVE Python (~30 hallazgos) |
|
|
578
|
+
| **0.10.0** | 2026-07-02 | 🧭 **Columna vertebral de plataforma** — SSOT `registry.yaml` (`packs.js` generado + gate anti-drift en CI), provisioning Python, fundaciones eval + memoria |
|
|
579
|
+
| **0.11.0** | 2026-07-02 | 🧠 **Bucle Karpathy** — `bmad mem` recall/write/reinforce, generador de adapters multi-CLI, gate de base legal OSINT (CG-02) |
|
|
580
|
+
| **0.12.0** | 2026-07-02 | 🏛️ **Load-bearing** — adapters raíz adoptados desde el registry, memoria vía MCP, gateway eval multi-proveedor; 333 tests |
|
|
576
581
|
|
|
577
582
|
Más descripciones a fondo en el archivo: [CHANGELOG.md](../CHANGELOG.md).
|
|
578
583
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# 🚀 BMAD+ — Framework Multi-Agent IA Augmenté
|
|
2
2
|
|
|
3
|
-
[](../CHANGELOG.md)
|
|
4
4
|
[](https://github.com/bmad-code-org/BMAD-METHOD)
|
|
5
5
|
[](../LICENSE)
|
|
6
6
|
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
<a href="../README.md">English</a> | 🌐 <b>Français</b> | <a href="README.es.md">Español</a> | <a href="README.de.md">Deutsch</a>
|
|
9
9
|
</div>
|
|
10
10
|
|
|
11
|
-
> **56+ agents multi-rôles · 9 packs modulaires · Mode Autopilot · Exécution parallèle ·
|
|
11
|
+
> **56+ agents multi-rôles · 9 packs modulaires · Mode Autopilot · Exécution parallèle · 333 tests**
|
|
12
12
|
> Fork intelligent de [BMAD-METHOD](https://github.com/bmad-code-org/BMAD-METHOD) — Agents auto-activables avec détection contextuelle 3 niveaux, conformité GRC (Shield), pipeline SDLC complet (Dev Studio), intelligence OSINT, audit SEO, mémoire persistante cross-session, et installeur CLI 10 langues.
|
|
13
13
|
|
|
14
14
|
---
|
|
@@ -571,8 +571,13 @@ BMAD+/
|
|
|
571
571
|
| **0.4.4** | 2026-05-17 | 🔧 Correction encodage UTF-8, i18n complète 10 langues, 62 tests unitaires |
|
|
572
572
|
| **0.5.0** | 2026-05-17 | 🛡️ **Pack Shield** — 38 agents de conformité GRC, 7 catégories, 25+ frameworks (RGPD, ISO 27001, SOC 2, EU AI Act...) |
|
|
573
573
|
| **0.6.0** | 2026-05-17 | 🏗️ **Pack Dev Studio** — 6 agents SDLC (Miriam, Yosef, Bezalel...) + 30 workflows SDLC, BWML DSL |
|
|
574
|
-
| **0.
|
|
575
|
-
| **0.
|
|
574
|
+
| **0.8.0** | 2026-06-24 | 🚀 **Augmenté** — 3 nouveaux packs (animated, backup, seo), passe de remédiation sécurité, sync i18n |
|
|
575
|
+
| **0.9.0** | 2026-06-24 | 🔒 **Sécurisé** — cycle de remédiation d'audit, npm audit propre, registre de packs partagé (`lib/packs.js`) |
|
|
576
|
+
| **0.9.1** | 2026-07-01 | ✅ **Crédibilité** — vraie CI sur push/PR, harnais Jest ESM réparé, config ESLint flat, faux badges retirés |
|
|
577
|
+
| **0.9.2** | 2026-07-01 | 🔐 **Sécurité** — RCE (allowlist ci_cd), SSRF, XSS stocké/DOM, XXE, bumps CVE Python (~30 findings) |
|
|
578
|
+
| **0.10.0** | 2026-07-02 | 🧭 **Épine dorsale plateforme** — SSOT `registry.yaml` (`packs.js` généré + gate anti-drift CI), provisioning Python, fondations eval + mémoire |
|
|
579
|
+
| **0.11.0** | 2026-07-02 | 🧠 **Boucle Karpathy** — `bmad mem` recall/write/reinforce, générateur d'adapters multi-CLI, gate base légale OSINT (CG-02) |
|
|
580
|
+
| **0.12.0** | 2026-07-02 | 🏛️ **Load-bearing** — adapters racine adoptés depuis le registry, mémoire via MCP, gateway eval multi-provider ; 333 tests |
|
|
576
581
|
|
|
577
582
|
Voir [CHANGELOG.md](../CHANGELOG.md) pour le détail complet.
|
|
578
583
|
|
|
@@ -29,6 +29,20 @@
|
|
|
29
29
|
└── <hash>.yaml ← Per-project metadata
|
|
30
30
|
```
|
|
31
31
|
|
|
32
|
+
### Portfolio Brain (workspace-level, takes precedence)
|
|
33
|
+
|
|
34
|
+
If a `_brain/` directory exists in the project directory or any ancestor (e.g. `D:\workspace\_brain\` above `D:\workspace\clients\my-project\`), install links the project to it instead of `~/.bmad-plus/brain`. The `BMAD_PLUS_BRAIN` env var overrides all auto-detection.
|
|
35
|
+
|
|
36
|
+
The kind of brain that was linked is recorded in `.brain-link`:
|
|
37
|
+
|
|
38
|
+
```json
|
|
39
|
+
{ "linked_brain": "D:\\workspace\\_brain", "brain_type": "portfolio", "linked_at": "…" }
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
`brain_type` values: `portfolio` (workspace `_brain/` or env var) · `bmad-global` (`~/.bmad-plus/brain`) · `claude-memory` (`~/.claude/memory`).
|
|
43
|
+
|
|
44
|
+
**Rule for agents**: a portfolio brain has its **own** conventions and layout — read its entry point (`README.md` / `AGENTS.md` / `HOT.md`) first and follow them. Do NOT assume the BMAD+ global layout above; in particular do not create `identity.yaml` or `projects/` inside a portfolio brain uninvited.
|
|
45
|
+
|
|
32
46
|
---
|
|
33
47
|
|
|
34
48
|
## Protocol: Session Start (READ)
|
|
@@ -100,7 +100,7 @@ Agents MUST follow these behavioral principles:
|
|
|
100
100
|
|
|
101
101
|
## Registry facts (computed from registry.yaml — never hand-typed)
|
|
102
102
|
|
|
103
|
-
- Product: BMAD+ v0.12.
|
|
103
|
+
- Product: BMAD+ v0.12.1 (derived from BMAD-METHOD v6.6.0)
|
|
104
104
|
- Models supported: claude, gpt, gemini, local (model-agnostic by contract)
|
|
105
105
|
- Packs (9): Core, OSINT, Maker, Shield, SEO, Memory, Dev Studio, Backup, Animated
|
|
106
106
|
- Installer agents (14 across all packs):
|
|
@@ -105,7 +105,7 @@ Agents MUST follow these behavioral principles:
|
|
|
105
105
|
|
|
106
106
|
## Registry facts (computed from registry.yaml — never hand-typed)
|
|
107
107
|
|
|
108
|
-
- Product: BMAD+ v0.12.
|
|
108
|
+
- Product: BMAD+ v0.12.1 (derived from BMAD-METHOD v6.6.0)
|
|
109
109
|
- Models supported: claude, gpt, gemini, local (model-agnostic by contract)
|
|
110
110
|
- Packs (9): Core, OSINT, Maker, Shield, SEO, Memory, Dev Studio, Backup, Animated
|
|
111
111
|
- Installer agents (14 across all packs):
|
|
@@ -100,7 +100,7 @@ Agents MUST follow these behavioral principles:
|
|
|
100
100
|
|
|
101
101
|
## Registry facts (computed from registry.yaml — never hand-typed)
|
|
102
102
|
|
|
103
|
-
- Product: BMAD+ v0.12.
|
|
103
|
+
- Product: BMAD+ v0.12.1 (derived from BMAD-METHOD v6.6.0)
|
|
104
104
|
- Models supported: claude, gpt, gemini, local (model-agnostic by contract)
|
|
105
105
|
- Packs (9): Core, OSINT, Maker, Shield, SEO, Memory, Dev Studio, Backup, Animated
|
|
106
106
|
- Installer agents (14 across all packs):
|
|
@@ -98,7 +98,7 @@ Agents MUST follow these behavioral principles:
|
|
|
98
98
|
|
|
99
99
|
## Registry facts (computed from registry.yaml — never hand-typed)
|
|
100
100
|
|
|
101
|
-
- Product: BMAD+ v0.12.
|
|
101
|
+
- Product: BMAD+ v0.12.1 (derived from BMAD-METHOD v6.6.0)
|
|
102
102
|
- Models supported: claude, gpt, gemini, local (model-agnostic by contract)
|
|
103
103
|
- Packs (9): Core, OSINT, Maker, Shield, SEO, Memory, Dev Studio, Backup, Animated
|
|
104
104
|
- Installer agents (14 across all packs):
|
|
@@ -101,7 +101,7 @@ Agents MUST follow these behavioral principles:
|
|
|
101
101
|
|
|
102
102
|
## Registry facts (computed from registry.yaml — never hand-typed)
|
|
103
103
|
|
|
104
|
-
- Product: BMAD+ v0.12.
|
|
104
|
+
- Product: BMAD+ v0.12.1 (derived from BMAD-METHOD v6.6.0)
|
|
105
105
|
- Models supported: claude, gpt, gemini, local (model-agnostic by contract)
|
|
106
106
|
- Packs (9): Core, OSINT, Maker, Shield, SEO, Memory, Dev Studio, Backup, Animated
|
|
107
107
|
- Installer agents (14 across all packs):
|
|
@@ -100,7 +100,7 @@ Agents MUST follow these behavioral principles:
|
|
|
100
100
|
|
|
101
101
|
## Registry facts (computed from registry.yaml — never hand-typed)
|
|
102
102
|
|
|
103
|
-
- Product: BMAD+ v0.12.
|
|
103
|
+
- Product: BMAD+ v0.12.1 (derived from BMAD-METHOD v6.6.0)
|
|
104
104
|
- Models supported: claude, gpt, gemini, local (model-agnostic by contract)
|
|
105
105
|
- Packs (9): Core, OSINT, Maker, Shield, SEO, Memory, Dev Studio, Backup, Animated
|
|
106
106
|
- Installer agents (14 across all packs):
|
|
@@ -105,7 +105,7 @@ Agents MUST follow these behavioral principles:
|
|
|
105
105
|
|
|
106
106
|
## Registry facts (computed from registry.yaml — never hand-typed)
|
|
107
107
|
|
|
108
|
-
- Product: BMAD+ v0.12.
|
|
108
|
+
- Product: BMAD+ v0.12.1 (derived from BMAD-METHOD v6.6.0)
|
|
109
109
|
- Models supported: claude, gpt, gemini, local (model-agnostic by contract)
|
|
110
110
|
- Packs (9): Core, OSINT, Maker, Shield, SEO, Memory, Dev Studio, Backup, Animated
|
|
111
111
|
- Installer agents (14 across all packs):
|
|
@@ -264,8 +264,7 @@ module.exports = {
|
|
|
264
264
|
clack.log.info('');
|
|
265
265
|
|
|
266
266
|
// Confirm
|
|
267
|
-
|
|
268
|
-
if (!confirmed) {
|
|
267
|
+
if (!options.yes) {
|
|
269
268
|
const answer = await clack.confirm({
|
|
270
269
|
message: `Install ${packs.length} recommended packs?`,
|
|
271
270
|
initialValue: true,
|
|
@@ -274,7 +273,6 @@ module.exports = {
|
|
|
274
273
|
clack.cancel('Autoconfig cancelled.');
|
|
275
274
|
return;
|
|
276
275
|
}
|
|
277
|
-
confirmed = true;
|
|
278
276
|
}
|
|
279
277
|
|
|
280
278
|
// Run install
|
|
@@ -235,9 +235,15 @@ module.exports = {
|
|
|
235
235
|
copiedSkills += result.copiedSkills;
|
|
236
236
|
copiedFiles += result.copiedFiles;
|
|
237
237
|
|
|
238
|
-
// Memory pack: initialize brain with existing brain detection
|
|
238
|
+
// Memory pack: initialize brain with existing brain detection.
|
|
239
|
+
// Non-fatal: a read-only or missing home dir (containers, CI) must not
|
|
240
|
+
// abort the install mid-flight and leave a manifest-less partial tree.
|
|
239
241
|
if (packId === 'memory' && pack.packDir) {
|
|
240
|
-
|
|
242
|
+
try {
|
|
243
|
+
initMemory({ projectDir, bmadSrc, userName, commLang, selectedPacks });
|
|
244
|
+
} catch (err) {
|
|
245
|
+
clack.log.warn(`Memory/brain initialization failed (non-fatal, install continues): ${err.message}`);
|
|
246
|
+
}
|
|
241
247
|
}
|
|
242
248
|
}
|
|
243
249
|
|
|
@@ -9,10 +9,10 @@
|
|
|
9
9
|
const path = require('node:path');
|
|
10
10
|
const fs = require('node:fs');
|
|
11
11
|
const os = require('node:os');
|
|
12
|
-
const crypto = require('node:crypto');
|
|
13
12
|
const clack = require('@clack/prompts');
|
|
14
13
|
const pc = require('picocolors');
|
|
15
14
|
const { PROJECT_MARKERS } = require('../lib/stack-detect');
|
|
15
|
+
const { normalizePathForHash, projectHash } = require('../lib/path-hash');
|
|
16
16
|
|
|
17
17
|
// Directories to skip during scanning
|
|
18
18
|
const SKIP_DIRS = new Set([
|
|
@@ -118,22 +118,6 @@ function scanDirectory(rootDir, maxDepth = 4, currentDepth = 0, activeDays = 30,
|
|
|
118
118
|
return projects;
|
|
119
119
|
}
|
|
120
120
|
|
|
121
|
-
/**
|
|
122
|
-
* Normalize a filesystem path for stable hashing.
|
|
123
|
-
* On Windows the same project can be referenced as `D:\proj` or `d:\proj`
|
|
124
|
-
* (case-insensitive drive) with mixed separators. Resolving + lowercasing the
|
|
125
|
-
* drive letter ensures the same project produces the same index key and is not
|
|
126
|
-
* double-indexed.
|
|
127
|
-
* @param {string} p - Raw filesystem path
|
|
128
|
-
* @returns {string} Normalized path suitable for hashing
|
|
129
|
-
*/
|
|
130
|
-
function normalizePathForHash(p) {
|
|
131
|
-
let resolved = path.resolve(p);
|
|
132
|
-
// Lowercase a leading Windows drive letter (e.g. "D:" → "d:").
|
|
133
|
-
resolved = resolved.replace(/^([A-Za-z]):/, (_m, drive) => drive.toLowerCase() + ':');
|
|
134
|
-
return resolved;
|
|
135
|
-
}
|
|
136
|
-
|
|
137
121
|
/**
|
|
138
122
|
* Index a single project in the global brain by writing its metadata YAML file.
|
|
139
123
|
* @param {object} project - Project metadata object
|
|
@@ -141,7 +125,7 @@ function normalizePathForHash(p) {
|
|
|
141
125
|
* @returns {void}
|
|
142
126
|
*/
|
|
143
127
|
function indexProject(project, globalBrainDir) {
|
|
144
|
-
const hash =
|
|
128
|
+
const hash = projectHash(project.path);
|
|
145
129
|
const meta = {
|
|
146
130
|
path: project.path,
|
|
147
131
|
name: project.name,
|
|
@@ -1,113 +1,204 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* BMAD+ Memory Initialization Module
|
|
3
|
-
* Extracted from install.js — initializes brain with existing brain detection.
|
|
4
|
-
*
|
|
5
|
-
* Author: Laurent Rochetta
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
|
-
const path = require('node:path');
|
|
9
|
-
const fs = require('node:fs');
|
|
10
|
-
const os = require('node:os');
|
|
11
|
-
const fsExtra = require('fs-extra');
|
|
12
|
-
const clack = require('@clack/prompts');
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
* @param {string}
|
|
19
|
-
* @
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
path.join(
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
const
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
path.join(
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
1
|
+
/**
|
|
2
|
+
* BMAD+ Memory Initialization Module
|
|
3
|
+
* Extracted from install.js — initializes brain with existing brain detection.
|
|
4
|
+
*
|
|
5
|
+
* Author: Laurent Rochetta
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
const path = require('node:path');
|
|
9
|
+
const fs = require('node:fs');
|
|
10
|
+
const os = require('node:os');
|
|
11
|
+
const fsExtra = require('fs-extra');
|
|
12
|
+
const clack = require('@clack/prompts');
|
|
13
|
+
const { projectHash } = require('./path-hash');
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* True when `p` exists AND is a directory. A stray *file* named `_brain` (or a
|
|
17
|
+
* file-valued BMAD_PLUS_BRAIN) must never be linked as a brain.
|
|
18
|
+
* @param {string} p
|
|
19
|
+
* @returns {boolean}
|
|
20
|
+
*/
|
|
21
|
+
function isBrainCandidateDir(p) {
|
|
22
|
+
try {
|
|
23
|
+
return fs.statSync(p).isDirectory();
|
|
24
|
+
} catch {
|
|
25
|
+
return false;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Resolve the brain directory a project should link to.
|
|
31
|
+
*
|
|
32
|
+
* Priority order:
|
|
33
|
+
* 1. `BMAD_PLUS_BRAIN` env var — explicit override, wins everywhere
|
|
34
|
+
* 2. A `_brain/` directory in the project dir or any ancestor (portfolio brain
|
|
35
|
+
* shared by sibling projects under a common workspace root)
|
|
36
|
+
* 3. `<home>/.bmad-plus/brain` — BMAD+ global brain
|
|
37
|
+
* 4. `<home>/.claude/memory` — Claude Code persistent memory, only when it is
|
|
38
|
+
* a non-empty directory (an empty shell is not evidence of a real memory)
|
|
39
|
+
*
|
|
40
|
+
* @param {string} projectDir - Absolute path of the target project
|
|
41
|
+
* @param {string} [homeDir] - Home directory (injectable for tests; defaults to os.homedir())
|
|
42
|
+
* @returns {{dir: string, type: 'portfolio'|'bmad-global'|'claude-memory'}|null}
|
|
43
|
+
*/
|
|
44
|
+
function resolveBrain(projectDir, homeDir = os.homedir()) {
|
|
45
|
+
const envBrain = process.env.BMAD_PLUS_BRAIN;
|
|
46
|
+
if (envBrain) {
|
|
47
|
+
if (isBrainCandidateDir(envBrain)) return { dir: envBrain, type: 'portfolio' };
|
|
48
|
+
clack.log.warn(`BMAD_PLUS_BRAIN is set but is not a directory: ${envBrain} — falling back to auto-detection`);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
let dir = path.resolve(projectDir);
|
|
52
|
+
for (;;) {
|
|
53
|
+
const candidate = path.join(dir, '_brain');
|
|
54
|
+
if (isBrainCandidateDir(candidate)) return { dir: candidate, type: 'portfolio' };
|
|
55
|
+
const parent = path.dirname(dir);
|
|
56
|
+
if (parent === dir) break;
|
|
57
|
+
dir = parent;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
const globalBrain = path.join(homeDir, '.bmad-plus', 'brain');
|
|
61
|
+
if (isBrainCandidateDir(globalBrain)) return { dir: globalBrain, type: 'bmad-global' };
|
|
62
|
+
|
|
63
|
+
const claudeMemory = path.join(homeDir, '.claude', 'memory');
|
|
64
|
+
if (isBrainCandidateDir(claudeMemory)) {
|
|
65
|
+
let entries;
|
|
66
|
+
try {
|
|
67
|
+
entries = fs.readdirSync(claudeMemory);
|
|
68
|
+
} catch {
|
|
69
|
+
entries = [];
|
|
70
|
+
}
|
|
71
|
+
if (entries.length > 0) return { dir: claudeMemory, type: 'claude-memory' };
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
return null;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Idempotently ensure the global brain is COMPLETE: identity.yaml, the global
|
|
79
|
+
* memory files, and projects/. Creates only what is missing, never overwrites.
|
|
80
|
+
*
|
|
81
|
+
* This must run before ANY write into the global brain: older versions wrote
|
|
82
|
+
* the projects/ index unconditionally while identity creation lived in a
|
|
83
|
+
* branch that was skipped whenever any brain was detected — leaving a
|
|
84
|
+
* permanent "half brain" (projects/ but no identity.yaml) that resolveBrain
|
|
85
|
+
* then detected as a valid global brain forever.
|
|
86
|
+
*
|
|
87
|
+
* @param {string} brainRoot - Path to <home>/.bmad-plus/brain
|
|
88
|
+
* @param {string} templateDir - Path to pack-memory templates
|
|
89
|
+
* @param {string} userName - User display name (identity.yaml)
|
|
90
|
+
* @param {string} commLang - Communication language (identity.yaml)
|
|
91
|
+
* @returns {void}
|
|
92
|
+
*/
|
|
93
|
+
function ensureGlobalBrain(brainRoot, templateDir, userName, commLang) {
|
|
94
|
+
fsExtra.ensureDirSync(path.join(brainRoot, 'projects'));
|
|
95
|
+
|
|
96
|
+
const identitySrc = path.join(templateDir, 'identity.yaml');
|
|
97
|
+
const identityDest = path.join(brainRoot, 'identity.yaml');
|
|
98
|
+
if (fs.existsSync(identitySrc) && !fs.existsSync(identityDest)) {
|
|
99
|
+
let content = fs.readFileSync(identitySrc, 'utf8');
|
|
100
|
+
content = content.replace(/\{\{user_name\}\}/g, userName);
|
|
101
|
+
content = content.replace(/\{\{language\}\}/g, commLang);
|
|
102
|
+
content = content.replace(/\{\{date\}\}/g, new Date().toISOString().slice(0, 10));
|
|
103
|
+
fs.writeFileSync(identityDest, content, 'utf8');
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
for (const gf of ['decisions.md', 'lessons.md', 'patterns.md']) {
|
|
107
|
+
const dest = path.join(brainRoot, gf);
|
|
108
|
+
if (!fs.existsSync(dest)) {
|
|
109
|
+
const src = path.join(templateDir, gf);
|
|
110
|
+
if (fs.existsSync(src)) {
|
|
111
|
+
let content = fs.readFileSync(src, 'utf8');
|
|
112
|
+
content = content.replace(/\{\{date\}\}/g, new Date().toISOString().slice(0, 10));
|
|
113
|
+
content = content.replace(/\{\{project_name\}\}/g, 'Global Brain');
|
|
114
|
+
fs.writeFileSync(dest, content, 'utf8');
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* Initialize the memory pack: create project memory files, detect or create global brain.
|
|
122
|
+
*
|
|
123
|
+
* @param {object} opts
|
|
124
|
+
* @param {string} opts.projectDir - Target project directory
|
|
125
|
+
* @param {string} opts.bmadSrc - Path to src/bmad-plus/
|
|
126
|
+
* @param {string} opts.userName - User display name
|
|
127
|
+
* @param {string} opts.commLang - Communication language
|
|
128
|
+
* @param {string[]} opts.selectedPacks - Array of pack IDs being installed
|
|
129
|
+
* @param {string} [opts.homeDir] - Home directory (injectable for tests; defaults to os.homedir())
|
|
130
|
+
* @returns {void}
|
|
131
|
+
*/
|
|
132
|
+
function initMemory({ projectDir, bmadSrc, userName, commLang, selectedPacks, homeDir = os.homedir() }) {
|
|
133
|
+
const memoryDir = path.join(projectDir, '.agents', 'memory');
|
|
134
|
+
const sessionsDir = path.join(memoryDir, 'sessions');
|
|
135
|
+
const globalBrainRoot = path.join(homeDir, '.bmad-plus', 'brain');
|
|
136
|
+
const templateDir = path.join(bmadSrc, 'packs', 'pack-memory', 'templates');
|
|
137
|
+
|
|
138
|
+
// Create project memory (never overwrite existing)
|
|
139
|
+
fsExtra.ensureDirSync(sessionsDir);
|
|
140
|
+
const memoryFiles = ['decisions.md', 'lessons.md', 'patterns.md', 'context.md'];
|
|
141
|
+
for (const mf of memoryFiles) {
|
|
142
|
+
const dest = path.join(memoryDir, mf);
|
|
143
|
+
if (!fs.existsSync(dest)) {
|
|
144
|
+
const src = path.join(templateDir, mf);
|
|
145
|
+
if (fs.existsSync(src)) {
|
|
146
|
+
let content = fs.readFileSync(src, 'utf8');
|
|
147
|
+
content = content.replace(/\{\{date\}\}/g, new Date().toISOString().slice(0, 10));
|
|
148
|
+
content = content.replace(/\{\{project_name\}\}/g, path.basename(projectDir));
|
|
149
|
+
content = content.replace(/\{\{project_path\}\}/g, projectDir);
|
|
150
|
+
fs.writeFileSync(dest, content, 'utf8');
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
// Detect existing brain (env var > portfolio _brain walk-up > global > claude)
|
|
156
|
+
const detected = resolveBrain(projectDir, homeDir);
|
|
157
|
+
|
|
158
|
+
let linkedBrain;
|
|
159
|
+
if (detected) {
|
|
160
|
+
clack.log.info(`🧠 Existing brain detected (${detected.type}): ${detected.dir}`);
|
|
161
|
+
linkedBrain = detected;
|
|
162
|
+
} else {
|
|
163
|
+
ensureGlobalBrain(globalBrainRoot, templateDir, userName, commLang);
|
|
164
|
+
clack.log.info(`🧠 Global brain created: ${globalBrainRoot}`);
|
|
165
|
+
linkedBrain = { dir: globalBrainRoot, type: 'bmad-global' };
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
// Write the brain link pointer in EVERY case — including first-ever creation,
|
|
169
|
+
// so a fresh machine's first install is linked exactly like the second one.
|
|
170
|
+
fs.writeFileSync(
|
|
171
|
+
path.join(memoryDir, '.brain-link'),
|
|
172
|
+
JSON.stringify(
|
|
173
|
+
{ linked_brain: linkedBrain.dir, brain_type: linkedBrain.type, linked_at: new Date().toISOString() },
|
|
174
|
+
null,
|
|
175
|
+
2
|
|
176
|
+
),
|
|
177
|
+
'utf8'
|
|
178
|
+
);
|
|
179
|
+
|
|
180
|
+
// Index this project in the global brain — only when the global brain IS the
|
|
181
|
+
// linked brain. Portfolio and claude-memory brains keep their own registries
|
|
182
|
+
// (see pack-memory/shared/memory-protocol.md); writing into ~/.bmad-plus from
|
|
183
|
+
// those installs is what used to create orphaned "half brains".
|
|
184
|
+
if (linkedBrain.type === 'bmad-global') {
|
|
185
|
+
ensureGlobalBrain(globalBrainRoot, templateDir, userName, commLang);
|
|
186
|
+
const projHash = projectHash(projectDir);
|
|
187
|
+
const projMeta = {
|
|
188
|
+
path: projectDir,
|
|
189
|
+
name: path.basename(projectDir),
|
|
190
|
+
hash: projHash,
|
|
191
|
+
status: 'active',
|
|
192
|
+
bmad_installed: true,
|
|
193
|
+
packs_installed: selectedPacks,
|
|
194
|
+
last_scanned: new Date().toISOString().slice(0, 10),
|
|
195
|
+
};
|
|
196
|
+
fs.writeFileSync(
|
|
197
|
+
path.join(globalBrainRoot, 'projects', `${projHash}.yaml`),
|
|
198
|
+
Object.entries(projMeta).map(([k, v]) => `${k}: ${JSON.stringify(v)}`).join('\n'),
|
|
199
|
+
'utf8'
|
|
200
|
+
);
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
module.exports = { initMemory, resolveBrain, ensureGlobalBrain };
|