wizz-method 2.0.0 → 2.1.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 (311) hide show
  1. package/LICENSE +60 -30
  2. package/README.md +80 -31
  3. package/SECURITY.md +24 -0
  4. package/THIRD-PARTY-NOTICES.md +136 -0
  5. package/package.json +31 -17
  6. package/skills-registry.yaml +128 -7
  7. package/src/bmm-skills/1-analysis/research/wizz-domain-research/SKILL.md +3 -4
  8. package/src/bmm-skills/1-analysis/research/wizz-domain-research/domain-steps/step-06-research-synthesis.md +1 -1
  9. package/src/bmm-skills/1-analysis/research/wizz-market-research/SKILL.md +3 -4
  10. package/src/bmm-skills/1-analysis/research/wizz-market-research/steps/step-06-research-completion.md +1 -1
  11. package/src/bmm-skills/1-analysis/research/wizz-technical-research/SKILL.md +3 -4
  12. package/src/bmm-skills/1-analysis/research/wizz-technical-research/technical-steps/step-06-research-synthesis.md +1 -1
  13. package/src/bmm-skills/1-analysis/wizz-agent-analyst/SKILL.md +3 -4
  14. package/src/bmm-skills/1-analysis/wizz-agent-tech-writer/SKILL.md +3 -4
  15. package/src/bmm-skills/1-analysis/wizz-document-project/SKILL.md +3 -4
  16. package/src/bmm-skills/1-analysis/wizz-document-project/workflows/deep-dive-instructions.md +1 -1
  17. package/src/bmm-skills/1-analysis/wizz-document-project/workflows/full-scan-instructions.md +1 -1
  18. package/src/bmm-skills/1-analysis/wizz-prfaq/SKILL.md +3 -4
  19. package/src/bmm-skills/1-analysis/wizz-prfaq/references/verdict.md +1 -1
  20. package/src/bmm-skills/1-analysis/wizz-product-brief/SKILL.md +1 -1
  21. package/src/bmm-skills/2-plan-workflows/wizz-agent-pm/SKILL.md +3 -4
  22. package/src/bmm-skills/2-plan-workflows/wizz-agent-ux-designer/SKILL.md +3 -4
  23. package/src/bmm-skills/2-plan-workflows/wizz-create-prd/SKILL.md +1 -1
  24. package/src/bmm-skills/2-plan-workflows/wizz-edit-prd/SKILL.md +1 -1
  25. package/src/bmm-skills/2-plan-workflows/wizz-prd/SKILL.md +1 -1
  26. package/src/bmm-skills/2-plan-workflows/wizz-ux/SKILL.md +1 -1
  27. package/src/bmm-skills/2-plan-workflows/wizz-validate-prd/SKILL.md +1 -1
  28. package/src/bmm-skills/3-solutioning/wizz-agent-architect/SKILL.md +3 -4
  29. package/src/bmm-skills/3-solutioning/wizz-architecture/SKILL.md +9 -9
  30. package/src/bmm-skills/3-solutioning/wizz-architecture/references/headless.md +1 -1
  31. package/src/bmm-skills/3-solutioning/wizz-check-implementation-readiness/SKILL.md +3 -4
  32. package/src/bmm-skills/3-solutioning/wizz-check-implementation-readiness/steps/step-06-final-assessment.md +1 -1
  33. package/src/bmm-skills/3-solutioning/wizz-create-architecture/SKILL.md +1 -1
  34. package/src/bmm-skills/3-solutioning/wizz-create-epics-and-stories/SKILL.md +3 -4
  35. package/src/bmm-skills/3-solutioning/wizz-create-epics-and-stories/steps/step-04-final-validation.md +1 -1
  36. package/src/bmm-skills/3-solutioning/wizz-generate-project-context/SKILL.md +3 -4
  37. package/src/bmm-skills/3-solutioning/wizz-generate-project-context/steps/step-03-complete.md +1 -1
  38. package/src/bmm-skills/4-implementation/wizz-agent-dev/SKILL.md +3 -4
  39. package/src/bmm-skills/4-implementation/wizz-checkpoint-preview/SKILL.md +3 -4
  40. package/src/bmm-skills/4-implementation/wizz-checkpoint-preview/step-05-wrapup.md +1 -1
  41. package/src/bmm-skills/4-implementation/wizz-code-review/SKILL.md +3 -4
  42. package/src/bmm-skills/4-implementation/wizz-code-review/customize.toml +3 -8
  43. package/src/bmm-skills/4-implementation/wizz-code-review/review-prompts/blind-hunter.md +20 -0
  44. package/src/bmm-skills/4-implementation/wizz-code-review/steps/step-04-present.md +1 -1
  45. package/src/bmm-skills/4-implementation/wizz-correct-course/SKILL.md +4 -5
  46. package/src/bmm-skills/4-implementation/wizz-create-story/SKILL.md +4 -5
  47. package/src/bmm-skills/4-implementation/wizz-dev-story/SKILL.md +4 -5
  48. package/src/bmm-skills/4-implementation/wizz-investigate/SKILL.md +1 -1
  49. package/src/bmm-skills/4-implementation/wizz-qa-generate-e2e-tests/SKILL.md +4 -5
  50. package/src/bmm-skills/4-implementation/wizz-quick-dev/SKILL.md +4 -5
  51. package/src/bmm-skills/4-implementation/wizz-quick-dev/customize.toml +10 -22
  52. package/src/bmm-skills/4-implementation/wizz-quick-dev/review-prompts/blind-hunter.md +20 -0
  53. package/src/bmm-skills/4-implementation/wizz-quick-dev/step-05-present.md +1 -1
  54. package/src/bmm-skills/4-implementation/wizz-quick-dev/step-oneshot.md +1 -1
  55. package/src/bmm-skills/4-implementation/wizz-retrospective/SKILL.md +1 -2
  56. package/src/bmm-skills/4-implementation/wizz-sprint-planning/SKILL.md +1 -1
  57. package/src/bmm-skills/4-implementation/wizz-sprint-status/SKILL.md +5 -6
  58. package/src/core-skills/_shared/handoff-protocol.md +9 -0
  59. package/src/core-skills/wizz-advanced-elicitation/SKILL.md +2 -2
  60. package/src/core-skills/wizz-brainstorming/SKILL.md +6 -6
  61. package/src/core-skills/wizz-brainstorming/references/converge.md +1 -1
  62. package/src/core-skills/wizz-brainstorming/references/finalize.md +1 -1
  63. package/src/core-skills/wizz-brainstorming/references/headless.md +3 -3
  64. package/src/core-skills/wizz-brainstorming/references/mode-autonomous.md +1 -1
  65. package/src/core-skills/wizz-customize/SKILL.md +13 -10
  66. package/src/core-skills/wizz-forge-idea/SKILL.md +6 -6
  67. package/src/core-skills/wizz-forge-idea/scripts/__pycache__/resolve_personas.cpython-314.pyc +0 -0
  68. package/src/core-skills/wizz-forge-idea/scripts/resolve_personas.py +17 -1
  69. package/src/core-skills/wizz-party-mode/SKILL.md +3 -3
  70. package/src/core-skills/wizz-party-mode/references/create-party.md +1 -1
  71. package/src/core-skills/wizz-party-mode/references/party-memory.md +2 -2
  72. package/src/core-skills/wizz-party-mode/scripts/__pycache__/resolve_party.cpython-314.pyc +0 -0
  73. package/src/core-skills/wizz-party-mode/scripts/resolve_party.py +17 -1
  74. package/src/core-skills/wizz-review-adversarial-general/SKILL.md +1 -1
  75. package/src/core-skills/wizz-spec/SKILL.md +5 -5
  76. package/src/modules/lowticket/README.md +6 -6
  77. package/src/modules/lowticket/module.yaml +4 -1
  78. package/src/modules/lowticket/skills/{lowticket-funil → wizz-lowticket-funil}/SKILL.md +4 -4
  79. package/src/modules/lowticket/skills/{lowticket-funil → wizz-lowticket-funil}/references/copy-das-paginas.md +1 -1
  80. package/src/modules/lowticket/skills/{lowticket-metodologia → wizz-lowticket-metodologia}/SKILL.md +1 -1
  81. package/src/modules/lowticket/skills/{lowticket-minerador → wizz-lowticket-minerador}/SKILL.md +3 -3
  82. package/src/modules/lowticket/skills/{lowticket-minerador → wizz-lowticket-minerador}/references/rubrica.md +1 -1
  83. package/src/modules/lowticket/skills/{lowticket-pagina → wizz-lowticket-pagina}/SKILL.md +4 -4
  84. package/src/modules/lowticket/skills/{lowticket-trafego → wizz-lowticket-trafego}/SKILL.md +3 -3
  85. package/src/modules/lowticket/skills/{lowticket-trafego → wizz-lowticket-trafego}/references/reguas.md +1 -1
  86. package/src/modules/wizz/_shared/communication-rules.md +1 -1
  87. package/src/modules/wizz/_shared/despacho-barato.md +9 -0
  88. package/src/modules/wizz/_shared/token-economy.md +7 -0
  89. package/src/modules/wizz/agents/wizz-ads/SKILL.md +1 -1
  90. package/src/modules/wizz/agents/wizz-ads/customize.toml +1 -2
  91. package/src/modules/wizz/agents/wizz-copy/SKILL.md +1 -1
  92. package/src/modules/wizz/agents/wizz-copy/customize.toml +1 -2
  93. package/src/modules/wizz/agents/wizz-designer/SKILL.md +1 -1
  94. package/src/modules/wizz/agents/wizz-designer/customize.toml +1 -2
  95. package/src/modules/wizz/agents/wizz-growth/SKILL.md +1 -1
  96. package/src/modules/wizz/agents/wizz-growth/customize.toml +1 -2
  97. package/src/modules/wizz/agents/wizz-maestro/SKILL.md +5 -5
  98. package/src/modules/wizz/agents/wizz-maestro/customize.toml +4 -8
  99. package/src/modules/wizz/agents/wizz-memoria/SKILL.md +1 -1
  100. package/src/modules/wizz/agents/wizz-memoria/customize.toml +1 -2
  101. package/src/modules/wizz/agents/wizz-qa/SKILL.md +1 -1
  102. package/src/modules/wizz/agents/wizz-qa/customize.toml +1 -2
  103. package/src/modules/wizz/agents/wizz-seo/SKILL.md +1 -1
  104. package/src/modules/wizz/agents/wizz-seo/customize.toml +1 -2
  105. package/src/modules/wizz/agents/wizz-social/SKILL.md +1 -1
  106. package/src/modules/wizz/agents/wizz-social/customize.toml +1 -2
  107. package/src/modules/wizz/module.yaml +3 -0
  108. package/src/modules/wizz/overrides/wizz-agent-analyst.toml +1 -2
  109. package/src/modules/wizz/overrides/wizz-agent-architect.toml +1 -2
  110. package/src/modules/wizz/overrides/wizz-agent-dev.toml +1 -2
  111. package/src/modules/wizz/overrides/wizz-agent-pm.toml +1 -2
  112. package/src/modules/wizz/overrides/wizz-agent-tech-writer.toml +1 -2
  113. package/src/modules/wizz/overrides/wizz-agent-ux-designer.toml +1 -2
  114. package/src/modules/wizz/subagents/codex/wizz-exec-haiku.toml +2 -0
  115. package/src/modules/wizz/subagents/codex/wizz-exec-opus.toml +2 -0
  116. package/src/modules/wizz/subagents/codex/wizz-exec-review.toml +2 -0
  117. package/src/modules/wizz/subagents/codex/wizz-exec-sonnet.toml +2 -0
  118. package/src/modules/wizz/subagents/gemini/wizz-exec-haiku.md +4 -1
  119. package/src/modules/wizz/subagents/gemini/wizz-exec-opus.md +4 -1
  120. package/src/modules/wizz/subagents/gemini/wizz-exec-review.md +4 -1
  121. package/src/modules/wizz/subagents/gemini/wizz-exec-sonnet.md +4 -1
  122. package/src/modules/wizz/subagents/opencode/wizz-exec-haiku.md +4 -1
  123. package/src/modules/wizz/subagents/opencode/wizz-exec-opus.md +4 -1
  124. package/src/modules/wizz/subagents/opencode/wizz-exec-review.md +4 -1
  125. package/src/modules/wizz/subagents/opencode/wizz-exec-sonnet.md +4 -1
  126. package/src/modules/wizz/subagents/spec.yaml +148 -0
  127. package/src/modules/wizz/subagents/wizz-exec-haiku.md +4 -1
  128. package/src/modules/wizz/subagents/wizz-exec-opus.md +4 -1
  129. package/src/modules/wizz/subagents/wizz-exec-review.md +4 -1
  130. package/src/modules/wizz/subagents/wizz-exec-sonnet.md +4 -1
  131. package/src/scripts/__pycache__/resolve_customization.cpython-314.pyc +0 -0
  132. package/src/scripts/memlog.js +368 -0
  133. package/src/scripts/resolve_customization.py +124 -15
  134. package/src/skills-lib/_shared/complexity-signal.md +14 -0
  135. package/src/skills-lib/wizz-canvas-design/canvas-fonts/InstrumentSerif-OFL.txt +93 -0
  136. package/src/skills-lib/wizz-huashu-design/references/sfx-library.md +1 -1
  137. package/src/skills-lib/wizz-huashu-design/scripts/add-music.sh +1 -1
  138. package/src/skills-lib/wizz-huashu-design/scripts/mix-voiceover.sh +1 -1
  139. package/src/skills-lib/wizz-impeccable/LICENSE.txt +202 -0
  140. package/src/skills-lib/wizz-offer-forge/SKILL.md +1 -1
  141. package/src/skills-lib/wizz-react-components/LICENSE.txt +202 -0
  142. package/src/skills-lib/wizz-router/SKILL.md +2 -2
  143. package/src/skills-lib/wizz-supabase-postgres-best-practices/LICENSE +21 -0
  144. package/src/skills-lib/wizz-taste-skill/SKILL.md +1 -1
  145. package/src/skills-lib/wizz-tracking-audit/SKILL.md +1 -1
  146. package/tools/fetch-assets.mjs +70 -38
  147. package/tools/hooks/README.md +22 -0
  148. package/tools/hooks/rtk-rewrite.sh +280 -0
  149. package/tools/hooks/security-defensive-context.js +70 -0
  150. package/tools/hooks/session-rules.js +368 -0
  151. package/tools/hooks/wizz-decision-trace.js +389 -0
  152. package/tools/hooks/wizz-router-enforce.js +258 -0
  153. package/tools/installer/banner.js +1 -1
  154. package/tools/installer/commands/doctor.js +124 -0
  155. package/tools/installer/commands/fetch-assets.js +7 -8
  156. package/tools/installer/commands/install.js +1 -1
  157. package/tools/installer/commands/resolve.js +95 -0
  158. package/tools/installer/core/doctor.js +648 -0
  159. package/tools/installer/core/hash-cache.js +156 -0
  160. package/tools/installer/core/help-catalog.js +4 -1
  161. package/tools/installer/core/hooks-settings.js +178 -0
  162. package/tools/installer/core/installer.js +297 -15
  163. package/tools/installer/core/legacy-warnings.js +0 -4
  164. package/tools/installer/core/manifest-generator.js +121 -43
  165. package/tools/installer/core/manifest.js +36 -32
  166. package/tools/installer/core/module-config-writer.js +4 -1
  167. package/tools/installer/core/python-check.js +60 -63
  168. package/tools/installer/core/quick-update.js +76 -43
  169. package/tools/installer/core/resolved-config.js +168 -0
  170. package/tools/installer/core/resolved-customizations.js +736 -0
  171. package/tools/installer/core/resolved-includes.js +262 -0
  172. package/tools/installer/core/resolved-schema.js +148 -0
  173. package/tools/installer/core/user-file-preservation.js +40 -8
  174. package/tools/installer/core/wizz-dir.js +117 -0
  175. package/tools/installer/core/yaml-cache.js +105 -0
  176. package/tools/installer/fs-native.js +97 -6
  177. package/tools/installer/ide/_config-driven.js +12 -75
  178. package/tools/installer/ide/platform-codes.js +111 -16
  179. package/tools/installer/ide/platform-codes.yaml +45 -100
  180. package/tools/installer/ide/shared/path-utils.js +6 -208
  181. package/tools/installer/install-messages.yaml +4 -14
  182. package/tools/installer/modules/channel-plan.js +15 -2
  183. package/tools/installer/modules/config-collector.js +762 -0
  184. package/tools/installer/modules/config-values.js +352 -0
  185. package/tools/installer/modules/custom-module-manager.js +161 -28
  186. package/tools/installer/modules/env-vars.js +119 -0
  187. package/tools/installer/modules/external-manager.js +133 -60
  188. package/tools/installer/modules/git-cache-utils.js +125 -0
  189. package/tools/installer/modules/module-catalog.js +565 -0
  190. package/tools/installer/modules/module-installer.js +618 -0
  191. package/tools/installer/modules/module-interface.js +86 -0
  192. package/tools/installer/modules/official-modules.js +98 -2172
  193. package/tools/installer/modules/pin-spec.js +125 -0
  194. package/tools/installer/modules/plugin-resolver.js +4 -0
  195. package/tools/installer/modules/skills-lib.js +3 -6
  196. package/tools/installer/prompts.js +0 -3
  197. package/tools/installer/ui.js +89 -54
  198. package/tools/installer/wizz-cli.js +1 -1
  199. package/tools/lib/frontmatter.js +139 -0
  200. package/tools/lib/sync-targets.mjs +49 -0
  201. package/tools/lib/walk.js +93 -0
  202. package/wizz-modules.yaml +9 -0
  203. package/src/scripts/__pycache__/memlog.cpython-313.pyc +0 -0
  204. package/src/scripts/memlog.py +0 -233
  205. package/src/scripts/tests/__pycache__/test_memlog.cpython-313-pytest-9.1.1.pyc +0 -0
  206. package/src/scripts/tests/__pycache__/test_resolve_customization.cpython-313-pytest-9.1.1.pyc +0 -0
  207. package/src/scripts/tests/test_memlog.py +0 -306
  208. package/src/skills-lib/wizz-huashu-design/assets/showcases/INDEX.md +0 -115
  209. package/src/skills-lib/wizz-huashu-design/assets/showcases/cover/cover-build.html +0 -235
  210. package/src/skills-lib/wizz-huashu-design/assets/showcases/cover/cover-build.png +0 -0
  211. package/src/skills-lib/wizz-huashu-design/assets/showcases/cover/cover-pentagram.html +0 -229
  212. package/src/skills-lib/wizz-huashu-design/assets/showcases/cover/cover-pentagram.png +0 -0
  213. package/src/skills-lib/wizz-huashu-design/assets/showcases/cover/cover-takram.html +0 -288
  214. package/src/skills-lib/wizz-huashu-design/assets/showcases/cover/cover-takram.png +0 -0
  215. package/src/skills-lib/wizz-huashu-design/assets/showcases/infographic/infographic-build.html +0 -503
  216. package/src/skills-lib/wizz-huashu-design/assets/showcases/infographic/infographic-build.png +0 -0
  217. package/src/skills-lib/wizz-huashu-design/assets/showcases/infographic/infographic-pentagram.html +0 -600
  218. package/src/skills-lib/wizz-huashu-design/assets/showcases/infographic/infographic-pentagram.png +0 -0
  219. package/src/skills-lib/wizz-huashu-design/assets/showcases/infographic/infographic-takram.html +0 -670
  220. package/src/skills-lib/wizz-huashu-design/assets/showcases/infographic/infographic-takram.png +0 -0
  221. package/src/skills-lib/wizz-huashu-design/assets/showcases/ppt/ppt-build.html +0 -382
  222. package/src/skills-lib/wizz-huashu-design/assets/showcases/ppt/ppt-build.png +0 -0
  223. package/src/skills-lib/wizz-huashu-design/assets/showcases/ppt/ppt-pentagram.html +0 -536
  224. package/src/skills-lib/wizz-huashu-design/assets/showcases/ppt/ppt-pentagram.png +0 -0
  225. package/src/skills-lib/wizz-huashu-design/assets/showcases/ppt/ppt-takram.html +0 -497
  226. package/src/skills-lib/wizz-huashu-design/assets/showcases/ppt/ppt-takram.png +0 -0
  227. package/src/skills-lib/wizz-huashu-design/assets/showcases/website-ai-nav/ainav-build.html +0 -385
  228. package/src/skills-lib/wizz-huashu-design/assets/showcases/website-ai-nav/ainav-build.png +0 -0
  229. package/src/skills-lib/wizz-huashu-design/assets/showcases/website-ai-nav/ainav-pentagram.html +0 -422
  230. package/src/skills-lib/wizz-huashu-design/assets/showcases/website-ai-nav/ainav-pentagram.png +0 -0
  231. package/src/skills-lib/wizz-huashu-design/assets/showcases/website-ai-nav/ainav-takram.html +0 -499
  232. package/src/skills-lib/wizz-huashu-design/assets/showcases/website-ai-nav/ainav-takram.png +0 -0
  233. package/src/skills-lib/wizz-huashu-design/assets/showcases/website-ai-writing/aiwriting-build.html +0 -562
  234. package/src/skills-lib/wizz-huashu-design/assets/showcases/website-ai-writing/aiwriting-build.png +0 -0
  235. package/src/skills-lib/wizz-huashu-design/assets/showcases/website-ai-writing/aiwriting-pentagram.html +0 -548
  236. package/src/skills-lib/wizz-huashu-design/assets/showcases/website-ai-writing/aiwriting-pentagram.png +0 -0
  237. package/src/skills-lib/wizz-huashu-design/assets/showcases/website-ai-writing/aiwriting-takram.html +0 -696
  238. package/src/skills-lib/wizz-huashu-design/assets/showcases/website-ai-writing/aiwriting-takram.png +0 -0
  239. package/src/skills-lib/wizz-huashu-design/assets/showcases/website-devdocs/devdocs-build.html +0 -372
  240. package/src/skills-lib/wizz-huashu-design/assets/showcases/website-devdocs/devdocs-build.png +0 -0
  241. package/src/skills-lib/wizz-huashu-design/assets/showcases/website-devdocs/devdocs-pentagram.html +0 -460
  242. package/src/skills-lib/wizz-huashu-design/assets/showcases/website-devdocs/devdocs-pentagram.png +0 -0
  243. package/src/skills-lib/wizz-huashu-design/assets/showcases/website-devdocs/devdocs-takram.html +0 -494
  244. package/src/skills-lib/wizz-huashu-design/assets/showcases/website-devdocs/devdocs-takram.png +0 -0
  245. package/src/skills-lib/wizz-huashu-design/assets/showcases/website-homepage/homepage-build.html +0 -367
  246. package/src/skills-lib/wizz-huashu-design/assets/showcases/website-homepage/homepage-build.png +0 -0
  247. package/src/skills-lib/wizz-huashu-design/assets/showcases/website-homepage/homepage-pentagram.html +0 -368
  248. package/src/skills-lib/wizz-huashu-design/assets/showcases/website-homepage/homepage-pentagram.png +0 -0
  249. package/src/skills-lib/wizz-huashu-design/assets/showcases/website-homepage/homepage-takram.html +0 -459
  250. package/src/skills-lib/wizz-huashu-design/assets/showcases/website-homepage/homepage-takram.png +0 -0
  251. package/src/skills-lib/wizz-huashu-design/assets/showcases/website-saas/saas-build.html +0 -493
  252. package/src/skills-lib/wizz-huashu-design/assets/showcases/website-saas/saas-build.png +0 -0
  253. package/src/skills-lib/wizz-huashu-design/assets/showcases/website-saas/saas-pentagram.html +0 -556
  254. package/src/skills-lib/wizz-huashu-design/assets/showcases/website-saas/saas-pentagram.png +0 -0
  255. package/src/skills-lib/wizz-huashu-design/assets/showcases/website-saas/saas-takram.html +0 -604
  256. package/src/skills-lib/wizz-huashu-design/assets/showcases/website-saas/saas-takram.png +0 -0
  257. package/tools/installer/file-ops.js +0 -204
  258. package/tools/installer/ide/shared/skill-manifest.js +0 -57
  259. package/tools/installer/yaml-format.js +0 -245
  260. package/web-bundles/README.md +0 -46
  261. package/web-bundles/brainstorming-coach/INSTRUCTIONS.md +0 -86
  262. package/web-bundles/brainstorming-coach/SKILL.md +0 -83
  263. package/web-bundles/brainstorming-coach/brain-methods.csv +0 -62
  264. package/web-bundles/bundles.json +0 -139
  265. package/web-bundles/market-and-industry-research/INSTRUCTIONS.md +0 -88
  266. package/web-bundles/market-and-industry-research/SKILL.md +0 -59
  267. package/web-bundles/prd-coach/INSTRUCTIONS.md +0 -86
  268. package/web-bundles/prd-coach/SKILL.md +0 -101
  269. package/web-bundles/prd-coach/prd-template.md +0 -165
  270. package/web-bundles/prd-coach/prd-validation-checklist.md +0 -135
  271. package/web-bundles/prfaq-coach/INSTRUCTIONS.md +0 -86
  272. package/web-bundles/prfaq-coach/SKILL.md +0 -139
  273. package/web-bundles/product-brief-coach/INSTRUCTIONS.md +0 -86
  274. package/web-bundles/product-brief-coach/SKILL.md +0 -113
  275. package/web-bundles/ux-coach/INSTRUCTIONS.md +0 -92
  276. package/web-bundles/ux-coach/SKILL.md +0 -187
  277. package/web-bundles/ux-coach/ux-validation.md +0 -100
  278. /package/src/modules/lowticket/skills/{lowticket-funil → wizz-lowticket-funil}/references/mapa-do-funil.md +0 -0
  279. /package/src/modules/lowticket/skills/{lowticket-metodologia → wizz-lowticket-metodologia}/CATALOGO.md +0 -0
  280. /package/src/modules/lowticket/skills/{lowticket-metodologia → wizz-lowticket-metodologia}/knowledge/01-principios.md +0 -0
  281. /package/src/modules/lowticket/skills/{lowticket-metodologia → wizz-lowticket-metodologia}/knowledge/02-diagnostico-funil.md +0 -0
  282. /package/src/modules/lowticket/skills/{lowticket-metodologia → wizz-lowticket-metodologia}/knowledge/03-campanha-bidcap.md +0 -0
  283. /package/src/modules/lowticket/skills/{lowticket-metodologia → wizz-lowticket-metodologia}/knowledge/04-criativos.md +0 -0
  284. /package/src/modules/lowticket/skills/{lowticket-metodologia → wizz-lowticket-metodologia}/knowledge/04a-criativos-ia.md +0 -0
  285. /package/src/modules/lowticket/skills/{lowticket-metodologia → wizz-lowticket-metodologia}/knowledge/04b-criativos-formatos.md +0 -0
  286. /package/src/modules/lowticket/skills/{lowticket-metodologia → wizz-lowticket-metodologia}/knowledge/05-oferta.md +0 -0
  287. /package/src/modules/lowticket/skills/{lowticket-metodologia → wizz-lowticket-metodologia}/knowledge/06-pagina-vendas.md +0 -0
  288. /package/src/modules/lowticket/skills/{lowticket-metodologia → wizz-lowticket-metodologia}/knowledge/06a-instagram.md +0 -0
  289. /package/src/modules/lowticket/skills/{lowticket-metodologia → wizz-lowticket-metodologia}/knowledge/06b-player-vsl.md +0 -0
  290. /package/src/modules/lowticket/skills/{lowticket-metodologia → wizz-lowticket-metodologia}/knowledge/07-funil-upsell.md +0 -0
  291. /package/src/modules/lowticket/skills/{lowticket-metodologia → wizz-lowticket-metodologia}/knowledge/07a-copy-humanizacao.md +0 -0
  292. /package/src/modules/lowticket/skills/{lowticket-metodologia → wizz-lowticket-metodologia}/knowledge/08-pesquisa-publico.md +0 -0
  293. /package/src/modules/lowticket/skills/{lowticket-metodologia → wizz-lowticket-metodologia}/knowledge/09-especialista-coproducao.md +0 -0
  294. /package/src/modules/lowticket/skills/{lowticket-metodologia → wizz-lowticket-metodologia}/knowledge/10-levantar-caixa.md +0 -0
  295. /package/src/modules/lowticket/skills/{lowticket-metodologia → wizz-lowticket-metodologia}/knowledge/11-checklist-roi.md +0 -0
  296. /package/src/modules/lowticket/skills/{lowticket-metodologia → wizz-lowticket-metodologia}/knowledge/12-mineracao-ofertas.md +0 -0
  297. /package/src/modules/lowticket/skills/{lowticket-metodologia → wizz-lowticket-metodologia}/knowledge/12a-mineracao-veredito.md +0 -0
  298. /package/src/modules/lowticket/skills/{lowticket-metodologia → wizz-lowticket-metodologia}/knowledge/12b-fabrica-de-ofertas.md +0 -0
  299. /package/src/modules/lowticket/skills/{lowticket-metodologia → wizz-lowticket-metodologia}/knowledge/12c-anatomia-low-ticket.md +0 -0
  300. /package/src/modules/lowticket/skills/{lowticket-metodologia → wizz-lowticket-metodologia}/knowledge/13-benchmarks-vsl.md +0 -0
  301. /package/src/modules/lowticket/skills/{lowticket-metodologia → wizz-lowticket-metodologia}/knowledge/14-vocabulario.md +0 -0
  302. /package/src/modules/lowticket/skills/{lowticket-metodologia → wizz-lowticket-metodologia}/knowledge/15-como-estender.md +0 -0
  303. /package/src/modules/lowticket/skills/{lowticket-metodologia → wizz-lowticket-metodologia}/knowledge/17-rastreamento.md +0 -0
  304. /package/src/modules/lowticket/skills/{lowticket-metodologia → wizz-lowticket-metodologia}/knowledge/18-copy-desejo-oferta.md +0 -0
  305. /package/src/modules/lowticket/skills/{lowticket-metodologia → wizz-lowticket-metodologia}/knowledge/INDEX.md +0 -0
  306. /package/src/modules/lowticket/skills/{lowticket-metodologia → wizz-lowticket-metodologia}/knowledge/guardrails.md +0 -0
  307. /package/src/modules/lowticket/skills/{lowticket-metodologia → wizz-lowticket-metodologia}/knowledge/pontos-em-aberto.md +0 -0
  308. /package/src/modules/lowticket/skills/{lowticket-metodologia → wizz-lowticket-metodologia}/references/swipe-file.md +0 -0
  309. /package/src/modules/lowticket/skills/{lowticket-pagina → wizz-lowticket-pagina}/references/metas-e-medicao.md +0 -0
  310. /package/src/modules/lowticket/skills/{lowticket-pagina → wizz-lowticket-pagina}/references/padroes-de-codigo.md +0 -0
  311. /package/src/modules/lowticket/skills/{lowticket-trafego → wizz-lowticket-trafego}/references/formato-do-diagnostico.md +0 -0
