wizz-method 2.12.0 → 2.14.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.
Files changed (119) hide show
  1. package/README.md +2 -1
  2. package/THIRD-PARTY-NOTICES.md +2 -0
  3. package/package.json +10 -3
  4. package/skills-registry.yaml +48 -48
  5. package/src/bmm-skills/1-analysis/research/wizz-domain-research/customize.toml +4 -3
  6. package/src/bmm-skills/1-analysis/research/wizz-market-research/customize.toml +4 -3
  7. package/src/bmm-skills/1-analysis/research/wizz-technical-research/customize.toml +3 -1
  8. package/src/bmm-skills/1-analysis/wizz-agent-analyst/customize.toml +3 -1
  9. package/src/bmm-skills/1-analysis/wizz-agent-tech-writer/customize.toml +4 -3
  10. package/src/bmm-skills/1-analysis/wizz-document-project/customize.toml +4 -3
  11. package/src/bmm-skills/1-analysis/wizz-prfaq/customize.toml +4 -3
  12. package/src/bmm-skills/1-analysis/wizz-product-brief/customize.toml +5 -6
  13. package/src/bmm-skills/2-plan-workflows/wizz-agent-pm/customize.toml +3 -1
  14. package/src/bmm-skills/2-plan-workflows/wizz-agent-ux-designer/customize.toml +3 -1
  15. package/src/bmm-skills/2-plan-workflows/wizz-create-prd/customize.toml +4 -3
  16. package/src/bmm-skills/2-plan-workflows/wizz-edit-prd/customize.toml +4 -3
  17. package/src/bmm-skills/2-plan-workflows/wizz-prd/customize.toml +5 -6
  18. package/src/bmm-skills/2-plan-workflows/wizz-ux/customize.toml +4 -3
  19. package/src/bmm-skills/2-plan-workflows/wizz-validate-prd/customize.toml +4 -3
  20. package/src/bmm-skills/3-solutioning/wizz-agent-architect/customize.toml +3 -1
  21. package/src/bmm-skills/3-solutioning/wizz-architecture/customize.toml +5 -6
  22. package/src/bmm-skills/3-solutioning/wizz-check-implementation-readiness/customize.toml +4 -3
  23. package/src/bmm-skills/3-solutioning/wizz-create-architecture/customize.toml +4 -3
  24. package/src/bmm-skills/3-solutioning/wizz-create-epics-and-stories/customize.toml +4 -3
  25. package/src/bmm-skills/3-solutioning/wizz-generate-project-context/steps/step-03-complete.md +7 -0
  26. package/src/bmm-skills/4-implementation/wizz-agent-dev/customize.toml +3 -1
  27. package/src/bmm-skills/4-implementation/wizz-checkpoint-preview/customize.toml +4 -3
  28. package/src/bmm-skills/4-implementation/wizz-code-review/customize.toml +4 -3
  29. package/src/bmm-skills/4-implementation/wizz-code-review/steps/step-03-triage.md +23 -14
  30. package/src/bmm-skills/4-implementation/wizz-code-review/steps/step-04-present.md +2 -2
  31. package/src/bmm-skills/4-implementation/wizz-correct-course/customize.toml +4 -3
  32. package/src/bmm-skills/4-implementation/wizz-create-story/customize.toml +4 -3
  33. package/src/bmm-skills/4-implementation/wizz-dev-story/customize.toml +4 -3
  34. package/src/bmm-skills/4-implementation/wizz-investigate/customize.toml +4 -3
  35. package/src/bmm-skills/4-implementation/wizz-qa-generate-e2e-tests/customize.toml +4 -3
  36. package/src/bmm-skills/4-implementation/wizz-quick-dev/customize.toml +4 -3
  37. package/src/bmm-skills/4-implementation/wizz-quick-dev/spec-template.md +6 -0
  38. package/src/bmm-skills/4-implementation/wizz-quick-dev/step-04-review.md +27 -16
  39. package/src/bmm-skills/4-implementation/wizz-quick-dev/step-oneshot.md +27 -6
  40. package/src/bmm-skills/4-implementation/wizz-retrospective/customize.toml +4 -3
  41. package/src/bmm-skills/4-implementation/wizz-sprint-planning/customize.toml +4 -3
  42. package/src/bmm-skills/4-implementation/wizz-sprint-status/customize.toml +4 -3
  43. package/src/bmm-skills/module.yaml +1 -1
  44. package/src/core-skills/wizz-brainstorming/customize.toml +5 -6
  45. package/src/core-skills/wizz-brainstorming/scripts/brain.py +19 -0
  46. package/src/core-skills/wizz-brainstorming/scripts/tests/test_brain.py +33 -0
  47. package/src/core-skills/wizz-forge-idea/scripts/resolve_personas.py +3 -1
  48. package/src/core-skills/wizz-forge-idea/scripts/tests/test_resolve_personas.py +21 -0
  49. package/src/core-skills/wizz-help/SKILL.md +5 -3
  50. package/src/core-skills/wizz-party-mode/customize.toml +5 -4
  51. package/src/core-skills/wizz-party-mode/scripts/resolve_party.py +3 -1
  52. package/src/core-skills/wizz-party-mode/scripts/tests/test_resolve_party.py +21 -0
  53. package/src/core-skills/wizz-spec/customize.toml +4 -5
  54. package/src/modules/wizz/_shared/model-ladder.md +4 -4
  55. package/src/modules/wizz/_shared/video-pipeline.md +1 -1
  56. package/src/modules/wizz/agents/wizz-maestro/SKILL.md +1 -1
  57. package/src/modules/wizz/subagents/opencode/wizz-exec-review.md +2 -2
  58. package/src/modules/wizz/subagents/opencode/wizz-exec-standard.md +2 -2
  59. package/src/modules/wizz/subagents/opencode/wizz-exec-strong.md +2 -2
  60. package/src/modules/wizz/subagents/spec.yaml +3 -3
  61. package/src/scripts/resolve_config.py +8 -0
  62. package/src/scripts/resolve_customization.py +24 -3
  63. package/src/scripts/tests/test_resolve_config.py +42 -0
  64. package/src/scripts/tests/test_resolve_customization.py +45 -0
  65. package/src/skills-lib/ctc-align/SKILL.md +1 -1
  66. package/src/skills-lib/wizz-agent-browser/SKILL.md +5 -0
  67. package/src/skills-lib/wizz-huashu-design/scripts/html2pptx.js +902 -1061
  68. package/src/skills-lib/wizz-humanizer/README.md +134 -71
  69. package/src/skills-lib/wizz-humanizer/SKILL.md +51 -37
  70. package/src/skills-lib/wizz-humanizer/references/ai-writing-patterns.md +208 -190
  71. package/src/skills-lib/wizz-router/references/routing-table-flat.md +2 -2
  72. package/tools/installer/banner.js +80 -29
  73. package/tools/installer/commands/catalog.js +87 -0
  74. package/tools/installer/commands/install.js +9 -0
  75. package/tools/installer/core/doctor.js +31 -1
  76. package/tools/installer/core/installer.js +32 -0
  77. package/tools/installer/core/project-instructions.js +199 -0
  78. package/tools/installer/guided/detect-tools.js +53 -0
  79. package/tools/installer/guided/flow.js +203 -0
  80. package/tools/installer/guided/labels.js +185 -0
  81. package/tools/installer/guided/messages.js +132 -0
  82. package/tools/installer/guided/outro.js +32 -0
  83. package/tools/installer/guided/profiles.js +95 -0
  84. package/tools/installer/guided/steps.js +154 -0
  85. package/tools/installer/install-messages.yaml +3 -3
  86. package/tools/installer/modules/external-manager.js +4 -0
  87. package/tools/installer/ui.js +57 -22
  88. package/wizz-modules.yaml +1 -0
  89. package/src/bmm-skills/3-solutioning/wizz-architecture/scripts/__pycache__/lint_spine.cpython-313.pyc +0 -0
  90. package/src/bmm-skills/3-solutioning/wizz-architecture/scripts/tests/__pycache__/test_lint_spine.cpython-313-pytest-9.1.1.pyc +0 -0
  91. package/src/bmm-skills/4-implementation/wizz-retrospective/scripts/__pycache__/sprint_status.cpython-313.pyc +0 -0
  92. package/src/bmm-skills/4-implementation/wizz-retrospective/scripts/tests/__pycache__/test_git_evidence.cpython-313-pytest-9.1.1.pyc +0 -0
  93. package/src/bmm-skills/4-implementation/wizz-retrospective/scripts/tests/__pycache__/test_sprint_status.cpython-313-pytest-9.1.1.pyc +0 -0
  94. package/src/bmm-skills/4-implementation/wizz-sprint-planning/scripts/__pycache__/sprint_plan.cpython-313.pyc +0 -0
  95. package/src/bmm-skills/4-implementation/wizz-sprint-planning/scripts/tests/__pycache__/test_sprint_plan.cpython-313-pytest-9.1.1.pyc +0 -0
  96. package/src/core-skills/wizz-advanced-elicitation/scripts/__pycache__/pick_methods.cpython-313.pyc +0 -0
  97. package/src/core-skills/wizz-advanced-elicitation/scripts/tests/__pycache__/test_pick_methods.cpython-313-pytest-9.1.1.pyc +0 -0
  98. package/src/core-skills/wizz-brainstorming/scripts/__pycache__/brain.cpython-313.pyc +0 -0
  99. package/src/core-skills/wizz-brainstorming/scripts/tests/__pycache__/test_brain.cpython-313-pytest-9.1.1.pyc +0 -0
  100. package/src/core-skills/wizz-brainstorming/scripts/tests/__pycache__/test_brain.cpython-314.pyc +0 -0
  101. package/src/core-skills/wizz-customize/scripts/__pycache__/list_customizable_skills.cpython-313.pyc +0 -0
  102. package/src/core-skills/wizz-customize/scripts/tests/__pycache__/test_list_customizable_skills.cpython-313-pytest-9.1.1.pyc +0 -0
  103. package/src/core-skills/wizz-forge-idea/scripts/__pycache__/resolve_personas.cpython-313.pyc +0 -0
  104. package/src/core-skills/wizz-forge-idea/scripts/__pycache__/resolve_personas.cpython-314.pyc +0 -0
  105. package/src/core-skills/wizz-forge-idea/scripts/tests/__pycache__/test_resolve_personas.cpython-313-pytest-9.1.1.pyc +0 -0
  106. package/src/core-skills/wizz-forge-idea/scripts/tests/__pycache__/test_resolve_personas.cpython-314.pyc +0 -0
  107. package/src/core-skills/wizz-party-mode/scripts/__pycache__/resolve_party.cpython-313.pyc +0 -0
  108. package/src/core-skills/wizz-party-mode/scripts/__pycache__/resolve_party.cpython-314.pyc +0 -0
  109. package/src/core-skills/wizz-party-mode/scripts/tests/__pycache__/test_resolve_party.cpython-313-pytest-9.1.1.pyc +0 -0
  110. package/src/core-skills/wizz-party-mode/scripts/tests/__pycache__/test_resolve_party.cpython-314.pyc +0 -0
  111. package/src/scripts/__pycache__/resolve_customization.cpython-314.pyc +0 -0
  112. package/src/skills-lib/wizz-huashu-design/package-lock.json +0 -846
  113. package/src/skills-lib/wizz-humanizer/WARP.md +0 -53
  114. package/src/skills-lib/wizz-humanizer/references/full-example.md +0 -72
  115. package/src/skills-lib/wizz-humanizer/references/personality-and-soul.md +0 -36
  116. package/src/skills-lib/wizz-react-components/package-lock.json +0 -231
  117. package/src/skills-lib/wizz-supabase-postgres-best-practices/CLAUDE.md +0 -68
  118. package/src/skills-lib/wizz-ui-ux-pro-max/scripts/__pycache__/core.cpython-314.pyc +0 -0
  119. package/src/skills-lib/wizz-ui-ux-pro-max/scripts/__pycache__/design_system.cpython-314.pyc +0 -0
