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,618 @@
1
+ /**
2
+ * Lado "install" de OfficialModules — item 20, etapa 3 (auditoria 2026-09-11).
3
+ *
4
+ * O que copia/instala módulos em disco: atomicModuleSwap (ACH-03/F01),
5
+ * install/installFromResolution, copyModuleWithFiltering,
6
+ * createModuleDirectories e remove. Leitura de catálogo mora em
7
+ * module-catalog.js; coleta interativa de config mora em config-collector.js.
8
+ *
9
+ * Os métodos são montados no prototype de OfficialModules (Object.assign em
10
+ * official-modules.js) em vez de virarem uma classe separada: o estado
11
+ * (externalModuleManager, catalog, collectedConfig) é compartilhado na
12
+ * mesma instância, e os testes fazem monkey-patch em métodos de instância
13
+ * (ex.: `officialModules.findModuleSource = async () => ...`) — uma classe
14
+ * dona própria quebra esse contrato.
15
+ */
16
+
17
+ const path = require('node:path');
18
+ const fs = require('../fs-native');
19
+ const prompts = require('../prompts');
20
+ const { getSourcePath } = require('../project-root');
21
+ const { loadYamlCached } = require('../core/yaml-cache');
22
+ const { assertModuleInterfaceVersion } = require('./module-interface');
23
+
24
+ const MODULE_SWAP_SUFFIX_RE = /\.(?:tmp|old)-\d+$/;
25
+
26
+ /**
27
+ * Remove any `<module>.tmp-<pid>` / `<module>.old-<pid>` leftovers directly
28
+ * under `wizzDir` — orphans from an `atomicModuleSwap` that was killed
29
+ * mid-swap in a previous run. Safe to call before every module swap: once
30
+ * the directory is clean there is nothing left to remove, and the entries
31
+ * a swap currently in flight creates are never visible here (this only runs
32
+ * before that swap starts writing anything).
33
+ * @param {string} wizzDir
34
+ */
35
+ async function cleanupStaleModuleSwapEntries(wizzDir) {
36
+ let entries;
37
+ try {
38
+ entries = await fs.readdir(wizzDir, { withFileTypes: true });
39
+ } catch {
40
+ return;
41
+ }
42
+ for (const entry of entries) {
43
+ if (MODULE_SWAP_SUFFIX_RE.test(entry.name)) {
44
+ await fs.remove(path.join(wizzDir, entry.name)).catch(() => {});
45
+ }
46
+ }
47
+ }
48
+
49
+ /**
50
+ * Atomic per-module install/update swap. Writes the new module content to a
51
+ * sibling `<targetPath>.tmp-<pid>` (same filesystem as `targetPath`, so every
52
+ * rename below is atomic — never `os.tmpdir()`), then promotes it: rename the
53
+ * existing module (if any) to `<targetPath>.old-<pid>`, rename the tmp copy
54
+ * onto `targetPath`, and only then remove the `.old`. Mirrors the
55
+ * `_wizz.tmp-<pid>` + rename scaffold used for fresh installs (A14, see
56
+ * `InstallPaths`/`Installer.install`), scoped to a single module directory
57
+ * instead of the whole `_wizz/` tree — this is what closes ACH-03/F01
58
+ * (remove-then-copy update with no rollback) for updates, which never went
59
+ * through that scaffold.
60
+ *
61
+ * Failure modes:
62
+ * - copy into tmp throws: tmp is removed, `targetPath` (old or absent) is
63
+ * never touched.
64
+ * - promotion rename (tmp → targetPath) throws after the demotion rename
65
+ * (targetPath → old) already succeeded: the old content is renamed back
66
+ * onto `targetPath`, so the module ends up exactly as it started.
67
+ * - anything else (process killed between renames): the next call for any
68
+ * module in this `wizzDir` sweeps the orphaned `.tmp-`/`.old-` entries via
69
+ * `cleanupStaleModuleSwapEntries` before doing its own swap.
70
+ *
71
+ * @param {string} wizzDir - Parent `_wizz/` (or tmp install scaffold) directory.
72
+ * @param {string} targetPath - Final module directory (`wizzDir/<module>`).
73
+ * @param {(tmpPath: string, track: (filePath: string) => void) => Promise<void>} copyInto -
74
+ * Copies the new module content into `tmpPath`. Must report every file it
75
+ * writes through `track(filePath)` instead of the caller's own tracking
76
+ * callback — those paths still live under the tmp directory and are
77
+ * rewritten onto their final `targetPath`-relative location only after a
78
+ * successful swap, so a caller's file list never references a path that
79
+ * stops existing once the tmp dir is renamed away.
80
+ * @param {Function|null} fileTrackingCallback - Caller's real tracking callback.
81
+ */
82
+ async function atomicModuleSwap(wizzDir, targetPath, copyInto, fileTrackingCallback) {
83
+ await cleanupStaleModuleSwapEntries(wizzDir);
84
+
85
+ const pid = process.pid;
86
+ const tmpPath = `${targetPath}.tmp-${pid}`;
87
+ const oldPath = `${targetPath}.old-${pid}`;
88
+
89
+ // Same pid reusing a leftover from an earlier crash of this exact process
90
+ // id is astronomically unlikely, but start clean regardless.
91
+ await fs.remove(tmpPath).catch(() => {});
92
+ await fs.remove(oldPath).catch(() => {});
93
+
94
+ const trackedTmpPaths = [];
95
+ const track = fileTrackingCallback ? (filePath) => trackedTmpPaths.push(filePath) : () => {};
96
+
97
+ try {
98
+ await copyInto(tmpPath, track);
99
+ } catch (error) {
100
+ await fs.remove(tmpPath).catch(() => {});
101
+ throw error;
102
+ }
103
+
104
+ const hadExisting = await fs.pathExists(targetPath);
105
+ if (hadExisting) {
106
+ await fs.rename(targetPath, oldPath);
107
+ }
108
+
109
+ try {
110
+ await fs.rename(tmpPath, targetPath);
111
+ } catch (error) {
112
+ if (hadExisting) {
113
+ await fs.rename(oldPath, targetPath).catch(() => {});
114
+ }
115
+ await fs.remove(tmpPath).catch(() => {});
116
+ throw error;
117
+ }
118
+
119
+ if (hadExisting) {
120
+ await fs.remove(oldPath).catch(() => {});
121
+ }
122
+
123
+ if (fileTrackingCallback) {
124
+ for (const tmpFilePath of trackedTmpPaths) {
125
+ fileTrackingCallback(targetPath + tmpFilePath.slice(tmpPath.length));
126
+ }
127
+ }
128
+ }
129
+
130
+ const ModuleInstallerMethods = {
131
+ /**
132
+ * Copy a file to the target location
133
+ * @param {string} sourcePath - Source file path
134
+ * @param {string} targetPath - Target file path
135
+ * @param {boolean} overwrite - Whether to overwrite existing files (default: true)
136
+ */
137
+ async copyFile(sourcePath, targetPath, overwrite = true) {
138
+ await fs.copy(sourcePath, targetPath, { overwrite });
139
+ },
140
+ /**
141
+ * Install a module
142
+ * @param {string} moduleName - Code of the module to install (from module.yaml)
143
+ * @param {string} wizzDir - Target wizz directory
144
+ * @param {Function} fileTrackingCallback - Optional callback to track installed files
145
+ * @param {Object} options - Additional installation options
146
+ * @param {Array<string>} options.installedIDEs - Array of IDE codes that were installed
147
+ * @param {Object} options.moduleConfig - Module configuration from config collector
148
+ * @param {Object} options.logger - Logger instance for output
149
+ */
150
+ async install(moduleName, wizzDir, fileTrackingCallback = null, options = {}) {
151
+ // Aliases (ex.: bauto → bmad-loop) chegam crus via --modules e via
152
+ // moduleIds de instalações antigas; sem normalizar aqui, o cache de
153
+ // getPluginResolution, o targetPath e o manifest usariam o código legado.
154
+ moduleName = await this.externalModuleManager.resolveCanonicalCode(moduleName);
155
+
156
+ // Check if this module has a plugin resolution (custom marketplace install)
157
+ const { CustomModuleManager } = require('./custom-module-manager');
158
+ const customMgr = new CustomModuleManager();
159
+ const resolved = customMgr.getResolution(moduleName);
160
+ if (resolved) {
161
+ return this.installFromResolution(resolved, wizzDir, fileTrackingCallback, options);
162
+ }
163
+
164
+ const sourcePath = await this.findModuleSource(moduleName, {
165
+ silent: options.silent,
166
+ channelOptions: options.channelOptions,
167
+ });
168
+ const targetPath = path.join(wizzDir, moduleName);
169
+
170
+ if (!sourcePath) {
171
+ throw new Error(
172
+ `Source for module '${moduleName}' is not available. It will be retained but cannot be updated without its source files.`,
173
+ );
174
+ }
175
+
176
+ // Contract gate (auditoria 2026-09-11, item 25): a module.yaml declaring
177
+ // an interface_version this installer doesn't support must never reach
178
+ // _wizz/ — check before anything below writes a single byte. Missing
179
+ // module.yaml (null) is handled elsewhere (it's not this gate's job to
180
+ // require one); a module.yaml that exists but fails to parse aborts the
181
+ // install with a clear error instead of the generic parser error.
182
+ let moduleYamlForInterfaceCheck;
183
+ try {
184
+ moduleYamlForInterfaceCheck = await loadYamlCached(path.join(sourcePath, 'module.yaml'));
185
+ } catch (error) {
186
+ throw new Error(`Invalid module.yaml for '${moduleName}': ${error.message}`);
187
+ }
188
+ if (moduleYamlForInterfaceCheck) {
189
+ assertModuleInterfaceVersion(moduleYamlForInterfaceCheck, moduleName);
190
+ }
191
+
192
+ // Módulos marketplace-plugin do registry mantêm as skills instaláveis fora do
193
+ // diretório que contém o module.yaml (sourcePath aponta para o assets/ da
194
+ // skill -setup), então não dá para instalá-los copiando o sourcePath. Copia
195
+ // os diretórios de skill resolvidos, do mesmo jeito que um install custom de
196
+ // marketplace monta um módulo. Todo o resto (manifest, versão) segue pelo
197
+ // caminho padrão de módulo externo abaixo.
198
+ const marketplaceInfo = await this.externalModuleManager.getModuleByCode(moduleName);
199
+ let pluginResolution = null;
200
+ if (marketplaceInfo && marketplaceInfo.marketplacePlugin) {
201
+ pluginResolution = this.externalModuleManager.getPluginResolution(moduleName);
202
+ // Falha alto: copiar o sourcePath aqui instalaria só o assets/ da skill
203
+ // -setup (module.yaml + module-help.csv) e nenhuma skill — um install
204
+ // parcial e silenciosamente quebrado. Aborta em vez disso.
205
+ if (!pluginResolution || !Array.isArray(pluginResolution.skillPaths) || pluginResolution.skillPaths.length === 0) {
206
+ throw new Error(
207
+ `Module '${moduleName}' is registered as a marketplace plugin but its skills could not be resolved ` +
208
+ `from .claude-plugin/marketplace.json (missing or malformed on the selected channel). ` +
209
+ `Aborting to avoid a partial install with no skills.`,
210
+ );
211
+ }
212
+ }
213
+
214
+ // Atomic swap (ACH-03/F01): write the new content beside the target and
215
+ // only then promote it — an update killed mid-write never leaves the
216
+ // module directory missing or half-copied. See `atomicModuleSwap` above.
217
+ await atomicModuleSwap(
218
+ wizzDir,
219
+ targetPath,
220
+ async (tmpPath, track) => {
221
+ if (pluginResolution) {
222
+ await this._copyResolvedSkills(pluginResolution, tmpPath, track, options.moduleConfig);
223
+ } else {
224
+ await this.copyModuleWithFiltering(sourcePath, tmpPath, track, options.moduleConfig);
225
+ }
226
+ },
227
+ fileTrackingCallback,
228
+ );
229
+
230
+ if (!options.skipModuleInstaller) {
231
+ await this.createModuleDirectories(moduleName, wizzDir, { ...options, sourcePath });
232
+ }
233
+
234
+ const { Manifest } = require('../core/manifest');
235
+ const manifestObj = new Manifest();
236
+ const versionInfo = await manifestObj.getModuleVersionInfo(moduleName, wizzDir, sourcePath);
237
+
238
+ // Pick up channel resolution recorded by the external manager (the only
239
+ // manager that does pre-clone resolution now that community is retired).
240
+ const resolution = this.externalModuleManager.getResolution(moduleName);
241
+
242
+ await manifestObj.addModule(wizzDir, moduleName, {
243
+ version: resolution?.version || versionInfo.version,
244
+ source: versionInfo.source,
245
+ npmPackage: versionInfo.npmPackage,
246
+ repoUrl: versionInfo.repoUrl,
247
+ channel: resolution?.channel,
248
+ sha: resolution?.sha,
249
+ });
250
+
251
+ return { success: true, module: moduleName, path: targetPath, versionInfo };
252
+ },
253
+ /**
254
+ * Assenta em disco uma resolução do PluginResolver: copia cada diretório de
255
+ * skill resolvido (achatado pelo nome da folha) para targetPath e coloca o
256
+ * module-help.csv na raiz do módulo. Compartilhado pelos installs custom de
257
+ * marketplace (installFromResolution) e pelos installs oficiais de módulo
258
+ * marketplace-plugin (install), para os dois caminhos não divergirem.
259
+ * @param {Object} resolved - ResolvedModule do PluginResolver
260
+ * @param {string} targetPath - Diretório de destino do módulo (ex.: wizzDir/<code>)
261
+ * @param {Function} fileTrackingCallback - Callback opcional de rastreio de arquivos
262
+ * @param {Object} moduleConfig - Configuração do módulo repassada ao filtro de cópia
263
+ */
264
+ async _copyResolvedSkills(resolved, targetPath, fileTrackingCallback = null, moduleConfig = {}) {
265
+ await fs.ensureDir(targetPath);
266
+
267
+ // Copia cada diretório de skill, achatado pelo nome da folha. Os nomes de
268
+ // folha precisam ser únicos — duas skills que achatam para o mesmo diretório
269
+ // se sobrescreveriam em silêncio, então falha alto em vez disso.
270
+ const seenLeaves = new Map();
271
+ for (const skillPath of resolved.skillPaths) {
272
+ const skillDirName = path.basename(skillPath);
273
+ if (seenLeaves.has(skillDirName)) {
274
+ throw new Error(
275
+ `Cannot install module '${resolved.code}': skill directories '${seenLeaves.get(skillDirName)}' and ` +
276
+ `'${skillPath}' share the leaf name '${skillDirName}' and would overwrite each other. ` +
277
+ `Skill directory names must be unique.`,
278
+ );
279
+ }
280
+ seenLeaves.set(skillDirName, skillPath);
281
+ const skillTarget = path.join(targetPath, skillDirName);
282
+ await this.copyModuleWithFiltering(skillPath, skillTarget, fileTrackingCallback, moduleConfig);
283
+ }
284
+
285
+ // Coloca o module-help.csv na raiz do módulo.
286
+ const helpTarget = path.join(targetPath, 'module-help.csv');
287
+ if (resolved.moduleHelpCsvPath) {
288
+ // Estratégias 1-4: copia o arquivo existente.
289
+ await fs.copy(resolved.moduleHelpCsvPath, helpTarget, { overwrite: true });
290
+ if (fileTrackingCallback) fileTrackingCallback(helpTarget);
291
+ } else if (resolved.synthesizedHelpCsv) {
292
+ // Estratégia 5: escreve o conteúdo sintetizado.
293
+ await fs.writeFile(helpTarget, resolved.synthesizedHelpCsv, 'utf8');
294
+ if (fileTrackingCallback) fileTrackingCallback(helpTarget);
295
+ }
296
+ },
297
+ /**
298
+ * Install a module from a PluginResolver resolution result.
299
+ * Copies specific skill directories and places module-help.csv at the target root.
300
+ * @param {Object} resolved - ResolvedModule from PluginResolver
301
+ * @param {string} wizzDir - Target wizz directory
302
+ * @param {Function} fileTrackingCallback - Optional callback to track installed files
303
+ * @param {Object} options - Installation options
304
+ */
305
+ async installFromResolution(resolved, wizzDir, fileTrackingCallback = null, options = {}) {
306
+ const targetPath = path.join(wizzDir, resolved.code);
307
+
308
+ // Contract gate (auditoria 2026-09-11, item 25) — same check as
309
+ // `install()` above, but a ResolvedModule never loads the full
310
+ // module.yaml, only the interfaceVersion PluginResolver carried over.
311
+ assertModuleInterfaceVersion({ interface_version: resolved.interfaceVersion }, resolved.code);
312
+
313
+ // Atomic swap (ACH-03/F01) — see `atomicModuleSwap` above.
314
+ await atomicModuleSwap(
315
+ wizzDir,
316
+ targetPath,
317
+ (tmpPath, track) => this._copyResolvedSkills(resolved, tmpPath, track, options.moduleConfig),
318
+ fileTrackingCallback,
319
+ );
320
+
321
+ // Create directories declared in module.yaml (strategies 1-4 may have these)
322
+ if (!options.skipModuleInstaller) {
323
+ await this.createModuleDirectories(resolved.code, wizzDir, options);
324
+ }
325
+
326
+ // Update manifest. For custom-source installs we derive channel from the
327
+ // cloneRef (present → pinned, absent → next; local paths have no channel).
328
+ const { Manifest } = require('../core/manifest');
329
+ const manifestObj = new Manifest();
330
+
331
+ const hasGitClone = !!resolved.repoUrl;
332
+ const manifestEntry = {
333
+ version: resolved.cloneRef || (hasGitClone ? 'main' : resolved.version || null),
334
+ source: 'custom',
335
+ npmPackage: null,
336
+ repoUrl: resolved.repoUrl || null,
337
+ };
338
+ if (hasGitClone) {
339
+ manifestEntry.channel = resolved.cloneRef ? 'pinned' : 'next';
340
+ if (resolved.cloneSha) manifestEntry.sha = resolved.cloneSha;
341
+ if (resolved.rawInput) manifestEntry.rawSource = resolved.rawInput;
342
+ }
343
+ if (resolved.localPath) manifestEntry.localPath = resolved.localPath;
344
+ await manifestObj.addModule(wizzDir, resolved.code, manifestEntry);
345
+
346
+ return {
347
+ success: true,
348
+ module: resolved.code,
349
+ path: targetPath,
350
+ // Mirror the manifestEntry.version precedence above so downstream summary
351
+ // lines show the same string we just wrote to disk (custom git-backed
352
+ // installs show the cloned ref or 'main').
353
+ versionInfo: {
354
+ version: resolved.cloneRef || (hasGitClone ? 'main' : resolved.version || ''),
355
+ },
356
+ };
357
+ },
358
+ /**
359
+ * Remove a module
360
+ * @param {string} moduleName - Name of the module to remove
361
+ * @param {string} wizzDir - Target wizz directory
362
+ */
363
+ async remove(moduleName, wizzDir) {
364
+ const targetPath = path.join(wizzDir, moduleName);
365
+
366
+ if (!(await fs.pathExists(targetPath))) {
367
+ throw new Error(`Module '${moduleName}' is not installed`);
368
+ }
369
+
370
+ await fs.remove(targetPath);
371
+
372
+ return {
373
+ success: true,
374
+ module: moduleName,
375
+ };
376
+ },
377
+ /**
378
+ * Copy module with filtering for localskip agents and conditional content
379
+ * @param {string} sourcePath - Source module path
380
+ * @param {string} targetPath - Target module path
381
+ * @param {Function} fileTrackingCallback - Optional callback to track installed files
382
+ * @param {Object} moduleConfig - Module configuration with conditional flags
383
+ */
384
+ async copyModuleWithFiltering(sourcePath, targetPath, fileTrackingCallback = null, moduleConfig = {}) {
385
+ // Get all files in source
386
+ const sourceFiles = await this.getFileList(sourcePath);
387
+
388
+ for (const file of sourceFiles) {
389
+ // Skip sub-modules directory - these are IDE-specific and handled separately
390
+ if (file.startsWith('sub-modules/')) {
391
+ continue;
392
+ }
393
+
394
+ // Skip sidecar directories - these contain agent-specific assets not needed at install time
395
+ const isInSidecarDirectory = path
396
+ .dirname(file)
397
+ .split('/')
398
+ .some((dir) => dir.toLowerCase().endsWith('-sidecar'));
399
+
400
+ if (isInSidecarDirectory) {
401
+ continue;
402
+ }
403
+
404
+ // Skip module.yaml at root - it's only needed at install time
405
+ if (file === 'module.yaml') {
406
+ continue;
407
+ }
408
+
409
+ // Skip module root config.yaml only - generated by config collector with actual values
410
+ // Workflow-level config.yaml (e.g. workflows/orchestrate-story/config.yaml) must be copied
411
+ // for custom modules that use workflow-specific configuration
412
+ if (file === 'config.yaml') {
413
+ continue;
414
+ }
415
+
416
+ const sourceFile = path.join(sourcePath, file);
417
+ const targetFile = path.join(targetPath, file);
418
+
419
+ // Check if this is an agent file
420
+ if (file.startsWith('agents/') && file.endsWith('.md')) {
421
+ // Read the file to check for localskip
422
+ const content = await fs.readFile(sourceFile, 'utf8');
423
+
424
+ // Check for localskip="true" in the agent tag
425
+ const agentMatch = content.match(/<agent[^>]*\slocalskip="true"[^>]*>/);
426
+ if (agentMatch) {
427
+ await prompts.log.message(` Skipping web-only agent: ${path.basename(file)}`);
428
+ continue; // Skip this agent
429
+ }
430
+ }
431
+
432
+ // Copy the file with placeholder replacement
433
+ await this.copyFile(sourceFile, targetFile);
434
+
435
+ // Track the file if callback provided
436
+ if (fileTrackingCallback) {
437
+ fileTrackingCallback(targetFile);
438
+ }
439
+ }
440
+ },
441
+ /**
442
+ * Create directories declared in module.yaml's `directories` key
443
+ * This replaces the security-risky module installer pattern with declarative config
444
+ * During updates, if a directory path changed, moves the old directory to the new path
445
+ * @param {string} moduleName - Name of the module
446
+ * @param {string} wizzDir - Target wizz directory
447
+ * @param {Object} options - Installation options
448
+ * @param {Object} options.moduleConfig - Module configuration from config collector
449
+ * @param {Object} options.existingModuleConfig - Previous module config (for detecting path changes during updates)
450
+ * @param {Object} options.coreConfig - Core configuration
451
+ * @returns {Promise<{createdDirs: string[], movedDirs: string[], createdWdsFolders: string[]}>} Created directories info
452
+ */
453
+ async createModuleDirectories(moduleName, wizzDir, options = {}) {
454
+ const moduleConfig = options.moduleConfig || {};
455
+ const existingModuleConfig = options.existingModuleConfig || {};
456
+ const projectRoot = path.dirname(wizzDir);
457
+ const emptyResult = { createdDirs: [], movedDirs: [], createdWdsFolders: [] };
458
+
459
+ // Special handling for core module - it's in src/core-skills not src/modules.
460
+ // OM-04 (auditoria 2026-09-11): install() já resolveu a fonte; aceita via
461
+ // options.sourcePath para não re-varrer caches externos nem quebrar quando
462
+ // o teste stuba findModuleSource na instância.
463
+ let sourcePath = options.sourcePath;
464
+ if (!sourcePath) {
465
+ if (moduleName === 'core') {
466
+ sourcePath = getSourcePath('core-skills');
467
+ } else {
468
+ sourcePath = await this.findModuleSource(moduleName, { silent: true });
469
+ if (!sourcePath) {
470
+ return emptyResult; // No source found, skip
471
+ }
472
+ }
473
+ }
474
+
475
+ // Read module.yaml to find the `directories` key
476
+ const moduleYamlPath = path.join(sourcePath, 'module.yaml');
477
+ let moduleYaml;
478
+ try {
479
+ moduleYaml = await loadYamlCached(moduleYamlPath);
480
+ } catch (error) {
481
+ await prompts.log.warn(`Invalid module.yaml for ${moduleName}: ${error.message}`);
482
+ return emptyResult;
483
+ }
484
+ if (!moduleYaml) {
485
+ return emptyResult; // No module.yaml, skip
486
+ }
487
+
488
+ if (!moduleYaml.directories) {
489
+ return emptyResult; // No directories declared, skip
490
+ }
491
+
492
+ const directories = moduleYaml.directories;
493
+ const wdsFolders = moduleYaml.wds_folders || [];
494
+ const createdDirs = [];
495
+ const movedDirs = [];
496
+ const createdWdsFolders = [];
497
+
498
+ for (const dirRef of directories) {
499
+ // Parse variable reference like "{design_artifacts}"
500
+ const varMatch = dirRef.match(/^\{([^}]+)\}$/);
501
+ if (!varMatch) {
502
+ // Not a variable reference, skip
503
+ continue;
504
+ }
505
+
506
+ const configKey = varMatch[1];
507
+ const dirValue = moduleConfig[configKey];
508
+ if (!dirValue || typeof dirValue !== 'string') {
509
+ continue; // No value or not a string, skip
510
+ }
511
+
512
+ // Strip {project-root}/ prefix if present
513
+ let dirPath = dirValue.replace(/^\{project-root\}\/?/, '');
514
+
515
+ // Handle remaining {project-root} anywhere in the path
516
+ dirPath = dirPath.replaceAll('{project-root}', '');
517
+
518
+ // Resolve to absolute path
519
+ const fullPath = path.join(projectRoot, dirPath);
520
+
521
+ // Validate path is within project root (prevent directory traversal)
522
+ const normalizedPath = path.normalize(fullPath);
523
+ const normalizedRoot = path.normalize(projectRoot);
524
+ if (!normalizedPath.startsWith(normalizedRoot + path.sep) && normalizedPath !== normalizedRoot) {
525
+ const color = await prompts.getColor();
526
+ await prompts.log.warn(color.yellow(`${configKey} path escapes project root, skipping: ${dirPath}`));
527
+ continue;
528
+ }
529
+
530
+ // Check if directory path changed from previous config (update/modify scenario)
531
+ const oldDirValue = existingModuleConfig[configKey];
532
+ let oldFullPath = null;
533
+ let oldDirPath = null;
534
+ if (oldDirValue && typeof oldDirValue === 'string') {
535
+ // F3: Normalize both values before comparing to avoid false negatives
536
+ // from trailing slashes, separator differences, or prefix format variations
537
+ let normalizedOld = oldDirValue.replace(/^\{project-root\}\/?/, '');
538
+ normalizedOld = path.normalize(normalizedOld.replaceAll('{project-root}', ''));
539
+ const normalizedNew = path.normalize(dirPath);
540
+
541
+ if (normalizedOld !== normalizedNew) {
542
+ oldDirPath = normalizedOld;
543
+ oldFullPath = path.join(projectRoot, oldDirPath);
544
+ const normalizedOldAbsolute = path.normalize(oldFullPath);
545
+ if (!normalizedOldAbsolute.startsWith(normalizedRoot + path.sep) && normalizedOldAbsolute !== normalizedRoot) {
546
+ oldFullPath = null; // Old path escapes project root, ignore it
547
+ }
548
+
549
+ // F13: Prevent parent/child move (e.g. docs/planning → docs/planning/v2)
550
+ if (oldFullPath) {
551
+ const normalizedNewAbsolute = path.normalize(fullPath);
552
+ if (
553
+ normalizedOldAbsolute.startsWith(normalizedNewAbsolute + path.sep) ||
554
+ normalizedNewAbsolute.startsWith(normalizedOldAbsolute + path.sep)
555
+ ) {
556
+ const color = await prompts.getColor();
557
+ await prompts.log.warn(
558
+ color.yellow(
559
+ `${configKey}: cannot move between parent/child paths (${oldDirPath} / ${dirPath}), creating new directory instead`,
560
+ ),
561
+ );
562
+ oldFullPath = null;
563
+ }
564
+ }
565
+ }
566
+ }
567
+
568
+ const dirName = configKey.replaceAll('_', ' ');
569
+
570
+ if (oldFullPath && (await fs.pathExists(oldFullPath)) && !(await fs.pathExists(fullPath))) {
571
+ // Path changed and old dir exists → move old to new location
572
+ // F1: Use fs.move() instead of fs.rename() for cross-device/volume support
573
+ // F2: Wrap in try/catch — fallback to creating new dir on failure
574
+ try {
575
+ await fs.ensureDir(path.dirname(fullPath));
576
+ await fs.move(oldFullPath, fullPath);
577
+ movedDirs.push(`${dirName}: ${oldDirPath} → ${dirPath}`);
578
+ } catch (moveError) {
579
+ const color = await prompts.getColor();
580
+ await prompts.log.warn(
581
+ color.yellow(
582
+ `Failed to move ${oldDirPath} → ${dirPath}: ${moveError.message}\n Creating new directory instead. Please move contents from the old directory manually.`,
583
+ ),
584
+ );
585
+ await fs.ensureDir(fullPath);
586
+ createdDirs.push(`${dirName}: ${dirPath}`);
587
+ }
588
+ } else if (oldFullPath && (await fs.pathExists(oldFullPath)) && (await fs.pathExists(fullPath))) {
589
+ // F5: Both old and new directories exist — warn user about potential orphaned documents
590
+ const color = await prompts.getColor();
591
+ await prompts.log.warn(
592
+ color.yellow(
593
+ `${dirName}: path changed but both directories exist:\n Old: ${oldDirPath}\n New: ${dirPath}\n Old directory may contain orphaned documents — please review and merge manually.`,
594
+ ),
595
+ );
596
+ } else if (!(await fs.pathExists(fullPath))) {
597
+ // New directory doesn't exist yet → create it
598
+ createdDirs.push(`${dirName}: ${dirPath}`);
599
+ await fs.ensureDir(fullPath);
600
+ }
601
+
602
+ // Create WDS subfolders if this is the design_artifacts directory
603
+ if (configKey === 'design_artifacts' && wdsFolders.length > 0) {
604
+ for (const subfolder of wdsFolders) {
605
+ const subPath = path.join(fullPath, subfolder);
606
+ if (!(await fs.pathExists(subPath))) {
607
+ await fs.ensureDir(subPath);
608
+ createdWdsFolders.push(subfolder);
609
+ }
610
+ }
611
+ }
612
+ }
613
+
614
+ return { createdDirs, movedDirs, createdWdsFolders };
615
+ },
616
+ };
617
+
618
+ module.exports = { ModuleInstallerMethods };