bmad-plus 0.14.0 → 0.16.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/CHANGELOG.md +52 -0
- package/README.md +34 -15
- package/SECURITY.md +71 -0
- package/THIRD-PARTY-LICENSES.md +349 -0
- package/osint-agent-package/README.md +1 -1
- package/package.json +9 -3
- package/readme-international/README.de.md +14 -8
- package/readme-international/README.es.md +15 -9
- package/readme-international/README.fr.md +14 -8
- package/src/bmad-plus/agents/agent-architect-dev/SKILL.md +11 -13
- package/src/bmad-plus/agents/agent-orchestrator/SKILL.md +147 -8
- package/src/bmad-plus/agents/agent-quality/SKILL.md +41 -11
- package/src/bmad-plus/data/role-triggers.yaml +19 -0
- package/src/bmad-plus/module-help.csv +1 -0
- package/src/bmad-plus/module.yaml +1 -0
- package/src/bmad-plus/packs/pack-dev-studio/categories/implementation/create-story.md +3 -1
- package/src/bmad-plus/packs/pack-dev-studio/categories/implementation/dev-story-checklist.md +2 -0
- package/src/bmad-plus/packs/pack-dev-studio/categories/implementation/dev-story.md +5 -1
- package/src/bmad-plus/packs/pack-memory/README.md +29 -4
- package/src/bmad-plus/packs/pack-memory/memory-orchestrator.md +21 -1
- package/src/bmad-plus/packs/pack-memory/shared/karpathy-guardrails.md +3 -3
- package/src/bmad-plus/packs/pack-memory/shared/memory-protocol.md +27 -3
- package/src/bmad-plus/packs/pack-memory/zecher-agent.md +18 -2
- package/src/bmad-plus/skills/bmad-plus-autopilot/SKILL.md +47 -10
- package/src/bmad-plus/skills/bmad-plus-parallel/SKILL.md +17 -3
- package/src/bmad-plus/skills/bmad-plus-sync/SKILL.md +76 -67
- package/src/bmad-plus/skills/bmad-plus-uat/SKILL.md +144 -0
- package/src/bmad-plus/skills/bmad-plus-uat/ref/uat-results.schema.json +60 -0
- package/src/bmad-plus/skills/bmad-plus-uat/ref/uat-spec.schema.json +121 -0
- package/src/bmad-plus/skills/bmad-plus-uat/ref/uat-triage.schema.json +60 -0
- package/src/bmad-plus/skills/bmad-plus-uat/template/page.html +552 -0
- package/src/bmad-plus/skills/bmad-plus-uat/template/strings.json +362 -0
- package/tools/build/check-install-contract.js +202 -4
- package/tools/build/generate.js +16 -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/bmad-plus-cli.js +15 -12
- package/tools/cli/commands/doctor.js +1 -0
- package/tools/cli/commands/install.js +21 -2
- package/tools/cli/commands/memory-journal-cmd.js +119 -19
- package/tools/cli/commands/nexus.js +111 -0
- package/tools/cli/commands/uat.js +389 -0
- package/tools/cli/lib/README-memory-journal.md +19 -8
- package/tools/cli/lib/installation-health.js +6 -0
- package/tools/cli/lib/memory-journal.js +0 -0
- package/tools/cli/lib/memory-outcomes.js +293 -0
- package/tools/cli/lib/memory-store.js +139 -0
- package/tools/cli/lib/nexus-process.js +377 -0
- package/tools/cli/lib/nexus.js +1532 -0
- package/tools/cli/lib/pack-copy.js +39 -11
- package/tools/cli/lib/packs.js +17 -3
- package/tools/cli/lib/uat.js +869 -0
- package/tools/maintain/upstream-candidate.js +456 -0
- package/tools/release/publication-content.js +3 -1
- package/tools/release/supply-chain.js +282 -0
|
@@ -0,0 +1,362 @@
|
|
|
1
|
+
{
|
|
2
|
+
"en": {
|
|
3
|
+
"name": "English",
|
|
4
|
+
"dir": "ltr",
|
|
5
|
+
"uiLanguage": "Page language",
|
|
6
|
+
"before": "Before you start",
|
|
7
|
+
"tester": "Your first name — it signs this run",
|
|
8
|
+
"start": "Start a new run",
|
|
9
|
+
"resume": "Or resume a run already started",
|
|
10
|
+
"stepsLabel": "steps",
|
|
11
|
+
"seen": "Seen",
|
|
12
|
+
"notSeen": "Not seen",
|
|
13
|
+
"blocked": "Blocked",
|
|
14
|
+
"skip": "Skip this optional step",
|
|
15
|
+
"optional": "Optional step",
|
|
16
|
+
"where": "Where",
|
|
17
|
+
"doIt": "Do",
|
|
18
|
+
"expect": "What you must see — tick every line",
|
|
19
|
+
"note": "What you see instead, or any remark (word for word if you can)",
|
|
20
|
+
"whyNot": "What did you see instead?",
|
|
21
|
+
"todo": "to do",
|
|
22
|
+
"finish": "Finish",
|
|
23
|
+
"finishRun": "Finish this run",
|
|
24
|
+
"finished": "Run finished",
|
|
25
|
+
"overall": "Overall remarks",
|
|
26
|
+
"saveJson": "Save the JSON on my device",
|
|
27
|
+
"copyJson": "Copy the JSON",
|
|
28
|
+
"copied": "JSON copied.",
|
|
29
|
+
"confirmUnanswered": "{n} line(s) are not ticked. Finish anyway?",
|
|
30
|
+
"writesWarning": "This step writes for real on",
|
|
31
|
+
"intended": "It is intended.",
|
|
32
|
+
"savedLocal": "Saved in this browser — remember to save the JSON at the end",
|
|
33
|
+
"savedRemote": "Saved ·",
|
|
34
|
+
"localMode": "This page is a local file: at the end, save the JSON and hand the file over — that is what the agent reads.",
|
|
35
|
+
"dbMode": "Your answers are saved as you go; the agent reads them directly, you have nothing to send.",
|
|
36
|
+
"serveMode": "Your answers are saved straight into the project as you tick; you have nothing to send."
|
|
37
|
+
},
|
|
38
|
+
"fr": {
|
|
39
|
+
"name": "Français",
|
|
40
|
+
"dir": "ltr",
|
|
41
|
+
"uiLanguage": "Langue de la page",
|
|
42
|
+
"before": "Avant de commencer",
|
|
43
|
+
"tester": "Ton prénom — il signe la recette",
|
|
44
|
+
"start": "Commencer une nouvelle recette",
|
|
45
|
+
"resume": "Ou reprendre une recette déjà commencée",
|
|
46
|
+
"stepsLabel": "étapes",
|
|
47
|
+
"seen": "Vu",
|
|
48
|
+
"notSeen": "Pas vu",
|
|
49
|
+
"blocked": "Bloqué",
|
|
50
|
+
"skip": "Sauter cette étape facultative",
|
|
51
|
+
"optional": "Étape facultative",
|
|
52
|
+
"where": "Où",
|
|
53
|
+
"doIt": "Fais",
|
|
54
|
+
"expect": "Ce que tu dois voir — coche chaque ligne",
|
|
55
|
+
"note": "Ce que tu vois à la place, ou toute remarque (mot pour mot si possible)",
|
|
56
|
+
"whyNot": "Qu'est-ce que tu vois à la place ?",
|
|
57
|
+
"todo": "à faire",
|
|
58
|
+
"finish": "Terminer",
|
|
59
|
+
"finishRun": "Terminer la recette",
|
|
60
|
+
"finished": "Recette terminée",
|
|
61
|
+
"overall": "Remarques d'ensemble",
|
|
62
|
+
"saveJson": "Enregistrer le JSON sur mon appareil",
|
|
63
|
+
"copyJson": "Copier le JSON",
|
|
64
|
+
"copied": "JSON copié.",
|
|
65
|
+
"confirmUnanswered": "{n} ligne(s) ne sont pas cochées. Terminer quand même ?",
|
|
66
|
+
"writesWarning": "Cette étape écrit pour de vrai sur",
|
|
67
|
+
"intended": "C'est voulu.",
|
|
68
|
+
"savedLocal": "Enregistré dans ce navigateur — pense à « Enregistrer le JSON » à la fin",
|
|
69
|
+
"savedRemote": "Enregistré ·",
|
|
70
|
+
"localMode": "Cette page est un fichier local : à la fin, enregistre le JSON et transmets le fichier — c'est lui que l'agent lit.",
|
|
71
|
+
"dbMode": "Tes réponses sont enregistrées au fur et à mesure : l'agent les lit directement, tu n'as rien à envoyer.",
|
|
72
|
+
"serveMode": "Tes réponses sont enregistrées directement dans le projet à chaque coche ; tu n'as rien à envoyer."
|
|
73
|
+
},
|
|
74
|
+
"es": {
|
|
75
|
+
"name": "Español",
|
|
76
|
+
"dir": "ltr",
|
|
77
|
+
"uiLanguage": "Idioma de la página",
|
|
78
|
+
"before": "Antes de empezar",
|
|
79
|
+
"tester": "Tu nombre — firma esta prueba",
|
|
80
|
+
"start": "Empezar una nueva prueba",
|
|
81
|
+
"resume": "O retomar una prueba ya empezada",
|
|
82
|
+
"stepsLabel": "pasos",
|
|
83
|
+
"seen": "Visto",
|
|
84
|
+
"notSeen": "No visto",
|
|
85
|
+
"blocked": "Bloqueado",
|
|
86
|
+
"skip": "Omitir este paso opcional",
|
|
87
|
+
"optional": "Paso opcional",
|
|
88
|
+
"where": "Dónde",
|
|
89
|
+
"doIt": "Haz",
|
|
90
|
+
"expect": "Lo que debes ver — marca cada línea",
|
|
91
|
+
"note": "Lo que ves en su lugar, o cualquier observación (palabra por palabra si puedes)",
|
|
92
|
+
"whyNot": "¿Qué ves en su lugar?",
|
|
93
|
+
"todo": "por hacer",
|
|
94
|
+
"finish": "Terminar",
|
|
95
|
+
"finishRun": "Terminar la prueba",
|
|
96
|
+
"finished": "Prueba terminada",
|
|
97
|
+
"overall": "Observaciones generales",
|
|
98
|
+
"saveJson": "Guardar el JSON en mi dispositivo",
|
|
99
|
+
"copyJson": "Copiar el JSON",
|
|
100
|
+
"copied": "JSON copiado.",
|
|
101
|
+
"confirmUnanswered": "{n} línea(s) sin marcar. ¿Terminar de todos modos?",
|
|
102
|
+
"writesWarning": "Este paso escribe de verdad en",
|
|
103
|
+
"intended": "Es intencionado.",
|
|
104
|
+
"savedLocal": "Guardado en este navegador — acuérdate de guardar el JSON al final",
|
|
105
|
+
"savedRemote": "Guardado ·",
|
|
106
|
+
"localMode": "Esta página es un archivo local: al final, guarda el JSON y entrega el archivo — es lo que lee el agente.",
|
|
107
|
+
"dbMode": "Tus respuestas se guardan sobre la marcha; el agente las lee directamente, no tienes que enviar nada.",
|
|
108
|
+
"serveMode": "Tus respuestas se guardan directamente en el proyecto con cada marca; no tienes que enviar nada."
|
|
109
|
+
},
|
|
110
|
+
"de": {
|
|
111
|
+
"name": "Deutsch",
|
|
112
|
+
"dir": "ltr",
|
|
113
|
+
"uiLanguage": "Sprache der Seite",
|
|
114
|
+
"before": "Bevor du beginnst",
|
|
115
|
+
"tester": "Dein Vorname — er unterschreibt diesen Durchlauf",
|
|
116
|
+
"start": "Neuen Durchlauf starten",
|
|
117
|
+
"resume": "Oder einen begonnenen Durchlauf fortsetzen",
|
|
118
|
+
"stepsLabel": "Schritte",
|
|
119
|
+
"seen": "Gesehen",
|
|
120
|
+
"notSeen": "Nicht gesehen",
|
|
121
|
+
"blocked": "Blockiert",
|
|
122
|
+
"skip": "Diesen optionalen Schritt überspringen",
|
|
123
|
+
"optional": "Optionaler Schritt",
|
|
124
|
+
"where": "Wo",
|
|
125
|
+
"doIt": "Tu",
|
|
126
|
+
"expect": "Was du sehen musst — jede Zeile abhaken",
|
|
127
|
+
"note": "Was du stattdessen siehst, oder eine Bemerkung (wörtlich, wenn möglich)",
|
|
128
|
+
"whyNot": "Was hast du stattdessen gesehen?",
|
|
129
|
+
"todo": "offen",
|
|
130
|
+
"finish": "Abschließen",
|
|
131
|
+
"finishRun": "Durchlauf abschließen",
|
|
132
|
+
"finished": "Durchlauf abgeschlossen",
|
|
133
|
+
"overall": "Allgemeine Bemerkungen",
|
|
134
|
+
"saveJson": "JSON auf meinem Gerät speichern",
|
|
135
|
+
"copyJson": "JSON kopieren",
|
|
136
|
+
"copied": "JSON kopiert.",
|
|
137
|
+
"confirmUnanswered": "{n} Zeile(n) sind nicht abgehakt. Trotzdem abschließen?",
|
|
138
|
+
"writesWarning": "Dieser Schritt schreibt wirklich auf",
|
|
139
|
+
"intended": "Das ist so gewollt.",
|
|
140
|
+
"savedLocal": "In diesem Browser gespeichert — denk am Ende an „JSON speichern“",
|
|
141
|
+
"savedRemote": "Gespeichert ·",
|
|
142
|
+
"localMode": "Diese Seite ist eine lokale Datei: speichere am Ende das JSON und gib die Datei weiter — sie ist es, die der Agent liest.",
|
|
143
|
+
"dbMode": "Deine Antworten werden laufend gespeichert; der Agent liest sie direkt, du musst nichts senden.",
|
|
144
|
+
"serveMode": "Deine Antworten werden bei jedem Klick direkt im Projekt gespeichert; du musst nichts senden."
|
|
145
|
+
},
|
|
146
|
+
"pt-br": {
|
|
147
|
+
"name": "Português (Brasil)",
|
|
148
|
+
"dir": "ltr",
|
|
149
|
+
"uiLanguage": "Idioma da página",
|
|
150
|
+
"before": "Antes de começar",
|
|
151
|
+
"tester": "Seu primeiro nome — ele assina esta rodada",
|
|
152
|
+
"start": "Começar uma nova rodada",
|
|
153
|
+
"resume": "Ou retomar uma rodada já iniciada",
|
|
154
|
+
"stepsLabel": "etapas",
|
|
155
|
+
"seen": "Visto",
|
|
156
|
+
"notSeen": "Não visto",
|
|
157
|
+
"blocked": "Bloqueado",
|
|
158
|
+
"skip": "Pular esta etapa opcional",
|
|
159
|
+
"optional": "Etapa opcional",
|
|
160
|
+
"where": "Onde",
|
|
161
|
+
"doIt": "Faça",
|
|
162
|
+
"expect": "O que você deve ver — marque cada linha",
|
|
163
|
+
"note": "O que você vê no lugar, ou qualquer observação (palavra por palavra, se possível)",
|
|
164
|
+
"whyNot": "O que você viu no lugar?",
|
|
165
|
+
"todo": "a fazer",
|
|
166
|
+
"finish": "Encerrar",
|
|
167
|
+
"finishRun": "Encerrar a rodada",
|
|
168
|
+
"finished": "Rodada encerrada",
|
|
169
|
+
"overall": "Observações gerais",
|
|
170
|
+
"saveJson": "Salvar o JSON no meu dispositivo",
|
|
171
|
+
"copyJson": "Copiar o JSON",
|
|
172
|
+
"copied": "JSON copiado.",
|
|
173
|
+
"confirmUnanswered": "{n} linha(s) sem marcação. Encerrar mesmo assim?",
|
|
174
|
+
"writesWarning": "Esta etapa grava de verdade em",
|
|
175
|
+
"intended": "É intencional.",
|
|
176
|
+
"savedLocal": "Salvo neste navegador — lembre-se de salvar o JSON no final",
|
|
177
|
+
"savedRemote": "Salvo ·",
|
|
178
|
+
"localMode": "Esta página é um arquivo local: no final, salve o JSON e entregue o arquivo — é ele que o agente lê.",
|
|
179
|
+
"dbMode": "Suas respostas são salvas conforme você avança; o agente as lê diretamente, você não precisa enviar nada.",
|
|
180
|
+
"serveMode": "Suas respostas são salvas direto no projeto a cada marcação; você não precisa enviar nada."
|
|
181
|
+
},
|
|
182
|
+
"ru": {
|
|
183
|
+
"name": "Русский",
|
|
184
|
+
"dir": "ltr",
|
|
185
|
+
"uiLanguage": "Язык страницы",
|
|
186
|
+
"before": "Перед началом",
|
|
187
|
+
"tester": "Ваше имя — оно подписывает этот прогон",
|
|
188
|
+
"start": "Начать новый прогон",
|
|
189
|
+
"resume": "Или продолжить начатый прогон",
|
|
190
|
+
"stepsLabel": "шагов",
|
|
191
|
+
"seen": "Видно",
|
|
192
|
+
"notSeen": "Не видно",
|
|
193
|
+
"blocked": "Недоступно",
|
|
194
|
+
"skip": "Пропустить этот необязательный шаг",
|
|
195
|
+
"optional": "Необязательный шаг",
|
|
196
|
+
"where": "Где",
|
|
197
|
+
"doIt": "Сделайте",
|
|
198
|
+
"expect": "Что вы должны увидеть — отметьте каждую строку",
|
|
199
|
+
"note": "Что вы видите вместо этого, или любое замечание (дословно, если можно)",
|
|
200
|
+
"whyNot": "Что вы увидели вместо этого?",
|
|
201
|
+
"todo": "осталось",
|
|
202
|
+
"finish": "Завершить",
|
|
203
|
+
"finishRun": "Завершить прогон",
|
|
204
|
+
"finished": "Прогон завершён",
|
|
205
|
+
"overall": "Общие замечания",
|
|
206
|
+
"saveJson": "Сохранить JSON на устройство",
|
|
207
|
+
"copyJson": "Скопировать JSON",
|
|
208
|
+
"copied": "JSON скопирован.",
|
|
209
|
+
"confirmUnanswered": "Строк без отметки: {n}. Всё равно завершить?",
|
|
210
|
+
"writesWarning": "Этот шаг реально пишет в",
|
|
211
|
+
"intended": "Так задумано.",
|
|
212
|
+
"savedLocal": "Сохранено в этом браузере — в конце не забудьте сохранить JSON",
|
|
213
|
+
"savedRemote": "Сохранено ·",
|
|
214
|
+
"localMode": "Эта страница — локальный файл: в конце сохраните JSON и передайте файл — именно его читает агент.",
|
|
215
|
+
"dbMode": "Ваши ответы сохраняются по ходу; агент читает их напрямую, отправлять ничего не нужно.",
|
|
216
|
+
"serveMode": "Ваши ответы сохраняются прямо в проект при каждой отметке; отправлять ничего не нужно."
|
|
217
|
+
},
|
|
218
|
+
"zh": {
|
|
219
|
+
"name": "中文 (简体)",
|
|
220
|
+
"dir": "ltr",
|
|
221
|
+
"uiLanguage": "页面语言",
|
|
222
|
+
"before": "开始之前",
|
|
223
|
+
"tester": "你的名字 — 它为这次验收签名",
|
|
224
|
+
"start": "开始一次新的验收",
|
|
225
|
+
"resume": "或继续已开始的验收",
|
|
226
|
+
"stepsLabel": "个步骤",
|
|
227
|
+
"seen": "看到了",
|
|
228
|
+
"notSeen": "没看到",
|
|
229
|
+
"blocked": "无法进行",
|
|
230
|
+
"skip": "跳过这个可选步骤",
|
|
231
|
+
"optional": "可选步骤",
|
|
232
|
+
"where": "在哪里",
|
|
233
|
+
"doIt": "怎么做",
|
|
234
|
+
"expect": "你应该看到什么 — 请逐行勾选",
|
|
235
|
+
"note": "你实际看到的内容,或任何备注(尽量逐字记录)",
|
|
236
|
+
"whyNot": "你实际看到了什么?",
|
|
237
|
+
"todo": "待办",
|
|
238
|
+
"finish": "结束",
|
|
239
|
+
"finishRun": "结束这次验收",
|
|
240
|
+
"finished": "验收已结束",
|
|
241
|
+
"overall": "总体备注",
|
|
242
|
+
"saveJson": "把 JSON 保存到我的设备",
|
|
243
|
+
"copyJson": "复制 JSON",
|
|
244
|
+
"copied": "JSON 已复制。",
|
|
245
|
+
"confirmUnanswered": "还有 {n} 行没有勾选。仍然结束吗?",
|
|
246
|
+
"writesWarning": "这一步会真实写入",
|
|
247
|
+
"intended": "这是有意为之。",
|
|
248
|
+
"savedLocal": "已保存在此浏览器 — 结束时记得保存 JSON",
|
|
249
|
+
"savedRemote": "已保存 ·",
|
|
250
|
+
"localMode": "本页是本地文件:结束时请保存 JSON 并把文件交出去 — 代理读取的正是这个文件。",
|
|
251
|
+
"dbMode": "你的回答会即时保存,代理直接读取,你无需发送任何东西。",
|
|
252
|
+
"serveMode": "你的每次勾选都会直接保存到项目中,你无需发送任何东西。"
|
|
253
|
+
},
|
|
254
|
+
"he": {
|
|
255
|
+
"name": "עברית",
|
|
256
|
+
"dir": "rtl",
|
|
257
|
+
"uiLanguage": "שפת הדף",
|
|
258
|
+
"before": "לפני שמתחילים",
|
|
259
|
+
"tester": "השם שלך — הוא חותם על ההרצה הזאת",
|
|
260
|
+
"start": "להתחיל הרצה חדשה",
|
|
261
|
+
"resume": "או להמשיך הרצה שכבר התחילה",
|
|
262
|
+
"stepsLabel": "שלבים",
|
|
263
|
+
"seen": "נראה",
|
|
264
|
+
"notSeen": "לא נראה",
|
|
265
|
+
"blocked": "חסום",
|
|
266
|
+
"skip": "לדלג על השלב הרשות הזה",
|
|
267
|
+
"optional": "שלב רשות",
|
|
268
|
+
"where": "איפה",
|
|
269
|
+
"doIt": "מה לעשות",
|
|
270
|
+
"expect": "מה צריך לראות — סמן כל שורה",
|
|
271
|
+
"note": "מה ראית במקום, או כל הערה (מילה במילה אם אפשר)",
|
|
272
|
+
"whyNot": "מה ראית במקום?",
|
|
273
|
+
"todo": "נותר",
|
|
274
|
+
"finish": "לסיים",
|
|
275
|
+
"finishRun": "לסיים את ההרצה",
|
|
276
|
+
"finished": "ההרצה הסתיימה",
|
|
277
|
+
"overall": "הערות כלליות",
|
|
278
|
+
"saveJson": "לשמור את ה‑JSON במכשיר שלי",
|
|
279
|
+
"copyJson": "להעתיק את ה‑JSON",
|
|
280
|
+
"copied": "ה‑JSON הועתק.",
|
|
281
|
+
"confirmUnanswered": "{n} שורות לא סומנו. לסיים בכל זאת?",
|
|
282
|
+
"writesWarning": "השלב הזה כותב באמת אל",
|
|
283
|
+
"intended": "זה מכוון.",
|
|
284
|
+
"savedLocal": "נשמר בדפדפן הזה — זכור לשמור את ה‑JSON בסוף",
|
|
285
|
+
"savedRemote": "נשמר ·",
|
|
286
|
+
"localMode": "הדף הזה הוא קובץ מקומי: בסוף שמור את ה‑JSON והעבר את הקובץ — זה מה שהסוכן קורא.",
|
|
287
|
+
"dbMode": "התשובות נשמרות תוך כדי, והסוכן קורא אותן ישירות. אין מה לשלוח.",
|
|
288
|
+
"serveMode": "כל סימון נשמר ישירות בפרויקט. אין מה לשלוח."
|
|
289
|
+
},
|
|
290
|
+
"ja": {
|
|
291
|
+
"name": "日本語",
|
|
292
|
+
"dir": "ltr",
|
|
293
|
+
"uiLanguage": "ページの言語",
|
|
294
|
+
"before": "はじめる前に",
|
|
295
|
+
"tester": "あなたの名前 — この実施に署名します",
|
|
296
|
+
"start": "新しい実施を始める",
|
|
297
|
+
"resume": "または開始済みの実施を再開する",
|
|
298
|
+
"stepsLabel": "ステップ",
|
|
299
|
+
"seen": "見えた",
|
|
300
|
+
"notSeen": "見えない",
|
|
301
|
+
"blocked": "実施できない",
|
|
302
|
+
"skip": "この任意ステップを飛ばす",
|
|
303
|
+
"optional": "任意のステップ",
|
|
304
|
+
"where": "どこで",
|
|
305
|
+
"doIt": "何をする",
|
|
306
|
+
"expect": "見えるはずのこと — 各行にチェック",
|
|
307
|
+
"note": "代わりに見えたもの、または気づいたこと(できれば一字一句)",
|
|
308
|
+
"whyNot": "代わりに何が見えましたか?",
|
|
309
|
+
"todo": "未実施",
|
|
310
|
+
"finish": "終了",
|
|
311
|
+
"finishRun": "この実施を終了する",
|
|
312
|
+
"finished": "実施を終了しました",
|
|
313
|
+
"overall": "全体の所見",
|
|
314
|
+
"saveJson": "JSON を端末に保存する",
|
|
315
|
+
"copyJson": "JSON をコピーする",
|
|
316
|
+
"copied": "JSON をコピーしました。",
|
|
317
|
+
"confirmUnanswered": "未チェックの行が {n} 件あります。それでも終了しますか?",
|
|
318
|
+
"writesWarning": "このステップは実際に書き込みます:",
|
|
319
|
+
"intended": "意図した動作です。",
|
|
320
|
+
"savedLocal": "このブラウザに保存しました — 最後に JSON の保存を忘れずに",
|
|
321
|
+
"savedRemote": "保存済み ·",
|
|
322
|
+
"localMode": "このページはローカルファイルです。最後に JSON を保存してファイルを渡してください — エージェントが読むのはそれです。",
|
|
323
|
+
"dbMode": "回答は随時保存され、エージェントが直接読みます。送信は不要です。",
|
|
324
|
+
"serveMode": "チェックするたびに回答がプロジェクトへ直接保存されます。送信は不要です。"
|
|
325
|
+
},
|
|
326
|
+
"it": {
|
|
327
|
+
"name": "Italiano",
|
|
328
|
+
"dir": "ltr",
|
|
329
|
+
"uiLanguage": "Lingua della pagina",
|
|
330
|
+
"before": "Prima di iniziare",
|
|
331
|
+
"tester": "Il tuo nome — firma questa sessione",
|
|
332
|
+
"start": "Iniziare una nuova sessione",
|
|
333
|
+
"resume": "Oppure riprendere una sessione già iniziata",
|
|
334
|
+
"stepsLabel": "passaggi",
|
|
335
|
+
"seen": "Visto",
|
|
336
|
+
"notSeen": "Non visto",
|
|
337
|
+
"blocked": "Bloccato",
|
|
338
|
+
"skip": "Saltare questo passaggio facoltativo",
|
|
339
|
+
"optional": "Passaggio facoltativo",
|
|
340
|
+
"where": "Dove",
|
|
341
|
+
"doIt": "Fai",
|
|
342
|
+
"expect": "Ciò che devi vedere — spunta ogni riga",
|
|
343
|
+
"note": "Ciò che vedi al suo posto, o qualsiasi osservazione (parola per parola se puoi)",
|
|
344
|
+
"whyNot": "Che cosa hai visto al suo posto?",
|
|
345
|
+
"todo": "da fare",
|
|
346
|
+
"finish": "Terminare",
|
|
347
|
+
"finishRun": "Terminare la sessione",
|
|
348
|
+
"finished": "Sessione terminata",
|
|
349
|
+
"overall": "Osservazioni generali",
|
|
350
|
+
"saveJson": "Salvare il JSON sul mio dispositivo",
|
|
351
|
+
"copyJson": "Copiare il JSON",
|
|
352
|
+
"copied": "JSON copiato.",
|
|
353
|
+
"confirmUnanswered": "{n} riga/righe non spuntate. Terminare comunque?",
|
|
354
|
+
"writesWarning": "Questo passaggio scrive davvero su",
|
|
355
|
+
"intended": "È voluto.",
|
|
356
|
+
"savedLocal": "Salvato in questo browser — ricordati di salvare il JSON alla fine",
|
|
357
|
+
"savedRemote": "Salvato ·",
|
|
358
|
+
"localMode": "Questa pagina è un file locale: alla fine salva il JSON e consegna il file — è quello che legge l'agente.",
|
|
359
|
+
"dbMode": "Le tue risposte vengono salvate man mano; l'agente le legge direttamente, non devi inviare nulla.",
|
|
360
|
+
"serveMode": "Le tue risposte vengono salvate direttamente nel progetto a ogni spunta; non devi inviare nulla."
|
|
361
|
+
}
|
|
362
|
+
}
|
|
@@ -238,24 +238,221 @@ function packAndExtract(tempRoot, env) {
|
|
|
238
238
|
],
|
|
239
239
|
{ cwd: REPO_ROOT, env, timeout: 120000 }
|
|
240
240
|
);
|
|
241
|
-
|
|
242
|
-
|
|
241
|
+
// npm 11 reports a list, npm 12 an object keyed by package name.
|
|
242
|
+
const reported = JSON.parse(output);
|
|
243
|
+
const packed = Array.isArray(reported) ? reported : Object.values(reported);
|
|
244
|
+
assert(
|
|
245
|
+
packed.length === 1 && typeof packed[0]?.filename === 'string',
|
|
246
|
+
'npm pack must produce exactly one package'
|
|
247
|
+
);
|
|
243
248
|
const archive = resolveWithin(destination, packed[0].filename);
|
|
244
|
-
|
|
249
|
+
// The archive already sits in cwd, and it is named relatively on purpose: GNU tar
|
|
250
|
+
// reads a Windows "C:\..." argument as a remote host and refuses to open it.
|
|
251
|
+
const archiveName = path.basename(archive);
|
|
252
|
+
const entries = run('tar', ['-tzf', archiveName], { cwd: destination, env })
|
|
253
|
+
.trim()
|
|
254
|
+
.split(/\r?\n/);
|
|
245
255
|
for (const entry of entries) {
|
|
246
256
|
assert(entry.startsWith('package/'), `Unexpected npm archive entry: ${entry}`);
|
|
247
257
|
resolveWithin(destination, entry);
|
|
248
258
|
}
|
|
249
|
-
run('tar', ['-xzf',
|
|
259
|
+
run('tar', ['-xzf', archiveName, '-C', '.'], { cwd: destination, env });
|
|
250
260
|
const packageRoot = path.join(destination, 'package');
|
|
251
261
|
assert(
|
|
252
262
|
!fs.existsSync(path.join(packageRoot, 'registry.yaml')),
|
|
253
263
|
'npm contract must work without registry.yaml'
|
|
254
264
|
);
|
|
255
265
|
assert(fs.statSync(packageRoot).isDirectory(), 'npm package directory is missing');
|
|
266
|
+
for (const file of ['LICENSE', 'THIRD-PARTY-LICENSES.md', 'SECURITY.md']) {
|
|
267
|
+
assert(fs.statSync(path.join(packageRoot, file)).isFile(), `npm archive is missing ${file}`);
|
|
268
|
+
}
|
|
269
|
+
assert(
|
|
270
|
+
!fs.existsSync(path.join(packageRoot, 'src/bmad-plus/packs/pack-seo/scripts/__pycache__')),
|
|
271
|
+
'npm archive must exclude local Python caches'
|
|
272
|
+
);
|
|
256
273
|
return packageRoot;
|
|
257
274
|
}
|
|
258
275
|
|
|
276
|
+
function verifyNexusConsumer(packageRoot, projectDir, env) {
|
|
277
|
+
const invoke = (args) =>
|
|
278
|
+
JSON.parse(
|
|
279
|
+
run(
|
|
280
|
+
process.execPath,
|
|
281
|
+
[
|
|
282
|
+
path.join(packageRoot, 'tools/cli/bmad-plus-cli.js'),
|
|
283
|
+
'nexus',
|
|
284
|
+
...args,
|
|
285
|
+
'--directory',
|
|
286
|
+
projectDir,
|
|
287
|
+
'--json',
|
|
288
|
+
],
|
|
289
|
+
{ cwd: projectDir, env }
|
|
290
|
+
)
|
|
291
|
+
);
|
|
292
|
+
const input = (name, value) => {
|
|
293
|
+
const file = path.join(projectDir, name);
|
|
294
|
+
fs.writeFileSync(file, JSON.stringify(value));
|
|
295
|
+
return file;
|
|
296
|
+
};
|
|
297
|
+
const instruction = '.agents/skills/agent-orchestrator/SKILL.md';
|
|
298
|
+
assert(
|
|
299
|
+
fs
|
|
300
|
+
.readFileSync(path.join(projectDir, instruction), 'utf8')
|
|
301
|
+
.includes('Durable host-managed attempts')
|
|
302
|
+
);
|
|
303
|
+
fs.mkdirSync(path.join(projectDir, 'checks'));
|
|
304
|
+
fs.mkdirSync(path.join(projectDir, 'result'));
|
|
305
|
+
fs.writeFileSync(
|
|
306
|
+
path.join(projectDir, 'checks/accepted.cjs'),
|
|
307
|
+
"const fs=require('node:fs');const assert=require('node:assert/strict');assert.equal(fs.readFileSync('result/value.txt','utf8'),'accepted');\n"
|
|
308
|
+
);
|
|
309
|
+
const plan = input('nexus-plan.json', {
|
|
310
|
+
id: 'consumer',
|
|
311
|
+
tasks: [
|
|
312
|
+
{
|
|
313
|
+
id: 'work',
|
|
314
|
+
objective: 'Verify a real relocated npm/source consumer',
|
|
315
|
+
scope: ['result'],
|
|
316
|
+
artifacts: ['result/value.txt'],
|
|
317
|
+
resources: [instruction, 'checks/accepted.cjs'],
|
|
318
|
+
checks: [{ id: 'actual-output', command: 'node', args: ['checks/accepted.cjs'] }],
|
|
319
|
+
},
|
|
320
|
+
],
|
|
321
|
+
});
|
|
322
|
+
invoke(['create', '--plan', plan]);
|
|
323
|
+
const backend = { kind: 'host', id: 'consumer-check', sessionId: 'observed-attempt' };
|
|
324
|
+
const started = invoke([
|
|
325
|
+
'start',
|
|
326
|
+
'consumer',
|
|
327
|
+
'work',
|
|
328
|
+
'--input',
|
|
329
|
+
input('nexus-host.json', { backend }),
|
|
330
|
+
]);
|
|
331
|
+
const attemptId = started.tasks[0].attempts[0].id;
|
|
332
|
+
fs.writeFileSync(path.join(projectDir, 'result/value.txt'), 'accepted');
|
|
333
|
+
// A separate CLI process reconciles an interrupted host without repeating its work.
|
|
334
|
+
invoke([
|
|
335
|
+
'reconcile',
|
|
336
|
+
'consumer',
|
|
337
|
+
'work',
|
|
338
|
+
'--input',
|
|
339
|
+
input('nexus-observation.json', {
|
|
340
|
+
attemptId,
|
|
341
|
+
backend,
|
|
342
|
+
ownerStopped: true,
|
|
343
|
+
outcome: 'completed',
|
|
344
|
+
summary: 'Test host stopped after writing its artifact; independent checker follows.',
|
|
345
|
+
}),
|
|
346
|
+
]);
|
|
347
|
+
const checked = invoke(['verify', 'consumer', 'work']);
|
|
348
|
+
assert.equal(checked.tasks[0].attempts[0].verification.status, 'passed');
|
|
349
|
+
const accepted = invoke(['accept', 'consumer', 'work']);
|
|
350
|
+
assert.equal(accepted.tasks[0].integration, 'accepted');
|
|
351
|
+
assert.equal(accepted.tasks[0].integrationReceipt.gitOperation, null);
|
|
352
|
+
const observed = invoke(['inspect', 'consumer']);
|
|
353
|
+
assert.equal(observed.observations[0].evidenceEligible, true);
|
|
354
|
+
assert.equal(observed.observations[0].stale, false);
|
|
355
|
+
|
|
356
|
+
fs.mkdirSync(path.join(projectDir, 'processed'));
|
|
357
|
+
fs.writeFileSync(path.join(projectDir, 'checks/task.txt'), 'Write the supervised result.\n');
|
|
358
|
+
fs.writeFileSync(
|
|
359
|
+
path.join(projectDir, 'checks/worker.cjs'),
|
|
360
|
+
"require('node:fs').writeFileSync('processed/value.txt','supervised');\n"
|
|
361
|
+
);
|
|
362
|
+
fs.writeFileSync(
|
|
363
|
+
path.join(projectDir, 'checks/process.cjs'),
|
|
364
|
+
"require('node:assert/strict').equal(require('node:fs').readFileSync('processed/value.txt','utf8'),'supervised');\n"
|
|
365
|
+
);
|
|
366
|
+
invoke([
|
|
367
|
+
'create',
|
|
368
|
+
'--plan',
|
|
369
|
+
input('process-plan.json', {
|
|
370
|
+
id: 'process-consumer',
|
|
371
|
+
tasks: [
|
|
372
|
+
{
|
|
373
|
+
id: 'work',
|
|
374
|
+
objective: 'Verify the packaged foreground process backend',
|
|
375
|
+
scope: ['processed'],
|
|
376
|
+
artifacts: ['processed/value.txt'],
|
|
377
|
+
resources: [instruction, 'checks/process.cjs'],
|
|
378
|
+
checks: [{ id: 'process-output', command: 'node', args: ['checks/process.cjs'] }],
|
|
379
|
+
execution: {
|
|
380
|
+
adapter: 'command',
|
|
381
|
+
command: 'node',
|
|
382
|
+
args: ['checks/worker.cjs'],
|
|
383
|
+
resources: ['checks/worker.cjs'],
|
|
384
|
+
input: 'checks/task.txt',
|
|
385
|
+
},
|
|
386
|
+
},
|
|
387
|
+
],
|
|
388
|
+
}),
|
|
389
|
+
]);
|
|
390
|
+
const launched = invoke(['launch', 'process-consumer', 'work']);
|
|
391
|
+
const processAttempt = launched.tasks[0].attempts[0];
|
|
392
|
+
assert.equal(processAttempt.process.receipt.outcome, 'completed');
|
|
393
|
+
invoke([
|
|
394
|
+
'collect',
|
|
395
|
+
'process-consumer',
|
|
396
|
+
'work',
|
|
397
|
+
'--input',
|
|
398
|
+
input('collect.json', {
|
|
399
|
+
attemptId: processAttempt.id,
|
|
400
|
+
backend: processAttempt.backend,
|
|
401
|
+
}),
|
|
402
|
+
]);
|
|
403
|
+
assert.equal(
|
|
404
|
+
invoke(['verify', 'process-consumer', 'work']).tasks[0].attempts[0].verification.status,
|
|
405
|
+
'passed'
|
|
406
|
+
);
|
|
407
|
+
assert.equal(invoke(['accept', 'process-consumer', 'work']).tasks[0].integration, 'accepted');
|
|
408
|
+
|
|
409
|
+
const mem = (args) =>
|
|
410
|
+
JSON.parse(
|
|
411
|
+
run(
|
|
412
|
+
process.execPath,
|
|
413
|
+
[
|
|
414
|
+
path.join(packageRoot, 'tools/cli/bmad-plus-cli.js'),
|
|
415
|
+
'mem',
|
|
416
|
+
...args,
|
|
417
|
+
'--directory',
|
|
418
|
+
projectDir,
|
|
419
|
+
'--json',
|
|
420
|
+
],
|
|
421
|
+
{ cwd: projectDir, env }
|
|
422
|
+
)
|
|
423
|
+
);
|
|
424
|
+
const memoryFile = '.agents/memory/patterns.md';
|
|
425
|
+
fs.mkdirSync(path.dirname(path.join(projectDir, memoryFile)), { recursive: true });
|
|
426
|
+
fs.appendFileSync(
|
|
427
|
+
path.join(projectDir, memoryFile),
|
|
428
|
+
'\n### Consumer supervision evidence\nVerify the supervised artifact before accepting process work.\n'
|
|
429
|
+
);
|
|
430
|
+
input('memory-observation.json', {
|
|
431
|
+
runId: 'process-consumer',
|
|
432
|
+
taskId: 'work',
|
|
433
|
+
memory: { file: memoryFile, heading: 'Consumer supervision evidence' },
|
|
434
|
+
scope: ['processed'],
|
|
435
|
+
interpretation:
|
|
436
|
+
'Consumer fixture links this note to the accepted result; causality is unmeasured.',
|
|
437
|
+
});
|
|
438
|
+
mem(['observe', '--input', 'memory-observation.json']);
|
|
439
|
+
const recall = () =>
|
|
440
|
+
mem([
|
|
441
|
+
'recall',
|
|
442
|
+
'Consumer supervision evidence',
|
|
443
|
+
'--ranking',
|
|
444
|
+
'evidence',
|
|
445
|
+
'--context-scope',
|
|
446
|
+
'processed',
|
|
447
|
+
]);
|
|
448
|
+
assert(recall().results.some((entry) => entry.ref === 'Consumer supervision evidence'));
|
|
449
|
+
fs.writeFileSync(path.join(projectDir, 'processed/value.txt'), 'changed after acceptance');
|
|
450
|
+
assert(
|
|
451
|
+
!recall().results.some((entry) => entry.ref === 'Consumer supervision evidence'),
|
|
452
|
+
'Packaged memory must reject evidence after its accepted artifact changes'
|
|
453
|
+
);
|
|
454
|
+
}
|
|
455
|
+
|
|
259
456
|
function runMatrix(packageRoot, variant, tempRoot, env, reference) {
|
|
260
457
|
const allPacks = Object.keys(reference.packDefinitions).filter(
|
|
261
458
|
(id) => !reference.packDefinitions[id].disabled
|
|
@@ -313,6 +510,7 @@ function runMatrix(packageRoot, variant, tempRoot, env, reference) {
|
|
|
313
510
|
derived: reference.derived,
|
|
314
511
|
variant,
|
|
315
512
|
});
|
|
513
|
+
if (installations === 1) verifyNexusConsumer(packageRoot, projectDir, env);
|
|
316
514
|
if (selection.packs.includes('dev-studio')) {
|
|
317
515
|
const list = JSON.parse(
|
|
318
516
|
run(
|
package/tools/build/generate.js
CHANGED
|
@@ -189,6 +189,21 @@ function validateRegistry(registry) {
|
|
|
189
189
|
'registry.yaml: targets.integration must declare the delivered instruction integration'
|
|
190
190
|
);
|
|
191
191
|
}
|
|
192
|
+
const processBackend = registry.targets?.optional_process_backend;
|
|
193
|
+
if (
|
|
194
|
+
processBackend &&
|
|
195
|
+
(!isDeepStrictEqual(processBackend.adapters, ['command', 'codex-exec']) ||
|
|
196
|
+
processBackend.supervisor !== 'foreground' ||
|
|
197
|
+
processBackend.launch !== 'explicit-plan' ||
|
|
198
|
+
processBackend.collect !== 'exact-attempt-receipt' ||
|
|
199
|
+
processBackend.cancellation !== 'original-owner-direct-child' ||
|
|
200
|
+
processBackend.verification !== 'independent-required' ||
|
|
201
|
+
processBackend.scheduling !== 'none')
|
|
202
|
+
) {
|
|
203
|
+
throw new Error(
|
|
204
|
+
'registry.yaml: optional process backend differs from the delivered Nexus contract'
|
|
205
|
+
);
|
|
206
|
+
}
|
|
192
207
|
for (const [runtime, config] of Object.entries(registry.runtimes || {})) {
|
|
193
208
|
if (
|
|
194
209
|
typeof config?.min_version !== 'string' ||
|
|
@@ -359,6 +374,7 @@ function buildDerived(registry, { sourceRoot = path.join(REPO_ROOT, 'src', 'bmad
|
|
|
359
374
|
pythonPacks,
|
|
360
375
|
diagnostics: {
|
|
361
376
|
schemaVersion: 1,
|
|
377
|
+
processExecution: registry.targets.optional_process_backend || null,
|
|
362
378
|
runtimeMinimums: Object.fromEntries(
|
|
363
379
|
Object.entries(registry.runtimes).map(([id, runtime]) => [id, runtime.min_version])
|
|
364
380
|
),
|
|
@@ -113,7 +113,7 @@ After a successful update, reread the project spine and relevant installed skill
|
|
|
113
113
|
|
|
114
114
|
## Registry facts (computed from registry.yaml — never hand-typed)
|
|
115
115
|
|
|
116
|
-
- Product: BMAD+ v0.
|
|
116
|
+
- Product: BMAD+ v0.16.0 (derived from BMAD-METHOD v6.6.0)
|
|
117
117
|
- Models supported: claude, gpt, gemini, local (model-agnostic by contract)
|
|
118
118
|
- Packs (9): Core, OSINT, Maker, Shield, SEO, Memory, Dev Studio, Backup, Animated
|
|
119
119
|
- Installer agents (14 across all packs):
|
|
@@ -118,7 +118,7 @@ After a successful update, reread the project spine and relevant installed skill
|
|
|
118
118
|
|
|
119
119
|
## Registry facts (computed from registry.yaml — never hand-typed)
|
|
120
120
|
|
|
121
|
-
- Product: BMAD+ v0.
|
|
121
|
+
- Product: BMAD+ v0.16.0 (derived from BMAD-METHOD v6.6.0)
|
|
122
122
|
- Models supported: claude, gpt, gemini, local (model-agnostic by contract)
|
|
123
123
|
- Packs (9): Core, OSINT, Maker, Shield, SEO, Memory, Dev Studio, Backup, Animated
|
|
124
124
|
- Installer agents (14 across all packs):
|
|
@@ -113,7 +113,7 @@ After a successful update, reread the project spine and relevant installed skill
|
|
|
113
113
|
|
|
114
114
|
## Registry facts (computed from registry.yaml — never hand-typed)
|
|
115
115
|
|
|
116
|
-
- Product: BMAD+ v0.
|
|
116
|
+
- Product: BMAD+ v0.16.0 (derived from BMAD-METHOD v6.6.0)
|
|
117
117
|
- Models supported: claude, gpt, gemini, local (model-agnostic by contract)
|
|
118
118
|
- Packs (9): Core, OSINT, Maker, Shield, SEO, Memory, Dev Studio, Backup, Animated
|
|
119
119
|
- Installer agents (14 across all packs):
|