bmad-plus 0.22.0 → 0.23.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 (60) hide show
  1. package/CHANGELOG.md +59 -0
  2. package/README.md +46 -26
  3. package/SECURITY.md +1 -1
  4. package/osint-agent-package/agents/osint-investigator.md +3 -3
  5. package/osint-agent-package/skills/bmad-osint-investigate/osint/SKILL.md +51 -51
  6. package/osint-agent-package/skills/bmad-osint-investigate/osint/references/content-extraction.md +7 -7
  7. package/osint-agent-package/skills/bmad-osint-investigate/osint/references/platforms.md +2 -2
  8. package/osint-agent-package/skills/bmad-osint-investigate/osint/references/tools.md +31 -41
  9. package/package.json +24 -5
  10. package/readme-international/README.de.md +46 -26
  11. package/readme-international/README.es.md +47 -27
  12. package/readme-international/README.fr.md +46 -26
  13. package/src/bmad-plus/agents/agent-maker/SKILL.md +39 -14
  14. package/src/bmad-plus/agents/agent-orchestrator/SKILL.md +5 -1
  15. package/src/bmad-plus/data/role-triggers.yaml +34 -0
  16. package/src/bmad-plus/module-help.csv +2 -0
  17. package/src/bmad-plus/module.yaml +26 -4
  18. package/src/bmad-plus/packs/pack-animated/animated-website-agent.md +40 -14
  19. package/src/bmad-plus/packs/pack-animated/templates/animated-website-workflow.md +15 -12
  20. package/src/bmad-plus/packs/pack-backup/backup-agent.md +2 -1
  21. package/src/bmad-plus/packs/pack-backup/templates/backup-workflow.md +2 -0
  22. package/src/bmad-plus/packs/pack-design/SKILL.md +72 -0
  23. package/src/bmad-plus/packs/pack-design/bmad-skill-manifest.yaml +13 -0
  24. package/src/bmad-plus/packs/pack-design/design-engine.md +126 -0
  25. package/src/bmad-plus/packs/pack-design/intake.yaml +105 -0
  26. package/src/bmad-plus/packs/pack-memory/zecher-agent.md +1 -1
  27. package/src/bmad-plus/packs/pack-shield/README.md +1 -1
  28. package/src/bmad-plus/packs/pack-shield/SKILL.md +3 -3
  29. package/src/bmad-plus/packs/pack-shield/categories/industry-compliance/pci-dss-agent.md +1 -1
  30. package/src/bmad-plus/packs/pack-shield/shield-orchestrator.md +2 -2
  31. package/src/bmad-plus/skills/bmad-plus-autopilot/SKILL.md +7 -0
  32. package/src/bmad-plus/skills/bmad-plus-intake/SKILL.md +87 -0
  33. package/src/bmad-plus/skills/bmad-plus-intake/ref/intake-format.md +112 -0
  34. package/src/bmad-plus/skills/bmad-plus-parallel/SKILL.md +18 -0
  35. package/src/bmad-plus/skills/bmad-plus-swarm/SKILL.md +115 -0
  36. package/src/bmad-plus/skills/bmad-plus-swarm/ref/definition.md +188 -0
  37. package/tools/build/adapters.config.js +3 -1
  38. package/tools/build/generate-adapters.js +26 -2
  39. package/tools/build/generate.js +269 -7
  40. package/tools/build/intake-contract.js +522 -0
  41. package/tools/cli/bmad-plus-cli.js +2 -0
  42. package/tools/cli/commands/install.js +45 -11
  43. package/tools/cli/commands/intake.js +124 -0
  44. package/tools/cli/commands/nexus.js +2 -1
  45. package/tools/cli/commands/review.js +1 -1
  46. package/tools/cli/commands/swarm.js +119 -0
  47. package/tools/cli/commands/uninstall.js +17 -0
  48. package/tools/cli/commands/update.js +30 -1
  49. package/tools/cli/i18n.js +50 -30
  50. package/tools/cli/lib/intake.js +202 -0
  51. package/tools/cli/lib/pack-copy.js +95 -5
  52. package/tools/cli/lib/packs.js +102 -12
  53. package/tools/cli/lib/review.js +2 -1
  54. package/tools/cli/lib/swarm-deal.js +116 -0
  55. package/tools/cli/lib/swarm-defaults.js +6 -0
  56. package/tools/cli/lib/swarm-tally.js +195 -0
  57. package/tools/cli/lib/swarm-validate.js +589 -0
  58. package/tools/cli/lib/swarm.js +712 -0
  59. package/tools/cli/lib/update-dispatch.js +10 -2
  60. package/tools/cli/lib/update-transaction.js +9 -6
