wizz-method 2.18.0 → 2.19.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 (154) hide show
  1. package/package.json +5 -3
  2. package/removals.txt +10 -0
  3. package/skills-registry.yaml +50 -38
  4. package/src/bmm-skills/1-analysis/wizz-set-feature/SKILL.md +9 -9
  5. package/src/bmm-skills/4-implementation/wizz-create-story/SKILL.md +1 -1
  6. package/src/bmm-skills/4-implementation/wizz-dev-story/SKILL.md +1 -1
  7. package/src/bmm-skills/4-implementation/wizz-qa-generate-e2e-tests/SKILL.md +1 -1
  8. package/src/bmm-skills/4-implementation/wizz-qa-generate-e2e-tests/checklist.md +1 -1
  9. package/src/bmm-skills/4-implementation/wizz-quick-dev/SKILL.md +1 -1
  10. package/src/bmm-skills/4-implementation/wizz-sprint-status/SKILL.md +5 -5
  11. package/src/bmm-skills/module-help.csv +1 -1
  12. package/src/bmm-skills/module.yaml +1 -1
  13. package/src/core-skills/_shared/handoff-protocol.md +2 -2
  14. package/src/modules/lowticket/skills/wizz-lowticket-funil/SKILL.md +1 -1
  15. package/src/modules/lowticket/skills/wizz-lowticket-guia/SKILL.md +1 -1
  16. package/src/modules/lowticket/skills/wizz-lowticket-metodologia/SKILL.md +1 -1
  17. package/src/modules/lowticket/skills/wizz-lowticket-minerador/SKILL.md +1 -1
  18. package/src/modules/lowticket/skills/wizz-lowticket-pagina/SKILL.md +1 -1
  19. package/src/modules/lowticket/skills/wizz-lowticket-trafego/SKILL.md +1 -1
  20. package/src/modules/wizz/_shared/cerebro.md +7 -7
  21. package/src/modules/wizz/_shared/communication-rules.md +1 -1
  22. package/src/modules/wizz/_shared/encerramento.md +4 -3
  23. package/src/modules/wizz/_shared/organizacao.md +8 -4
  24. package/src/modules/wizz/_shared/token-economy.md +1 -1
  25. package/src/modules/wizz/_shared/video-pipeline.md +4 -4
  26. package/src/modules/wizz/agents/wizz-ads/SKILL.md +4 -1
  27. package/src/modules/wizz/agents/wizz-ads/customize.toml +12 -3
  28. package/src/modules/wizz/agents/wizz-ads/knowledge/playbook.md +36 -0
  29. package/src/modules/wizz/agents/wizz-copy/SKILL.md +4 -1
  30. package/src/modules/wizz/agents/wizz-copy/customize.toml +2 -3
  31. package/src/modules/wizz/agents/wizz-copy/knowledge/playbook.md +34 -0
  32. package/src/modules/wizz/agents/wizz-designer/SKILL.md +2 -2
  33. package/src/modules/wizz/agents/wizz-designer/customize.toml +2 -3
  34. package/src/modules/wizz/agents/wizz-growth/SKILL.md +4 -1
  35. package/src/modules/wizz/agents/wizz-growth/customize.toml +33 -4
  36. package/src/modules/wizz/agents/wizz-growth/knowledge/playbook.md +39 -0
  37. package/src/modules/wizz/agents/wizz-maestro/SKILL.md +6 -8
  38. package/src/modules/wizz/agents/wizz-maestro/customize.toml +2 -3
  39. package/src/modules/wizz/agents/wizz-memoria/SKILL.md +7 -7
  40. package/src/modules/wizz/agents/wizz-memoria/customize.toml +5 -6
  41. package/src/modules/wizz/agents/wizz-qa/SKILL.md +5 -6
  42. package/src/modules/wizz/agents/wizz-qa/customize.toml +3 -4
  43. package/src/modules/wizz/agents/wizz-seo/SKILL.md +4 -1
  44. package/src/modules/wizz/agents/wizz-seo/customize.toml +2 -3
  45. package/src/modules/wizz/agents/wizz-seo/knowledge/playbook.md +31 -0
  46. package/src/modules/wizz/agents/wizz-social/SKILL.md +3 -3
  47. package/src/modules/wizz/agents/wizz-social/customize.toml +2 -3
  48. package/src/modules/wizz/overrides/wizz-agent-analyst.toml +2 -2
  49. package/src/modules/wizz/overrides/wizz-agent-architect.toml +3 -3
  50. package/src/modules/wizz/overrides/wizz-agent-dev.toml +3 -3
  51. package/src/modules/wizz/overrides/wizz-agent-pm.toml +2 -2
  52. package/src/modules/wizz/overrides/wizz-agent-tech-writer.toml +2 -2
  53. package/src/modules/wizz/overrides/wizz-agent-ux-designer.toml +2 -2
  54. package/src/skills-lib/_shared/complexity-signal.md +8 -9
  55. package/src/skills-lib/_shared/dispatch-rule.yaml +21 -0
  56. package/src/skills-lib/{cerebro → wizz-cerebro}/SKILL.md +1 -1
  57. package/src/skills-lib/{ctc-align → wizz-ctc-align}/SKILL.md +1 -1
  58. package/src/skills-lib/{enhance-prompt → wizz-enhance-prompt}/SKILL.md +1 -1
  59. package/src/skills-lib/{find-skills → wizz-find-skills}/SKILL.md +1 -1
  60. package/src/skills-lib/wizz-huashu-design/references/sfx-library.md +1 -1
  61. package/src/skills-lib/wizz-huashu-design/scripts/add-music.sh +1 -1
  62. package/src/skills-lib/wizz-huashu-design/scripts/html2pptx.js +45 -37
  63. package/src/skills-lib/wizz-huashu-design/scripts/mix-voiceover.sh +1 -1
  64. package/src/skills-lib/wizz-huashu-design/scripts/narrate-pipeline.mjs +11 -5
  65. package/src/skills-lib/wizz-huashu-design/scripts/test_scripts.py +209 -0
  66. package/src/skills-lib/wizz-huashu-design/scripts/tts-doubao.mjs +42 -28
  67. package/src/skills-lib/wizz-ig-profile-optimizer/SKILL.md +1 -1
  68. package/src/skills-lib/wizz-inicio-de-projeto/SKILL.md +1 -1
  69. package/src/skills-lib/wizz-launch-readiness/SKILL.md +7 -7
  70. package/src/skills-lib/wizz-launch-readiness/references/02-seguranca.md +3 -3
  71. package/src/skills-lib/wizz-launch-readiness/references/03-seo-descoberta.md +5 -5
  72. package/src/skills-lib/wizz-launch-readiness/references/04-analytics-medicao.md +1 -1
  73. package/src/skills-lib/wizz-launch-readiness/references/05-conteudo-prova-social.md +6 -6
  74. package/src/skills-lib/wizz-launch-readiness/references/06-legal-lgpd.md +1 -1
  75. package/src/skills-lib/wizz-launch-readiness/references/08-fusao-priorizacao.md +1 -1
  76. package/src/skills-lib/wizz-offer-forge/SKILL.md +3 -3
  77. package/src/skills-lib/{pesquisa-de-publico-do-piva → wizz-pesquisa-de-publico-do-piva}/README.md +1 -1
  78. package/src/skills-lib/{pesquisa-de-publico-do-piva → wizz-pesquisa-de-publico-do-piva}/SKILL.md +1 -1
  79. package/src/skills-lib/wizz-router/SKILL.md +3 -3
  80. package/src/skills-lib/wizz-router/references/routing-table-flat.md +9 -9
  81. package/src/skills-lib/{security-audit-pentest → wizz-security-audit-pentest}/SKILL.md +1 -1
  82. package/src/skills-lib/{site-launch-kit → wizz-site-launch-kit}/SKILL.md +1 -1
  83. package/src/skills-lib/wizz-video-effects/SKILL.md +3 -3
  84. package/src/skills-lib/wizz-video-effects/references/data-contract.md +3 -3
  85. package/src/skills-lib/wizz-video-effects/scripts/fill_breaths.py +15 -1
  86. package/src/skills-lib/wizz-video-effects/scripts/test_fill_breaths.py +20 -0
  87. package/src/skills-lib/wizz-video-styles/SKILL.md +2 -2
  88. package/src/skills-lib/wizz-video-styles/data/recipes.json +32 -1
  89. package/src/skills-lib/wizz-video-styles/data/references.json +211 -1
  90. package/src/skills-lib/wizz-video-styles/data/styles.json +54 -0
  91. package/src/skills-lib/wizz-video-styles/references/generated-prompts.md +13 -3
  92. package/src/skills-lib/wizz-video-styles/references/style-picker.md +4 -2
  93. package/src/skills-lib/wizz-video-styles/references/styles/ui-morph.md +68 -0
  94. package/src/skills-lib/wizz-video-styles/scripts/analyze.sh +21 -9
  95. package/src/skills-lib/wizz-video-styles/scripts/references.mjs +1 -0
  96. package/src/skills-lib/wizz-web-security/SKILL.md +1 -1
  97. package/tools/fetch-assets.mjs +1 -1
  98. package/tools/hooks/README.md +18 -14
  99. package/tools/hooks/rtk-rewrite.js +95 -0
  100. package/tools/hooks/security-defensive-context.js +17 -1
  101. package/tools/hooks/session-rules.js +25 -5
  102. package/tools/hooks/wizz-arrumar.js +126 -12
  103. package/tools/hooks/wizz-artifact-guard.js +41 -7
  104. package/tools/hooks/wizz-cerebro-lib.js +239 -0
  105. package/tools/hooks/wizz-close-reminder.js +124 -0
  106. package/tools/hooks/wizz-debug-lib.js +55 -0
  107. package/tools/hooks/wizz-decision-trace.js +19 -2
  108. package/tools/hooks/wizz-feature.js +20 -4
  109. package/tools/hooks/wizz-router-enforce.js +30 -13
  110. package/tools/installer/command-text.js +243 -0
  111. package/tools/installer/commands/catalog.js +2 -0
  112. package/tools/installer/commands/doctor.js +10 -12
  113. package/tools/installer/commands/fetch-assets.js +5 -5
  114. package/tools/installer/commands/install.js +6 -7
  115. package/tools/installer/commands/resolve.js +17 -17
  116. package/tools/installer/commands/trace-report.js +40 -37
  117. package/tools/installer/core/doctor.js +60 -55
  118. package/tools/installer/core/hooks-settings.js +88 -14
  119. package/tools/installer/core/hooks-smoke.js +134 -0
  120. package/tools/installer/core/installer.js +61 -52
  121. package/tools/installer/core/quick-update.js +2 -3
  122. package/tools/installer/install-text.js +201 -0
  123. package/tools/installer/modules/channel-plan.js +2 -2
  124. package/tools/installer/modules/env-vars.js +5 -6
  125. package/tools/installer/modules/skills-lib.js +1 -1
  126. package/tools/installer/ui.js +17 -9
  127. /package/src/skills-lib/{cerebro → wizz-cerebro}/references/comandos-pesquisa-e-memoria.md +0 -0
  128. /package/src/skills-lib/{cerebro → wizz-cerebro}/references/comandos-rotina-e-captura.md +0 -0
  129. /package/src/skills-lib/{cerebro → wizz-cerebro}/references/comandos-sessao.md +0 -0
  130. /package/src/skills-lib/{ctc-align → wizz-ctc-align}/scripts/align.py +0 -0
  131. /package/src/skills-lib/{enhance-prompt → wizz-enhance-prompt}/README.md +0 -0
  132. /package/src/skills-lib/{enhance-prompt → wizz-enhance-prompt}/references/KEYWORDS.md +0 -0
  133. /package/src/skills-lib/{pesquisa-de-publico-do-piva → wizz-pesquisa-de-publico-do-piva}/assets/template.html +0 -0
  134. /package/src/skills-lib/{pesquisa-de-publico-do-piva → wizz-pesquisa-de-publico-do-piva}/prompts.md +0 -0
  135. /package/src/skills-lib/{security-audit-pentest → wizz-security-audit-pentest}/references/stage-1-validacao-entrada.md +0 -0
  136. /package/src/skills-lib/{security-audit-pentest → wizz-security-audit-pentest}/references/stage-2-autorizacao.md +0 -0
  137. /package/src/skills-lib/{security-audit-pentest → wizz-security-audit-pentest}/references/stage-3-abuso-volume.md +0 -0
  138. /package/src/skills-lib/{security-audit-pentest → wizz-security-audit-pentest}/references/stage-4-vazamento-resposta.md +0 -0
  139. /package/src/skills-lib/{security-audit-pentest → wizz-security-audit-pentest}/references/stage-5-fusao-plano.md +0 -0
  140. /package/src/skills-lib/{site-launch-kit → wizz-site-launch-kit}/references/01-cta-principal.md +0 -0
  141. /package/src/skills-lib/{site-launch-kit → wizz-site-launch-kit}/references/02-barra-fixa-mobile.md +0 -0
  142. /package/src/skills-lib/{site-launch-kit → wizz-site-launch-kit}/references/03-tempo-de-resposta.md +0 -0
  143. /package/src/skills-lib/{site-launch-kit → wizz-site-launch-kit}/references/04-prova-social.md +0 -0
  144. /package/src/skills-lib/{site-launch-kit → wizz-site-launch-kit}/references/05-faq-decisao.md +0 -0
  145. /package/src/skills-lib/{site-launch-kit → wizz-site-launch-kit}/references/06-imagens-reais.md +0 -0
  146. /package/src/skills-lib/{site-launch-kit → wizz-site-launch-kit}/references/07-endereco-como-chegar.md +0 -0
  147. /package/src/skills-lib/{site-launch-kit → wizz-site-launch-kit}/references/08-titles.md +0 -0
  148. /package/src/skills-lib/{site-launch-kit → wizz-site-launch-kit}/references/09-open-graph.md +0 -0
  149. /package/src/skills-lib/{site-launch-kit → wizz-site-launch-kit}/references/10-breadcrumbs.md +0 -0
  150. /package/src/skills-lib/{site-launch-kit → wizz-site-launch-kit}/references/11-alt-text.md +0 -0
  151. /package/src/skills-lib/{site-launch-kit → wizz-site-launch-kit}/references/12-schema-local.md +0 -0
  152. /package/src/skills-lib/{site-launch-kit → wizz-site-launch-kit}/references/13-robots-sitemap.md +0 -0
  153. /package/src/skills-lib/{site-launch-kit → wizz-site-launch-kit}/references/14-privacidade-termos.md +0 -0
  154. /package/src/skills-lib/{site-launch-kit → wizz-site-launch-kit}/references/15-medicao.md +0 -0
