wizz-method 2.0.0 → 2.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (310) 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 +62 -37
  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/install.js +1 -1
  156. package/tools/installer/commands/resolve.js +95 -0
  157. package/tools/installer/core/doctor.js +648 -0
  158. package/tools/installer/core/hash-cache.js +156 -0
  159. package/tools/installer/core/help-catalog.js +4 -1
  160. package/tools/installer/core/hooks-settings.js +178 -0
  161. package/tools/installer/core/installer.js +297 -15
  162. package/tools/installer/core/legacy-warnings.js +0 -4
  163. package/tools/installer/core/manifest-generator.js +121 -43
  164. package/tools/installer/core/manifest.js +36 -32
  165. package/tools/installer/core/module-config-writer.js +4 -1
  166. package/tools/installer/core/python-check.js +60 -63
  167. package/tools/installer/core/quick-update.js +76 -43
  168. package/tools/installer/core/resolved-config.js +168 -0
  169. package/tools/installer/core/resolved-customizations.js +736 -0
  170. package/tools/installer/core/resolved-includes.js +262 -0
  171. package/tools/installer/core/resolved-schema.js +148 -0
  172. package/tools/installer/core/user-file-preservation.js +40 -8
  173. package/tools/installer/core/wizz-dir.js +117 -0
  174. package/tools/installer/core/yaml-cache.js +105 -0
  175. package/tools/installer/fs-native.js +97 -6
  176. package/tools/installer/ide/_config-driven.js +12 -75
  177. package/tools/installer/ide/platform-codes.js +111 -16
  178. package/tools/installer/ide/platform-codes.yaml +45 -100
  179. package/tools/installer/ide/shared/path-utils.js +6 -208
  180. package/tools/installer/install-messages.yaml +4 -14
  181. package/tools/installer/modules/channel-plan.js +15 -2
  182. package/tools/installer/modules/config-collector.js +762 -0
  183. package/tools/installer/modules/config-values.js +352 -0
  184. package/tools/installer/modules/custom-module-manager.js +161 -28
  185. package/tools/installer/modules/env-vars.js +119 -0
  186. package/tools/installer/modules/external-manager.js +133 -60
  187. package/tools/installer/modules/git-cache-utils.js +125 -0
  188. package/tools/installer/modules/module-catalog.js +565 -0
  189. package/tools/installer/modules/module-installer.js +618 -0
  190. package/tools/installer/modules/module-interface.js +86 -0
  191. package/tools/installer/modules/official-modules.js +98 -2172
  192. package/tools/installer/modules/pin-spec.js +125 -0
  193. package/tools/installer/modules/plugin-resolver.js +4 -0
  194. package/tools/installer/modules/skills-lib.js +3 -6
  195. package/tools/installer/prompts.js +0 -3
  196. package/tools/installer/ui.js +89 -54
  197. package/tools/installer/wizz-cli.js +1 -1
  198. package/tools/lib/frontmatter.js +139 -0
  199. package/tools/lib/sync-targets.mjs +49 -0
  200. package/tools/lib/walk.js +93 -0
  201. package/wizz-modules.yaml +9 -0
  202. package/src/scripts/__pycache__/memlog.cpython-313.pyc +0 -0
  203. package/src/scripts/memlog.py +0 -233
  204. package/src/scripts/tests/__pycache__/test_memlog.cpython-313-pytest-9.1.1.pyc +0 -0
  205. package/src/scripts/tests/__pycache__/test_resolve_customization.cpython-313-pytest-9.1.1.pyc +0 -0
  206. package/src/scripts/tests/test_memlog.py +0 -306
  207. package/src/skills-lib/wizz-huashu-design/assets/showcases/INDEX.md +0 -115
  208. package/src/skills-lib/wizz-huashu-design/assets/showcases/cover/cover-build.html +0 -235
  209. package/src/skills-lib/wizz-huashu-design/assets/showcases/cover/cover-build.png +0 -0
  210. package/src/skills-lib/wizz-huashu-design/assets/showcases/cover/cover-pentagram.html +0 -229
  211. package/src/skills-lib/wizz-huashu-design/assets/showcases/cover/cover-pentagram.png +0 -0
  212. package/src/skills-lib/wizz-huashu-design/assets/showcases/cover/cover-takram.html +0 -288
  213. package/src/skills-lib/wizz-huashu-design/assets/showcases/cover/cover-takram.png +0 -0
  214. package/src/skills-lib/wizz-huashu-design/assets/showcases/infographic/infographic-build.html +0 -503
  215. package/src/skills-lib/wizz-huashu-design/assets/showcases/infographic/infographic-build.png +0 -0
  216. package/src/skills-lib/wizz-huashu-design/assets/showcases/infographic/infographic-pentagram.html +0 -600
  217. package/src/skills-lib/wizz-huashu-design/assets/showcases/infographic/infographic-pentagram.png +0 -0
  218. package/src/skills-lib/wizz-huashu-design/assets/showcases/infographic/infographic-takram.html +0 -670
  219. package/src/skills-lib/wizz-huashu-design/assets/showcases/infographic/infographic-takram.png +0 -0
  220. package/src/skills-lib/wizz-huashu-design/assets/showcases/ppt/ppt-build.html +0 -382
  221. package/src/skills-lib/wizz-huashu-design/assets/showcases/ppt/ppt-build.png +0 -0
  222. package/src/skills-lib/wizz-huashu-design/assets/showcases/ppt/ppt-pentagram.html +0 -536
  223. package/src/skills-lib/wizz-huashu-design/assets/showcases/ppt/ppt-pentagram.png +0 -0
  224. package/src/skills-lib/wizz-huashu-design/assets/showcases/ppt/ppt-takram.html +0 -497
  225. package/src/skills-lib/wizz-huashu-design/assets/showcases/ppt/ppt-takram.png +0 -0
  226. package/src/skills-lib/wizz-huashu-design/assets/showcases/website-ai-nav/ainav-build.html +0 -385
  227. package/src/skills-lib/wizz-huashu-design/assets/showcases/website-ai-nav/ainav-build.png +0 -0
  228. package/src/skills-lib/wizz-huashu-design/assets/showcases/website-ai-nav/ainav-pentagram.html +0 -422
  229. package/src/skills-lib/wizz-huashu-design/assets/showcases/website-ai-nav/ainav-pentagram.png +0 -0
  230. package/src/skills-lib/wizz-huashu-design/assets/showcases/website-ai-nav/ainav-takram.html +0 -499
  231. package/src/skills-lib/wizz-huashu-design/assets/showcases/website-ai-nav/ainav-takram.png +0 -0
  232. package/src/skills-lib/wizz-huashu-design/assets/showcases/website-ai-writing/aiwriting-build.html +0 -562
  233. package/src/skills-lib/wizz-huashu-design/assets/showcases/website-ai-writing/aiwriting-build.png +0 -0
  234. package/src/skills-lib/wizz-huashu-design/assets/showcases/website-ai-writing/aiwriting-pentagram.html +0 -548
  235. package/src/skills-lib/wizz-huashu-design/assets/showcases/website-ai-writing/aiwriting-pentagram.png +0 -0
  236. package/src/skills-lib/wizz-huashu-design/assets/showcases/website-ai-writing/aiwriting-takram.html +0 -696
  237. package/src/skills-lib/wizz-huashu-design/assets/showcases/website-ai-writing/aiwriting-takram.png +0 -0
  238. package/src/skills-lib/wizz-huashu-design/assets/showcases/website-devdocs/devdocs-build.html +0 -372
  239. package/src/skills-lib/wizz-huashu-design/assets/showcases/website-devdocs/devdocs-build.png +0 -0
  240. package/src/skills-lib/wizz-huashu-design/assets/showcases/website-devdocs/devdocs-pentagram.html +0 -460
  241. package/src/skills-lib/wizz-huashu-design/assets/showcases/website-devdocs/devdocs-pentagram.png +0 -0
  242. package/src/skills-lib/wizz-huashu-design/assets/showcases/website-devdocs/devdocs-takram.html +0 -494
  243. package/src/skills-lib/wizz-huashu-design/assets/showcases/website-devdocs/devdocs-takram.png +0 -0
  244. package/src/skills-lib/wizz-huashu-design/assets/showcases/website-homepage/homepage-build.html +0 -367
  245. package/src/skills-lib/wizz-huashu-design/assets/showcases/website-homepage/homepage-build.png +0 -0
  246. package/src/skills-lib/wizz-huashu-design/assets/showcases/website-homepage/homepage-pentagram.html +0 -368
  247. package/src/skills-lib/wizz-huashu-design/assets/showcases/website-homepage/homepage-pentagram.png +0 -0
  248. package/src/skills-lib/wizz-huashu-design/assets/showcases/website-homepage/homepage-takram.html +0 -459
  249. package/src/skills-lib/wizz-huashu-design/assets/showcases/website-homepage/homepage-takram.png +0 -0
  250. package/src/skills-lib/wizz-huashu-design/assets/showcases/website-saas/saas-build.html +0 -493
  251. package/src/skills-lib/wizz-huashu-design/assets/showcases/website-saas/saas-build.png +0 -0
  252. package/src/skills-lib/wizz-huashu-design/assets/showcases/website-saas/saas-pentagram.html +0 -556
  253. package/src/skills-lib/wizz-huashu-design/assets/showcases/website-saas/saas-pentagram.png +0 -0
  254. package/src/skills-lib/wizz-huashu-design/assets/showcases/website-saas/saas-takram.html +0 -604
  255. package/src/skills-lib/wizz-huashu-design/assets/showcases/website-saas/saas-takram.png +0 -0
  256. package/tools/installer/file-ops.js +0 -204
  257. package/tools/installer/ide/shared/skill-manifest.js +0 -57
  258. package/tools/installer/yaml-format.js +0 -245
  259. package/web-bundles/README.md +0 -46
  260. package/web-bundles/brainstorming-coach/INSTRUCTIONS.md +0 -86
  261. package/web-bundles/brainstorming-coach/SKILL.md +0 -83
  262. package/web-bundles/brainstorming-coach/brain-methods.csv +0 -62
  263. package/web-bundles/bundles.json +0 -139
  264. package/web-bundles/market-and-industry-research/INSTRUCTIONS.md +0 -88
  265. package/web-bundles/market-and-industry-research/SKILL.md +0 -59
  266. package/web-bundles/prd-coach/INSTRUCTIONS.md +0 -86
  267. package/web-bundles/prd-coach/SKILL.md +0 -101
  268. package/web-bundles/prd-coach/prd-template.md +0 -165
  269. package/web-bundles/prd-coach/prd-validation-checklist.md +0 -135
  270. package/web-bundles/prfaq-coach/INSTRUCTIONS.md +0 -86
  271. package/web-bundles/prfaq-coach/SKILL.md +0 -139
  272. package/web-bundles/product-brief-coach/INSTRUCTIONS.md +0 -86
  273. package/web-bundles/product-brief-coach/SKILL.md +0 -113
  274. package/web-bundles/ux-coach/INSTRUCTIONS.md +0 -92
  275. package/web-bundles/ux-coach/SKILL.md +0 -187
  276. package/web-bundles/ux-coach/ux-validation.md +0 -100
  277. /package/src/modules/lowticket/skills/{lowticket-funil → wizz-lowticket-funil}/references/mapa-do-funil.md +0 -0
  278. /package/src/modules/lowticket/skills/{lowticket-metodologia → wizz-lowticket-metodologia}/CATALOGO.md +0 -0
  279. /package/src/modules/lowticket/skills/{lowticket-metodologia → wizz-lowticket-metodologia}/knowledge/01-principios.md +0 -0
  280. /package/src/modules/lowticket/skills/{lowticket-metodologia → wizz-lowticket-metodologia}/knowledge/02-diagnostico-funil.md +0 -0
  281. /package/src/modules/lowticket/skills/{lowticket-metodologia → wizz-lowticket-metodologia}/knowledge/03-campanha-bidcap.md +0 -0
  282. /package/src/modules/lowticket/skills/{lowticket-metodologia → wizz-lowticket-metodologia}/knowledge/04-criativos.md +0 -0
  283. /package/src/modules/lowticket/skills/{lowticket-metodologia → wizz-lowticket-metodologia}/knowledge/04a-criativos-ia.md +0 -0
  284. /package/src/modules/lowticket/skills/{lowticket-metodologia → wizz-lowticket-metodologia}/knowledge/04b-criativos-formatos.md +0 -0
  285. /package/src/modules/lowticket/skills/{lowticket-metodologia → wizz-lowticket-metodologia}/knowledge/05-oferta.md +0 -0
  286. /package/src/modules/lowticket/skills/{lowticket-metodologia → wizz-lowticket-metodologia}/knowledge/06-pagina-vendas.md +0 -0
  287. /package/src/modules/lowticket/skills/{lowticket-metodologia → wizz-lowticket-metodologia}/knowledge/06a-instagram.md +0 -0
  288. /package/src/modules/lowticket/skills/{lowticket-metodologia → wizz-lowticket-metodologia}/knowledge/06b-player-vsl.md +0 -0
  289. /package/src/modules/lowticket/skills/{lowticket-metodologia → wizz-lowticket-metodologia}/knowledge/07-funil-upsell.md +0 -0
  290. /package/src/modules/lowticket/skills/{lowticket-metodologia → wizz-lowticket-metodologia}/knowledge/07a-copy-humanizacao.md +0 -0
  291. /package/src/modules/lowticket/skills/{lowticket-metodologia → wizz-lowticket-metodologia}/knowledge/08-pesquisa-publico.md +0 -0
  292. /package/src/modules/lowticket/skills/{lowticket-metodologia → wizz-lowticket-metodologia}/knowledge/09-especialista-coproducao.md +0 -0
  293. /package/src/modules/lowticket/skills/{lowticket-metodologia → wizz-lowticket-metodologia}/knowledge/10-levantar-caixa.md +0 -0
  294. /package/src/modules/lowticket/skills/{lowticket-metodologia → wizz-lowticket-metodologia}/knowledge/11-checklist-roi.md +0 -0
  295. /package/src/modules/lowticket/skills/{lowticket-metodologia → wizz-lowticket-metodologia}/knowledge/12-mineracao-ofertas.md +0 -0
  296. /package/src/modules/lowticket/skills/{lowticket-metodologia → wizz-lowticket-metodologia}/knowledge/12a-mineracao-veredito.md +0 -0
  297. /package/src/modules/lowticket/skills/{lowticket-metodologia → wizz-lowticket-metodologia}/knowledge/12b-fabrica-de-ofertas.md +0 -0
  298. /package/src/modules/lowticket/skills/{lowticket-metodologia → wizz-lowticket-metodologia}/knowledge/12c-anatomia-low-ticket.md +0 -0
  299. /package/src/modules/lowticket/skills/{lowticket-metodologia → wizz-lowticket-metodologia}/knowledge/13-benchmarks-vsl.md +0 -0
  300. /package/src/modules/lowticket/skills/{lowticket-metodologia → wizz-lowticket-metodologia}/knowledge/14-vocabulario.md +0 -0
  301. /package/src/modules/lowticket/skills/{lowticket-metodologia → wizz-lowticket-metodologia}/knowledge/15-como-estender.md +0 -0
  302. /package/src/modules/lowticket/skills/{lowticket-metodologia → wizz-lowticket-metodologia}/knowledge/17-rastreamento.md +0 -0
  303. /package/src/modules/lowticket/skills/{lowticket-metodologia → wizz-lowticket-metodologia}/knowledge/18-copy-desejo-oferta.md +0 -0
  304. /package/src/modules/lowticket/skills/{lowticket-metodologia → wizz-lowticket-metodologia}/knowledge/INDEX.md +0 -0
  305. /package/src/modules/lowticket/skills/{lowticket-metodologia → wizz-lowticket-metodologia}/knowledge/guardrails.md +0 -0
  306. /package/src/modules/lowticket/skills/{lowticket-metodologia → wizz-lowticket-metodologia}/knowledge/pontos-em-aberto.md +0 -0
  307. /package/src/modules/lowticket/skills/{lowticket-metodologia → wizz-lowticket-metodologia}/references/swipe-file.md +0 -0
  308. /package/src/modules/lowticket/skills/{lowticket-pagina → wizz-lowticket-pagina}/references/metas-e-medicao.md +0 -0
  309. /package/src/modules/lowticket/skills/{lowticket-pagina → wizz-lowticket-pagina}/references/padroes-de-codigo.md +0 -0
  310. /package/src/modules/lowticket/skills/{lowticket-trafego → wizz-lowticket-trafego}/references/formato-do-diagnostico.md +0 -0