@@ -0,0 +1,195 @@
1
+ /** Counts valid answers by group; quotes stay verbatim and the disclosure comes first. */
2
+ 'use strict';
3
+
4
+ const round = (value) => Math.round(value * 10000) / 10000;
5
+
6
+ function stats(values) {
7
+ if (!values.length) return { count: 0, median: null, mean: null, min: null, max: null };
8
+ const sorted = [...values].sort((a, b) => a - b);
9
+ const middle = sorted.length >> 1;
10
+ const median = sorted.length % 2 ? sorted[middle] : (sorted[middle - 1] + sorted[middle]) / 2;
11
+ return {
12
+ count: sorted.length,
13
+ median: round(median),
14
+ mean: round(sorted.reduce((sum, value) => sum + value, 0) / sorted.length),
15
+ min: sorted[0],
16
+ max: sorted[sorted.length - 1],
17
+ };
18
+ }
19
+
20
+ function rateOf(rows, field) {
21
+ const of = rows.length;
22
+ const yes = rows.filter(({ answer }) => answer[field] === true).length;
23
+ return { yes, of, rate: of ? round(yes / of) : null };
24
+ }
25
+
26
+ function countsOf(rows, field, values) {
27
+ const counts = Object.fromEntries(values.map((value) => [value, 0]));
28
+ for (const { answer } of rows) if (Object.hasOwn(answer, field)) counts[answer[field]] += 1;
29
+ return counts;
30
+ }
31
+
32
+ function quotesOf(rows, field, keep) {
33
+ return rows
34
+ .filter(({ answer }) => typeof answer[field] === 'string' && answer[field].trim())
35
+ .slice(0, keep)
36
+ .map(({ card, answer }) => ({ unit: card.id, text: answer[field] }));
37
+ }
38
+
39
+ function numbersOf(rows, field) {
40
+ return stats(
41
+ rows.map(({ answer }) => answer[field]).filter((value) => typeof value === 'number')
42
+ );
43
+ }
44
+
45
+ /**
46
+ * @param rows valid answers in unit order: [{ card, answer }]
47
+ * @param skipped units without a valid answer: [{ unit, reason }]
48
+ */
49
+ function tally({ run, definition, cards, rows, skipped }) {
50
+ const { groupBy } = definition.tally;
51
+ const groupValues = Object.fromEntries(
52
+ groupBy.map((field) => [field, [...new Set(cards.map((card) => String(card[field])))]])
53
+ );
54
+ const partition = (compute) => ({
55
+ all: compute(rows),
56
+ groups: Object.fromEntries(
57
+ groupBy.map((field) => [
58
+ field,
59
+ Object.fromEntries(
60
+ groupValues[field].map((value) => [
61
+ value,
62
+ compute(rows.filter(({ card }) => String(card[field]) === value)),
63
+ ])
64
+ ),
65
+ ])
66
+ ),
67
+ });
68
+ const { rate, counts, quotes, numbers } = definition.tally;
69
+ return {
70
+ schemaVersion: 1,
71
+ run: run.id,
72
+ definition: definition.id,
73
+ kind: definition.kind,
74
+ title: definition.title,
75
+ disclosure: definition.disclosure,
76
+ units: { total: cards.length, valid: rows.length, skipped },
77
+ groupBy,
78
+ rate: rate ? { field: rate, ...partition((set) => rateOf(set, rate)) } : null,
79
+ counts: Object.fromEntries(
80
+ counts.map((field) => [
81
+ field,
82
+ partition((set) => countsOf(set, field, definition.answer.fields[field].values)),
83
+ ])
84
+ ),
85
+ quotes: Object.fromEntries(
86
+ Object.entries(quotes).map(([field, keep]) => [
87
+ field,
88
+ { keep, ...partition((set) => quotesOf(set, field, keep)) },
89
+ ])
90
+ ),
91
+ numbers: Object.fromEntries(
92
+ numbers.map((field) => [field, partition((set) => numbersOf(set, field))])
93
+ ),
94
+ };
95
+ }
96
+
97
+ const percent = (rate) => (rate === null ? 'n/a' : (rate * 100).toFixed(1) + '%');
98
+ const cell = (value) => (value === null ? 'n/a' : String(value));
99
+
100
+ function sections(section, render) {
101
+ const lines = render('all', section.all);
102
+ for (const [field, values] of Object.entries(section.groups))
103
+ for (const [value, subset] of Object.entries(values))
104
+ lines.push(...render(field + ' = ' + value, subset));
105
+ return lines;
106
+ }
107
+
108
+ function renderTally(result) {
109
+ const lines = [
110
+ '> ' + result.disclosure,
111
+ '',
112
+ '# ' + result.title + ' (run ' + result.run + ')',
113
+ '',
114
+ ];
115
+ const skipped = result.units.skipped;
116
+ lines.push(
117
+ result.units.valid +
118
+ ' of ' +
119
+ result.units.total +
120
+ ' units gave a valid answer; ' +
121
+ skipped.length +
122
+ ' skipped' +
123
+ (skipped.length
124
+ ? ': ' + skipped.map((entry) => entry.unit + ' (' + entry.reason + ')').join(', ')
125
+ : '') +
126
+ '.'
127
+ );
128
+ if (result.rate) {
129
+ lines.push(
130
+ '',
131
+ '## Rate: ' + result.rate.field,
132
+ '',
133
+ '| group | yes | of | rate |',
134
+ '|---|---|---|---|'
135
+ );
136
+ lines.push(
137
+ ...sections(result.rate, (name, value) => [
138
+ '| ' + name + ' | ' + value.yes + ' | ' + value.of + ' | ' + percent(value.rate) + ' |',
139
+ ])
140
+ );
141
+ }
142
+ for (const [field, section] of Object.entries(result.counts)) {
143
+ const values = Object.keys(section.all);
144
+ lines.push(
145
+ '',
146
+ '## Counts: ' + field,
147
+ '',
148
+ '| group | ' + values.join(' | ') + ' |',
149
+ '|---|' + values.map(() => '---|').join('')
150
+ );
151
+ lines.push(
152
+ ...sections(section, (name, value) => [
153
+ '| ' + name + ' | ' + values.map((key) => value[key]).join(' | ') + ' |',
154
+ ])
155
+ );
156
+ }
157
+ for (const [field, section] of Object.entries(result.quotes)) {
158
+ lines.push('', '## Quotes: ' + field + ' (up to ' + section.keep + ' per group, verbatim)');
159
+ lines.push(
160
+ ...sections(section, (name, value) => [
161
+ '',
162
+ '**' + name + '**',
163
+ ...(value.length
164
+ ? value.map((quote) => '- ' + quote.unit + ': ' + JSON.stringify(quote.text))
165
+ : ['- (no quote)']),
166
+ ])
167
+ );
168
+ }
169
+ for (const [field, section] of Object.entries(result.numbers)) {
170
+ lines.push(
171
+ '',
172
+ '## Numbers: ' + field,
173
+ '',
174
+ '| group | count | median | mean | min | max |',
175
+ '|---|---|---|---|---|---|'
176
+ );
177
+ lines.push(
178
+ ...sections(section, (name, value) => [
179
+ '| ' +
180
+ [
181
+ name,
182
+ value.count,
183
+ cell(value.median),
184
+ cell(value.mean),
185
+ cell(value.min),
186
+ cell(value.max),
187
+ ].join(' | ') +
188
+ ' |',
189
+ ])
190
+ );
191
+ }
192
+ return lines.join('\n') + '\n';
193
+ }
194
+
195
+ module.exports = { tally, renderTally, stats };