@@ -0,0 +1,134 @@
1
+ // hooks-smoke.js — o `wizz doctor` EXECUTA cada hook instalado em
2
+ // `_wizz/hooks/` com um payload mínimo válido (por evento) e reporta o que
3
+ // quebrou. Existe porque os hooks são fail-open: uma cópia parcial (lib
4
+ // faltando, arquivo corrompido) faz a feature sumir em silêncio, e checar só
5
+ // "o arquivo existe" não pega isso.
6
+ //
7
+ // Roda com WIZZ_DEBUG=1, então os erros que o hook engole (ver
8
+ // tools/hooks/wizz-debug-lib.js) chegam em stderr e entram no relatório.
9
+ // Nada é gravado: WIZZ_DEBUG_FILE aponta para o null device, WIZZ_TRACE fica
10
+ // vazio e o payload do artifact-guard usa um arquivo que não existe.
11
+ //
12
+ // Rápido de propósito: ~40 ms por hook, timeout curto, sem rede.
13
+
14
+ const os = require('node:os');
15
+ const path = require('node:path');
16
+ const { it } = require('../install-text');
17
+ const { HOOK_DEFS } = require('./hooks-settings');
18
+
19
+ const HOOK_TIMEOUT_MS = 4000;
20
+
21
+ // Falha ao carregar o código do próprio hook = feature morta. É o caso que o
22
+ // smoke existe para pegar, então vira error (o resto é warn).
23
+ const LOAD_FAILURE_RE = /require |Cannot find module|MODULE_NOT_FOUND|SyntaxError/;
24
+
25
+ /**
26
+ * Payload mínimo válido por hook (formato real que o Claude Code envia).
27
+ * @param {string} id - basename do hook
28
+ * @param {string} projectDir
29
+ * @returns {object}
30
+ */
31
+ function probePayload(id, projectDir) {
32
+ const base = { cwd: projectDir };
33
+ switch (id) {
34
+ case 'session-rules.js': {
35
+ return { ...base, hook_event_name: 'SessionStart', source: 'startup' };
36
+ }
37
+ case 'wizz-router-enforce.js': {
38
+ return { ...base, hook_event_name: 'UserPromptSubmit', prompt: 'implementa a feature de login com testes e validação' };
39
+ }
40
+ case 'security-defensive-context.js': {
41
+ return { ...base, hook_event_name: 'PreToolUse', tool_name: 'Skill', tool_input: { skill: 'security-review' } };
42
+ }
43
+ case 'rtk-rewrite.sh':
44
+ case 'rtk-rewrite.js': {
45
+ return { ...base, hook_event_name: 'PreToolUse', tool_name: 'Bash', tool_input: { command: 'echo wizz-doctor' } };
46
+ }
47
+ case 'wizz-artifact-guard.js': {
48
+ return {
49
+ ...base,
50
+ hook_event_name: 'PostToolUse',
51
+ tool_name: 'Write',
52
+ tool_input: { file_path: path.join(projectDir, '__wizz-doctor-probe__.txt'), content: '' },
53
+ };
54
+ }
55
+ case 'wizz-decision-trace.js':
56
+ case 'wizz-close-reminder.js': {
57
+ return { ...base, hook_event_name: 'Stop', stop_hook_active: false };
58
+ }
59
+ default: {
60
+ return base;
61
+ }
62
+ }
63
+ }
64
+
65
+ /**
66
+ * Execução real de um hook. Injetável em `deps.runHookProcess` nos testes.
67
+ * @param {{file: string, kind: 'node'|'shell', payload: object, cwd: string}} args
68
+ * @returns {{status: number|null, stderr: string, error: string|null}}
69
+ */
70
+ function defaultRunHookProcess({ file, kind, payload, cwd }) {
71
+ const { spawnSync } = require('node:child_process');
72
+ const [cmd, args] = kind === 'shell' ? ['bash', [file]] : [process.execPath, [file]];
73
+ const res = spawnSync(cmd, args, {
74
+ cwd,
75
+ input: JSON.stringify(payload),
76
+ encoding: 'utf8',
77
+ timeout: HOOK_TIMEOUT_MS,
78
+ env: { ...process.env, WIZZ_DEBUG: '1', WIZZ_DEBUG_FILE: os.devNull, WIZZ_TRACE: '', CLAUDE_PROJECT_DIR: cwd },
79
+ });
80
+ return { status: res.status, stderr: res.stderr || '', error: res.error ? res.error.message : null };
81
+ }
82
+
83
+ function debugLines(stderr) {
84
+ return String(stderr)
85
+ .split('\n')
86
+ .filter((line) => line.startsWith('[wizz-debug]'));
87
+ }
88
+
89
+ /**
90
+ * Executa cada hook instalado e classifica o resultado.
91
+ * @param {object} deps
92
+ * @param {string} deps.wizzDir
93
+ * @param {string} deps.projectDir
94
+ * @param {(p: string) => boolean} deps.fileExists
95
+ * @param {boolean} deps.rtkOnPath - sem rtk no PATH o rtk-rewrite.sh é pulado
96
+ * @param {Function} [deps.runHookProcess]
97
+ * @returns {{check: 'hooks-run', status: 'ok'|'warn'|'error', detail: string}}
98
+ */
99
+ function checkHooksRun({ wizzDir, projectDir, fileExists, rtkOnPath, runHookProcess = defaultRunHookProcess }) {
100
+ const hooksDir = path.join(wizzDir, 'hooks');
101
+ const errors = [];
102
+ const warnings = [];
103
+ let ran = 0;
104
+
105
+ for (const def of HOOK_DEFS) {
106
+ if (def.requires === 'rtk' && !rtkOnPath) continue;
107
+ const file = path.join(hooksDir, def.id);
108
+ if (!fileExists(file)) continue; // ausência é do check `hooks`
109
+ ran++;
110
+ const res = runHookProcess({ file, kind: def.kind, payload: probePayload(def.id, projectDir), cwd: projectDir });
111
+ const lines = debugLines(res.stderr);
112
+ if (res.error || res.status !== 0) {
113
+ const why = res.error || `exit ${res.status}`;
114
+ const tail = String(res.stderr).trim().split('\n').slice(-2).join(' | ');
115
+ errors.push(it('hrBroke', { id: def.id, why, tail: tail ? `: ${tail}` : '' }));
116
+ } else if (lines.some((l) => LOAD_FAILURE_RE.test(l))) {
117
+ errors.push(it('hrNoLibs', { id: def.id, line: lines.find((l) => LOAD_FAILURE_RE.test(l)) }));
118
+ } else if (lines.length > 0) {
119
+ warnings.push(it('hrSwallowed', { id: def.id, line: lines[0].replace('[wizz-debug] ', '') }));
120
+ }
121
+ }
122
+
123
+ if (errors.length > 0) {
124
+ return {
125
+ check: 'hooks-run',
126
+ status: 'error',
127
+ detail: `${errors.join('\n')}${warnings.length > 0 ? `\n${warnings.join('\n')}` : ''}\n${it('hrPartialCopy')}`,
128
+ };
129
+ }
130
+ if (warnings.length > 0) return { check: 'hooks-run', status: 'warn', detail: warnings.join('\n') };
131
+ return { check: 'hooks-run', status: 'ok', detail: it('hrOk', { n: ran }) };
132
+ }
133
+
134
+ module.exports = { checkHooksRun, probePayload, defaultRunHookProcess, HOOK_TIMEOUT_MS };
@@ -1,3 +1,4 @@
1
+ const { it } = require('../install-text');
1
2
  const os = require('node:os');
