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
@@ -1,7 +1,7 @@
1
1
  const fs = require('../fs-native');
2
2
  const os = require('node:os');
3
3
  const path = require('node:path');
4
- const { execSync } = require('node:child_process');
4
+ const { execFileSync } = require('node:child_process');
5
5
  const yaml = require('yaml');
6
6
  const prompts = require('../prompts');
7
7
  const { resolveChannel, tagExists, parseGitHubRepo } = require('./channel-resolver');
@@ -10,37 +10,20 @@ const { getProjectRoot } = require('../project-root');
10
10
 
11
11
  const VALID_CHANNELS = new Set(['stable', 'next', 'pinned']);
12
12
 
13
- // Retry pontual (1 re-tentativa, backoff curto) para `git clone`/`git fetch`.
14
- // Para comandos de shell não temos código de erro estruturado como em
15
- // requisições HTTP; classificamos como transitório por padrões conhecidos na
16
- // mensagem/stderr do git. Erro lógico (repo/tag inexistente, permissão
17
- // negada etc.) não bate nesses padrões e propaga direto, sem retry.
18
- const GIT_RETRY_DELAY_MS = 300;
19
- const TRANSIENT_GIT_ERROR_PATTERNS = [/could not resolve host/i, /timed out/i, /early eof/i, /connection reset/i];
20
-
21
- function isTransientGitError(error) {
22
- const message = `${error?.message || ''}\n${error?.stderr?.toString?.() || ''}`;
23
- return TRANSIENT_GIT_ERROR_PATTERNS.some((pattern) => pattern.test(message));
24
- }
25
-
26
- // Sleep síncrono curto (execSync é bloqueante; não há await aqui). Usa
27
- // Atomics.wait sobre um buffer compartilhado, sem depender de `sleep` de shell.
28
- function blockingDelay(ms) {
29
- const sharedBuffer = new Int32Array(new SharedArrayBuffer(4));
30
- Atomics.wait(sharedBuffer, 0, 0, ms);
31
- }
32
-
33
- // Wrapper de execSync com 1 re-tentativa em falha transitória de rede
34
- // (ver isTransientGitError). Erro não-transitório propaga direto.
35
- function execSyncWithRetry(command, options) {
36
- try {
37
- return execSync(command, options);
38
- } catch (error) {
39
- if (!isTransientGitError(error)) throw error;
40
- blockingDelay(GIT_RETRY_DELAY_MS);
41
- return execSync(command, options);
42
- }
43
- }
13
+ // Timeouts, retry e classificação transitória (ACH-01/EXT-01) moram em
14
+ // git-cache-utils.js (item 20, etapa 1 da auditoria de 2026-09-11) — uma
15
+ // fonte única compartilhada com custom-module-manager.js. Re-exportados daqui
16
+ // para callers/testes que já importavam de external-manager.
17
+ const {
18
+ GIT_NETWORK_TIMEOUT_MS,
19
+ GIT_LOCAL_TIMEOUT_MS,
20
+ NPM_INSTALL_TIMEOUT_MS,
21
+ isTimeoutKillError,
22
+ describeGitTimeout,
23
+ isTransientGitError,
24
+ execSyncWithRetry,
25
+ validateGitRef: validateShellRef,
26
+ } = require('./git-cache-utils');
44
27
 