@@ -0,0 +1,203 @@
1
+ /**
2
+ * Guided install: the default path for a first install in an interactive
3
+ * terminal. Four steps (folder, profile, AI tool, name), a review screen and
4
+ * sensible defaults for everything else. The full question-by-question flow
5
+ * stays available with --advanced, and every non-interactive flag keeps
6
+ * working exactly as before (those paths never reach this file).
7
+ */
8
+ const prompts = require('../prompts');
9
+ const { t, LANGUAGES } = require('./messages');
10
+ const { getProfile, summarizeAreas } = require('./profiles');
11
+ const steps = require('./steps');
12
+ const { AREA_LABELS } = require('./labels');
13
+
14
+ // Flags that already answer part of the install: when present the user is
15
+ // scripting or knows what they want, so the legacy flow handles it verbatim.
16
+ const SCRIPTED_FLAGS = [
17
+ 'yes',
18
+ 'advanced',
19
+ 'modules',
20
+ 'tools',
21
+ 'areas',
22
+ 'mcps',
23
+ 'clis',
24
+ 'customSource',
25
+ 'action',
26
+ 'set',
27
+ 'channel',
28
+ 'allStable',
29
+ 'allNext',
30
+ 'next',
31
+ 'pin',
32
+ ];
33
+
34
+ /**
35
+ * Whether this run should take the guided path.
36
+ * @param {Object} options - Parsed CLI options
37
+ * @param {boolean} [isTTY] - Injection seam for tests
38
+ * @returns {boolean}
39
+ */
40
+ function isGuidedEligible(options = {}, isTTY = !!process.stdin.isTTY) {
41
+ if (!isTTY) return false;
42
+ return !SCRIPTED_FLAGS.some((flag) => {
43
+ const value = options[flag];
44
+ return Array.isArray(value) ? value.length > 0 : value !== undefined && value !== false;
45
+ });
46
+ }
47
+
48
+ async function listModules() {
49
+ const { OfficialModules } = require('../modules/official-modules');
50
+ const { ExternalModuleManager } = require('../modules/external-manager');
51
+ const builtIn = ((await new OfficialModules().listAvailable()).modules || []).map((mod) => ({
52
+ code: mod.id,
53
+ name: mod.name,
54
+ description: mod.description,
55
+ defaultSelected: mod.defaultSelected,
56
+ fromBmad: false,
57
+ }));
58
+ const seen = new Set(builtIn.map((mod) => mod.code));
59
+ const external = (await new ExternalModuleManager().listAvailable())
60
+ .filter((mod) => !mod.builtIn && !mod.deprecated && !mod.advancedOnly && !seen.has(mod.code))
61
+ .map((mod) => ({
62
+ code: mod.code,
63
+ name: mod.name,
64
+ description: mod.description,
65
+ defaultSelected: false,
66
+ fromBmad: String(mod.url || '').includes('bmad-code-org'),
67
+ }));
68
+ return [...builtIn, ...external];
69
+ }
70
+
71
+ /**
72
+ * Resolve what a profile installs. Custom asks modules and areas here.
73
+ * @returns {Promise<{modules: string[], areas: string[]}>} areas [] = all
74
+ */
75
+ async function resolveSelection(profileId, lang, registry) {
76
+ const profile = getProfile(profileId);
77
+ if (profile.id !== 'custom') {
78
+ return { modules: [...profile.modules], areas: profile.areas ? [...profile.areas] : [] };
79
+ }
80
+ const modules = await steps.askModules(lang, await listModules());
81
+ const areas = modules.includes('bmm') ? await steps.askAreas(lang, registry) : [];
82
+ return { modules, areas };
83
+ }
84
+
85
+ async function showReview(ctx) {
86
+ const { lang, profileId, selection, registry, ides } = ctx;
87
+ const color = await prompts.getColor();
88
+ const summary = summarizeAreas(registry, selection.areas);
89
+ const ok = color.green('✓');
90
+ const lines = [
91
+ `${ok} ${t(lang, 'reviewAgents', { n: summary.agents })} ${color.dim(summary.areas.map((key) => (AREA_LABELS[key] ? AREA_LABELS[key][lang].name : key)).join(' · '))}`,
92
+ `${ok} ${t(lang, 'reviewSkills', { n: summary.skills })} ${color.dim(t(lang, 'reviewSkillsHint'))}`,
93
+ `${ok} ${t(lang, 'reviewMemory')} ${color.dim(t(lang, 'reviewMemoryHint'))}`,
94
+ `${ok} ${t(lang, 'reviewTools')} ${color.dim(ides.join(', '))}`,
95
+ ];
96
+ if (selection.modules.includes('lowticket')) lines.push(`${ok} ${t(lang, 'reviewLowticket')}`);
97
+ await prompts.note(lines.join('\n'), `${t(lang, 'reviewTitle')} (${getProfile(profileId)[lang].name})`);
98
+ }
99
+
100
+ async function chooseClis(ui, lang, selection) {
101
+ const plan = await ui.selectClis(selection.modules, selection.areas, {
102
+ cliMessage: t(lang, 'optionalTitle'),
103
+ cliOption: (cli) => steps.cliOption(cli, lang),
104
+ });
105
+ if (plan.alreadyInstalled.length > 0) {
106
+ await prompts.log.info(t(lang, 'alreadyInstalled', { list: plan.alreadyInstalled.map((c) => c.id).join(', ') }));
107
+ }
108
+ return plan;
109
+ }
110
+
111
+ async function chooseMcps(ui, lang, profileId, selection) {
112
+ // Profiles never write MCP config on their own: they only print the
113
+ // command, like --yes does. Custom asks, same as the legacy flow.
114
+ if (profileId !== 'custom') return ui.selectMcps(selection.modules, selection.areas, { yes: true });
115
+ return ui.selectMcps(selection.modules, selection.areas, { mcpMessage: t(lang, 'mcpsQuestion') });
116
+ }
117
+
118
+ /**
119
+ * Steps 2 to 4 plus the review loop. Returns everything the installer
120
+ * needs except module configs.
121
+ */
122
+ async function collectChoices(ui, lang, registry, ideManager) {
123
+ let profileId = 'everything';
124
+ let selection;
125
+ let ides;
126
+ let userName;
127
+ for (;;) {
128
+ await steps.stepHeader(lang, 2);
129
+ profileId = await steps.askProfile(lang, profileId);
130
+ selection = await resolveSelection(profileId, lang, registry);
131
+ if (!ides) {
132
+ await steps.stepHeader(lang, 3);
133
+ ides = await steps.askTools(lang, ideManager);
134
+ await steps.stepHeader(lang, 4);
135
+ userName = await steps.askName(lang);
136
+ }
137
+ await showReview({ lang, profileId, selection, registry, ides });
138
+ const cliPlan = await chooseClis(ui, lang, selection);
139
+ const action = await prompts.select({
140
+ message: t(lang, 'reviewAction'),
141
+ choices: [
142
+ { name: t(lang, 'actionInstall'), value: 'install' },
143
+ { name: t(lang, 'actionProfile'), value: 'profile' },
144
+ { name: t(lang, 'actionCustomize'), value: 'customize' },
145
+ ],
146
+ default: 'install',
147
+ });
148
+ if (action === 'install') {
149
+ const mcpPlan = await chooseMcps(ui, lang, profileId, selection);
150
+ return { profileId, selection, ides, userName, cliPlan, mcpPlan };
151
+ }
152
+ if (action === 'customize') profileId = 'custom';
153
+ }
154
+ }
155
+
156
+ /**
157
+ * Run the guided fresh install and return the same config shape the legacy
158
+ * flow returns, so the installer itself does not change.
159
+ * @param {Object} ui - The UI instance (reuses its validators and pickers)
160
+ * @param {Object} options - Parsed CLI options
161
+ * @param {{directory: string, lang: 'en'|'pt', channelOptions: Object}} ctx
162
+ */
163
+ async function runGuidedInstall(ui, options, ctx) {
164
+ const { directory, lang, channelOptions } = ctx;
165
+ const registry = await ui._loadSkillsRegistry();
166
+ const { IdeManager } = require('../ide/manager');
167
+ const ideManager = new IdeManager();
168
+ await ideManager.ensureInitialized();
169
+
170
+ const choices = await collectChoices(ui, lang, registry, ideManager);
171
+ const modules = ['core', ...choices.selection.modules.filter((code) => code !== 'core')];
172
+ const language = LANGUAGES.find((l) => l.value === lang).communication;
173
+ const { moduleConfigs, setOverrides } = await ui.collectModuleConfigs(directory, modules, {
174
+ ...options,
175
+ userName: choices.userName,
176
+ communicationLanguage: language,
177
+ documentOutputLanguage: language,
178
+ outputFolder: '_wizz-output',
179
+ yes: true,
180
+ quiet: true,
181
+ channelOptions,
182
+ });
183
+
184
+ return {
185
+ actionType: 'install',
186
+ directory,
187
+ modules,
188
+ ides: choices.ides,
189
+ skipIde: choices.ides.length === 0,
190
+ selectedAreas: choices.selection.areas,
191
+ mcpPlan: choices.mcpPlan,
192
+ cliPlan: choices.cliPlan,
193
+ coreConfig: moduleConfigs.core || {},
194
+ moduleConfigs,
195
+ setOverrides,
196
+ skipPrompts: false,
197
+ channelOptions,
198
+ traceEnabled: null,
199
+ guided: { lang, profile: choices.profileId },
200
+ };
201
+ }
202
+
203
+ module.exports = { isGuidedEligible, runGuidedInstall, SCRIPTED_FLAGS };
@@ -0,0 +1,185 @@
1
+ /**
2
+ * Human-facing labels for the guided installer: one line per area and per
3
+ * CLI, in English (default) and Portuguese.
4
+ *
5
+ * Lives here, not in skills-registry.yaml, on purpose: agents read the
6
+ * registry at runtime and every extra field there costs tokens on every
7
+ * routed request. The registry stays the routing contract; this file is only
8
+ * what a person reads while installing. test/test-guided-installer.js fails
9
+ * when an area or CLI in the registry has no entry here, so the two cannot
10
+ * drift apart silently.
11
+ */
12
+
13
+ const AREA_LABELS = {
14
+ designer: {
15
+ en: { name: 'Design', help: 'UI, landing pages, design systems, motion, video' },
16
+ pt: { name: 'Design', help: 'interface, landing page, design system, motion, vídeo' },
17
+ },
18
+ copy: {
19
+ en: { name: 'Copy', help: 'sales copy, headlines, emails, sequences' },
20
+ pt: { name: 'Copy', help: 'texto de venda, headline, e-mail, sequência' },
21
+ },
22
+ seo: {
23
+ en: { name: 'SEO', help: 'audits, AI search, schema, programmatic pages' },
24
+ pt: { name: 'SEO', help: 'auditoria, busca por IA, schema, páginas em escala' },
25
+ },
26
+ growth: {
27
+ en: { name: 'Growth', help: 'conversion, launch, pricing, retention, offers' },
28
+ pt: { name: 'Growth', help: 'conversão, lançamento, preço, retenção, oferta' },
29
+ },
30
+ social: {
31
+ en: { name: 'Social', help: 'posts, Reels scripts, content calendar, publishing' },
32
+ pt: { name: 'Social', help: 'post, roteiro de Reels, calendário, publicação' },
33
+ },
34
+ ads: {
35
+ en: { name: 'Ads', help: 'paid campaigns, ad creatives, conversion tracking' },
36
+ pt: { name: 'Anúncios', help: 'campanha paga, criativo, tracking de conversão' },
37
+ },
38
+ architect: {
39
+ en: { name: 'Architecture', help: 'databases, security, infra, technical decisions' },
40
+ pt: { name: 'Arquitetura', help: 'banco, segurança, infra, decisão técnica' },
41
+ },
42
+ qa: {
43
+ en: { name: 'QA', help: 'tests, browser checks, security audit, launch readiness' },
44
+ pt: { name: 'QA', help: 'teste, verificação no navegador, auditoria, pré-lançamento' },
45
+ },
46
+ analyst: {
47
+ en: { name: 'Analysis', help: 'research, project kickoff, implementation plan' },
48
+ pt: { name: 'Análise', help: 'pesquisa, kickoff de projeto, plano de implementação' },
49
+ },
50
+ dev: {
51
+ en: { name: 'Development', help: 'build features, fix bugs, code review, sprints' },
52
+ pt: { name: 'Desenvolvimento', help: 'feature, bug, review de código, sprint' },
53
+ },
54
+ pm: {
55
+ en: { name: 'Product', help: 'briefs, PRDs, requirements, scope' },
56
+ pt: { name: 'Produto', help: 'brief, PRD, requisitos, escopo' },
57
+ },
58
+ 'tech-writer': {
59
+ en: { name: 'Docs', help: 'technical documentation and diagrams' },
60
+ pt: { name: 'Documentação', help: 'docs técnicas e diagramas' },
61
+ },
62
+ 'ux-designer': {
63
+ en: { name: 'UX', help: 'user flows, UX specs, user stories' },
64
+ pt: { name: 'UX', help: 'fluxos, especificação de UX, user stories' },
65
+ },
66
+ memoria: {
67
+ en: { name: 'Memory', help: 'saves decisions and project state between sessions' },
68
+ pt: { name: 'Memória', help: 'guarda decisões e estado do projeto entre sessões' },
69
+ },
70
+ };
71
+
72
+ // Requirement tokens a CLI can carry. Anything not listed means the tool is
73
+ // free and light. `platform` gates come from the registry itself.
74
+ const NEED_LABELS = {
75
+ 'api-key': { en: 'API key', pt: 'chave de API' },
76
+ account: { en: 'account', pt: 'conta' },
77
+ paid: { en: 'paid', pt: 'pago' },
78
+ 'free-plan': { en: 'free plan', pt: 'plano grátis' },
79
+ docker: { en: 'Docker', pt: 'Docker' },
80
+ python: { en: 'Python', pt: 'Python' },
81
+ ffmpeg: { en: 'ffmpeg', pt: 'ffmpeg' },
82
+ heavy: { en: 'heavy download', pt: 'download pesado' },
83
+ };
84
+
85
+ const CLI_LABELS = {
86
+ hyperframes: {
87
+ needs: ['ffmpeg'],
88
+ en: 'design video scenes in HTML',
89
+ pt: 'desenhar cenas de vídeo em HTML',
90
+ },
91
+ 'claude-video': {
92
+ needs: ['ffmpeg'],
93
+ en: 'watch and summarize an existing video',
94
+ pt: 'assistir e resumir um vídeo existente',
95
+ },
96
+ 'get-brolls': {
97
+ needs: ['ffmpeg', 'python'],
98
+ en: 'find real B-roll footage for a video',
99
+ pt: 'achar imagens de apoio reais para um vídeo',
100
+ },
101
+ buttercut: {
102
+ needs: ['heavy'],
103
+ en: 'cut and rough-edit recorded video',
104
+ pt: 'cortar e pré-editar vídeo gravado',
105
+ },
106
+ voicebox: {
107
+ needs: ['heavy'],
108
+ en: 'local voice-over and voice cloning',
109
+ pt: 'narração e clonagem de voz local',
110
+ },
111
+ 'ctc-align': {
112
+ needs: ['python'],
113
+ en: 'word-level timing to sync captions',
114
+ pt: 'timing palavra a palavra para legenda',
115
+ },
116
+ 'apple-design': {
117
+ needs: [],
118
+ en: 'review native iOS/macOS UI against Apple HIG',
119
+ pt: 'revisar UI nativa iOS/macOS pelo guia da Apple',
120
+ },
121
+ distribb: {
122
+ needs: ['account', 'paid'],
123
+ en: 'publish SEO articles and build backlinks',
124
+ pt: 'publicar artigos de SEO e ganhar backlinks',
125
+ },
126
+ buffer: {
127
+ needs: ['account', 'free-plan'],
128
+ en: 'publish and schedule social posts',
129
+ pt: 'publicar e agendar posts nas redes',
130
+ },
131
+ 'sentry-cli': {
132
+ needs: ['account'],
133
+ en: 'read errors from a project that already uses Sentry',
134
+ pt: 'ler erros de um projeto que já usa Sentry',
135
+ },
136
+ archify: {
137
+ needs: [],
138
+ en: 'draw validated architecture diagrams',
139
+ pt: 'desenhar diagramas de arquitetura validados',
140
+ },
141
+ 'agent-browser': {
142
+ needs: [],
143
+ en: 'drive a real browser for checks and screenshots',
144
+ pt: 'usar um navegador real para testar e tirar print',
145
+ },
146
+ strix: {
147
+ needs: ['docker', 'api-key'],
148
+ en: 'automated pentest, only on systems you own',
149
+ pt: 'pentest automático, só em sistema seu',
150
+ },
151
+ rtk: {
152
+ needs: [],
153
+ en: 'cuts 60-90% of tokens on dev commands',
154
+ pt: 'corta 60-90% dos tokens em comandos de dev',
155
+ },
156
+ };
157
+
158
+ /**
159
+ * Requirement badges for a CLI, in the chosen language. Adds the platform
160
+ * gate (Apple Silicon, macOS) from the registry entry.
161
+ * @param {{id: string, platform?: string|string[]}} cli - Resolved CLI entry
162
+ * @param {'en'|'pt'} lang - Display language
163
+ * @returns {string[]} Short badge texts; empty means free and light
164
+ */
165
+ function cliBadges(cli, lang) {
166
+ const info = CLI_LABELS[cli.id];
167
+ const badges = ((info && info.needs) || []).map((need) => NEED_LABELS[need][lang]);
168
+ const platforms = [cli.platform || []].flat();
169
+ if (platforms.includes('darwin-arm64')) badges.push('Apple Silicon');
170
+ else if (platforms.length === 1 && platforms[0] === 'darwin') badges.push('macOS');
171
+ return badges;
172
+ }
173
+
174
+ /**
175
+ * One-line description for a CLI, falling back to the registry id.
176
+ * @param {string} id - CLI id
177
+ * @param {'en'|'pt'} lang - Display language
178
+ * @returns {string}
179
+ */
180
+ function cliDescription(id, lang) {
181
+ const info = CLI_LABELS[id];
182
+ return info ? info[lang] : '';
183
+ }
184
+
185
+ module.exports = { AREA_LABELS, CLI_LABELS, NEED_LABELS, cliBadges, cliDescription };
@@ -0,0 +1,132 @@
1
+ /**
2
+ * Guided installer text, English (default) and Portuguese. Every string the
3
+ * guided path prints comes from here, so adding a language is one more
4
+ * block and nothing else.
5
+ */
6
+
7
+ const MESSAGES = {
8
+ en: {
9
+ tagline: 'Your AI team: one agent for each area.',
10
+ whatHappens: 'What happens next',
11
+ duration: '~2 min',
12
+ stepNames: ['Where to install', "What you'll use it for", 'Which AI tool you use', 'Your name'],
13
+ languageHint: 'Language: English. Portuguese is available on the next screen.',
14
+ languageQuestion: 'Language · Idioma',
15
+ step: 'Step {n} of {total}',
16
+ dirQuestion: 'Where should Wizz Method be installed?',
17
+ dirCreate: 'This folder does not exist yet. Create {dir}?',
18
+ dirRetry: 'Okay, pick another folder.',
19
+ existingFound: 'Wizz Method is already installed here. Choose what to do.',
20
+ profileQuestion: 'What will you use it for?',
21
+ toolQuestion: 'Which AI tool do you use?',
22
+ toolDetected: 'found on this machine',
23
+ toolOther: 'Other tools…',
24
+ toolOtherHelp: '45 more: Windsurf, Cline, Gemini CLI, Kiro…',
25
+ toolOtherQuestion: 'Pick your tools (type to filter)',
26
+ toolNone: 'Pick at least one tool so the agents have somewhere to live.',
27
+ nameQuestion: 'What should the agents call you?',
28
+ modulesQuestion: 'Which modules?',
29
+ fromBmad: 'from BMAD',
30
+ areasQuestion: 'Which areas?',
31
+ mcpsQuestion: 'Which MCP servers? (they give the agents live access to a service)',
32
+ reviewTitle: "You're getting",
33
+ reviewAgents: '{n} agents',
34
+ reviewSkills: '{n} skills',
35
+ reviewSkillsHint: 'list them anytime: wizz catalog',
36
+ reviewMemory: 'Memory',
37
+ reviewMemoryHint: 'decisions saved per project',
38
+ reviewTools: 'AI tool',
39
+ reviewLowticket: 'Low Ticket playbook',
40
+ optionalTitle: 'Optional tools (tick to install now, or install later)',
41
+ free: 'free',
42
+ alreadyInstalled: 'already installed: {list}',
43
+ reviewAction: 'Ready?',
44
+ actionInstall: 'Install',
45
+ actionProfile: 'Change profile',
46
+ actionCustomize: 'Customize',
47
+ nextSteps: 'Next steps',
48
+ tryAsking: 'Try asking your agent:',
49
+ skippedTools: 'Tools left for later (install commands are listed above):',
50
+ docs: 'Docs',
51
+ help: 'Help',
52
+ catalogLegend: '✓ installed ⌘ command-line tool ◇ MCP server',
53
+ },
54
+ pt: {
55
+ tagline: 'Seu time de IA: um agente para cada área.',
56
+ whatHappens: 'O que vai acontecer',
57
+ duration: '~2 min',
58
+ stepNames: ['Onde instalar', 'Pra que você vai usar', 'Qual IA você usa', 'Seu nome'],
59
+ languageHint: 'Idioma: inglês. Português está disponível na próxima tela.',
60
+ languageQuestion: 'Language · Idioma',
61
+ step: 'Passo {n} de {total}',
62
+ dirQuestion: 'Onde instalar o Wizz Method?',
63
+ dirCreate: 'Essa pasta ainda não existe. Criar {dir}?',
64
+ dirRetry: 'Tudo bem, escolha outra pasta.',
65
+ existingFound: 'O Wizz Method já está instalado aqui. Escolha o que fazer.',
66
+ profileQuestion: 'Pra que você vai usar?',
67
+ toolQuestion: 'Qual IA você usa?',
68
+ toolDetected: 'encontrada nesta máquina',
69
+ toolOther: 'Outras ferramentas…',
70
+ toolOtherHelp: 'mais 45: Windsurf, Cline, Gemini CLI, Kiro…',
71
+ toolOtherQuestion: 'Escolha suas ferramentas (digite pra filtrar)',
72
+ toolNone: 'Escolha pelo menos uma ferramenta, é nela que os agentes vão morar.',
73
+ nameQuestion: 'Como os agentes devem te chamar?',
74
+ modulesQuestion: 'Quais módulos?',
75
+ fromBmad: 'do BMAD',
76
+ areasQuestion: 'Quais áreas?',
77
+ mcpsQuestion: 'Quais servidores MCP? (dão aos agentes acesso direto a um serviço)',
78
+ reviewTitle: 'O que vai entrar',
79
+ reviewAgents: '{n} agentes',
80
+ reviewSkills: '{n} skills',
81
+ reviewSkillsHint: 'veja a lista quando quiser: wizz catalog',
82
+ reviewMemory: 'Memória',
83
+ reviewMemoryHint: 'decisões salvas por projeto',
84
+ reviewTools: 'IA',
85
+ reviewLowticket: 'Playbook Low Ticket',
86
+ optionalTitle: 'Ferramentas opcionais (marque pra instalar agora, ou instale depois)',
87
+ free: 'grátis',
88
+ alreadyInstalled: 'já instaladas: {list}',
89
+ reviewAction: 'Tudo certo?',
90
+ actionInstall: 'Instalar',
91
+ actionProfile: 'Trocar perfil',
92
+ actionCustomize: 'Personalizar',
93
+ nextSteps: 'Próximos passos',
94
+ tryAsking: 'Experimente pedir ao seu agente:',
95
+ skippedTools: 'Ferramentas que ficaram pra depois (os comandos estão logo acima):',
96
+ docs: 'Docs',
97
+ help: 'Ajuda',
98
+ catalogLegend: '✓ instalada ⌘ ferramenta de terminal ◇ servidor MCP',
99
+ },
100
+ };
101
+
102
+ const LANGUAGES = [
103
+ { value: 'en', label: 'English', communication: 'English' },
104
+ { value: 'pt', label: 'Português', communication: 'Português (Brasil)' },
105
+ ];
106
+
107
+ /**
108
+ * Normalize a --lang value to a supported code.
109
+ * @param {string|undefined} raw - e.g. "pt", "pt-BR", "en"
110
+ * @returns {'en'|'pt'|null} null when absent or unknown
111
+ */
112
+ function normalizeLang(raw) {
113
+ if (!raw) return null;
114
+ const code = String(raw).toLowerCase().slice(0, 2);
115
+ return MESSAGES[code] ? code : null;
116
+ }
117
+
118
+ /**
119
+ * Translate a key, filling {placeholders}.
120
+ * @param {'en'|'pt'} lang - Display language
121
+ * @param {string} key - Message key
122
+ * @param {Object} [vars] - Placeholder values
123
+ * @returns {string}
124
+ */
125
+ function t(lang, key, vars = {}) {
126
+ const table = MESSAGES[lang] || MESSAGES.en;
127
+ const value = key in table ? table[key] : MESSAGES.en[key];
128
+ if (typeof value !== 'string') return value;
129
+ return value.replaceAll(/\{(\w+)\}/g, (match, name) => (name in vars ? String(vars[name]) : match));
130
+ }
131
+
132
+ module.exports = { MESSAGES, LANGUAGES, normalizeLang, t };
@@ -0,0 +1,32 @@
1
+ const prompts = require('../prompts');
2
+ const { paint, BRAND_ORANGE } = require('../banner');
3
+ const { t } = require('./messages');
4
+ const { getProfile } = require('./profiles');
5
+
6
+ /**
7
+ * Closing screen of the guided install: three things to ask the agent
8
+ * right now (picked by profile) and the names of the tools the user left
9
+ * for later.
10
+ * @param {Object} config - The config returned by runGuidedInstall
11
+ */
12
+ async function showGuidedOutro(config) {
13
+ const { lang, profile } = config.guided;
14
+ const color = await prompts.getColor();
15
+ const colorOn = color.isColorSupported !== false;
16
+ const lines = [color.bold(t(lang, 'tryAsking'))];
17
+ for (const ask of getProfile(profile).tryAsking[lang]) {
18
+ lines.push(` ${paint(BRAND_ORANGE, '›', colorOn)} ${ask}`);
19
+ }
20
+
21
+ // Only the names here: the full install commands were printed above by the
22
+ // installer, and repeating long clone commands buries the next steps.
23
+ const skipped = ((config.cliPlan && config.cliPlan.toRecommend) || []).map((cli) => cli.id);
24
+ if (skipped.length > 0) {
25
+ lines.push('', color.bold(t(lang, 'skippedTools')), ` ${color.dim(skipped.join(' · '))}`);
26
+ }
27
+
28
+ lines.push('', color.dim(`${t(lang, 'docs')} method.wizzcomms.com`), color.dim(`${t(lang, 'help')} wizz doctor · wizz catalog`));
29
+ await prompts.note(lines.join('\n'), t(lang, 'nextSteps'));
30
+ }
31
+
32
+ module.exports = { showGuidedOutro };
@@ -0,0 +1,95 @@
1
+ /**
2
+ * Install profiles for the guided installer. A profile answers "what will
3
+ * you use it for?" and decides modules and skill areas in one choice, so the
4
+ * normal path never shows the module or area lists.
5
+ *
6
+ * `areas: null` means every area (the installSkillsLib sentinel is `[]`).
7
+ */
8
+
9
+ const BASE_MODULES = ['wizz', 'bmm'];
10
+
11
+ const PROFILES = [
12
+ {
13
+ id: 'everything',
14
+ modules: BASE_MODULES,
15
+ areas: null,
16
+ en: { name: 'Everything', help: 'product, code, design, content and marketing' },
17
+ pt: { name: 'Completo', help: 'produto, código, design, conteúdo e marketing' },
18
+ tryAsking: {
19
+ en: ['plan a new feature from the brief to the first story', 'write a LinkedIn post about our launch', 'audit the SEO of my site'],
20
+ pt: [
21
+ 'planeja uma feature nova, do brief à primeira story',
22
+ 'escreve um post pro LinkedIn sobre o lançamento',
23
+ 'faz uma auditoria de SEO do meu site',
24
+ ],
25
+ },
26
+ },
27
+ {
28
+ id: 'marketing',
29
+ modules: BASE_MODULES,
30
+ areas: ['designer', 'copy', 'seo', 'growth', 'social', 'ads', 'analyst', 'memoria'],
31
+ en: { name: 'Content & marketing', help: 'copy, social, video, ads and SEO' },
32
+ pt: { name: 'Conteúdo e marketing', help: 'copy, social, vídeo, anúncios e SEO' },
33
+ tryAsking: {
34
+ en: ['write a LinkedIn post about our launch', "plan next week's content calendar", 'write 3 headline variations for a Meta ad'],
35
+ pt: [
36
+ 'escreve um post pro LinkedIn sobre o lançamento',
37
+ 'monta o calendário de conteúdo da semana',
38
+ 'cria 3 variações de headline pra um anúncio na Meta',
39
+ ],
40
+ },
41
+ },
42
+ {
43
+ id: 'product',
44
+ modules: BASE_MODULES,
45
+ areas: ['designer', 'architect', 'qa', 'analyst', 'dev', 'pm', 'tech-writer', 'ux-designer', 'memoria'],
46
+ en: { name: 'Product & code', help: 'planning, architecture, development and tests' },
47
+ pt: { name: 'Produto e código', help: 'planejamento, arquitetura, desenvolvimento e testes' },
48
+ tryAsking: {
49
+ en: ['write the PRD for a new feature', 'fix this bug and add a test for it', 'review the code in my last commit'],
50
+ pt: ['escreve o PRD de uma feature nova', 'corrige esse bug e cria um teste pra ele', 'revisa o código do meu último commit'],
51
+ },
52
+ },
53
+ {
54
+ id: 'custom',
55
+ modules: null,
56
+ areas: null,
57
+ en: { name: 'Custom', help: 'pick modules, areas and tools one by one' },
58
+ pt: { name: 'Personalizar', help: 'escolher módulos, áreas e ferramentas um a um' },
59
+ tryAsking: {
60
+ en: ['what can you do in this project?', 'start a new project with me'],
61
+ pt: ['o que você sabe fazer neste projeto?', 'começa um projeto novo comigo'],
62
+ },
63
+ },
64
+ ];
65
+
66
+ /**
67
+ * @param {string} id - Profile id
68
+ * @returns {Object|undefined}
69
+ */
70
+ function getProfile(id) {
71
+ return PROFILES.find((profile) => profile.id === id);
72
+ }
73
+
74
+ /**
75
+ * What a set of areas brings in, read from the registry so the review screen
76
+ * never shows a number that drifted from the real catalog.
77
+ * @param {Object|null} registry - Parsed skills-registry.yaml
78
+ * @param {string[]|null} areas - Chosen areas; null or [] means all
79
+ * @returns {{areas: string[], agents: number, skills: number}}
80
+ */
81
+ function summarizeAreas(registry, areas) {
82
+ const all = (registry && registry.areas) || {};
83
+ const chosen = !areas || areas.length === 0 ? Object.keys(all) : areas.filter((key) => all[key]);
84
+ const skillIds = new Set();
85
+ const agents = new Set();
86
+ for (const key of chosen) {
87
+ const area = all[key];
88
+ if (area.agent) agents.add(area.agent);
89
+ for (const skill of area.skills || []) skillIds.add(skill.id);
90
+ }
91
+ for (const skill of (registry && registry.utility) || []) skillIds.add(skill.id);
92
+ return { areas: chosen, agents: agents.size, skills: skillIds.size };
93
+ }
94
+
95
+ module.exports = { PROFILES, getProfile, summarizeAreas };