2
3
  const path = require('node:path');
3
4
  const fs = require('../fs-native');
@@ -16,7 +17,7 @@ const { WIZZ_FOLDER_NAME } = require('../ide/shared/path-utils');
16
17
  const { InstallPaths } = require('./install-paths');
17
18
  const { ExternalModuleManager } = require('../modules/external-manager');
18
19
  const { resolveModuleVersion } = require('../modules/version-resolver');
19
- const { buildHookEntries, filterHooksRegisteredGlobally, mergeHooksIntoSettings } = require('./hooks-settings');
20
+ const { buildHookEntries, filterHooksRegisteredGlobally, mergeHooksIntoSettings, removeHooksFromSettings } = require('./hooks-settings');
20
21
 
21
22
  const { ExistingInstall } = require('./existing-install');
22
23
  const { warnPreNativeSkillsLegacy } = require('./legacy-warnings');
@@ -426,7 +427,7 @@ class Installer {
426
427
  addResult('Resolved customizations', 'ok', `${resolvedCount} snapshot(s) → _wizz/_resolved/`);
427
428
  }
428
429
  } catch (error) {
429
- await prompts.log.warn(`Falha ao gerar _wizz/_resolved/ (fail-open): ${error.message}`);
430
+ await prompts.log.warn(it('resolvedFail', { error: error.message }));
430
431
  addResult('Resolved customizations', 'warn', error.message);
431
432
  }