45
28
  function normalizeChannelName(raw) {
46
29
  if (typeof raw !== 'string') return null;
@@ -48,17 +31,11 @@ function normalizeChannelName(raw) {
48
31
  return VALID_CHANNELS.has(lower) ? lower : null;
49
32
  }
50
33
 
51
- /**
52
- * Conservative quoting for tag names passed to git commands. Tags are
53
- * user-typed (--pin) or come from the GitHub API. Only allow the semver
54
- * character class we use to tag Wizz releases; anything else throws.
55
- */
56
- function quoteShell(ref) {
57
- if (typeof ref !== 'string' || !/^[\w.\-+/]+$/.test(ref)) {
58
- throw new Error(`Unsafe ref name: ${JSON.stringify(ref)}`);
59
- }
60
- return `"${ref}"`;
61
- }
34
+ // Item 8b (auditoria 2026-09-11): the TAG@SHA split + validation lives in
35
+ // pin-spec.js, shared with custom-module-manager.js (item 8c) and surfaced at
36
+ // the CLI gate by channel-plan.js — one format, one error message, three
37
+ // consumers. Re-exported here for existing callers/tests.
38
+ const { parsePinTagAndSha } = require('./pin-spec');
62
39
 
63
40
  async function readChannelMarker(markerPath) {
64
41
  try {
@@ -303,6 +280,18 @@ class ExternalModuleManager {
303
280
  registryDefault: moduleInfo.defaultChannel,
304
281
  });
305
282
 
283
+ // Item 8 fase 2 (auditoria 2026-09-11, EXT-02 / IM-ACH-06): --pin
284
+ // CODE=TAG@SHA. channel-plan.js only knows CODE=<opaque value>, so the
285
+ // TAG@SHA split (and its validation) happens here, before anything else
286
+ // in this function reads `planEntry.pin` as a git ref. From this point
287
+ // on `planEntry.pin` is always a plain tag name.
288
+ let expectedPinSha = null;
289
+ if (planEntry.channel === 'pinned' && planEntry.pin) {
290
+ const parsedPin = parsePinTagAndSha(planEntry.pin);
291
+ planEntry.pin = parsedPin.tag;
292
+ expectedPinSha = parsedPin.expectedSha;
293
+ }
294
+
306
295
  // Same-plan short-circuit: a single install calls cloneExternalModule
307
296
  // several times (config collection, directory setup, help-catalog rebuild)
308
297
  // with the same channelOptions. The first call resolves + clones; later
@@ -311,7 +300,8 @@ class ExternalModuleManager {
311
300
  // on flaky networks even though the tagCache dedupes the GitHub API hit).
312
301
  if (existingResolution && haveUsableCache && existingResolution.channel === planEntry.channel) {
313
302
  const samePin = planEntry.channel !== 'pinned' || existingResolution.version === planEntry.pin;
314
- if (samePin) return moduleCacheDir;
303
+ const sameExpectedSha = planEntry.channel !== 'pinned' || (existingResolution.expectedSha || null) === expectedPinSha;
304
+ if (samePin && sameExpectedSha) return moduleCacheDir;
315
305
  }
316
306
 
317
307
  let resolved;
@@ -399,33 +389,56 @@ class ExternalModuleManager {
399
389
  const fetchSpinner = await createSpinner();
400
390
  fetchSpinner.start(`Fetching ${moduleInfo.name}...`);
401
391
  try {
402
- const currentSha = execSync('git rev-parse HEAD', { cwd: moduleCacheDir, stdio: 'pipe' }).toString().trim();
392
+ const currentSha = execFileSync('git', ['rev-parse', 'HEAD'], {
393
+ cwd: moduleCacheDir,
394
+ stdio: 'pipe',
395
+ timeout: GIT_LOCAL_TIMEOUT_MS,
396
+ killSignal: 'SIGKILL',
397
+ })
398
+ .toString()
399
+ .trim();
403
400
 
404
401
  if (resolved.channel === 'next') {
405
- execSyncWithRetry('git fetch origin --depth 1', {
402
+ execSyncWithRetry('git', ['fetch', 'origin', '--depth', '1'], {
406
403
  cwd: moduleCacheDir,
407
404
  stdio: ['ignore', 'pipe', 'pipe'],
408
405
  env: { ...process.env, GIT_TERMINAL_PROMPT: '0' },
406
+ timeout: GIT_NETWORK_TIMEOUT_MS,
407
+ killSignal: 'SIGKILL',
409
408
  });
410
- execSync('git reset --hard origin/HEAD', {
409
+ execFileSync('git', ['reset', '--hard', 'origin/HEAD'], {
411
410
  cwd: moduleCacheDir,
412
411
  stdio: ['ignore', 'pipe', 'pipe'],
413
412
  env: { ...process.env, GIT_TERMINAL_PROMPT: '0' },
413
+ timeout: GIT_LOCAL_TIMEOUT_MS,
414
+ killSignal: 'SIGKILL',
414
415
  });
415
416
  } else {
416
417
  // stable or pinned — fetch the specific tag and check it out.
417
- execSyncWithRetry(`git fetch --depth 1 origin tag ${quoteShell(resolved.ref)} --no-tags`, {
418
+ validateShellRef(resolved.ref);
419
+ execSyncWithRetry('git', ['fetch', '--depth', '1', 'origin', 'tag', resolved.ref, '--no-tags'], {
418
420
  cwd: moduleCacheDir,
419
421
  stdio: ['ignore', 'pipe', 'pipe'],
420
422
  env: { ...process.env, GIT_TERMINAL_PROMPT: '0' },
423
+ timeout: GIT_NETWORK_TIMEOUT_MS,
424
+ killSignal: 'SIGKILL',
421
425
  });
422
- execSync(`git checkout --quiet FETCH_HEAD`, {
426
+ execFileSync('git', ['checkout', '--quiet', 'FETCH_HEAD'], {
423
427
  cwd: moduleCacheDir,
424
428
  stdio: ['ignore', 'pipe', 'pipe'],
429
+ timeout: GIT_LOCAL_TIMEOUT_MS,
430
+ killSignal: 'SIGKILL',
425
431
  });
426
432
  }
427
433
 
428
- const newSha = execSync('git rev-parse HEAD', { cwd: moduleCacheDir, stdio: 'pipe' }).toString().trim();
434
+ const newSha = execFileSync('git', ['rev-parse', 'HEAD'], {
435
+ cwd: moduleCacheDir,
436
+ stdio: 'pipe',
437
+ timeout: GIT_LOCAL_TIMEOUT_MS,
438
+ killSignal: 'SIGKILL',
439
+ })
440
+ .toString()
441
+ .trim();
429
442
  fetchSpinner.stop(`Fetched ${moduleInfo.name}`);
430
443
  if (currentSha !== newSha) needsDependencyInstall = true;
431
444
  } catch {
@@ -442,35 +455,79 @@ class ExternalModuleManager {
442
455
  fetchSpinner.start(`Fetching ${moduleInfo.name}...`);
443
456
  try {
444
457
  if (resolved.channel === 'next') {
445
- execSyncWithRetry(`git clone --depth 1 "${moduleInfo.url}" "${moduleCacheDir}"`, {
458
+ execSyncWithRetry('git', ['clone', '--depth', '1', moduleInfo.url, moduleCacheDir], {
446
459
  stdio: ['ignore', 'pipe', 'pipe'],
447
460
  env: { ...process.env, GIT_TERMINAL_PROMPT: '0' },
461
+ timeout: GIT_NETWORK_TIMEOUT_MS,
462
+ killSignal: 'SIGKILL',
448
463
  });
449
464
  } else {
450
- execSyncWithRetry(`git clone --depth 1 --branch ${quoteShell(resolved.ref)} "${moduleInfo.url}" "${moduleCacheDir}"`, {
465
+ validateShellRef(resolved.ref);
466
+ execSyncWithRetry('git', ['clone', '--depth', '1', '--branch', resolved.ref, moduleInfo.url, moduleCacheDir], {
451
467
  stdio: ['ignore', 'pipe', 'pipe'],
452
468
  env: { ...process.env, GIT_TERMINAL_PROMPT: '0' },
469
+ timeout: GIT_NETWORK_TIMEOUT_MS,
470
+ killSignal: 'SIGKILL',
453
471
  });
454
472
  }
455
473
  fetchSpinner.stop(`Fetched ${moduleInfo.name}`);
456
474
  } catch (error) {
457
475
  fetchSpinner.error(`Failed to fetch ${moduleInfo.name}`);
458
- throw new Error(`Failed to clone external module '${moduleCode}' at ${resolved.version}: ${error.message}`);
476
+ throw new Error(
477
+ `Failed to clone external module '${moduleCode}' at ${resolved.version}: ${error.message}${describeGitTimeout(error)}`,
478
+ );
459
479
  }
460
480
  }
461
481
 
462
482
  // Record resolution (channel + tag + SHA) for the manifest writer to pick up.
463
- const sha = execSync('git rev-parse HEAD', { cwd: moduleCacheDir, stdio: 'pipe' }).toString().trim();
483
+ const sha = execFileSync('git', ['rev-parse', 'HEAD'], {
484
+ cwd: moduleCacheDir,
485
+ stdio: 'pipe',
486
+ timeout: GIT_LOCAL_TIMEOUT_MS,
487
+ killSignal: 'SIGKILL',
488
+ })
489
+ .toString()
490
+ .trim();
491
+
492
+ // Item 8 fase 2 (auditoria 2026-09-11, EXT-02 / IM-ACH-06): with --pin
493
+ // CODE=TAG@SHA, verify the commit we actually checked out matches what
494
+ // was requested. A git tag is a mutable ref — nothing stops the remote
495
+ // from force-moving it between installs — so this is a trust check, not
496
+ // a network hiccup: it must run before we record any resolution/marker
497
+ // a later run would trust, and it must never be retried as transient
498
+ // (compare isTransientGitError / isTimeoutKillError above, neither of
499
+ // which this error matches). On mismatch we remove the whole cache dir
500
+ // rather than leave a "cloned fine but at the wrong commit" checkout
501
+ // sitting there indistinguishable from a good one on the next run — the
502
+ // simplest safe option, and the same posture as the corrupted-cache
503
+ // cleanup earlier in this function (fetch-failed / EXT-03 branch above).
504
+ //
505
+ // Bug 3 (review da fase 3, 2026-09-11): strict equality, not a prefix
506
+ // compare — expectedSha is always the full 40-hex SHA (parsePinTagAndSha
507
+ // rejects anything shorter) and `sha` here is always a full 40-hex SHA.
508
+ if (expectedPinSha && sha.toLowerCase() !== expectedPinSha) {
509
+ await fs.remove(moduleCacheDir);
510
+ throw new Error(
511
+ `Tag '${planEntry.pin}' aponta para o SHA ${sha}, esperado ${expectedPinSha} (--pin ${moduleCode}=${planEntry.pin}@${expectedPinSha}); a tag pode ter sido movida no repositório remoto.`,
512
+ );
513
+ }
514
+
464
515
  ExternalModuleManager._resolutions.set(moduleCode, {
465
516
  channel: resolved.channel,
466
517
  version: resolved.version,
467
518
  ref: resolved.ref,
468
519
  sha,
520
+ expectedSha: expectedPinSha,
469
521
  repoUrl: moduleInfo.url,
470
522
  resolvedFallback: !!resolved.resolvedFallback,
471
523
  planSource: planEntry.source,
472
524
  });
473
- await writeChannelMarker(markerPath, { channel: resolved.channel, version: resolved.version, sha });
525
+ await writeChannelMarker(markerPath, {
526
+ channel: resolved.channel,
527
+ version: resolved.version,
528
+ sha,
529
+ expectedSha: expectedPinSha,
530
+ });
474
531
 
475
532
  // Install dependencies if package.json exists
476
533
  const packageJsonPath = path.join(moduleCacheDir, 'package.json');
@@ -484,10 +541,13 @@ class ExternalModuleManager {
484
541
  const installSpinner = await createSpinner();
485
542
  installSpinner.start(`Installing dependencies for ${moduleInfo.name}...`);
486
543
  try {
487
- execSync('npm install --omit=dev --no-audit --no-fund --no-progress --legacy-peer-deps', {
544
+ execFileSync('npm', ['install', '--omit=dev', '--no-audit', '--no-fund', '--no-progress', '--legacy-peer-deps'], {
545
+ // npm é npm.cmd no Windows e só roda via shell; os args acima são constantes, sem input do usuário.
546
+ shell: process.platform === 'win32',
488
547
  cwd: moduleCacheDir,
489
548
  stdio: ['ignore', 'pipe', 'pipe'],
490
- timeout: 120_000, // 2 minute timeout
549
+ timeout: NPM_INSTALL_TIMEOUT_MS,
550
+ killSignal: 'SIGKILL',
491
551
  });
492
552
  installSpinner.stop(`Installed dependencies for ${moduleInfo.name}`);
493
553
  } catch (error) {
@@ -510,10 +570,13 @@ class ExternalModuleManager {
510
570
  const installSpinner = await createSpinner();
511
571
  installSpinner.start(`Installing dependencies for ${moduleInfo.name}...`);
512
572
  try {
513
- execSync('npm install --omit=dev --no-audit --no-fund --no-progress --legacy-peer-deps', {
573
+ execFileSync('npm', ['install', '--omit=dev', '--no-audit', '--no-fund', '--no-progress', '--legacy-peer-deps'], {
574
+ // npm é npm.cmd no Windows e só roda via shell; os args acima são constantes, sem input do usuário.
575
+ shell: process.platform === 'win32',
514
576
  cwd: moduleCacheDir,
515
577
  stdio: ['ignore', 'pipe', 'pipe'],
516
- timeout: 120_000, // 2 minute timeout
578
+ timeout: NPM_INSTALL_TIMEOUT_MS,
579
+ killSignal: 'SIGKILL',
517
580
  });
518
581
  installSpinner.stop(`Installed dependencies for ${moduleInfo.name}`);
519
582
  } catch (error) {
@@ -696,4 +759,14 @@ class ExternalModuleManager {
696
759
  cachedModules = null;
697
760
  }
698
761
 
699
- module.exports = { ExternalModuleManager, isTransientGitError, execSyncWithRetry };
762
+ module.exports = {
763
+ ExternalModuleManager,
764
+ isTransientGitError,
765
+ execSyncWithRetry,
766
+ isTimeoutKillError,
767
+ describeGitTimeout,
768
+ GIT_NETWORK_TIMEOUT_MS,
769
+ GIT_LOCAL_TIMEOUT_MS,
770
+ NPM_INSTALL_TIMEOUT_MS,
771
+ parsePinTagAndSha,
772
+ };
@@ -0,0 +1,125 @@
1
+ /**
2
+ * Shared primitives for the two git downloaders (external-manager.js and
3
+ * custom-module-manager.js) — item 20, etapa 1 (auditoria 2026-09-11).
4
+ *
5
+ * This module owns:
6
+ * - the ACH-01/EXT-01 timeout constants and the WIZZ_GIT_TIMEOUT_MS override
7
+ * - transient-error classification + `execSyncWithRetry` (1 re-tentativa)
8
+ * - the defensive ref-shape check (was duplicated as `validateShellRef` in
9
+ * external-manager.js and `validateCustomRef` in custom-module-manager.js)
10
+ *
11
+ * Policy-level decisions (channels, pins, cache layout, marker files) stay in
12
+ * each manager — this file deliberately knows nothing about them.
13
+ *
14
+ * `execFileSync` blocks Node's main thread with no built-in ceiling: a host
15
+ * that accepts the TCP connection and never responds (no RST — a network
16
+ * black hole) hangs the installer forever, with no message and no way out
17
+ * short of the user killing the process. Every git/npm `execFileSync` call in
18
+ * both managers must pass an explicit `timeout` (+ `killSignal: 'SIGKILL'`,
19
+ * since git can ignore SIGTERM while blocked on a syscall). `WIZZ_GIT_TIMEOUT_MS`
20
+ * lets a user on a slow/high-latency network raise the git timeouts without
21
+ * touching source; npm install's timeout is fixed — dependency install time
22
+ * is bounded by package.json, not by the network path to a single git remote,
23
+ * so it isn't part of the same override.
24
+ */
25
+
26
+ const { execFileSync } = require('node:child_process');
27
+
28
+ function parseGitTimeoutOverride() {
29
+ const raw = process.env.WIZZ_GIT_TIMEOUT_MS;
30
+ if (raw === undefined || raw === '') return null;
31
+ const parsed = Number.parseInt(raw, 10);
32
+ return Number.isInteger(parsed) && parsed > 0 ? parsed : null;
33
+ }
34
+
35
+ const GIT_TIMEOUT_OVERRIDE_MS = parseGitTimeoutOverride();
36
+ // Network git ops: clone / fetch.
37
+ const GIT_NETWORK_TIMEOUT_MS = GIT_TIMEOUT_OVERRIDE_MS ?? 120_000;
38
+ // Local git ops: rev-parse, symbolic-ref, checkout, reset. No network
39
+ // round-trip, but still shelled out via execFileSync, so still needs a
40
+ // ceiling (a corrupted/locked local repo can hang git indefinitely too).
41
+ const GIT_LOCAL_TIMEOUT_MS = GIT_TIMEOUT_OVERRIDE_MS ?? 30_000;
42
+ // npm install for a module's own dependencies. Not affected by WIZZ_GIT_TIMEOUT_MS.
43
+ const NPM_INSTALL_TIMEOUT_MS = 300_000;
44
+
45
+ /**
46
+ * True when an execFileSync error is our own timeout kill: Node reports this
47
+ * via `error.killed`/`error.signal`, not through stdout/stderr text, so the
48
+ * message-pattern checks below never see it.
49
+ */
50
+ function isTimeoutKillError(error) {
51
+ return !!(error && (error.killed === true || error.signal));
52
+ }
53
+
54
+ /**
55
+ * PT-BR hint appended to a final thrown/logged error when a git call timed
56
+ * out, pointing the user at the override env var.
57
+ */
58
+ function describeGitTimeout(error) {
59
+ if (!isTimeoutKillError(error)) return '';
60
+ return ` O comando git estourou o tempo limite (${error.signal || 'timeout'}). Se sua rede é lenta, ajuste com a variável de ambiente WIZZ_GIT_TIMEOUT_MS (em milissegundos).`;
61
+ }
62
+
63
+ // Retry pontual (1 re-tentativa, backoff curto) para `git clone`/`git fetch`.
64
+ // Para comandos de shell não temos código de erro estruturado como em
65
+ // requisições HTTP; classificamos como transitório por padrões conhecidos na
66
+ // mensagem/stderr do git, OU por ter sido morto pelo nosso próprio `timeout`
67
+ // (error.killed/error.signal — ver isTimeoutKillError). Erro lógico (repo/tag
68
+ // inexistente, permissão negada etc.) não bate em nenhum dos dois e propaga
69
+ // direto, sem retry.
70
+ const GIT_RETRY_DELAY_MS = 300;
71
+ const TRANSIENT_GIT_ERROR_PATTERNS = [/could not resolve host/i, /timed out/i, /early eof/i, /connection reset/i];
72
+
73
+ function isTransientGitError(error) {
74
+ if (isTimeoutKillError(error)) return true;
75
+ const message = `${error?.message || ''}\n${error?.stderr?.toString?.() || ''}`;
76
+ return TRANSIENT_GIT_ERROR_PATTERNS.some((pattern) => pattern.test(message));
77
+ }
78
+
79
+ // Sleep síncrono curto (execSync é bloqueante; não há await aqui). Usa
80
+ // Atomics.wait sobre um buffer compartilhado, sem depender de `sleep` de shell.
81
+ function blockingDelay(ms) {
82
+ const sharedBuffer = new Int32Array(new SharedArrayBuffer(4));
83
+ Atomics.wait(sharedBuffer, 0, 0, ms);
84
+ }
85
+
86
+ // Wrapper de execFileSync com 1 re-tentativa em falha transitória de rede
87
+ // (ver isTransientGitError). Erro não-transitório propaga direto.
88
+ // Assinatura (file, args, options) — array de argumentos, nunca uma string
89
+ // de shell — para que nenhum call site precise (nem consiga) interpolar URL
90
+ // ou ref não sanitizada dentro de um comando de shell (ver EXT-09).
91
+ function execSyncWithRetry(file, args, options) {
92
+ try {
93
+ return execFileSync(file, args, options);
94
+ } catch (error) {
95
+ if (!isTransientGitError(error)) throw error;
96
+ blockingDelay(GIT_RETRY_DELAY_MS);
97
+ return execFileSync(file, args, options);
98
+ }
99
+ }
100
+
101
+ /**
102
+ * Conservative validation for tag/branch names passed to git commands. Refs
103
+ * are user-typed (--pin, --next, version from a /tree/ URL) or come from the
104
+ * GitHub API. Refs reach `execFileSync('git', [...])` as a single argv
105
+ * element (no shell), so this isn't shell-quoting anymore — it's a defensive
106
+ * shape check so a malformed ref fails loudly instead of confusing `git`.
107
+ */
108
+ function validateGitRef(ref) {
109
+ // Ref que começa com '-' viraria opção do git (ex.: --upload-pack): rejeitar.
110
+ if (typeof ref !== 'string' || ref.startsWith('-') || !/^[\w.\-+/]+$/.test(ref)) {
111
+ throw new Error(`Unsafe ref name: ${JSON.stringify(ref)}`);
112
+ }
113
+ return ref;
114
+ }
115
+
116
+ module.exports = {
117
+ GIT_NETWORK_TIMEOUT_MS,
118
+ GIT_LOCAL_TIMEOUT_MS,
119
+ NPM_INSTALL_TIMEOUT_MS,
120
+ isTimeoutKillError,
121
+ describeGitTimeout,
122
+ isTransientGitError,
123
+ execSyncWithRetry,
124
+ validateGitRef,
125
+ };