bmad-plus 0.3.3 → 0.4.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.
Files changed (62) hide show
  1. package/CHANGELOG.md +34 -0
  2. package/README.md +12 -56
  3. package/osint-agent-package/skills/bmad-osint-investigate/osint/SKILL.md +452 -452
  4. package/osint-agent-package/skills/bmad-osint-investigate/osint/assets/dossier-template.md +116 -116
  5. package/osint-agent-package/skills/bmad-osint-investigate/osint/references/content-extraction.md +100 -100
  6. package/osint-agent-package/skills/bmad-osint-investigate/osint/references/platforms.md +130 -130
  7. package/osint-agent-package/skills/bmad-osint-investigate/osint/references/psychoprofile.md +69 -69
  8. package/osint-agent-package/skills/bmad-osint-investigate/osint/references/tools.md +281 -281
  9. package/osint-agent-package/skills/bmad-osint-investigate/osint/scripts/mcp-client.py +136 -136
  10. package/package.json +1 -1
  11. package/readme-international/README.de.md +1 -1
  12. package/readme-international/README.es.md +1 -1
  13. package/readme-international/README.fr.md +1 -1
  14. package/tools/cli/commands/install.js +74 -46
  15. package/tools/cli/i18n.js +501 -0
  16. package/oveanet-pack/animated-website/DEPLOYMENT.md +0 -104
  17. package/oveanet-pack/animated-website/README.md +0 -63
  18. package/oveanet-pack/animated-website/agent/animated-website-agent.md +0 -325
  19. package/oveanet-pack/animated-website/agent.yaml +0 -63
  20. package/oveanet-pack/animated-website/templates/animated-website-workflow.md +0 -55
  21. package/oveanet-pack/seo-audit-360/DEPLOYMENT.md +0 -115
  22. package/oveanet-pack/seo-audit-360/README.md +0 -66
  23. package/oveanet-pack/seo-audit-360/SKILL.md +0 -171
  24. package/oveanet-pack/seo-audit-360/agent/seo-chief.md +0 -294
  25. package/oveanet-pack/seo-audit-360/agent/seo-judge.md +0 -241
  26. package/oveanet-pack/seo-audit-360/agent/seo-scout.md +0 -171
  27. package/oveanet-pack/seo-audit-360/agent.yaml +0 -70
  28. package/oveanet-pack/seo-audit-360/checklist.md +0 -140
  29. package/oveanet-pack/seo-audit-360/hooks/seo-check.sh +0 -95
  30. package/oveanet-pack/seo-audit-360/pagespeed-playbook.md +0 -320
  31. package/oveanet-pack/seo-audit-360/ref/audit-schema.json +0 -187
  32. package/oveanet-pack/seo-audit-360/ref/cwv-thresholds.md +0 -87
  33. package/oveanet-pack/seo-audit-360/ref/eeat-criteria.md +0 -123
  34. package/oveanet-pack/seo-audit-360/ref/geo-signals.md +0 -167
  35. package/oveanet-pack/seo-audit-360/ref/hreflang-rules.md +0 -153
  36. package/oveanet-pack/seo-audit-360/ref/quality-gates.md +0 -133
  37. package/oveanet-pack/seo-audit-360/ref/schema-catalog.md +0 -91
  38. package/oveanet-pack/seo-audit-360/ref/schema-templates.json +0 -356
  39. package/oveanet-pack/seo-audit-360/requirements.txt +0 -14
  40. package/oveanet-pack/seo-audit-360/scripts/__pycache__/seo_crawl.cpython-314.pyc +0 -0
  41. package/oveanet-pack/seo-audit-360/scripts/__pycache__/seo_parse.cpython-314.pyc +0 -0
  42. package/oveanet-pack/seo-audit-360/scripts/install.ps1 +0 -53
  43. package/oveanet-pack/seo-audit-360/scripts/install.sh +0 -48
  44. package/oveanet-pack/seo-audit-360/scripts/seo_apis.py +0 -464
  45. package/oveanet-pack/seo-audit-360/scripts/seo_crawl.py +0 -282
  46. package/oveanet-pack/seo-audit-360/scripts/seo_fetch.py +0 -231
  47. package/oveanet-pack/seo-audit-360/scripts/seo_parse.py +0 -255
  48. package/oveanet-pack/seo-audit-360/scripts/seo_report.py +0 -403
  49. package/oveanet-pack/seo-audit-360/scripts/seo_screenshot.py +0 -202
  50. package/oveanet-pack/seo-audit-360/templates/seo-audit-workflow.md +0 -241
  51. package/oveanet-pack/seo-audit-360/tests/__pycache__/test_crawl.cpython-314-pytest-9.0.2.pyc +0 -0
  52. package/oveanet-pack/seo-audit-360/tests/__pycache__/test_parse.cpython-314-pytest-9.0.2.pyc +0 -0
  53. package/oveanet-pack/seo-audit-360/tests/fixtures/sample_page.html +0 -62
  54. package/oveanet-pack/seo-audit-360/tests/test_apis.py +0 -75
  55. package/oveanet-pack/seo-audit-360/tests/test_crawl.py +0 -121
  56. package/oveanet-pack/seo-audit-360/tests/test_fetch.py +0 -70
  57. package/oveanet-pack/seo-audit-360/tests/test_parse.py +0 -184
  58. package/oveanet-pack/universal-backup/DEPLOYMENT.md +0 -80
  59. package/oveanet-pack/universal-backup/README.md +0 -58
  60. package/oveanet-pack/universal-backup/agent/backup-agent.md +0 -71
  61. package/oveanet-pack/universal-backup/agent.yaml +0 -45
  62. package/oveanet-pack/universal-backup/templates/backup-workflow.md +0 -51