@@ -0,0 +1,648 @@
1
+ // doctor.js — diagnóstico do projeto Wizz (`wizz doctor`, item 17 da
2
+ // auditoria 2026-09-11). Fecha os achados RT-M3 (drift silencioso entre
3
+ // _wizz/ e o pacote) e RT-M4 (cadeia de tools quebrada sem sinal):
4
+ // um comando que verifica, com saída legível, os 6 pontos que o dia a dia
5
+ // do Wizz Method depende:
6
+ //
7
+ // 1. hooks — arquivos em `_wizz/hooks/` + registro em `.claude/settings.json`
8
+ // 2. rtk — binário no PATH + versão (piso do hook: 0.23.0)
9
+ // 3. jq — binário no PATH (o hook rtk-rewrite.sh precisa dele)
10
+ // 4. python — informativo: `python3` é OPCIONAL desde o item 29 (só as
11
+ // skills BMAD com scripts próprios usam); reusa python-check.js
12
+ // 5. drift — hashes do files-manifest.csv vs os arquivos instalados em _wizz/
13
+ // 6. resolved — snapshots de `_wizz/_resolved/` contra o hash das entradas
14
+ // que os geraram (`.index.json`)
15
+ //
16
+ // Forma dos resultados: cada check devolve
17
+ // { check, status: 'ok'|'warn'|'error', detail }
18
+ // e o agregador devolve { results, exitCode } seguindo a convenção do repo
19
+ // (0 = ok/warn, 1 = error). Toda detecção de ambiente é INJETÁVEL: os
20
+ // checkers (hasCommand, runVersion, pythonDetect, ...) chegam por `deps`
21
+ // — os testes rodam sem rtk/jq/python instalados e sem rede.
22
+
23
+ const path = require('node:path');
24
+ const { HOOK_DEFS, isOurHookCommand } = require('./hooks-settings');
25
+ const { classifyPython, PYTHON_ONLY_SKILLS } = require('./python-check');
26
+
27
+ // Piso de versão do rtk que o hook rtk-rewrite.sh exige para `rtk rewrite`
28
+ // (o registry pin do CLI é mais alto, 0.45.0, e é aplicado pelo detectClis
29
+ // no install; aqui reportamos o piso que quebra o hook hoje).
30
+ const RTK_HOOK_FLOOR = '0.23.0';
31
+
32
+ const CHECKS = ['hooks', 'rtk', 'jq', 'python', 'drift', 'resolved'];
33
+
34
+ /**
35
+ * Versão numérica comparável a partir de texto de `rtk --version` etc.
36
+ * (mesmo formato "x.y.z" que cli-config.js#extractVersion usa).
37
+ * @param {string} text
38
+ * @returns {string|null}
39
+ */
40
+ function extractVersion(text) {
41
+ const m = String(text || '').match(/\d+\.\d+\.\d+/);
42
+ return m ? m[0] : null;
43
+ }
44
+
45
+ /**
46
+ * Compara "x.y.z" por segmento numérico (a<b negativo, igual 0, a>b positivo).
47
+ * @param {string} a
48
+ * @param {string} b
49
+ * @returns {number}
50
+ */
51
+ function compareSemver(a, b) {
52
+ const pa = String(a)
53
+ .split('.')
54
+ .map((n) => Number(n) || 0);
55
+ const pb = String(b)
56
+ .split('.')
57
+ .map((n) => Number(n) || 0);
58
+ for (let i = 0; i < Math.max(pa.length, pb.length); i++) {
59
+ const diff = (pa[i] || 0) - (pb[i] || 0);
60
+ if (diff !== 0) return diff;
61
+ }
62
+ return 0;
63
+ }
64
+
65
+ /**
66
+ * Lê CSV de uma linha só respeitando aspas duplas com vírgula/aspas dentro
67
+ * (suficiente pros manifests que o próprio installer escreve). Não suporta
68
+ * aspas escapadas embutidas — os manifests não geram esse caso.
69
+ * @param {string} line
70
+ * @returns {string[]}
71
+ */
72
+ function parseCsvLine(line) {
73
+ const fields = [];
74
+ let current = '';
75
+ let inQuotes = false;
76
+ for (let i = 0; i < line.length; i++) {
77
+ const ch = line[i];
78
+ if (inQuotes) {
79
+ if (ch === '"') {
80
+ if (line[i + 1] === '"') {
81
+ current += '"';
82
+ i++;
83
+ } else {
84
+ inQuotes = false;
85
+ }
86
+ } else {
87
+ current += ch;
88
+ }
89
+ } else if (ch === '"') {
90
+ inQuotes = true;
91
+ } else if (ch === ',') {
92
+ fields.push(current);
93
+ current = '';
94
+ } else {
95
+ current += ch;
96
+ }
97
+ }
98
+ fields.push(current);
99
+ return fields;
100
+ }
101
+
102
+ /**
103
+ * Checagem de hooks: para cada HOOK_DEF canônico, o arquivo existe em
104
+ * `_wizz/hooks/` e (para o settings) há uma entrada nossa no evento certo
105
+ * de `.claude/settings.json`? Hooks com `requires: 'rtk'` (rtk-rewrite.sh)
106
+ * degradam para warn quando o arquivo não existe — o installer também os
107
+ * pula quando rtk não está no PATH (RT-C1, item 4). Falta de registro no
108
+ * settings é warn (hook roda menos, não quebra), não error.
109
+ * @param {object} deps
110
+ * @param {string} deps.wizzDir
111
+ * @param {string} deps.settingsFile - .claude/settings.json do projeto
112
+ * @param {string} [deps.globalSettingsFile] - ~/.claude/settings.json (só para a mensagem)
113
+ * @param {(p: string) => boolean} deps.fileExists
114
+ * @param {() => object|null} deps.readProjectSettings
115
+ * @param {() => object|null} deps.readGlobalSettings - ~/.claude/settings.json
116
+ * @param {boolean} [deps.rtkOnPath] - igual ao installer: sem rtk no PATH,
117
+ * o registro do rtk-rewrite.sh não é exigido (ele é opcional, RT-C1 item 4)
118
+ * @returns {{check: 'hooks', status: 'ok'|'warn'|'error', detail: string}}
119
+ */
120
+ function checkHooks({ wizzDir, settingsFile, globalSettingsFile, fileExists, readProjectSettings, readGlobalSettings, rtkOnPath = false }) {
121
+ // `wizzDir` já É o diretório _wizz/ do projeto; HOOKS_DIR ('_wizz/hooks')
122
+ // é relativo à raiz, então o subdiretório aqui é só 'hooks'.
123
+ const hooksDir = path.join(wizzDir, 'hooks');
124
+ const missingFiles = [];
125
+ const missingSettings = [];
126
+ const skippedGlobal = [];
127
+
128
+ const globalSettings = readGlobalSettings ? readGlobalSettings() : null;
129
+ const projectSettings = readProjectSettings ? readProjectSettings() : null;
130
+
131
+ for (const def of HOOK_DEFS) {
132
+ const fileOnDisk = fileExists(path.join(hooksDir, def.id));
133
+ if (!fileOnDisk) {
134
+ if (def.requires === 'rtk') {
135
+ // Opcional por design: o installer só registra rtk-rewrite.sh
136
+ // quando rtk está no PATH; ausência aqui é estado normal.
137
+ continue;
138
+ }
139
+ missingFiles.push(def.id);
140
+ continue;
141
+ }
142
+
143
+ // Registrado no global? Mesma semântica de filterHooksRegisteredGlobally
144
+ // (hooks-settings.js): basename dentro do command, qualquer matcher do
145
+ // evento conta. O path global (~/.claude/hooks/...) nunca contém
146
+ // _wizz/hooks/, então isOurHookCommand não serve aqui — compara por id.
147
+ const registeredGlobally = (() => {
148
+ const blocks =
149
+ globalSettings && globalSettings.hooks && Array.isArray(globalSettings.hooks[def.event]) ? globalSettings.hooks[def.event] : [];
150
+ return blocks.some(
151
+ (block) => Array.isArray(block.hooks) && block.hooks.some((h) => h && typeof h.command === 'string' && h.command.includes(def.id)),
152
+ );
153
+ })();
154
+ if (registeredGlobally) {
155
+ skippedGlobal.push(def.id);
156
+ continue;
157
+ }
158
+
159
+ const blocks =
160
+ projectSettings && projectSettings.hooks && Array.isArray(projectSettings.hooks[def.event]) ? projectSettings.hooks[def.event] : [];
161
+ const registered = blocks.some(
162
+ (block) => Array.isArray(block.hooks) && block.hooks.some((h) => isOurHookCommand(h && h.command, def.id)),
163
+ );
164
+ if (!registered) {
165
+ // rtk-rewrite.sh presente em disco mas rtk ausente: o installer não
166
+ // o registra (RT-C1 item 4), então não cobrar registro aqui.
167
+ if (def.requires === 'rtk' && !rtkOnPath) continue;
168
+ missingSettings.push(def.id);
169
+ }
170
+ }
171
+
172
+ if (missingFiles.length > 0) {
173
+ return {
174
+ check: 'hooks',
175
+ status: 'error',
176
+ detail: `Faltam arquivos de hook em _wizz/hooks/: ${missingFiles.join(', ')}. Execute wizz update para repor.`,
177
+ };
178
+ }
179
+
180
+ if (missingSettings.length > 0) {
181
+ return {
182
+ check: 'hooks',
183
+ status: 'warn',
184
+ detail:
185
+ `Arquivos ok, mas sem registro no settings do PROJETO (${settingsFile}): ${missingSettings.join(', ')}. ` +
186
+ `Também não estão no settings GLOBAL (${globalSettingsFile || '~/.claude/settings.json'}). ` +
187
+ `Rode wizz install para registrar no projeto, ou registre no global.`,
188
+ };
189
+ }
190
+
191
+ const skippedNote =
192
+ skippedGlobal.length > 0
193
+ ? ` (${skippedGlobal.length} já registrado(s) no settings global ${globalSettingsFile || '~/.claude/settings.json'}, ok)`
194
+ : '';
195
+ return { check: 'hooks', status: 'ok', detail: `${HOOK_DEFS.length} hooks verificados${skippedNote}.` };
196
+ }
197
+
198
+ /**
199
+ * Checagem genérica de binário no PATH, com versão opcional contra um piso.
200
+ * `runVersion(cmd)` devolve stdout+stderr de `<cmd> --version` (ou null).
201
+ * @param {object} args
202
+ * @param {string} args.check - 'rtk' | 'jq'
203
+ * @param {string|null} args.version - saída de --version (null se ausente)
204
+ * @param {string} [args.floor] - versão mínima (só rtk)
205
+ * @returns {{check: 'rtk'|'jq', status: 'ok'|'warn'|'error', detail: string}}
206
+ */
207
+ function checkCli({ check, version, floor }) {
208
+ if (check === 'rtk') {
209
+ if (!version) {
210
+ return {
211
+ check,
212
+ status: 'warn',
213
+ detail: `rtk não encontrado no PATH. Opcional, mas sem ele o hook rtk-rewrite.sh não é registrado e a economia de tokens não roda. Instale: cargo install rtk`,
214
+ };
215
+ }
216
+ const installed = extractVersion(version);
217
+ if (installed && compareSemver(installed, RTK_HOOK_FLOOR) < 0) {
218
+ return {
219
+ check,
220
+ status: 'warn',
221
+ detail: `rtk ${installed} é mais antigo que o piso do hook (${RTK_HOOK_FLOOR}); o rewrite falha em warn. Atualize: cargo install rtk`,
222
+ };
223
+ }
224
+ return { check, status: 'ok', detail: `rtk ${installed || '(versão não informada)'} no PATH.` };
225
+ }
226
+
227
+ // jq — sem verificação de versão, o hook só precisa dele presente.
228
+ if (!version) {
229
+ return {
230
+ check: 'jq',
231
+ status: 'warn',
232
+ detail:
233
+ 'jq não encontrado no PATH. O hook rtk-rewrite.sh precisa dele; sem jq o rewrite de Bash avisa e segue sem reescrever. Instale: brew install jq',
234
+ };
235
+ }
236
+ return { check: 'jq', status: 'ok', detail: 'jq no PATH.' };
237
+ }
238
+
239
+ /**
240
+ * Checagem de python: INFORMATIVA desde o item 29 (2026-09-12). O núcleo do
241
+ * Wizz roda só com Node — memlog é `memlog.js` e as configs TOML viram
242
+ * `_wizz/_resolved/*.json` na instalação. Python só compra as skills BMAD que
243
+ * trazem script próprio, então a ausência dele nunca é `warn`: é `ok` com o
244
+ * detalhe dizendo o que fica de fora. Reusa classifyPython de python-check.js
245
+ * sobre o resultado do detector injetado (mesmo contrato de detectPython).
246
+ * @param {object} args
247
+ * @param {{command: string, version: {major: number, minor: number, patch: number, raw: string}, isRuntimeCommand: boolean}|null} args.detected
248
+ * @returns {{check: 'python', status: 'ok'|'warn'|'error', detail: string}}
249
+ */
250
+ function checkPython({ detected }) {
251
+ const status = classifyPython(detected ? detected.version : null);
252
+ // Nunca warn: Python é opcional. O detalhe diz o que está disponível.
253
+ const detail = pythonDetail(status, detected);
254
+ return { check: 'python', status: 'ok', detail };
255
+ }
256
+
257
+ /**
258
+ * Frase do check de python por caso detectado. Toda variante fecha dizendo
259
+ * que o núcleo não depende disso, para ninguém ler "opcional" como "quebrado".
260
+ * @param {'full'|'partial'|'unsupported'|'none'} status
261
+ * @param {object|null} detected
262
+ * @returns {string}
263
+ */
264
+ function pythonDetail(status, detected) {
265
+ const optional = `Opcional: o núcleo roda só com Node; Python só habilita as skills com script próprio (${PYTHON_ONLY_SKILLS}).`;
266
+ if (status === 'full' && detected.isRuntimeCommand) {
267
+ return `Python ${detected.version.raw} via ${detected.command} (tomllib ok): as skills Python também rodam.`;
268
+ }
269
+ if (status === 'full') {
270
+ return `Python ${detected.version.raw} existe via ${detected.command}, mas os scripts chamam python3, que não está no PATH. ${optional}`;
271
+ }
272
+ if (status === 'partial') {
273
+ return `Python ${detected.version.raw} no PATH, sem tomllib (as skills com script próprio pedem 3.11+). ${optional}`;
274
+ }
275
+ if (status === 'unsupported') {
276
+ return `Python ${detected.version.raw} é antigo demais (as skills com script próprio pedem 3.11+). ${optional}`;
277
+ }
278
+ return `python3 não encontrado no PATH. ${optional} Para tê-las: brew install python3 (macOS).`;
279
+ }
280
+
281
+ /**
282
+ * Checagem de drift (RT-M3): compara o hash de cada linha do
283
+ * `_wizz/_config/files-manifest.csv` com o hash atual do arquivo em
284
+ * `_wizz/<path>`. Hash divergente ou arquivo sumido = drift. Não tenta
285
+ * adivinhar fonte no pacote: o files-manifest é escrito pelo installer
286
+ * contra o INSTALADO, então basta o estado em disco — funciona igual para
287
+ * módulos builtin, externos e custom.
288
+ * @param {object} args
289
+ * @param {string} args.wizzDir
290
+ * @param {string|null} args.manifestContent - conteúdo de files-manifest.csv (null = ausente)
291
+ * @param {(p: string) => Promise<string|null>} args.hashFile - sha256 (fs-native.calculateFileHash)
292
+ * @param {(p: string) => Promise<boolean>} args.fileExists
293
+ * @returns {Promise<{check: 'drift', status: 'ok'|'warn'|'error', detail: string}>}
294
+ */
295
+ async function checkDrift({ wizzDir, manifestContent, hashFile, fileExists }) {
296
+ if (manifestContent == null) {
297
+ return {
298
+ check: 'drift',
299
+ status: 'warn',
300
+ detail: 'files-manifest.csv não encontrado em _wizz/_config/. Sem ele não dá para detectar drift; rode wizz update para gerar.',
301
+ };
302
+ }
303
+
304
+ const lines = manifestContent.split('\n').filter((l) => l.trim());
305
+ // header: type,name,module,path,hash
306
+ const rows = lines
307
+ .slice(1)
308
+ .map(parseCsvLine)
309
+ .filter((f) => f.length >= 5 && f[3] && f[4]);
310
+ if (rows.length === 0) {
311
+ return { check: 'drift', status: 'ok', detail: 'files-manifest.csv vazio, nada a comparar.' };
312
+ }
313
+
314
+ const drifted = [];
315
+ const missing = [];
316
+ for (const fields of rows) {
317
+ const relPath = fields[3];
318
+ const recorded = fields[4];
319
+ const absPath = path.join(wizzDir, relPath);
320
+ if (!(await fileExists(absPath))) {
321
+ missing.push(relPath);
322
+ continue;
323
+ }
324
+ const current = await hashFile(absPath);
325
+ if (current && current !== recorded) {
326
+ drifted.push(relPath);
327
+ }
328
+ }
329
+
330
+ if (drifted.length === 0 && missing.length === 0) {
331
+ return { check: 'drift', status: 'ok', detail: `${rows.length} arquivos batem com o files-manifest.csv.` };
332
+ }
333
+
334
+ const parts = [];
335
+ if (drifted.length > 0) parts.push(`${drifted.length} alterado(s)`);
336
+ if (missing.length > 0) parts.push(`${missing.length} ausente(s)`);
337
+ return {
338
+ check: 'drift',
339
+ status: 'warn',
340
+ detail: `Drift em _wizz/: ${parts.join(' e ')} contra o files-manifest.csv (ex.: ${[...drifted, ...missing].slice(0, 3).join(', ')}). Edita manuais em _wizz/ são perdidos no próximo update — mova para _wizz/custom/ e rode wizz update.`,
341
+ };
342
+ }
343
+
344
+ /**
345
+ * Checagem dos snapshots de customização (`_wizz/_resolved/`, item 19).
346
+ *
347
+ * A ativação de agente lê `_resolved/<skill>.json` com um único Read e não
348
+ * checa nada — sem mtime, sem stat, sem spawn. O preço disso é que um
349
+ * snapshot desatualizado é invisível em runtime, então a detecção mora
350
+ * aqui: `_resolved/.index.json` guarda o sha256 de cada arquivo que
351
+ * alimentou cada snapshot (customize.toml base, seus includes, as camadas
352
+ * team/user e os includes delas) e este check recalcula.
353
+ *
354
+ * Duas sutilezas do layout instalado:
355
+ * - o pipeline verbatim MOVE o diretório da skill de `_wizz/` para a pasta
356
+ * de skills do IDE, então o path do customize.toml gravado no índice
357
+ * costuma não existir mais; a cópia implantada
358
+ * (`.claude/skills/<skill>/customize.toml`) é a que o usuário edita e é
359
+ * contra ela que o hash é comparado nesse caso;
360
+ * - entrada que sumiu e não tem cópia implantada é "não verificável", não
361
+ * é obsolescência: avisar ali seria gritar em toda instalação limpa.
362
+ *
363
+ * Nunca é error: um snapshot ausente ou velho degrada para o fallback
364
+ * Python ou para uma customização antiga, nunca quebra a instalação.
365
+ *
366
+ * @param {object} args
367
+ * @param {string} args.projectDir - raiz do projeto (os paths do índice são relativos a ela)
368
+ * @param {Map<string, string[]>} args.skillSources - skill → customize.toml encontrados
369
+ * @param {object|null} args.index - `.index.json` já lido (null = ausente/ilegível)
370
+ * @param {(p: string) => boolean|Promise<boolean>} args.fileExists
371
+ * @param {(p: string) => Promise<string|null>} args.hashFile - sha256
372
+ * @param {string} args.resolvedDir
373
+ * @returns {Promise<{check: 'resolved', status: 'ok'|'warn', detail: string}>}
374
+ */
375
+ async function checkResolved({ projectDir, skillSources, index, fileExists, hashFile, resolvedDir }) {
376
+ const sources = skillSources instanceof Map ? skillSources : new Map(Object.entries(skillSources || {}));
377
+ const skills = [...sources.keys()].sort();
378
+ if (skills.length === 0) {
379
+ return { check: 'resolved', status: 'ok', detail: 'Nenhuma skill com customize.toml instalada; nada a resolver.' };
380
+ }
381
+
382
+ if (!index || typeof index !== 'object' || !index.skills || typeof index.skills !== 'object') {
383
+ return {
384
+ check: 'resolved',
385
+ status: 'warn',
386
+ detail: `Índice ${path.join(resolvedDir, '.index.json')} ausente ou ilegível: não dá para saber se os ${skills.length} snapshots estão atualizados. Rode wizz resolve.`,
387
+ };
388
+ }
389
+
390
+ const missing = [];
391
+ const stale = [];
392
+ for (const skill of skills) {
393
+ // Prototype-safe: um skill chamado "constructor" (ou qualquer outra
394
+ // chave herdada de Object.prototype) não deve resolver para
395
+ // Object.prototype.constructor quando não há entrada própria no índice.
396
+ const entry = Object.hasOwn(index.skills, skill) ? index.skills[skill] : undefined;
397
+ const snapshotPath = path.join(resolvedDir, `${skill}.json`);
398
+ if (!entry || !(await fileExists(snapshotPath))) {
399
+ missing.push(skill);
400
+ continue;
401
+ }
402
+ // O snapshot em si também é conferido: truncado, corrompido ou editado
403
+ // à mão diverge do hash gravado na geração (entry.output).
404
+ if (typeof entry.output === 'string') {
405
+ const currentOutput = await hashFile(snapshotPath);
406
+ if (currentOutput !== null && currentOutput !== entry.output) {
407
+ stale.push(`${skill} (snapshot)`);
408
+ continue;
409
+ }
410
+ }
411
+ const inputs = entry.inputs && typeof entry.inputs === 'object' ? entry.inputs : {};
412
+ for (const [relPath, recorded] of Object.entries(inputs)) {
413
+ const current = await currentInputHash({ projectDir, relPath, skill, sources, fileExists, hashFile, recorded });
414
+ if (current !== null && current !== recorded) {
415
+ stale.push(`${skill} (${relPath})`);
416
+ break;
417
+ }
418
+ }
419
+ }
420
+
421
+ if (missing.length === 0 && stale.length === 0) {
422
+ return {
423
+ check: 'resolved',
424
+ status: 'ok',
425
+ detail: `${skills.length} snapshots em _wizz/_resolved/ batem com as entradas que os geraram.`,
426
+ };
427
+ }
428
+
429
+ const parts = [];
430
+ if (missing.length > 0) parts.push(`${missing.length} sem snapshot (${missing.slice(0, 3).join(', ')})`);
431
+ if (stale.length > 0) parts.push(`${stale.length} com snapshot obsoleto (${stale.slice(0, 3).join(', ')})`);
432
+ const prefix = stale.length > 0 ? 'snapshot obsoleto: rode wizz resolve' : 'rode wizz resolve';
433
+ return { check: 'resolved', status: 'warn', detail: `${prefix} — ${parts.join('; ')}.` };
434
+ }
435
+
436
+ /**
437
+ * Hash atual de uma entrada do índice, ou null quando não dá para verificar.
438
+ * O path gravado vale primeiro; se o arquivo sumiu e a entrada é o
439
+ * `customize.toml` da skill, compara com as cópias implantadas nas pastas
440
+ * de skills dos IDEs (é lá que o arquivo vive depois do install, e é lá que
441
+ * o usuário edita). Nenhuma cópia encontrada = não verificável (null).
442
+ * @returns {Promise<string|null>}
443
+ */
444
+ async function currentInputHash({ projectDir, relPath, skill, sources, fileExists, hashFile, recorded }) {
445
+ const absPath = path.resolve(projectDir, relPath);
446
+ if (await fileExists(absPath)) return hashFile(absPath);
447
+ if (path.basename(relPath) !== 'customize.toml') return null;
448
+
449
+ const candidates = (sources.get(skill) || []).filter((p) => p !== absPath);
450
+ let first = null;
451
+ for (const candidate of candidates) {
452
+ const hash = await hashFile(candidate);
453
+ if (hash === null) continue;
454
+ if (hash === recorded) return hash;
455
+ if (first === null) first = hash;
456
+ }
457
+ return first;
458
+ }
459
+
460
+ /**
461
+ * Orquestra os 6 checks. Todos os efeitos de ambiente chegam por `deps`,
462
+ * então esta função é pura o bastante para testes com fixtures em tmp dir.
463
+ * @param {object} [options]
464
+ * @param {object} [options.deps] - checkers injetáveis (ver chamadas abaixo)
465
+ * @returns {Promise<{results: Array<{check, status, detail}>, exitCode: number, hasError: boolean}>}
466
+ */
467
+ async function runDoctor(options = {}) {
468
+ const deps = options.deps || {};
469
+ const {
470
+ wizzDir,
471
+ projectDir = process.cwd(),
472
+ fileExists = (p) => require('../fs-native').pathExistsSync(p),
473
+ hashFile = (p) => require('../fs-native').calculateFileHash(p),
474
+ readFile = (p) => require('../fs-native').readFileSync(p, 'utf8'),
475
+ hasCommand = defaultHasCommand,
476
+ runVersion = defaultRunVersion,
477
+ detectPython: detectPy = () => require('./python-check').detectPython(),
478
+ readProjectSettings,
479
+ readGlobalSettings,
480
+ globalSettingsFile,
481
+ discoverSkillSources = (root, dir) =>
482
+ require('./resolved-customizations').discoverSkillCustomizeTomls({ projectRoot: root, wizzDir: dir }),
483
+ readResolvedIndex = (dir) => require('./resolved-customizations').readIndex(dir),
484
+ rtkOnPath = () => hasCommand('rtk'),
485
+ skip = [],
486
+ } = deps;
487
+
488
+ const settingsFile = path.join(projectDir, '.claude', 'settings.json');
489
+ const readSettingsSafe = readProjectSettings || (() => safeReadJson(settingsFile));
490
+ const readGlobalSafe = readGlobalSettings || (() => null);
491
+
492
+ const results = [];
493
+
494
+ // 1) hooks — só faz sentido com _wizz/ presente.
495
+ if (skip.includes('hooks')) {
496
+ results.push({ check: 'hooks', status: 'ok', detail: 'pulado.' });
497
+ } else if (wizzDir) {
498
+ results.push(
499
+ checkHooks({
500
+ wizzDir,
501
+ settingsFile,
502
+ globalSettingsFile,
503
+ fileExists,
504
+ readProjectSettings: readSettingsSafe,
505
+ readGlobalSettings: readGlobalSafe,
506
+ rtkOnPath: rtkOnPath(),
507
+ }),
508
+ );
509
+ } else {
510
+ results.push({
511
+ check: 'hooks',
512
+ status: 'warn',
513
+ detail: 'Sem instalação Wizz neste diretório (_wizz/ ausente); hooks do projeto não verificados. Rode wizz install.',
514
+ });
515
+ }
516
+
517
+ // 2) rtk (com piso de versão do hook) e 3) jq (presença).
518
+ for (const cli of ['rtk', 'jq']) {
519
+ if (skip.includes(cli)) {
520
+ results.push({ check: cli, status: 'ok', detail: 'pulado.' });
521
+ continue;
522
+ }
523
+ const onPath = hasCommand(cli);
524
+ let version = null;
525
+ if (onPath) {
526
+ version = runVersion(cli);
527
+ if (version == null && cli === 'rtk') {
528
+ // No PATH mas --version falhou: reporta presente sem versão em vez
529
+ // de "não encontrado" — o binário quebra por outro motivo.
530
+ version = '';
531
+ }
532
+ }
533
+ results.push(checkCli({ check: cli, version }));
534
+ }
535
+
536
+ // 4) python — detector stubável (mesmo padrão de checkPythonEnvironment).
537
+ if (skip.includes('python')) {
538
+ results.push({ check: 'python', status: 'ok', detail: 'pulado.' });
539
+ } else {
540
+ results.push(checkPython({ detected: detectPy() }));
541
+ }
542
+
543
+ // 5) drift — só com _wizz/ presente; sem instalação, skip informado.
544
+ if (skip.includes('drift')) {
545
+ results.push({ check: 'drift', status: 'ok', detail: 'pulado.' });
546
+ } else if (wizzDir) {
547
+ const manifestPath = path.join(wizzDir, '_config', 'files-manifest.csv');
548
+ const manifestContent = (await fileExists(manifestPath)) ? await readFile(manifestPath) : null;
549
+ results.push(await checkDrift({ wizzDir, manifestContent, hashFile, fileExists }));
550
+ } else {
551
+ results.push({
552
+ check: 'drift',
553
+ status: 'warn',
554
+ detail: 'Sem instalação Wizz neste diretório; drift não verificado. Rode wizz install.',
555
+ });
556
+ }
557
+
558
+ // 6) resolved — snapshots de customização contra o hash das entradas.
559
+ if (skip.includes('resolved')) {
560
+ results.push({ check: 'resolved', status: 'ok', detail: 'pulado.' });
561
+ } else if (wizzDir) {
562
+ const resolvedDir = path.join(wizzDir, '_resolved');
563
+ results.push(
564
+ await checkResolved({
565
+ projectDir,
566
+ skillSources: discoverSkillSources(projectDir, wizzDir),
567
+ index: readResolvedIndex(resolvedDir),
568
+ fileExists,
569
+ hashFile,
570
+ resolvedDir,
571
+ }),
572
+ );
573
+ } else {
574
+ results.push({
575
+ check: 'resolved',
576
+ status: 'warn',
577
+ detail: 'Sem instalação Wizz neste diretório; snapshots de _wizz/_resolved/ não verificados. Rode wizz install.',
578
+ });
579
+ }
580
+
581
+ const hasError = results.some((r) => r.status === 'error');
582
+ return { results, exitCode: hasError ? 1 : 0, hasError };
583
+ }
584
+
585
+ /**
586
+ * `command -v <cmd>` via sh — mesmo padrão dos testes do repo; spawnSync
587
+ * com args estáticos, sem risco de injection (cmd é literal da lista).
588
+ * @param {string} cmd
589
+ * @returns {boolean}
590
+ */
591
+ function defaultHasCommand(cmd) {
592
+ try {
593
+ const { spawnSync } = require('node:child_process');
594
+ const res = spawnSync('sh', ['-c', `command -v ${cmd}`], { encoding: 'utf8', timeout: 5000 });
595
+ return res.status === 0;
596
+ } catch {
597
+ return false;
598
+ }
599
+ }
600
+
601
+ /**
602
+ * Roda `<cmd> --version` e devolve stdout+stderr juntos (o rtk imprime em
603
+ * stdout, python em stderr; ambos os casos caem no mesmo regex).
604
+ * @param {string} cmd
605
+ * @returns {string|null} saída combinada, null quando o comando falha
606
+ */
607
+ function defaultRunVersion(cmd) {
608
+ try {
609
+ const { spawnSync } = require('node:child_process');
610
+ const res = spawnSync(cmd, ['--version'], { encoding: 'utf8', timeout: 5000 });
611
+ if (res.error || (res.status !== 0 && !res.stdout)) return null;
612
+ return `${res.stdout || ''}\n${res.stderr || ''}`;
613
+ } catch {
614
+ return null;
615
+ }
616
+ }
617
+
618
+ /**
619
+ * Lê JSON de settings.json com fallback seguro para null (nunca lança).
620
+ * @param {string} file
621
+ * @returns {object|null}
622
+ */
623
+ function safeReadJson(file) {
624
+ try {
625
+ const raw = require('../fs-native').readFileSync(file, 'utf8');
626
+ if (!raw.trim()) return null;
627
+ return JSON.parse(raw);
628
+ } catch {
629
+ return null;
630
+ }
631
+ }
632
+
633
+ module.exports = {
634
+ CHECKS,
635
+ RTK_HOOK_FLOOR,
636
+ extractVersion,
637
+ compareSemver,
638
+ parseCsvLine,
639
+ checkHooks,
640
+ checkCli,
641
+ checkPython,
642
+ pythonDetail,
643
+ checkDrift,
644
+ checkResolved,
645
+ runDoctor,
646
+ defaultHasCommand,
647
+ defaultRunVersion,
648
+ };