432
433
 
@@ -454,7 +455,7 @@ class Installer {
454
455
  await prompts.log.warn(`Skills no registry sem pasta em skills-lib (ignoradas): ${result.skipped.join(', ')}`);
455
456
  }
456
457
  } catch (error) {
457
- await prompts.log.warn(`Falha ao instalar skills globais: ${error.message}`);
458
+ await prompts.log.warn(it('globalSkillsFail', { error: error.message }));
458
459
  addResult('Global skills', 'warn', error.message);
459
460
  }
460
461
 
@@ -480,12 +481,10 @@ class Installer {
480
481
  // network-heavy install/post_install steps.
481
482
  let { ready: mcpsReady, failed: mcpsFailed } = await prepareMcps({ mcps: toWrite });
482
483
  for (const f of mcpsFailed) {
483
- await prompts.log.warn(
484
- `MCP ${f.id} não pôde ser preparado (${f.error}). Config NÃO escrita para evitar ENOENT — instale manualmente e adicione depois com \`claude mcp add\`.`,
485
- );
484
+ await prompts.log.warn(it('mcpPrepareFail', { id: f.id, error: f.error }));
486
485
  }
487
486
  if (mcpsFailed.length > 0) {
488
- addResult('MCP servers', 'warn', `falharam: ${mcpsFailed.map((f) => f.id).join(', ')}`);
487
+ addResult('MCP servers', 'warn', it('failedList', { list: mcpsFailed.map((f) => f.id).join(', ') }));
489
488
  }
490
489
 
491
490
  // Env var assistance (3.3, design em _audit parte 3 seção E):
@@ -521,14 +520,12 @@ class Installer {
521
520
  const missingIds = new Set(missingEnv.map((m) => m.id));
522
521
  mcpsReady = mcpsReady.filter((m) => !missingIds.has(m.id));
523
522
  for (const m of missingEnv) {
524
- await prompts.log.warn(
525
- `MCP ${m.id} não gravado: faltou ${m.missing.join(', ')}. Rode o installer de novo quando tiver a chave, ou adicione com \`claude mcp add\`.`,
526
- );
523
+ await prompts.log.warn(it('mcpNotWritten', { id: m.id, missing: m.missing.join(', ') }));
527
524
  }
528
- addResult('MCP servers', 'warn', `não gravados por falta de env var: ${missingEnv.map((m) => m.id).join(', ')}`);
525
+ addResult('MCP servers', 'warn', it('mcpMissingEnv', { list: missingEnv.map((m) => m.id).join(', ') }));
529
526
  }
530
527
  } catch (error) {
531
- await prompts.log.warn(`Falha ao configurar env vars dos MCPs: ${error.message}`);
528
+ await prompts.log.warn(it('mcpEnvFail', { error: error.message }));
532
529
  addResult('MCP env vars', 'warn', error.message);
533
530
  }
534
531
 
@@ -558,34 +555,30 @@ class Installer {
558
555
  }
559
556
  const pinUpdated = mcpResult.pinUpdated || [];
560
557
  if (pinUpdated.length > 0) {
561
- await prompts.log.info(
562
- `MCPs com pin atualizado (bloco não havia sido customizado): ${pinUpdated.map((u) => u.id).join(', ')}`,
563
- );
564
- addResult('MCP servers', 'ok', `pin atualizado: ${pinUpdated.map((u) => u.id).join(', ')}`);
558
+ await prompts.log.info(it('mcpPinUpdated', { list: pinUpdated.map((u) => u.id).join(', ') }));
559
+ addResult('MCP servers', 'ok', it('mcpPinUpdatedShort', { list: pinUpdated.map((u) => u.id).join(', ') }));
565
560
  }
566
561
  const pinCustomized = mcpResult.pinCustomized || [];
567
562
  if (pinCustomized.length > 0) {
568
- await prompts.log.warn(
569
- `Há atualização de pin disponível para ${pinCustomized.map((c) => c.id).join(', ')}, mas o bloco no .mcp.json foi customizado (diferente do que o installer escreveu) — mantido intacto. Atualize manualmente se quiser o pin novo.`,
570
- );
563
+ await prompts.log.warn(it('mcpPinCustomized', { list: pinCustomized.map((c) => c.id).join(', ') }));
571
564
  }
572
565
  if (mcpResult.skipped.length > 0) {
573
- await prompts.log.info(`MCPs já presentes e atualizados no .mcp.json (mantidos): ${mcpResult.skipped.join(', ')}`);
566
+ await prompts.log.info(it('mcpKept', { list: mcpResult.skipped.join(', ') }));
574
567
  }
575
568
  }
576
569
  const toRecommend = mcpPlan.toRecommend || [];
577
570
  if (toRecommend.length > 0) {
578
571
  const lines = toRecommend.map((m) => ` ${renderAddCommand(m)}`).join('\n');
579
- await prompts.log.info(`MCPs recomendados (rode quando quiser):\n${lines}`);
572
+ await prompts.log.info(it('mcpRecommend', { lines }));
580
573
  }