@@ -1,136 +1,136 @@
1
- #!/usr/bin/env python3
2
- """Lightweight MCP client for Streamable HTTP/SSE transport.
3
-
4
- Usage:
5
- python3 mcp-client.py <mcp_url> --list-tools
6
- python3 mcp-client.py <mcp_url> <tool_name> '<json_args>'
7
- """
8
-
9
- import json
10
- import sys
11
- import http.client
12
- from urllib.parse import urlparse, urlencode
13
-
14
-
15
- def mcp_request(url: str, method: str, params: dict | None = None,
16
- req_id: int = 1, session_id: str | None = None) -> tuple[dict, str | None]:
17
- """Send MCP JSON-RPC request and parse SSE response. Returns (result, session_id)."""
18
- parsed = urlparse(url)
19
-
20
- payload = {
21
- "jsonrpc": "2.0",
22
- "id": req_id,
23
- "method": method,
24
- }
25
- if params:
26
- payload["params"] = params
27
-
28
- data = json.dumps(payload).encode()
29
-
30
- headers = {
31
- "Content-Type": "application/json",
32
- "Accept": "application/json, text/event-stream",
33
- }
34
- if session_id:
35
- headers["Mcp-Session-Id"] = session_id
36
-
37
- conn = http.client.HTTPSConnection(parsed.hostname, timeout=120)
38
- path = parsed.path
39
- if parsed.query:
40
- path += "?" + parsed.query
41
-
42
- conn.request("POST", path, body=data, headers=headers)
43
- resp = conn.getresponse()
44
-
45
- # Get session ID from response headers
46
- new_session_id = resp.getheader("Mcp-Session-Id") or session_id
47
-
48
- body = resp.read().decode()
49
- conn.close()
50
-
51
- if resp.status >= 400:
52
- return {"error": f"HTTP {resp.status}: {body[:200]}"}, new_session_id
53
-
54
- # Parse SSE: look for data: lines
55
- for line in body.split("\n"):
56
- if line.startswith("data: "):
57
- try:
58
- return json.loads(line[6:]), new_session_id
59
- except json.JSONDecodeError:
60
- continue
61
-
62
- # Try direct JSON
63
- try:
64
- return json.loads(body), new_session_id
65
- except json.JSONDecodeError:
66
- return {"raw": body[:500]}, new_session_id
67
-
68
-
69
- def init_and_call(url: str, method: str, params: dict | None = None) -> dict:
70
- """Initialize session then make a call."""
71
- # Step 1: Initialize
72
- init_result, session_id = mcp_request(url, "initialize", {
73
- "protocolVersion": "2024-11-05",
74
- "capabilities": {},
75
- "clientInfo": {"name": "osint-skill", "version": "3.1"},
76
- }, req_id=1)
77
-
78
- if "error" in init_result:
79
- return init_result
80
-
81
- # Step 2: Send initialized notification (optional but polite)
82
- # Step 3: Make actual call
83
- result, _ = mcp_request(url, method, params, req_id=2, session_id=session_id)
84
- return result
85
-
86
-
87
- def list_tools(url: str) -> list:
88
- """List available tools on MCP server."""
89
- result = init_and_call(url, "tools/list")
90
- tools = result.get("result", {}).get("tools", [])
91
- return tools
92
-
93
-
94
- def call_tool(url: str, tool_name: str, arguments: dict) -> dict:
95
- """Call a specific tool on MCP server."""
96
- result = init_and_call(url, "tools/call", {
97
- "name": tool_name,
98
- "arguments": arguments,
99
- })
100
- return result
101
-
102
-
103
- def main():
104
- if len(sys.argv) < 3:
105
- print(__doc__)
106
- sys.exit(1)
107
-
108
- url = sys.argv[1]
109
-
110
- if sys.argv[2] == "--list-tools":
111
- tools = list_tools(url)
112
- if not tools:
113
- print("No tools found or error occurred")
114
- return
115
- for t in tools:
116
- desc = t.get("description", "")[:100]
117
- print(f" {t['name']}: {desc}")
118
- return
119
-
120
- tool_name = sys.argv[2]
121
- args = json.loads(sys.argv[3]) if len(sys.argv) > 3 else {}
122
-
123
- result = call_tool(url, tool_name, args)
124
-
125
- # Extract content from MCP response
126
- content = result.get("result", {}).get("content", [])
127
- if content:
128
- for item in content:
129
- if item.get("type") == "text":
130
- print(item["text"])
131
- else:
132
- print(json.dumps(result, indent=2, ensure_ascii=False))
133
-
134
-
135
- if __name__ == "__main__":
136
- main()
1
+ #!/usr/bin/env python3
2
+ """Lightweight MCP client for Streamable HTTP/SSE transport.
3
+
4
+ Usage:
5
+ python3 mcp-client.py <mcp_url> --list-tools
6
+ python3 mcp-client.py <mcp_url> <tool_name> '<json_args>'
7
+ """
8
+
9
+ import json
10
+ import sys
11
+ import http.client
12
+ from urllib.parse import urlparse, urlencode
13
+
14
+
15
+ def mcp_request(url: str, method: str, params: dict | None = None,
16
+ req_id: int = 1, session_id: str | None = None) -> tuple[dict, str | None]:
17
+ """Send MCP JSON-RPC request and parse SSE response. Returns (result, session_id)."""
18
+ parsed = urlparse(url)
19
+
20
+ payload = {
21
+ "jsonrpc": "2.0",
22
+ "id": req_id,
23
+ "method": method,
24
+ }
25
+ if params:
26
+ payload["params"] = params
27
+
28
+ data = json.dumps(payload).encode()
29
+
30
+ headers = {
31
+ "Content-Type": "application/json",
32
+ "Accept": "application/json, text/event-stream",
33
+ }
34
+ if session_id:
35
+ headers["Mcp-Session-Id"] = session_id
36
+
37
+ conn = http.client.HTTPSConnection(parsed.hostname, timeout=120)
38
+ path = parsed.path
39
+ if parsed.query:
40
+ path += "?" + parsed.query
41
+
42
+ conn.request("POST", path, body=data, headers=headers)
43
+ resp = conn.getresponse()
44
+
45
+ # Get session ID from response headers
46
+ new_session_id = resp.getheader("Mcp-Session-Id") or session_id
47
+
48
+ body = resp.read().decode()
49
+ conn.close()
50
+
51
+ if resp.status >= 400:
52
+ return {"error": f"HTTP {resp.status}: {body[:200]}"}, new_session_id
53
+
54
+ # Parse SSE: look for data: lines
55
+ for line in body.split("\n"):
56
+ if line.startswith("data: "):
57
+ try:
58
+ return json.loads(line[6:]), new_session_id
59
+ except json.JSONDecodeError:
60
+ continue
61
+
62
+ # Try direct JSON
63
+ try:
64
+ return json.loads(body), new_session_id
65
+ except json.JSONDecodeError:
66
+ return {"raw": body[:500]}, new_session_id
67
+
68
+
69
+ def init_and_call(url: str, method: str, params: dict | None = None) -> dict:
70
+ """Initialize session then make a call."""
71
+ # Step 1: Initialize
72
+ init_result, session_id = mcp_request(url, "initialize", {
73
+ "protocolVersion": "2024-11-05",
74
+ "capabilities": {},
75
+ "clientInfo": {"name": "osint-skill", "version": "3.1"},
76
+ }, req_id=1)
77
+
78
+ if "error" in init_result:
79
+ return init_result
80
+
81
+ # Step 2: Send initialized notification (optional but polite)
82
+ # Step 3: Make actual call
83
+ result, _ = mcp_request(url, method, params, req_id=2, session_id=session_id)
84
+ return result
85
+
86
+
87
+ def list_tools(url: str) -> list:
88
+ """List available tools on MCP server."""
89
+ result = init_and_call(url, "tools/list")
90
+ tools = result.get("result", {}).get("tools", [])
91
+ return tools
92
+
93
+
94
+ def call_tool(url: str, tool_name: str, arguments: dict) -> dict:
95
+ """Call a specific tool on MCP server."""
96
+ result = init_and_call(url, "tools/call", {
97
+ "name": tool_name,
98
+ "arguments": arguments,
99
+ })
100
+ return result
101
+
102
+
103
+ def main():
104
+ if len(sys.argv) < 3:
105
+ print(__doc__)
106
+ sys.exit(1)
107
+
108
+ url = sys.argv[1]
109
+
110
+ if sys.argv[2] == "--list-tools":
111
+ tools = list_tools(url)
112
+ if not tools:
113
+ print("No tools found or error occurred")
114
+ return
115
+ for t in tools:
116
+ desc = t.get("description", "")[:100]
117
+ print(f" {t['name']}: {desc}")
118
+ return
119
+
120
+ tool_name = sys.argv[2]
121
+ args = json.loads(sys.argv[3]) if len(sys.argv) > 3 else {}
122
+
123
+ result = call_tool(url, tool_name, args)
124
+
125
+ # Extract content from MCP response
126
+ content = result.get("result", {}).get("content", [])
127
+ if content:
128
+ for item in content:
129
+ if item.get("type") == "text":
130
+ print(item["text"])
131
+ else:
132
+ print(json.dumps(result, indent=2, ensure_ascii=False))
133
+
134
+
135
+ if __name__ == "__main__":
136
+ main()
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.3.3",
4
+ "version": "0.4.1",
5
5
  "description": "BMAD+ — Augmented AI-Driven Development Framework with multi-role agents, autopilot, and parallel execution",