@@ -0,0 +1,762 @@
1
+ /**
2
+ * Lado "coleta de configuração" de OfficialModules — item 20, etapa 3
3
+ * (auditoria 2026-09-11).
4
+ *
5
+ * Único módulo do split que importa `prompts`: collectAllConfigurations
6
+ * (gateway express/customize), collectModuleConfig(Quick), buildQuestion e
7
+ * a exibição das post-install notes. Os helpers puros de valor
8
+ * (processResultTemplate, replacePlaceholders, resolveConfigValue,
9
+ * normalizeExistingValueForPrompt, ...) foram para config-values.js e voltam
10
+ * por spread, sem mudar nada para os callers.
11
+ *
12
+ * Os métodos são montados no prototype de OfficialModules (Object.assign em
13
+ * official-modules.js): o estado da coleta (collectedConfig, allAnswers,
14
+ * _existingConfig, currentProjectDir, _silentConfig, skipPrompts,
15
+ * modulesToCustomize) vive na mesma instância usada pelo install.
16
+ */
17
+
18
+ const path = require('node:path');
19
+ const prompts = require('../prompts');
20
+ const { CLIUtils } = require('../banner');
21
+ const { getProjectRoot } = require('../project-root');
22
+ const { isMissingDefault, resolveModuleConfigPath, MODULE_METADATA_FIELDS } = require('./module-catalog');
23
+ const { loadYamlCached } = require('../core/yaml-cache');
24
+ const { ConfigValueMethods, buildQuestionChoices } = require('./config-values');
25
+
26
+ const ConfigCollectorMethods = {
27
+ // Helpers puros de valor (processResultTemplate, replacePlaceholders,
28
+ // resolveConfigValue, ...) moram em config-values.js desde o item 20 e são
29
+ // remontados aqui para os callers continuarem chamando-os como métodos.
30
+ ...ConfigValueMethods,
31
+ /**
32
+ * Collect configuration for all modules
33
+ * @param {Array} modules - List of modules to configure (including 'core')
34
+ * @param {string} projectDir - Target project directory
35
+ * @param {Object} options - Additional options
36
+ * @param {boolean} options.skipPrompts - Skip prompts and use defaults (for --yes flag)
37
+ */
38
+ async collectAllConfigurations(modules, projectDir, options = {}) {
39
+ this.skipPrompts = options.skipPrompts || false;
40
+ this.modulesToCustomize = undefined;
41
+ await this.loadExistingConfig(projectDir);
42
+
43
+ // Check if core was already collected (e.g., in early collection phase)
44
+ const coreAlreadyCollected = this.collectedConfig.core && Object.keys(this.collectedConfig.core).length > 0;
45
+
46
+ // If core wasn't already collected, include it
47
+ const allModules = coreAlreadyCollected ? modules.filter((m) => m !== 'core') : ['core', ...modules.filter((m) => m !== 'core')];
48
+
49
+ // Store all answers across modules for cross-referencing
50
+ if (!this.allAnswers) {
51
+ this.allAnswers = {};
52
+ }
53
+
54
+ // Split processing: core first, then gateway, then remaining modules
55
+ const coreModules = allModules.filter((m) => m === 'core');
56
+ const nonCoreModules = allModules.filter((m) => m !== 'core');
57
+
58
+ // Collect core config first (always fully prompted)
59
+ for (const moduleName of coreModules) {
60
+ await this.collectModuleConfig(moduleName, projectDir);
61
+ }
62
+
63
+ // Show batch configuration gateway for non-core modules
64
+ // Scan all non-core module schemas for display names and config metadata
65
+ let scannedModules = [];
66
+ if (!this.skipPrompts && nonCoreModules.length > 0) {
67
+ scannedModules = await this.scanModuleSchemas(nonCoreModules);
68
+ const customizableModules = scannedModules.filter((m) => m.questionCount > 0);
69
+
70
+ if (customizableModules.length > 0) {
71
+ const configMode = await prompts.select({
72
+ message: 'Module configuration',
73
+ choices: [
74
+ { name: 'Express Setup', value: 'express', hint: 'accept all defaults (recommended)' },
75
+ { name: 'Customize', value: 'customize', hint: 'choose modules to configure' },
76
+ ],
77
+ default: 'express',
78
+ });
79
+
80
+ if (configMode === 'customize') {
81
+ const choices = customizableModules.map((m) => ({
82
+ name: `${m.displayName} (${m.questionCount} option${m.questionCount === 1 ? '' : 's'})`,
83
+ value: m.moduleName,
84
+ hint: m.hasFieldsWithoutDefaults ? 'has fields without defaults' : undefined,
85
+ checked: m.hasFieldsWithoutDefaults,
86
+ }));
87
+ const selected = await prompts.multiselect({
88
+ message: 'Select modules to customize:',
89
+ choices,
90
+ required: false,
91
+ });
92
+ this.modulesToCustomize = new Set(selected);
93
+ } else {
94
+ // Express mode: no modules to customize
95
+ this.modulesToCustomize = new Set();
96
+ }
97
+ } else {
98
+ // All non-core modules have zero config - no gateway needed
99
+ this.modulesToCustomize = new Set();
100
+ }
101
+ }
102
+
103
+ // Collect remaining non-core modules
104
+ if (this.modulesToCustomize === undefined) {
105
+ // No gateway was shown (skipPrompts, no non-core modules, or direct call) - process all normally
106
+ for (const moduleName of nonCoreModules) {
107
+ await this.collectModuleConfig(moduleName, projectDir);
108
+ }
109
+ } else {
110
+ // Split into default modules (tasks progress) and customized modules (interactive)
111
+ const defaultModules = nonCoreModules.filter((m) => !this.modulesToCustomize.has(m));
112
+ const customizeModules = nonCoreModules.filter((m) => this.modulesToCustomize.has(m));
113
+
114
+ // Run default modules with a single spinner
115
+ if (defaultModules.length > 0) {
116
+ // Build display name map from all scanned modules for pre-call spinner messages
117
+ const displayNameMap = new Map();
118
+ for (const m of scannedModules) {
119
+ displayNameMap.set(m.moduleName, m.displayName);
120
+ }
121
+
122
+ const configSpinner = await prompts.spinner();
123
+ configSpinner.start('Configuring modules...');
124
+ try {
125
+ for (const moduleName of defaultModules) {
126
+ const displayName = displayNameMap.get(moduleName) || moduleName.toUpperCase();
127
+ configSpinner.message(`Configuring ${displayName}...`);
128
+ try {
129
+ this._silentConfig = true;
130
+ await this.collectModuleConfig(moduleName, projectDir);
131
+ } finally {
132
+ this._silentConfig = false;
133
+ }
134
+ }
135
+ } finally {
136
+ configSpinner.stop(customizeModules.length > 0 ? 'Module defaults applied' : 'Module configuration complete');
137
+ }
138
+ }
139
+
140
+ // Run customized modules individually (may show interactive prompts)
141
+ for (const moduleName of customizeModules) {
142
+ await this.collectModuleConfig(moduleName, projectDir);
143
+ }
144
+
145
+ if (customizeModules.length > 0) {
146
+ await prompts.log.step('Module configuration complete');
147
+ }
148
+ }
149
+
150
+ // Add metadata
151
+ this.collectedConfig._meta = {
152
+ version: require(path.join(getProjectRoot(), 'package.json')).version,
153
+ installDate: new Date().toISOString(),
154
+ lastModified: new Date().toISOString(),
155
+ };
156
+
157
+ return this.collectedConfig;
158
+ },
159
+ /**
160
+ * Collect configuration for a single module (Quick Update mode - only new fields)
161
+ * @param {string} moduleName - Module name
162
+ * @param {string} projectDir - Target project directory
163
+ * @param {boolean} silentMode - If true, only prompt for new/missing fields
164
+ * @returns {boolean} True if new fields were prompted, false if all fields existed
165
+ */
166
+ async collectModuleConfigQuick(moduleName, projectDir, silentMode = true) {
167
+ this.currentProjectDir = projectDir;
168
+ // Load existing config if not already loaded
169
+ if (!this._existingConfig) {
170
+ await this.loadExistingConfig(projectDir);
171
+ }
172
+
173
+ // Initialize allAnswers if not already initialized
174
+ if (!this.allAnswers) {
175
+ this.allAnswers = {};
176
+ }
177
+
178
+ // Load module's config schema from module.yaml ( resolução unificada no
179
+ // catálogo — item 20, etapa 2: o mesmo bloco estava copiado 3x)
180
+ const moduleConfigPath = await resolveModuleConfigPath((code, opts) => this.findModuleSource(code, opts), moduleName);
181
+
182
+ const moduleConfig = moduleConfigPath ? await loadYamlCached(moduleConfigPath) : null;
183
+
184
+ // No usable config schema for this module — keep the existing values.
185
+ // `moduleConfigPath` is non-null whenever a module SOURCE was found, even
186
+ // if that source has no module.yaml; before the item 20 split the check
187
+ // was `pathExists(module.yaml)`, so both cases landed here. Treating only
188
+ // the null-path case as "no schema" silently dropped the module's prior
189
+ // answers from collectedConfig on quick update.
190
+ if (!moduleConfig) {
191
+ if (this._existingConfig && this._existingConfig[moduleName]) {
192
+ if (!this.collectedConfig[moduleName]) {
193
+ this.collectedConfig[moduleName] = {};
194
+ }
195
+ this.collectedConfig[moduleName] = { ...this._existingConfig[moduleName] };
196
+ }
197
+ return false;
198
+ }
199
+
200
+ // Compare schema with existing config to find new/missing fields
201
+ const configKeys = Object.keys(moduleConfig).filter((key) => key !== 'prompt');
202
+ const existingKeys = this._existingConfig && this._existingConfig[moduleName] ? Object.keys(this._existingConfig[moduleName]) : [];
203
+
204
+ // Check if this module has no configuration keys at all (like CIS)
205
+ // Filter out metadata fields and only count actual config objects
206
+ const actualConfigKeys = configKeys.filter((key) => !MODULE_METADATA_FIELDS.has(key));
207
+ const hasNoConfig = actualConfigKeys.length === 0;
208
+
209
+ // If module has no config keys at all, handle it specially
210
+ if (hasNoConfig && moduleConfig.subheader) {
211
+ const moduleDisplayName = moduleConfig.header || `${moduleName.toUpperCase()} Module`;
212
+ await prompts.log.step(moduleDisplayName);
213
+ await prompts.log.message(` \u2713 ${moduleConfig.subheader}`);
214
+ return false; // No new fields
215
+ }
216
+
217
+ // Find new interactive fields (with prompt)
218
+ const newKeys = configKeys.filter((key) => {
219
+ const item = moduleConfig[key];
220
+ // Check if it's a config item and doesn't exist in existing config
221
+ return item && typeof item === 'object' && item.prompt && !existingKeys.includes(key);
222
+ });
223
+
224
+ // Find new static fields (without prompt, just result)
225
+ const newStaticKeys = configKeys.filter((key) => {
226
+ const item = moduleConfig[key];
227
+ return item && typeof item === 'object' && !item.prompt && item.result && !existingKeys.includes(key);
228
+ });
229
+
230
+ // If in silent mode and no new keys (neither interactive nor static), use existing config and skip prompts
231
+ if (silentMode && newKeys.length === 0 && newStaticKeys.length === 0) {
232
+ if (this._existingConfig && this._existingConfig[moduleName]) {
233
+ if (!this.collectedConfig[moduleName]) {
234
+ this.collectedConfig[moduleName] = {};
235
+ }
236
+ this.collectedConfig[moduleName] = { ...this._existingConfig[moduleName] };
237
+
238
+ // Special handling for user_name: ensure it has a value
239
+ if (
240
+ moduleName === 'core' &&
241
+ (!this.collectedConfig[moduleName].user_name || this.collectedConfig[moduleName].user_name === '[USER_NAME]')
242
+ ) {
243
+ this.collectedConfig[moduleName].user_name = this.getDefaultUsername();
244
+ }
245
+
246
+ // Also populate allAnswers for cross-referencing
247
+ for (const [key, value] of Object.entries(this._existingConfig[moduleName])) {
248
+ // Ensure user_name is properly set in allAnswers too
249
+ let finalValue = value;
250
+ if (moduleName === 'core' && key === 'user_name' && (!value || value === '[USER_NAME]')) {
251
+ finalValue = this.getDefaultUsername();
252
+ }
253
+ this.allAnswers[`${moduleName}_${key}`] = finalValue;
254
+ }
255
+ } else if (moduleName === 'core') {
256
+ // No existing core config - ensure we at least have user_name
257
+ if (!this.collectedConfig[moduleName]) {
258
+ this.collectedConfig[moduleName] = {};
259
+ }
260
+ if (!this.collectedConfig[moduleName].user_name) {
261
+ this.collectedConfig[moduleName].user_name = this.getDefaultUsername();
262
+ this.allAnswers[`${moduleName}_user_name`] = this.getDefaultUsername();
263
+ }
264
+ }
265
+
266
+ // Show "no config" message for modules with no new questions (that have config keys)
267
+ await prompts.log.message(` \u2713 ${moduleName.toUpperCase()} module already up to date`);
268
+ return false; // No new fields
269
+ }
270
+
271
+ // If we have new fields (interactive or static), process them
272
+ if (newKeys.length > 0 || newStaticKeys.length > 0) {
273
+ const questions = [];
274
+ const staticAnswers = {};
275
+
276
+ // Build questions for interactive fields
277
+ for (const key of newKeys) {
278
+ const item = moduleConfig[key];
279
+ const question = await this.buildQuestion(moduleName, key, item, moduleConfig);
280
+ if (question) {
281
+ questions.push(question);
282
+ }
283
+ }
284
+
285
+ // Prepare static answers (no prompt, just result)
286
+ for (const key of newStaticKeys) {
287
+ staticAnswers[`${moduleName}_${key}`] = undefined;
288
+ }
289
+
290
+ // Collect all answers (static + prompted)
291
+ let allAnswers = { ...staticAnswers };
292
+
293
+ if (questions.length > 0 && silentMode) {
294
+ // In silent mode (quick update), use defaults for new fields instead of prompting
295
+ for (const q of questions) {
296
+ allAnswers[q.name] = typeof q.default === 'function' ? q.default({}) : q.default;
297
+ }
298
+ await prompts.log.message(` \u2713 ${moduleName.toUpperCase()} module configured with defaults`);
299
+ } else if (questions.length > 0) {
300
+ // Only show header if we actually have questions
301
+ await CLIUtils.displayModuleConfigHeader(moduleName, moduleConfig.header, moduleConfig.subheader);
302
+ await prompts.log.message('');
303
+ const promptedAnswers = await prompts.prompt(questions);
304
+
305
+ // Merge prompted answers with static answers
306
+ Object.assign(allAnswers, promptedAnswers);
307
+ } else if (newStaticKeys.length > 0) {
308
+ // Only static fields, no questions - show no config message
309
+ await prompts.log.message(` \u2713 ${moduleName.toUpperCase()} module configuration updated`);
310
+ }
311
+
312
+ // Store all answers for cross-referencing
313
+ Object.assign(this.allAnswers, allAnswers);
314
+
315
+ // Process all answers (both static and prompted)
316
+ // First, copy existing config to preserve values that aren't being updated
317
+ if (this._existingConfig && this._existingConfig[moduleName]) {
318
+ this.collectedConfig[moduleName] = { ...this._existingConfig[moduleName] };
319
+ } else {
320
+ this.collectedConfig[moduleName] = {};
321
+ }
322
+
323
+ for (const key of Object.keys(allAnswers)) {
324
+ const originalKey = key.replace(`${moduleName}_`, '');
325
+ const item = moduleConfig[originalKey];
326
+ const value = allAnswers[key];
327
+
328
+ let result;
329
+ if (Array.isArray(value)) {
330
+ result = value;
331
+ } else if (item.result) {
332
+ result = this.processResultTemplate(item.result, value);
333
+ } else {
334
+ result = value;
335
+ }
336
+
337
+ // Update the collected config with new/updated values
338
+ this.collectedConfig[moduleName][originalKey] = result;
339
+ }
340
+ }
341
+
342
+ // Copy over existing values for fields that weren't prompted
343
+ if (this._existingConfig && this._existingConfig[moduleName]) {
344
+ if (!this.collectedConfig[moduleName]) {
345
+ this.collectedConfig[moduleName] = {};
346
+ }
347
+ for (const [key, value] of Object.entries(this._existingConfig[moduleName])) {
348
+ if (!this.collectedConfig[moduleName][key]) {
349
+ this.collectedConfig[moduleName][key] = value;
350
+ this.allAnswers[`${moduleName}_${key}`] = value;
351
+ }
352
+ }
353
+ }
354
+
355
+ await this.displayModulePostConfigNotes(moduleName, moduleConfig);
356
+
357
+ return newKeys.length > 0 || newStaticKeys.length > 0; // Return true if we had any new fields (interactive or static)
358
+ },
359
+ /**
360
+ * Collect configuration for a single module
361
+ * @param {string} moduleName - Module name
362
+ * @param {string} projectDir - Target project directory
363
+ * @param {boolean} skipLoadExisting - Skip loading existing config (for early core collection)
364
+ * @param {boolean} skipCompletion - Skip showing completion message (for early core collection)
365
+ */
366
+ async collectModuleConfig(moduleName, projectDir, skipLoadExisting = false, skipCompletion = false) {
367
+ this.currentProjectDir = projectDir;
368
+ // Load existing config if needed and not already loaded
369
+ if (!skipLoadExisting && !this._existingConfig) {
370
+ await this.loadExistingConfig(projectDir);
371
+ }
372
+
373
+ // Initialize allAnswers if not already initialized
374
+ if (!this.allAnswers) {
375
+ this.allAnswers = {};
376
+ }
377
+ // Load module's config (resolução unificada no catálogo — item 20, etapa 2)
378
+ const moduleConfigPath = await resolveModuleConfigPath((code, opts) => this.findModuleSource(code, opts), moduleName);
379
+
380
+ if (!moduleConfigPath) {
381
+ // No config for this module
382
+ return;
383
+ }
384
+
385
+ const moduleConfig = await loadYamlCached(moduleConfigPath);
386
+
387
+ if (!moduleConfig) {
388
+ return;
389
+ }
390
+
391
+ // Process each config item
392
+ const questions = [];
393
+ const staticAnswers = {};
394
+ const configKeys = Object.keys(moduleConfig).filter((key) => key !== 'prompt');
395
+
396
+ for (const key of configKeys) {
397
+ const item = moduleConfig[key];
398
+
399
+ // Skip if not a config object
400
+ if (!item || typeof item !== 'object') {
401
+ continue;
402
+ }
403
+
404
+ // Handle static values (no prompt, just result)
405
+ if (!item.prompt && item.result) {
406
+ // Add to static answers with a marker value
407
+ staticAnswers[`${moduleName}_${key}`] = undefined;
408
+ continue;
409
+ }
410
+
411
+ // Handle interactive values (with prompt)
412
+ if (item.prompt) {
413
+ const question = await this.buildQuestion(moduleName, key, item, moduleConfig);
414
+ if (question) {
415
+ questions.push(question);
416
+ }
417
+ }
418
+ }
419
+
420
+ // Collect all answers (static + prompted)
421
+ let allAnswers = { ...staticAnswers };
422
+
423
+ // If there are questions to ask, prompt for accepting defaults vs customizing
424
+ if (questions.length > 0) {
425
+ const moduleDisplayName = moduleConfig.header || `${moduleName.toUpperCase()} Module`;
426
+
427
+ // Skip prompts mode: use all defaults without asking
428
+ if (this.skipPrompts) {
429
+ await prompts.log.info(`Using default configuration for ${moduleDisplayName}`);
430
+ // Use defaults for all questions
431
+ for (const question of questions) {
432
+ const hasDefault = !isMissingDefault(question.default);
433
+ if (hasDefault && typeof question.default !== 'function') {
434
+ allAnswers[question.name] = question.default;
435
+ }
436
+ }
437
+ } else {
438
+ if (!this._silentConfig) await prompts.log.step(`Configuring ${moduleDisplayName}`);
439
+ let useDefaults = true;
440
+ if (moduleName === 'core') {
441
+ useDefaults = false; // Core: always show all questions
442
+ } else if (this.modulesToCustomize === undefined) {
443
+ // Fallback: original per-module confirm (backward compat for direct calls)
444
+ const customizeAnswer = await prompts.prompt([
445
+ {
446
+ type: 'confirm',
447
+ name: 'customize',
448
+ message: 'Accept Defaults (no to customize)?',
449
+ default: true,
450
+ },
451
+ ]);
452
+ useDefaults = customizeAnswer.customize;
453
+ } else {
454
+ // Batch mode: use defaults unless module was selected for customization
455
+ useDefaults = !this.modulesToCustomize.has(moduleName);
456
+ }
457
+
458
+ if (useDefaults && moduleName !== 'core') {
459
+ // Accept defaults - only ask questions that have NO default value
460
+ const questionsWithoutDefaults = questions.filter((q) => isMissingDefault(q.default));
461
+
462
+ if (questionsWithoutDefaults.length > 0) {
463
+ await prompts.log.message(` Asking required questions for ${moduleName.toUpperCase()}...`);
464
+ const promptedAnswers = await prompts.prompt(questionsWithoutDefaults);
465
+ Object.assign(allAnswers, promptedAnswers);
466
+ }
467
+
468
+ // For questions with defaults that weren't asked, we need to process them with their default values
469
+ const questionsWithDefaults = questions.filter((q) => !isMissingDefault(q.default));
470
+ for (const question of questionsWithDefaults) {
471
+ // Skip function defaults - these are dynamic and will be evaluated later
472
+ if (typeof question.default === 'function') {
473
+ continue;
474
+ }
475
+ allAnswers[question.name] = question.default;
476
+ }
477
+ } else {
478
+ const promptedAnswers = await prompts.prompt(questions);
479
+ Object.assign(allAnswers, promptedAnswers);
480
+ }
481
+ }
482
+ }
483
+
484
+ // Store all answers for cross-referencing
485
+ Object.assign(this.allAnswers, allAnswers);
486
+
487
+ // Process all answers (both static and prompted)
488
+ // Always process if we have any answers or static answers
489
+ if (Object.keys(allAnswers).length > 0 || Object.keys(staticAnswers).length > 0) {
490
+ const answers = allAnswers;
491
+
492
+ // Process answers and build result values
493
+ for (const key of Object.keys(answers)) {
494
+ const originalKey = key.replace(`${moduleName}_`, '');
495
+ const item = moduleConfig[originalKey];
496
+ const value = answers[key];
497
+
498
+ // Build the result using the template (OM-01: usa o processResultTemplate
499
+ // compartilhado em vez da reimplementação inline que tinha aqui — as duas
500
+ // versões já tinham divergido no lookup cross-module)
501
+ let result;
502
+ if (Array.isArray(value)) {
503
+ result = value;
504
+ } else if (item.result) {
505
+ result = this.processResultTemplate(item.result, value);
506
+ } else {
507
+ result = value;
508
+ }
509
+
510
+ // Store only the result value (no prompts, defaults, examples, etc.)
511
+ if (!this.collectedConfig[moduleName]) {
512
+ this.collectedConfig[moduleName] = {};
513
+ }
514
+ this.collectedConfig[moduleName][originalKey] = result;
515
+ }
516
+
517
+ // No longer display completion boxes - keep output clean
518
+ } else {
519
+ // No questions for this module - show completion message with header if available
520
+ const moduleDisplayName = moduleConfig.header || `${moduleName.toUpperCase()} Module`;
521
+
522
+ // Check if this module has NO configuration keys at all (like CIS)
523
+ // Filter out metadata fields and only count actual config objects
524
+ const actualConfigKeys = configKeys.filter((key) => !MODULE_METADATA_FIELDS.has(key));
525
+ const hasNoConfig = actualConfigKeys.length === 0;
526
+
527
+ if (!this._silentConfig) {
528
+ if (hasNoConfig && (moduleConfig.subheader || moduleConfig.header)) {
529
+ await prompts.log.step(moduleDisplayName);
530
+ if (moduleConfig.subheader) {
531
+ await prompts.log.message(` \u2713 ${moduleConfig.subheader}`);
532
+ } else {
533
+ await prompts.log.message(` \u2713 No custom configuration required`);
534
+ }
535
+ } else {
536
+ // Module has config but just no questions to ask
537
+ await prompts.log.message(` \u2713 ${moduleName.toUpperCase()} module configured`);
538
+ }
539
+ }
540
+ }
541
+
542
+ // If we have no collected config for this module, but we have a module schema,
543
+ // ensure we have at least an empty object
544
+ if (!this.collectedConfig[moduleName]) {
545
+ this.collectedConfig[moduleName] = {};
546
+
547
+ // If we accepted defaults and have no answers, we still need to check
548
+ // if there are any static values in the schema that should be applied
549
+ if (moduleConfig) {
550
+ for (const key of Object.keys(moduleConfig)) {
551
+ if (key !== 'prompt' && moduleConfig[key] && typeof moduleConfig[key] === 'object') {
552
+ const item = moduleConfig[key];
553
+ // For static items (no prompt, just result), apply the result
554
+ if (!item.prompt && item.result) {
555
+ // Apply any placeholder replacements to the result
556
+ let result = item.result;
557
+ if (typeof result === 'string') {
558
+ result = this.replacePlaceholders(result, moduleName, moduleConfig);
559
+ }
560
+ this.collectedConfig[moduleName][key] = result;
561
+ }
562
+ }
563
+ }
564
+ }
565
+ }
566
+
567
+ await this.displayModulePostConfigNotes(moduleName, moduleConfig);
568
+ },
569
+ /**
570
+ * Build a prompt question from a config item
571
+ * @param {string} moduleName - Module name
572
+ * @param {string} key - Config key
573
+ * @param {Object} item - Config item definition
574
+ * @param {Object} moduleConfig - Full module config schema (for resolving defaults)
575
+ */
576
+ async buildQuestion(moduleName, key, item, moduleConfig = null) {
577
+ const questionName = `${moduleName}_${key}`;
578
+
579
+ // Check for existing value
580
+ let existingValue = null;
581
+ if (this._existingConfig && this._existingConfig[moduleName]) {
582
+ existingValue = this._existingConfig[moduleName][key];
583
+ existingValue = this.normalizeExistingValueForPrompt(existingValue, moduleName, item, moduleConfig);
584
+ }
585
+
586
+ // Special handling for user_name: default to system user
587
+ if (moduleName === 'core' && key === 'user_name' && !existingValue) {
588
+ item.default = this.getDefaultUsername();
589
+ }
590
+
591
+ // Determine question type and default value (helpers puros em
592
+ // config-values.js — item 20)
593
+ const resolved = this.resolveQuestionDefault(item.default, moduleName, moduleConfig);
594
+ let defaultValue = resolved.defaultValue;
595
+ const dynamicDefault = resolved.dynamicDefault;
596
+
597
+ // Handle different question types
598
+ const { questionType, choices } = buildQuestionChoices(item, existingValue, defaultValue);
599
+ if (questionType === 'list' && existingValue) {
600
+ defaultValue = existingValue;
601
+ }
602
+
603
+ // Build the prompt message
604
+ let message = '';
605
+
606
+ // Handle array prompts for multi-line messages
607
+ if (Array.isArray(item.prompt)) {
608
+ message = item.prompt.join('\n');
609
+ } else {
610
+ message = item.prompt;
611
+ }
612
+
613
+ // Replace placeholders in prompt message with collected config values
614
+ if (typeof message === 'string') {
615
+ message = this.replacePlaceholders(message, moduleName, moduleConfig);
616
+ }
617
+
618
+ // Add current value indicator for existing configs
619
+ const color = await prompts.getColor();
620
+ if (existingValue !== null && existingValue !== undefined) {
621
+ if (typeof existingValue === 'boolean') {
622
+ message += color.dim(` (current: ${existingValue ? 'true' : 'false'})`);
623
+ } else if (Array.isArray(existingValue)) {
624
+ message += color.dim(` (current: ${existingValue.join(', ')})`);
625
+ } else if (questionType !== 'list') {
626
+ // Show the cleaned value (without {project-root}/) for display
627
+ message += color.dim(` (current: ${existingValue})`);
628
+ }
629
+ } else if (item.example && questionType === 'input') {
630
+ // Show example for input fields
631
+ let exampleText = typeof item.example === 'string' ? item.example : JSON.stringify(item.example);
632
+ // Replace placeholders in example
633
+ if (typeof exampleText === 'string') {
634
+ exampleText = this.replacePlaceholders(exampleText, moduleName, moduleConfig);
635
+ exampleText = exampleText.replace('{project-root}/', '');
636
+ }
637
+ message += color.dim(` (e.g., ${exampleText})`);
638
+ }
639
+
640
+ // Build the question object
641
+ const question = {
642
+ type: questionType,
643
+ name: questionName,
644
+ message: message,
645
+ };
646
+
647
+ // Set default - if it's dynamic, use a function that the prompt will evaluate with current answers
648
+ // But if we have an existing value, always use that instead
649
+ if (existingValue !== null && existingValue !== undefined && questionType !== 'list') {
650
+ question.default = existingValue;
651
+ } else if (dynamicDefault && typeof item.default === 'string') {
652
+ const originalDefault = item.default;
653
+ question.default = (answers) => {
654
+ // Replace placeholders using answers from previous questions in the same batch
655
+ let resolved = originalDefault;
656
+ resolved = resolved.replaceAll(/{([^}]+)}/g, (match, fieldName) => {
657
+ // Look for the answer in the current batch (prefixed with module name)
658
+ const answerKey = `${moduleName}_${fieldName}`;
659
+ if (answers[answerKey] !== undefined) {
660
+ return answers[answerKey];
661
+ }
662
+ // Fall back to collected config
663
+ return this.collectedConfig[moduleName]?.[fieldName] || match;
664
+ });
665
+ // Strip {project-root}/ for cleaner display
666
+ if (resolved.includes('{project-root}/')) {
667
+ resolved = resolved.replace('{project-root}/', '');
668
+ }
669
+ return resolved;
670
+ };
671
+ } else {
672
+ question.default = defaultValue;
673
+ }
674
+
675
+ // Add choices for select types
676
+ if (choices) {
677
+ question.choices = choices;
678
+ }
679
+
680
+ // Add validation for input fields
681
+ if (questionType === 'input') {
682
+ question.validate = (input) => {
683
+ if (!input && item.required) {
684
+ return 'This field is required';
685
+ }
686
+ // Validate against regex pattern if provided
687
+ if (input && item.regex) {
688
+ const regex = new RegExp(item.regex);
689
+ if (!regex.test(input)) {
690
+ return `Invalid format. Must match pattern: ${item.regex}`;
691
+ }
692
+ }
693
+ return true;
694
+ };
695
+ }
696
+
697
+ // Add validation for checkbox (multi-select) fields
698
+ if (questionType === 'checkbox' && item.required) {
699
+ question.validate = (answers) => {
700
+ if (!answers || answers.length === 0) {
701
+ return 'At least one option must be selected';
702
+ }
703
+ return true;
704
+ };
705
+ }
706
+
707
+ return question;
708
+ },
709
+ /**
710
+ * Display post-configuration notes for a module
711
+ * Shows prerequisite guidance based on collected config values
712
+ * Reads notes from the module's `post-install-notes` section in module.yaml
713
+ * Supports two formats:
714
+ * - Simple string: always displayed
715
+ * - Object keyed by config field name, with value-specific messages
716
+ * @param {string} moduleName - Module name
717
+ * @param {Object} moduleConfig - Parsed module.yaml content
718
+ */
719
+ async displayModulePostConfigNotes(moduleName, moduleConfig) {
720
+ if (this._silentConfig) return;
721
+ if (!moduleConfig || !moduleConfig['post-install-notes']) return;
722
+
723
+ const notes = moduleConfig['post-install-notes'];
724
+ const color = await prompts.getColor();
725
+
726
+ // Format 1: Simple string - always display
727
+ if (typeof notes === 'string') {
728
+ await prompts.log.message('');
729
+ for (const line of notes.trim().split('\n')) {
730
+ await prompts.log.message(color.dim(line));
731
+ }
732
+ return;
733
+ }
734
+
735
+ // Format 2: Conditional on config values
736
+ if (typeof notes === 'object') {
737
+ const config = this.collectedConfig[moduleName];
738
+ if (!config) return;
739
+
740
+ let hasOutput = false;
741
+ for (const [configKey, valueMessages] of Object.entries(notes)) {
742
+ const selectedValue = config[configKey];
743
+ if (!selectedValue || !valueMessages[selectedValue]) continue;
744
+
745
+ if (hasOutput) await prompts.log.message('');
746
+ hasOutput = true;
747
+
748
+ const message = valueMessages[selectedValue];
749
+ for (const line of message.trim().split('\n')) {
750
+ const trimmedLine = line.trim();
751
+ if (trimmedLine.endsWith(':') && !trimmedLine.startsWith(' ')) {
752
+ await prompts.log.info(color.bold(trimmedLine));
753
+ } else {
754
+ await prompts.log.message(color.dim(' ' + trimmedLine));
755
+ }
756
+ }
757
+ }
758
+ }
759
+ },
760
+ };
761
+
762
+ module.exports = { ConfigCollectorMethods };