581
574
  // Remind only when a written server expects secrets the user must fill.
582
575
  const needsSecrets = toWrite.filter((m) => m.server && m.server.env && Object.keys(m.server.env).length > 0);
583
576
  if (needsSecrets.length > 0) {
584
577
  const vars = [...new Set(needsSecrets.flatMap((m) => Object.values(m.server.env)))];
585
- await prompts.log.warn(`Defina as variáveis de ambiente dos MCPs antes de usar: ${vars.join(', ')}`);
578
+ await prompts.log.warn(it('mcpDefineEnv', { list: vars.join(', ') }));
586
579
  }
587
580
  } catch (error) {
588
- await prompts.log.warn(`Falha ao configurar MCPs: ${error.message}`);
581
+ await prompts.log.warn(it('mcpFail', { error: error.message }));
589
582
  addResult('MCP servers', 'warn', error.message);
590
583
  }
591
584
 
@@ -599,37 +592,41 @@ class Installer {
599
592
  try {
600
593
  const alreadyInstalled = cliPlan.alreadyInstalled || [];
601
594
  if (alreadyInstalled.length > 0) {
602
- await prompts.log.info(`CLIs já instalados (mantidos): ${alreadyInstalled.map((c) => c.id).join(', ')}`);
595
+ await prompts.log.info(it('cliKept', { list: alreadyInstalled.map((c) => c.id).join(', ') }));
603
596
  }
604
597
  const toInstall = cliPlan.toInstall || [];
605
598
  if (toInstall.length > 0) {
606
599
  message('Installing CLIs...');
607
600
  const cliResult = await installClis({ clis: toInstall });
608
601
  if (cliResult.installed.length > 0) {
609
- addResult('CLIs', 'ok', `instalados: ${cliResult.installed.join(', ')}`);
602
+ addResult('CLIs', 'ok', it('installedList', { list: cliResult.installed.join(', ') }));
610
603
  }
611
604
  for (const f of cliResult.failed) {
612
605
  await prompts.log.warn(
613
- `Falha ao instalar CLI ${f.id}: ${f.error}. Rode manualmente: ${renderInstallCommand(toInstall.find((c) => c.id === f.id) || {})}`,
606
+ it('cliInstallFail', {
607
+ id: f.id,
608
+ error: f.error,
609
+ command: renderInstallCommand(toInstall.find((c) => c.id === f.id) || {}),
610
+ }),
614
611
  );
615
612
  }
616
613
  if (cliResult.failed.length > 0) {
617
- addResult('CLIs', 'warn', `falharam: ${cliResult.failed.map((f) => f.id).join(', ')}`);
614
+ addResult('CLIs', 'warn', it('failedList', { list: cliResult.failed.map((f) => f.id).join(', ') }));
618
615
  }
619
616
  // M14: verify failure never aborts (CLIs are opt-in) — just a
620
617
  // clear warning that the tool cloned/installed but a runtime
621
618
  // dependency might still be missing.
622
619
  for (const w of cliResult.warnings || []) {
623
- await prompts.log.warn(`CLI ${w.id} instalado, mas ${w.warning}`);
620
+ await prompts.log.warn(it('cliInstalledBut', { id: w.id, warning: w.warning }));
624
621
  }
625
622
  }
626
623
  const toRecommend = cliPlan.toRecommend || [];
627
624
  if (toRecommend.length > 0) {
628
625
  const lines = toRecommend.map((c) => ` ${renderInstallCommand(c)}`).join('\n');
629
- await prompts.log.info(`CLIs recomendados (rode quando quiser):\n${lines}`);
626
+ await prompts.log.info(it('cliRecommend', { lines }));
630
627
  }
631
628
  } catch (error) {
632
- await prompts.log.warn(`Falha ao configurar CLIs: ${error.message}`);
629
+ await prompts.log.warn(it('cliFail', { error: error.message }));
633
630
  addResult('CLIs', 'warn', error.message);
634
631
  }
635
632
 
@@ -654,7 +651,7 @@ class Installer {
654
651
  addResult('Skill deps cache', 'ok', 'skill-deps-cache.json');
655
652
  }
656
653
  } catch (error) {
657
- await prompts.log.warn(`Falha ao gravar cache de dependências: ${error.message}`);
654
+ await prompts.log.warn(it('depsCacheFail', { error: error.message }));
658
655
  addResult('Skill deps cache', 'warn', error.message);
659
656
  }