6
6
  "keywords": [
7
7
  "bmad",
@@ -1,6 +1,6 @@
1
1
  # 🚀 BMAD+ — Erweitertes KI-gestütztes Entwicklungs-Framework
2
2
 
3
- [![Version](https://img.shields.io/badge/version-0.1.0-blue.svg)](../CHANGELOG.md)
3
+ [![Version](https://img.shields.io/badge/version-0.4.1-blue.svg)](../CHANGELOG.md)
4
4
  [![Based on](https://img.shields.io/badge/based%20on-BMAD--METHOD%20v6.2.0-green.svg)](https://github.com/bmad-code-org/BMAD-METHOD)
5
5
  [![License](https://img.shields.io/badge/license-MIT-yellow.svg)](../LICENSE)
6
6
 
@@ -1,6 +1,6 @@
1
1
  # 🚀 BMAD+ — Framework de Desarrollo Impulsado por IA Aumentada
2
2
 
3
- [![Version](https://img.shields.io/badge/version-0.1.0-blue.svg)](../CHANGELOG.md)
3
+ [![Version](https://img.shields.io/badge/version-0.4.1-blue.svg)](../CHANGELOG.md)
4
4
  [![Based on](https://img.shields.io/badge/based%20on-BMAD--METHOD%20v6.2.0-green.svg)](https://github.com/bmad-code-org/BMAD-METHOD)
5
5
  [![License](https://img.shields.io/badge/license-MIT-yellow.svg)](../LICENSE)
6
6
 
@@ -1,6 +1,6 @@
1
1
  # 🚀 BMAD+ — Augmented AI-Driven Development Framework
2
2
 
3
- [![Version](https://img.shields.io/badge/version-0.1.0-blue.svg)](../CHANGELOG.md)
3
+ [![Version](https://img.shields.io/badge/version-0.4.1-blue.svg)](../CHANGELOG.md)
4
4
  [![Based on](https://img.shields.io/badge/based%20on-BMAD--METHOD%20v6.2.0-green.svg)](https://github.com/bmad-code-org/BMAD-METHOD)
5
5
  [![License](https://img.shields.io/badge/license-MIT-yellow.svg)](../LICENSE)
6
6
 
@@ -1,6 +1,9 @@
1
1
  /**
2
2
  * BMAD+ Install Command
3
3
  * Installs agents, skills, and IDE configs into the current project
4
+ * Supports 9 languages: EN, FR, ES, DE, PT-BR, RU, ZH, HE, JA
5
+ *
6
+ * Author: Laurent Rochetta
4
7
  */
5
8
 
6
9
  const path = require('node:path');
@@ -8,6 +11,7 @@ const fs = require('node:fs');
8
11
  const fsExtra = require('fs-extra');
9
12
  const clack = require('@clack/prompts');
10
13
  const pc = require('picocolors');
14
+ const { t, getLanguageOptions, getCommLanguageOptions } = require('../i18n');
11
15
 
12
16
  // Pack definitions
13
17
  const PACKS = {
@@ -113,17 +117,33 @@ module.exports = {
113
117
  const projectDir = path.resolve(options.directory || process.cwd());
114
118
  const bmadSrc = path.join(__dirname, '..', '..', '..', 'src', 'bmad-plus');
115
119
 
116
- // ── Intro ──
117
- clack.intro(pc.bgCyan(pc.black(' BMAD+ Installer v0.1.0 ')));
120
+ // ── Step 0: Language Selection ──
121
+ clack.intro(pc.bgCyan(pc.black(' BMAD+ Installer v0.4.1 ')));
122
+
123
+ let lang = 'en';
124
+ if (!options.yes) {
125
+ const langChoice = await clack.select({
126
+ message: '🌐 Select your language / Choisissez votre langue / 选择语言',
127
+ options: getLanguageOptions(),
128
+ });
129
+
130
+ if (clack.isCancel(langChoice)) {
131
+ clack.cancel('Installation cancelled.');
132
+ process.exit(0);
133
+ }
134
+ lang = langChoice;
135
+ }
136
+
137
+ const i = t(lang); // Get translations for selected language
118
138
 
119
139
  // Verify source exists
120
140
  if (!fs.existsSync(bmadSrc)) {
121
- clack.log.error(`Source directory not found: ${bmadSrc}`);
122
- clack.outro(pc.red('Installation failed.'));
141
+ clack.log.error(`${i.source_not_found}: ${bmadSrc}`);
142
+ clack.outro(pc.red(i.failed));
123
143
  process.exit(1);
124
144
  }
125
145
 
126
- clack.log.info(`Installing to: ${pc.cyan(projectDir)}`);
146
+ clack.log.info(`${i.installing_to}: ${pc.cyan(projectDir)}`);
127
147
 
128
148
  // ── Step 1: Pack Selection ──
129
149
  let selectedPacks = ['core']; // Core always included
@@ -137,27 +157,27 @@ module.exports = {
137
157
  }
138
158
  } else if (!options.yes) {
139
159
  const packChoice = await clack.multiselect({
140
- message: 'Quels packs installer ? (Core est toujours inclus)',
160
+ message: i.select_packs,
141
161
  options: Object.entries(PACKS)
142
162
  .filter(([, p]) => !p.required)
143
163
  .map(([key, pack]) => ({
144
164
  value: key,
145
165
  label: `${pack.icon} ${pack.name}`,
146
- hint: pack.disabled ? 'bientôt' : pack.description,
166
+ hint: pack.disabled ? i.soon : pack.description,
147
167
  disabled: pack.disabled,
148
168
  })),
149
169
  required: false,
150
170
  });
151
171
 
152
172
  if (clack.isCancel(packChoice)) {
153
- clack.cancel('Installation annulée.');
173
+ clack.cancel(i.cancelled);
154
174
  process.exit(0);
155
175
  }
156
176
 
157
177
  selectedPacks = [...new Set(['core', ...packChoice])];
158
178
  }
159
179
 
160
- clack.log.success(`Packs sélectionnés: ${selectedPacks.map(p => `${PACKS[p].icon} ${PACKS[p].name}`).join(', ')}`);
180
+ clack.log.success(`${i.selected_packs}: ${selectedPacks.map(p => `${PACKS[p].icon} ${PACKS[p].name}`).join(', ')}`);
161
181
 
162
182
  // ── Step 2: IDE Detection ──
163
183
  let detectedIDEs = [];
@@ -178,7 +198,7 @@ module.exports = {
178
198
  // If nothing detected, ask
179
199
  if (detectedIDEs.length === 0 && !options.yes) {
180
200
  const ideChoice = await clack.multiselect({
181
- message: 'Quels IDE utilises-tu ?',
201
+ message: i.select_ide,
182
202
  options: Object.entries(IDE_CONFIGS).map(([key, ide]) => ({
183
203
  value: key,
184
204
  label: ide.name,
@@ -198,7 +218,7 @@ module.exports = {
198
218
  }
199
219
 
200
220
  if (detectedIDEs.length > 0) {
201
- clack.log.info(`IDE détectés: ${detectedIDEs.map(id => IDE_CONFIGS[id].name).join(', ')}`);
221
+ clack.log.info(`${i.detected_ides}: ${detectedIDEs.map(id => IDE_CONFIGS[id].name).join(', ')}`);
202
222
  }
203
223
 
204
224
  // ── Step 3: User Config ──
@@ -208,31 +228,26 @@ module.exports = {
208
228
  if (!options.yes) {
209
229
  const userConfig = await clack.group({
210
230
  userName: () => clack.text({
211
- message: 'Ton prénom (les agents l\'utilisent pour te saluer)',
231
+ message: i.enter_name,
212
232
  placeholder: userName,
213
233
  defaultValue: userName,
214
234
  }),
215
235
  commLang: () => clack.select({
216
- message: 'Langue de communication',
217
- options: [
218
- { value: 'French', label: '🇫🇷 Français' },
219
- { value: 'English', label: '🇬🇧 English' },
220
- { value: 'German', label: '🇩🇪 Deutsch' },
221
- { value: 'Spanish', label: '🇪🇸 Español' },
222
- ],
236
+ message: i.comm_language,
237
+ options: getCommLanguageOptions(),
223
238
  }),
224
239
  execMode: () => clack.select({
225
- message: 'Mode d\'exécution',
240
+ message: i.exec_mode,
226
241
  options: [
227
- { value: 'manual', label: 'Manuel — Tu appelles les agents toi-même' },
228
- { value: 'autopilot', label: 'Autopilot — Nexus gère tout le pipeline' },
229
- { value: 'hybrid', label: 'Hybride — Autopilot avec checkpoints fréquents' },
242
+ { value: 'manual', label: i.exec_manual },
243
+ { value: 'autopilot', label: i.exec_autopilot },
244
+ { value: 'hybrid', label: i.exec_hybrid },
230
245
  ],
231
246
  }),
232
247
  });
233
248
 
234
249
  if (clack.isCancel(userConfig)) {
235
- clack.cancel('Installation annulée.');
250
+ clack.cancel(i.cancelled);
236
251
  process.exit(0);
237
252
  }
238
253
 
@@ -242,7 +257,7 @@ module.exports = {
242
257
 
243
258
  // ── Step 4: Install Files ──
244
259
  const spinner = clack.spinner();
245
- spinner.start('Installation des fichiers...');
260
+ spinner.start(i.installing_files);
246
261
 
247
262
  const targetAgentsDir = path.join(projectDir, '.agents', 'skills');
248
263
  const targetDataDir = path.join(projectDir, '.agents', 'data');
@@ -325,12 +340,12 @@ module.exports = {
325
340
  copiedFiles++;
326
341
  }
327
342
 
328
- spinner.stop(`✅ ${copiedAgents} agents, ${copiedSkills} skills, ${copiedFiles} fichiers copiés`);
343
+ spinner.stop(i.installed_summary(copiedAgents, copiedSkills, copiedFiles));
329
344
 
330
345
  // ── Step 5: Generate IDE Configs ──
331
346
  if (detectedIDEs.length > 0) {
332
347
  const ideSpinner = clack.spinner();
333
- ideSpinner.start('Configuration des IDE...');
348
+ ideSpinner.start(i.configuring_ides);
334
349
 
335
350
  const configContent = generateIDEConfig(userName, commLang, selectedPacks);
336
351
 
@@ -342,7 +357,7 @@ module.exports = {
342
357
  fs.writeFileSync(configPath, configContent, 'utf8');
343
358
  }
344
359
 
345
- ideSpinner.stop(`✅ ${detectedIDEs.length} IDE configuré(s)`);
360
+ ideSpinner.stop(i.ide_configured(detectedIDEs.length));
346
361
  }
347
362
 
348
363
  // ── Step 6: Create config.yaml ──
@@ -358,7 +373,8 @@ module.exports = {
358
373
 
359
374
  // ── Step 8: Write install manifest ──
360
375
  const manifest = {
361
- version: '0.1.0',
376
+ version: '0.4.0',
377
+ uiLanguage: lang,
362
378
  installed: new Date().toISOString(),
363
379
  packs: selectedPacks,
364
380
  ides: detectedIDEs,
@@ -373,43 +389,55 @@ module.exports = {
373
389
 
374
390
  // ── Summary — Contextual Getting Started ──
375
391
  const agentGuide = [
376
- '💬 À qui parler ?',
392
+ i.guide_who,
377
393
  '',
378
- ' Discuter d\'une idée → "Atlas, j\'ai une idée de projet : [...]"',
379
- ' Créer un PRD → "Atlas, crée le PRD"',
380
- ' Architecture technique → "Forge, propose une architecture"',
381
- ' Implémenter du code → "Forge, implémente la story [X]"',
382
- ' Tester / code review → "Sentinel, review le module [X]"',
383
- ' Planifier un sprint → "Nexus, crée les epics et stories"',
384
- ' Tout automatiser → "autopilot" puis décris ton projet',
394
+ ` ${i.guide_idea.padEnd(28)} → "Atlas, [...]"`,
395
+ ` ${i.guide_prd.padEnd(28)} → "Atlas, create PRD"`,
396
+ ` ${i.guide_arch.padEnd(28)} → "Forge, propose architecture"`,
397
+ ` ${i.guide_code.padEnd(28)} → "Forge, implement story [X]"`,
398
+ ` ${i.guide_test.padEnd(28)} → "Sentinel, review module [X]"`,
399
+ ` ${i.guide_sprint.padEnd(28)} → "Nexus, create epics"`,
400
+ ` ${i.guide_auto.padEnd(28)} → "autopilot"`,
385
401
  ];
386
402
 
387
403
  if (selectedPacks.includes('osint')) {
388
- agentGuide.push(' Investigation OSINT → "Shadow, investigate [nom]"');
404
+ agentGuide.push(` ${i.guide_osint.padEnd(28)} → "Shadow, investigate [name]"`);
389
405
  }
390
406
 
391
407
  if (selectedPacks.includes('maker')) {
392
- agentGuide.push(' Créer un nouvel agent → "Maker, crée un agent [description]"');
408
+ agentGuide.push(` ${i.guide_maker.padEnd(28)} → "Maker, create agent [desc]"`);
409
+ }
410
+
411
+ if (selectedPacks.includes('seo')) {
412
+ agentGuide.push(` ${i.guide_seo.padEnd(28)} → "/seo audit <url>"`);
413
+ }
414
+
415
+ if (selectedPacks.includes('backup')) {
416
+ agentGuide.push(` ${i.guide_backup.padEnd(28)} → "/backup create"`);
417
+ }
418
+
419
+ if (selectedPacks.includes('animated')) {
420
+ agentGuide.push(` ${i.guide_animated.padEnd(28)} → "/animated build <video>"`);
393
421
  }
394
422
 
395
423
  agentGuide.push(
396
424
  '',
397
- '🚀 Workflow recommandé:',
398
- ' 1. Atlas (idée → brief → PRD)',
425
+ i.guide_workflow,
426
+ ' 1. Atlas (idea → brief → PRD)',
399
427
  ' 2. Forge (architecture → code)',
400
428
  ' 3. Sentinel (tests → review)',
401
429
  '',
402
- '⚡ Ou: "autopilot" pour tout gérer automatiquement',
430
+ i.guide_or_auto,
403
431
  '',
404
- `📁 Output: _bmad-output/discovery/ et _bmad-output/build/`,
432
+ `${i.guide_output}: _bmad-output/discovery/ & _bmad-output/build/`,
405
433
  '',
406
434
  '---',
407
- '✨ BMAD+ is created by Laurent Rochetta — github.com/lrochetta | linkedin.com/in/laurentrochetta ✨'
435
+ i.guide_credits
408
436
  );
409
437
 
410
- clack.note(agentGuide.join('\n'), '✅ Installation terminée — Comment commencer');
438
+ clack.note(agentGuide.join('\n'), i.guide_title);
411
439
 
412
- clack.outro(pc.green('BMAD+ est prêt! Parle à Atlas pour commencer 🚀'));
440
+ clack.outro(pc.green(i.guide_ready));
413
441
  },
414
442
  };
415
443