660
657
  } else if (config.isQuickUpdate() && (config.modules || []).includes('bmm')) {
@@ -662,9 +659,7 @@ class Installer {
662
659
  // preserves settings and skips provisioning entirely, so say it
663
660
  // explicitly instead of leaving the user to notice by absence
664
661
  // (see project memory: "atualizei e não veio skill").
665
- await prompts.log.info(
666
- 'Quick Update: skills globais, MCPs e CLIs não foram alterados. Rode install e escolha "Modify Wizz Installation" para instalar itens novos.',
667
- );
662
+ await prompts.log.info(it('quickUpdateSkipped'));
668
663
  }
669
664
 
670
665
  // RT-C1 (item 3): registra os hooks copiados acima em
@@ -688,19 +683,15 @@ class Installer {
688
683
  const { settings: globalSettings } = await this._readSettingsJson(this._globalSettingsFile());
689
684
  const { entries: hookEntries, skipped: skippedGlobalHooks } = filterHooksRegisteredGlobally(allHookEntries, globalSettings);
690
685
  if (skippedGlobalHooks.length > 0) {
691
- await prompts.log.info(
692
- `Hook(s) já registrados no settings.json global (~/.claude/settings.json), pulando no projeto para não rodar 2x: ${skippedGlobalHooks.join(', ')}.`,
693
- );
686
+ await prompts.log.info(it('hooksGlobalSkipped', { list: skippedGlobalHooks.join(', ') }));
694
687
  }
695
688
 
696
689
  if (hookEntries.length > 0) {
697
690
  const settingsFile = path.join(paths.projectRoot, '.claude', 'settings.json');
698
691
  const { settings: existingSettings, invalidJson } = await this._readSettingsJson(settingsFile);
699
692
  if (invalidJson) {
700
- await prompts.log.warn(
701
- `${settingsFile} existe mas não é JSON válido — hooks copiados para _wizz/hooks/, mas NÃO registrados em settings.json. Corrija o arquivo e rode o install de novo.`,
702
- );
703
- addResult('Hooks settings', 'warn', 'settings.json inválido, hooks não registrados');
693
+ await prompts.log.warn(it('hooksSettingsInvalid', { file: settingsFile }));
694
+ addResult('Hooks settings', 'warn', it('hooksInvalidSettings'));
704
695
  } else {
705
696
  const newSettings = mergeHooksIntoSettings(existingSettings, hookEntries);
706
697
  pendingHooksSettingsWrite = {
@@ -726,14 +717,12 @@ class Installer {
726
717
  `0 hook(s) → .claude/settings.json (${skippedGlobalHooks.length} pulado(s) por já estar no global)`,
727
718
  );
728
719
  }
729
- if (!rtkOnPath && installedHookFiles.includes('rtk-rewrite.sh')) {
730
- addResult('Hooks settings', 'warn', 'rtk não encontrado no PATH: rtk-rewrite.sh copiado mas não registrado (opcional)');
731
- await prompts.log.info(
732
- 'rtk não encontrado no PATH: rtk-rewrite.sh foi copiado para _wizz/hooks/ mas NÃO registrado em settings.json (rtk é opcional). Instale rtk e rode o install de novo para ativá-lo.',
733
- );
720
+ if (!rtkOnPath && installedHookFiles.includes(require('./hooks-settings').RTK_HOOK_ID)) {
721
+ addResult('Hooks settings', 'warn', it('hooksRtkMissing'));
722
+ await prompts.log.info(it('hooksRtkMissingLong'));
734
723
  }
735
724
  } catch (error) {
736
- await prompts.log.warn(`Falha ao registrar hooks em .claude/settings.json: ${error.message}`);
725
+ await prompts.log.warn(it('hooksFail', { error: error.message }));
737
726
  addResult('Hooks settings', 'warn', error.message);
738
727
  }
739
728
 
@@ -845,7 +834,7 @@ class Installer {
845
834
  await prompts.log.warn(`_resolved/_config.json: ${warning}`);
846
835
  }
847
836
  } catch (error) {
848
- await prompts.log.warn(`Falha ao gerar _wizz/_resolved/_config.json (fail-open): ${error.message}`);
837
+ await prompts.log.warn(it('resolvedConfigFail', { error: error.message }));
849
838
  }
850
839
 
851
840
  message('Generating help catalog...');
@@ -1244,12 +1233,10 @@ class Installer {
1244
1233
  }
1245
1234
  const totalLegacy = results.reduce((n, r) => n + r.findings.length, 0);
1246
1235
  if (totalLegacy > 0) {
1247
- await prompts.log.warn(
1248
- `${totalLegacy} regra(s) antiga(s) no CLAUDE.md/AGENTS.md (GSD, superpowers, BMAD puro ou modelo aposentado). O bloco Wizz no topo tem prioridade, mas vale limpar: rode wizz doctor para ver as linhas.`,
1249
- );
1236
+ await prompts.log.warn(it('legacyRules', { n: totalLegacy }));
1250
1237
  }
1251
1238
  } catch (error) {
1252
- await prompts.log.warn(`Falha ao gravar o bloco Wizz no CLAUDE.md/AGENTS.md: ${error.message}`);
1239
+ await prompts.log.warn(it('instructionsFail', { error: error.message }));
1253
1240
  addResult('Project instructions', 'warn', error.message);
1254
1241
  }
1255
1242
  }
@@ -1693,12 +1680,34 @@ class Installer {
1693
1680
  async uninstallModules(projectDir) {
1694
1681
  const { wizzDir } = await this.findWizzDir(projectDir);
1695
1682
  if (await fs.pathExists(wizzDir)) {
1683
+ await this._unregisterHooks(projectDir);
1696
1684
  await fs.remove(wizzDir);
1697
1685
  return true;
1698
1686
  }
1699
1687
  return false;
1700
1688
  }
1701
1689
 
1690
+ /**
1691
+ * Tira de .claude/settings.json os hooks que o install registrou (apontam para
1692
+ * _wizz/hooks/, que o uninstall apaga). Hook de terceiro e demais chaves ficam;
1693
+ * settings.json inválido não é tocado; arquivo que sobraria vazio é removido.
1694
+ * @param {string} projectDir - Project directory
1695
+ * @returns {Promise<number>} Quantos hooks foram desregistrados
1696
+ */
1697
+ async _unregisterHooks(projectDir) {
1698
+ const file = path.join(projectDir, '.claude', 'settings.json');
1699
+ const { settings, invalidJson } = await this._readSettingsJson(file);
1700
+ if (invalidJson) return 0;
1701
+ const { settings: cleaned, removed } = removeHooksFromSettings(settings);
1702
+ if (removed === 0) return 0;
1703
+ if (Object.keys(cleaned).length === 0) {
1704
+ await fs.remove(file);
1705
+ } else {
1706
+ await this._writeSettingsJson(file, cleaned);
1707
+ }
1708
+ return removed;
1709
+ }
1710
+
1702
1711
  /**
1703
1712
  * Get installation status
1704
1713
  */
@@ -8,6 +8,7 @@
8
8
  * `externalModuleManager`, `manifest`, `install`) instead of inheriting from
9
9
  * it, so it can be tested/reasoned about independently.
10
10
  */
11
+ const { it } = require('../install-text');
11
12
  const path = require('node:path');
12
13
  const fs = require('../fs-native');
13
14
  const { OfficialModules } = require('../modules/official-modules');
@@ -110,9 +111,7 @@ async function quickUpdate(installer, config) {
110
111
  // _installAndConfigure); that only happens on a fresh install or
111
112
  // Modify. Surfacing this before any work starts avoids the confusion of
112
113
  // "I updated and skills didn't come" (see project memory).
113
- await prompts.log.info(
114
- 'Quick Update: atualiza os módulos já instalados com as configurações preservadas. Skills globais, MCPs e CLIs novos não são provisionados neste modo; rode install e escolha "Modify Wizz Installation" para isso.',
115
- );
114
+ await prompts.log.info(it('quickUpdateScope'));
116
115
 
117
116
  // Detect existing installation
118
117
  const existingInstall = await ExistingInstall.detect(wizzDir);
@@ -0,0 +1,201 @@
1
+ /**
2
+ * Text the install/update flow prints OUTSIDE the guided screens: the copy
3
+ * phase, the `--advanced` prompts and the final summary. The guided screens
4
+ * use guided/messages.js; both follow the language picked at the start
5
+ * (`--lang` or the guided question), so English mode never mixes in
6
+ * Portuguese (pendência de 2026-09-25).
7
+ *
8
+ * The language lives here as module state because these strings are printed
9
+ * deep inside core/installer.js and modules/*, far from where it is chosen.
10
+ * ui.promptInstall calls setInstallLang once; the default is English.
11
+ */
12
+
13
+ const fs = require('node:fs');
14
+ const path = require('node:path');
15
+ const { normalizeLang } = require('./guided/messages');
16
+ const COMMAND_TEXT = require('./command-text');
17
+
18
+ const MESSAGES = {
19
+ en: {
20
+ resolvedFail: 'Could not generate _wizz/_resolved/ (fail-open): {error}',
21
+ resolvedConfigFail: 'Could not generate _wizz/_resolved/_config.json (fail-open): {error}',
22
+ globalSkillsFail: 'Could not install global skills: {error}',
23
+ failedList: 'failed: {list}',
24
+ installedList: 'installed: {list}',
25
+ mcpMissingEnv: 'not written, missing env var: {list}',
26
+ mcpEnvFail: 'Could not configure the MCP env vars: {error}',
27
+ mcpPinUpdated: 'MCPs with updated pin (block had not been customized): {list}',
28
+ mcpPinUpdatedShort: 'pin updated: {list}',
29
+ mcpPinCustomized:
30
+ 'A pin update is available for {list}, but the block in .mcp.json was customized (differs from what the installer wrote), so it was left as is. Update it by hand if you want the new pin.',
31
+ mcpKept: 'MCPs already present and up to date in .mcp.json (kept): {list}',
32
+ mcpRecommend: 'Recommended MCPs (run whenever you want):\n{lines}',
33
+ mcpDefineEnv: 'Set the MCP environment variables before using them: {list}',
34
+ mcpFail: 'Could not configure MCPs: {error}',
35
+ cliKept: 'CLIs already installed (kept): {list}',
36
+ cliInstallFail: 'Could not install CLI {id}: {error}. Run it by hand: {command}',
37
+ cliInstalledBut: 'CLI {id} installed, but {warning}',
38
+ cliRecommend: 'Recommended CLIs (run whenever you want):\n{lines}',
39
+ cliFail: 'Could not configure CLIs: {error}',
40
+ depsCacheFail: 'Could not write the dependency cache: {error}',
41
+ hooksInvalidSettings: 'invalid settings.json, hooks not registered',
42
+ hooksRtkMissing: 'rtk not found on PATH: rtk-rewrite.sh copied but not registered (optional)',
43
+ hooksFail: 'Could not register hooks in .claude/settings.json: {error}',
44
+ instructionsFail: 'Could not write the Wizz block to CLAUDE.md/AGENTS.md: {error}',
45
+ mcpPrepareFail:
46
+ 'MCP {id} could not be prepared ({error}). Config NOT written to avoid ENOENT: install it by hand and add it later with `claude mcp add`.',
47
+ mcpNotWritten:
48
+ 'MCP {id} not written: missing {missing}. Run the installer again once you have the key, or add it with `claude mcp add`.',
49
+ quickUpdateScope:
50
+ 'Quick Update: refreshes the modules already installed, keeping their settings. New global skills, MCPs and CLIs are not provisioned in this mode; run install and choose "Modify Wizz Installation" for that.',
51
+ quickUpdateSkipped:
52
+ 'Quick Update: global skills, MCPs and CLIs were not changed. Run install and choose "Modify Wizz Installation" to install new items.',
53
+ hooksGlobalSkipped:
54
+ 'Hook(s) already registered in the global settings.json (~/.claude/settings.json), skipped in the project so they do not run twice: {list}.',
55
+ hooksSettingsInvalid:
56
+ '{file} exists but is not valid JSON: hooks were copied to _wizz/hooks/ but NOT registered in settings.json. Fix the file and run install again.',
57
+ hooksRtkMissingLong:
58
+ 'rtk not found on PATH: rtk-rewrite.sh was copied to _wizz/hooks/ but NOT registered in settings.json (rtk is optional). Install rtk and run install again to turn it on.',
59
+ legacyRules:
60
+ '{n} old rule(s) in CLAUDE.md/AGENTS.md (GSD, superpowers, plain BMAD or a retired model). The Wizz block at the top wins, but it is worth cleaning up: run wizz doctor to see the lines.',
61
+ unknownAreas: 'Unknown areas ignored: {list}',
62
+ areasQuestion: 'Which global skill areas should be installed? (empty = all)',
63
+ mcpGlobalSkipped: 'MCPs already configured in your global Claude (~/.claude.json), skipped: {list}',
64
+ mcpPluginSkipped: 'MCPs already covered by a Claude Code plugin (user scope), skipped: {list}',
65
+ mcpQuestion: 'Which MCPs should go into .mcp.json? (unticked ones become a command to run later)',
66
+ unknownClis: 'Unknown or already installed CLIs ignored: {list}',
67
+ cliQuestion: 'Which CLIs should be installed now? (unticked ones become a command to run later)',
68
+ traceQuestion: 'Turn on the routing meter? (local, writes only to ~/.claude/wizz-trace.jsonl on your machine, never leaves it)',
69
+ quickUpdateNoSkills:
70
+ 'Skills/MCPs/CLIs were not changed (Quick Update). To provision them, run install and choose "Modify Wizz Installation".',
71
+ doneWarnings: 'Finished with {n} warning(s). See the summary above for details.',
72
+ doneErrors: 'Finished with {n} real failure(s). See the summary above for details.',
73
+ envValue: 'Value for {name}{usedBy} (Enter to skip):',
74
+ envUsedBy: ' (used by: {list})',
75
+ gitignoreAdded: ".claude/settings.local.json was added to the project's .gitignore (it holds API keys and must not go to git).",
76
+ notGitRepo: 'This folder is not a git repository: make sure .claude/settings.local.json (API keys) is never committed.',
77
+ },
78
+ pt: {
79
+ resolvedFail: 'Falha ao gerar _wizz/_resolved/ (fail-open): {error}',
80
+ resolvedConfigFail: 'Falha ao gerar _wizz/_resolved/_config.json (fail-open): {error}',
81
+ globalSkillsFail: 'Falha ao instalar skills globais: {error}',
82
+ failedList: 'falharam: {list}',
83
+ installedList: 'instalados: {list}',
84
+ mcpMissingEnv: 'não gravados por falta de env var: {list}',
85
+ mcpEnvFail: 'Falha ao configurar env vars dos MCPs: {error}',
86
+ mcpPinUpdated: 'MCPs com pin atualizado (bloco não havia sido customizado): {list}',
87
+ mcpPinUpdatedShort: 'pin atualizado: {list}',
88
+ mcpPinCustomized:
89
+ 'Há atualização de pin disponível para {list}, mas o bloco no .mcp.json foi customizado (diferente do que o installer escreveu), então ficou intacto. Atualize manualmente se quiser o pin novo.',
90
+ mcpKept: 'MCPs já presentes e atualizados no .mcp.json (mantidos): {list}',
91
+ mcpRecommend: 'MCPs recomendados (rode quando quiser):\n{lines}',
92
+ mcpDefineEnv: 'Defina as variáveis de ambiente dos MCPs antes de usar: {list}',
93
+ mcpFail: 'Falha ao configurar MCPs: {error}',
94
+ cliKept: 'CLIs já instalados (mantidos): {list}',
95
+ cliInstallFail: 'Falha ao instalar CLI {id}: {error}. Rode manualmente: {command}',
96
+ cliInstalledBut: 'CLI {id} instalado, mas {warning}',
97
+ cliRecommend: 'CLIs recomendados (rode quando quiser):\n{lines}',
98
+ cliFail: 'Falha ao configurar CLIs: {error}',
99
+ depsCacheFail: 'Falha ao gravar cache de dependências: {error}',
100
+ hooksInvalidSettings: 'settings.json inválido, hooks não registrados',
101
+ hooksRtkMissing: 'rtk não encontrado no PATH: rtk-rewrite.sh copiado mas não registrado (opcional)',
102
+ hooksFail: 'Falha ao registrar hooks em .claude/settings.json: {error}',
103
+ instructionsFail: 'Falha ao gravar o bloco Wizz no CLAUDE.md/AGENTS.md: {error}',
104
+ mcpPrepareFail:
105
+ 'MCP {id} não pôde ser preparado ({error}). Config NÃO escrita para evitar ENOENT: instale manualmente e adicione depois com `claude mcp add`.',
106
+ mcpNotWritten:
107
+ 'MCP {id} não gravado: faltou {missing}. Rode o installer de novo quando tiver a chave, ou adicione com `claude mcp add`.',
108
+ quickUpdateScope:
109
+ 'Quick Update: atualiza os módulos já instalados com as configurações preservadas. Skills globais, MCPs e CLIs novos não são provisionados neste modo; rode install e escolha "Modify Wizz Installation" para isso.',
110
+ quickUpdateSkipped:
111
+ 'Quick Update: skills globais, MCPs e CLIs não foram alterados. Rode install e escolha "Modify Wizz Installation" para instalar itens novos.',
112
+ hooksGlobalSkipped:
113
+ 'Hook(s) já registrados no settings.json global (~/.claude/settings.json), pulando no projeto para não rodar 2x: {list}.',
114
+ hooksSettingsInvalid:
115
+ '{file} existe mas não é JSON válido: hooks copiados para _wizz/hooks/, mas NÃO registrados em settings.json. Corrija o arquivo e rode o install de novo.',
116
+ hooksRtkMissingLong:
117
+ 'rtk não encontrado no PATH: rtk-rewrite.sh foi copiado para _wizz/hooks/ mas NÃO registrado em settings.json (rtk é opcional). Instale rtk e rode o install de novo para ativá-lo.',
118
+ legacyRules:
119
+ '{n} regra(s) antiga(s) no CLAUDE.md/AGENTS.md (GSD, superpowers, BMAD puro ou modelo aposentado). O bloco Wizz no topo tem prioridade, mas vale limpar: rode wizz doctor para ver as linhas.',
120
+ unknownAreas: 'Áreas desconhecidas ignoradas: {list}',
121
+ areasQuestion: 'Quais áreas de skills globais instalar? (vazio = todas)',
122
+ mcpGlobalSkipped: 'MCPs já configurados no seu Claude global (~/.claude.json), pulados: {list}',
123
+ mcpPluginSkipped: 'MCPs já cobertos por plugin do Claude Code (user scope), pulados: {list}',
124
+ mcpQuestion: 'Quais MCPs configurar no .mcp.json? (não marcados viram comando pra rodar depois)',
125
+ unknownClis: 'CLIs desconhecidos/já instalados ignorados: {list}',
126
+ cliQuestion: 'Quais CLIs instalar agora? (não marcados viram comando pra rodar depois)',
127
+ traceQuestion: 'Quer ligar o medidor de roteamento? (local, grava só em ~/.claude/wizz-trace.jsonl na sua máquina, nunca sai daqui)',
128
+ quickUpdateNoSkills:
129
+ 'Skills/MCPs/CLIs não foram alterados (Quick Update). Para provisioná-los, rode install e escolha "Modify Wizz Installation".',
130
+ doneWarnings: 'Concluído com {n} aviso(s). Veja o resumo acima para detalhes.',
131
+ doneErrors: 'Concluído com {n} falha(s) real(is). Veja o resumo acima para detalhes.',
132
+ envValue: 'Valor para {name}{usedBy} (Enter para pular):',
133
+ envUsedBy: ' (usada por: {list})',
134
+ gitignoreAdded: '.claude/settings.local.json foi adicionado ao .gitignore do projeto (guarda API keys, não deve ir pro git).',
135
+ notGitRepo: 'Este diretório não é um repositório git: garanta que .claude/settings.local.json (API keys) nunca seja versionado.',
136
+ },
137
+ };
138
+
139
+ // doctor, resolve e trace-report (command-text.js) entram na mesma tabela.
140
+ Object.assign(MESSAGES.en, COMMAND_TEXT.en);
141
+ Object.assign(MESSAGES.pt, COMMAND_TEXT.pt);
142
+
143
+ let current = 'en';
144
+
145
+ /**
146
+ * Set the language for the rest of the run.
147
+ * @param {string|undefined} raw - "en", "pt", "pt-BR"…; unknown keeps English
148
+ */
149
+ function setInstallLang(raw) {
150
+ current = normalizeLang(raw) || 'en';
151
+ }
152
+
153
+ /**
154
+ * Language of an existing install, from `communication_language` in
155
+ * _wizz/core/config.yaml ("Portugues", "Português (Brasil)", "English"…), so
156
+ * `wizz update` without --lang keeps talking the language picked at install.
157
+ * @param {string} wizzDir
158
+ * @returns {'en'|'pt'|null} null when absent or unreadable
159
+ */
160
+ function langOfInstall(wizzDir) {
161
+ try {
162
+ const text = fs.readFileSync(path.join(wizzDir, 'core', 'config.yaml'), 'utf8');
163
+ const match = text.match(/^communication_language:\s*["']?([^"'\n]+)/m);
164
+ if (!match) return null;
165
+ return /^portugu/i.test(match[1].trim()) ? 'pt' : 'en';
166
+ } catch {
167
+ return null;
168
+ }
169
+ }
170
+
171
+ /**
172
+ * Language for the commands that run on an existing install (doctor,
173
+ * resolve, trace-report): WIZZ_LANG wins, then `communication_language` of
174
+ * the install, then English. Sets it for the rest of the run.
175
+ * @param {string|null} wizzDir - _wizz/ of the project, or null
176
+ * @returns {'en'|'pt'}
177
+ */
178
+ function useCommandLang(wizzDir) {
179
+ const fromEnv = normalizeLang(process.env.WIZZ_LANG);
180
+ setInstallLang(fromEnv || (wizzDir && langOfInstall(wizzDir)) || 'en');
181
+ return current;
182
+ }
183
+
184
+ function getInstallLang() {
185
+ return current;
186
+ }
187
+
188
+ /**
189
+ * Translate a key in the current language, filling {placeholders}.
190
+ * @param {string} key
191
+ * @param {Object} [vars]
192
+ * @returns {string}
193
+ */
194
+ function it(key, vars = {}) {
195
+ const table = MESSAGES[current] || MESSAGES.en;
196
+ const value = key in table ? table[key] : MESSAGES.en[key];
197
+ if (typeof value !== 'string') throw new Error(`install-text: unknown key "${key}"`);
198
+ return value.replaceAll(/\{(\w+)\}/g, (match, name) => (name in vars ? String(vars[name]) : match));
199
+ }
200
+
201
+ module.exports = { MESSAGES, setInstallLang, getInstallLang, langOfInstall, useCommandLang, it };
@@ -187,12 +187,12 @@ function orphanPinWarnings(channelOptions, selectedCodes) {
187
187
  * Warn when --pin / --next targets a bundled module (core, bmm). Those are
188
188
  * shipped inside the installer binary — there's no git clone to override, so
189
189
  * the flag has no effect. Users who actually want a prerelease core/bmm
190
- * should use `npx bmad-method@next install`.
190
+ * should use `npx wizz-method@next install`.
191
191
  */
192
192
  function bundledTargetWarnings(channelOptions, bundledCodes) {
193
193
  const warnings = [];
194
194
  const bundled = new Set(bundledCodes || []);
195
- const hint = '(bundled module; use `npx bmad-method@next install` for a prerelease)';
195
+ const hint = '(bundled module; use `npx wizz-method@next install` for a prerelease)';
196
196
  for (const code of channelOptions?.pins?.keys() || []) {
197
197
  if (bundled.has(code)) {
198
198
  warnings.push(`--pin for '${code}' has no effect ${hint}.`);