wizz-method 2.0.0 → 2.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +60 -30
- package/README.md +80 -31
- package/SECURITY.md +24 -0
- package/THIRD-PARTY-NOTICES.md +136 -0
- package/package.json +31 -17
- package/skills-registry.yaml +128 -7
- package/src/bmm-skills/1-analysis/research/wizz-domain-research/SKILL.md +3 -4
- package/src/bmm-skills/1-analysis/research/wizz-domain-research/domain-steps/step-06-research-synthesis.md +1 -1
- package/src/bmm-skills/1-analysis/research/wizz-market-research/SKILL.md +3 -4
- package/src/bmm-skills/1-analysis/research/wizz-market-research/steps/step-06-research-completion.md +1 -1
- package/src/bmm-skills/1-analysis/research/wizz-technical-research/SKILL.md +3 -4
- package/src/bmm-skills/1-analysis/research/wizz-technical-research/technical-steps/step-06-research-synthesis.md +1 -1
- package/src/bmm-skills/1-analysis/wizz-agent-analyst/SKILL.md +3 -4
- package/src/bmm-skills/1-analysis/wizz-agent-tech-writer/SKILL.md +3 -4
- package/src/bmm-skills/1-analysis/wizz-document-project/SKILL.md +3 -4
- package/src/bmm-skills/1-analysis/wizz-document-project/workflows/deep-dive-instructions.md +1 -1
- package/src/bmm-skills/1-analysis/wizz-document-project/workflows/full-scan-instructions.md +1 -1
- package/src/bmm-skills/1-analysis/wizz-prfaq/SKILL.md +3 -4
- package/src/bmm-skills/1-analysis/wizz-prfaq/references/verdict.md +1 -1
- package/src/bmm-skills/1-analysis/wizz-product-brief/SKILL.md +1 -1
- package/src/bmm-skills/2-plan-workflows/wizz-agent-pm/SKILL.md +3 -4
- package/src/bmm-skills/2-plan-workflows/wizz-agent-ux-designer/SKILL.md +3 -4
- package/src/bmm-skills/2-plan-workflows/wizz-create-prd/SKILL.md +1 -1
- package/src/bmm-skills/2-plan-workflows/wizz-edit-prd/SKILL.md +1 -1
- package/src/bmm-skills/2-plan-workflows/wizz-prd/SKILL.md +1 -1
- package/src/bmm-skills/2-plan-workflows/wizz-ux/SKILL.md +1 -1
- package/src/bmm-skills/2-plan-workflows/wizz-validate-prd/SKILL.md +1 -1
- package/src/bmm-skills/3-solutioning/wizz-agent-architect/SKILL.md +3 -4
- package/src/bmm-skills/3-solutioning/wizz-architecture/SKILL.md +9 -9
- package/src/bmm-skills/3-solutioning/wizz-architecture/references/headless.md +1 -1
- package/src/bmm-skills/3-solutioning/wizz-check-implementation-readiness/SKILL.md +3 -4
- package/src/bmm-skills/3-solutioning/wizz-check-implementation-readiness/steps/step-06-final-assessment.md +1 -1
- package/src/bmm-skills/3-solutioning/wizz-create-architecture/SKILL.md +1 -1
- package/src/bmm-skills/3-solutioning/wizz-create-epics-and-stories/SKILL.md +3 -4
- package/src/bmm-skills/3-solutioning/wizz-create-epics-and-stories/steps/step-04-final-validation.md +1 -1
- package/src/bmm-skills/3-solutioning/wizz-generate-project-context/SKILL.md +3 -4
- package/src/bmm-skills/3-solutioning/wizz-generate-project-context/steps/step-03-complete.md +1 -1
- package/src/bmm-skills/4-implementation/wizz-agent-dev/SKILL.md +3 -4
- package/src/bmm-skills/4-implementation/wizz-checkpoint-preview/SKILL.md +3 -4
- package/src/bmm-skills/4-implementation/wizz-checkpoint-preview/step-05-wrapup.md +1 -1
- package/src/bmm-skills/4-implementation/wizz-code-review/SKILL.md +3 -4
- package/src/bmm-skills/4-implementation/wizz-code-review/customize.toml +3 -8
- package/src/bmm-skills/4-implementation/wizz-code-review/review-prompts/blind-hunter.md +20 -0
- package/src/bmm-skills/4-implementation/wizz-code-review/steps/step-04-present.md +1 -1
- package/src/bmm-skills/4-implementation/wizz-correct-course/SKILL.md +4 -5
- package/src/bmm-skills/4-implementation/wizz-create-story/SKILL.md +4 -5
- package/src/bmm-skills/4-implementation/wizz-dev-story/SKILL.md +4 -5
- package/src/bmm-skills/4-implementation/wizz-investigate/SKILL.md +1 -1
- package/src/bmm-skills/4-implementation/wizz-qa-generate-e2e-tests/SKILL.md +4 -5
- package/src/bmm-skills/4-implementation/wizz-quick-dev/SKILL.md +4 -5
- package/src/bmm-skills/4-implementation/wizz-quick-dev/customize.toml +10 -22
- package/src/bmm-skills/4-implementation/wizz-quick-dev/review-prompts/blind-hunter.md +20 -0
- package/src/bmm-skills/4-implementation/wizz-quick-dev/step-05-present.md +1 -1
- package/src/bmm-skills/4-implementation/wizz-quick-dev/step-oneshot.md +1 -1
- package/src/bmm-skills/4-implementation/wizz-retrospective/SKILL.md +1 -2
- package/src/bmm-skills/4-implementation/wizz-sprint-planning/SKILL.md +1 -1
- package/src/bmm-skills/4-implementation/wizz-sprint-status/SKILL.md +5 -6
- package/src/core-skills/_shared/handoff-protocol.md +9 -0
- package/src/core-skills/wizz-advanced-elicitation/SKILL.md +2 -2
- package/src/core-skills/wizz-brainstorming/SKILL.md +6 -6
- package/src/core-skills/wizz-brainstorming/references/converge.md +1 -1
- package/src/core-skills/wizz-brainstorming/references/finalize.md +1 -1
- package/src/core-skills/wizz-brainstorming/references/headless.md +3 -3
- package/src/core-skills/wizz-brainstorming/references/mode-autonomous.md +1 -1
- package/src/core-skills/wizz-customize/SKILL.md +13 -10
- package/src/core-skills/wizz-forge-idea/SKILL.md +6 -6
- package/src/core-skills/wizz-forge-idea/scripts/__pycache__/resolve_personas.cpython-314.pyc +0 -0
- package/src/core-skills/wizz-forge-idea/scripts/resolve_personas.py +17 -1
- package/src/core-skills/wizz-party-mode/SKILL.md +3 -3
- package/src/core-skills/wizz-party-mode/references/create-party.md +1 -1
- package/src/core-skills/wizz-party-mode/references/party-memory.md +2 -2
- package/src/core-skills/wizz-party-mode/scripts/__pycache__/resolve_party.cpython-314.pyc +0 -0
- package/src/core-skills/wizz-party-mode/scripts/resolve_party.py +17 -1
- package/src/core-skills/wizz-review-adversarial-general/SKILL.md +1 -1
- package/src/core-skills/wizz-spec/SKILL.md +5 -5
- package/src/modules/lowticket/README.md +6 -6
- package/src/modules/lowticket/module.yaml +4 -1
- package/src/modules/lowticket/skills/{lowticket-funil → wizz-lowticket-funil}/SKILL.md +4 -4
- package/src/modules/lowticket/skills/{lowticket-funil → wizz-lowticket-funil}/references/copy-das-paginas.md +1 -1
- package/src/modules/lowticket/skills/{lowticket-metodologia → wizz-lowticket-metodologia}/SKILL.md +1 -1
- package/src/modules/lowticket/skills/{lowticket-minerador → wizz-lowticket-minerador}/SKILL.md +3 -3
- package/src/modules/lowticket/skills/{lowticket-minerador → wizz-lowticket-minerador}/references/rubrica.md +1 -1
- package/src/modules/lowticket/skills/{lowticket-pagina → wizz-lowticket-pagina}/SKILL.md +4 -4
- package/src/modules/lowticket/skills/{lowticket-trafego → wizz-lowticket-trafego}/SKILL.md +3 -3
- package/src/modules/lowticket/skills/{lowticket-trafego → wizz-lowticket-trafego}/references/reguas.md +1 -1
- package/src/modules/wizz/_shared/communication-rules.md +1 -1
- package/src/modules/wizz/_shared/despacho-barato.md +9 -0
- package/src/modules/wizz/_shared/token-economy.md +7 -0
- package/src/modules/wizz/agents/wizz-ads/SKILL.md +1 -1
- package/src/modules/wizz/agents/wizz-ads/customize.toml +1 -2
- package/src/modules/wizz/agents/wizz-copy/SKILL.md +1 -1
- package/src/modules/wizz/agents/wizz-copy/customize.toml +1 -2
- package/src/modules/wizz/agents/wizz-designer/SKILL.md +1 -1
- package/src/modules/wizz/agents/wizz-designer/customize.toml +1 -2
- package/src/modules/wizz/agents/wizz-growth/SKILL.md +1 -1
- package/src/modules/wizz/agents/wizz-growth/customize.toml +1 -2
- package/src/modules/wizz/agents/wizz-maestro/SKILL.md +5 -5
- package/src/modules/wizz/agents/wizz-maestro/customize.toml +4 -8
- package/src/modules/wizz/agents/wizz-memoria/SKILL.md +1 -1
- package/src/modules/wizz/agents/wizz-memoria/customize.toml +1 -2
- package/src/modules/wizz/agents/wizz-qa/SKILL.md +1 -1
- package/src/modules/wizz/agents/wizz-qa/customize.toml +1 -2
- package/src/modules/wizz/agents/wizz-seo/SKILL.md +1 -1
- package/src/modules/wizz/agents/wizz-seo/customize.toml +1 -2
- package/src/modules/wizz/agents/wizz-social/SKILL.md +1 -1
- package/src/modules/wizz/agents/wizz-social/customize.toml +1 -2
- package/src/modules/wizz/module.yaml +3 -0
- package/src/modules/wizz/overrides/wizz-agent-analyst.toml +1 -2
- package/src/modules/wizz/overrides/wizz-agent-architect.toml +1 -2
- package/src/modules/wizz/overrides/wizz-agent-dev.toml +1 -2
- package/src/modules/wizz/overrides/wizz-agent-pm.toml +1 -2
- package/src/modules/wizz/overrides/wizz-agent-tech-writer.toml +1 -2
- package/src/modules/wizz/overrides/wizz-agent-ux-designer.toml +1 -2
- package/src/modules/wizz/subagents/codex/wizz-exec-haiku.toml +2 -0
- package/src/modules/wizz/subagents/codex/wizz-exec-opus.toml +2 -0
- package/src/modules/wizz/subagents/codex/wizz-exec-review.toml +2 -0
- package/src/modules/wizz/subagents/codex/wizz-exec-sonnet.toml +2 -0
- package/src/modules/wizz/subagents/gemini/wizz-exec-haiku.md +4 -1
- package/src/modules/wizz/subagents/gemini/wizz-exec-opus.md +4 -1
- package/src/modules/wizz/subagents/gemini/wizz-exec-review.md +4 -1
- package/src/modules/wizz/subagents/gemini/wizz-exec-sonnet.md +4 -1
- package/src/modules/wizz/subagents/opencode/wizz-exec-haiku.md +4 -1
- package/src/modules/wizz/subagents/opencode/wizz-exec-opus.md +4 -1
- package/src/modules/wizz/subagents/opencode/wizz-exec-review.md +4 -1
- package/src/modules/wizz/subagents/opencode/wizz-exec-sonnet.md +4 -1
- package/src/modules/wizz/subagents/spec.yaml +148 -0
- package/src/modules/wizz/subagents/wizz-exec-haiku.md +4 -1
- package/src/modules/wizz/subagents/wizz-exec-opus.md +4 -1
- package/src/modules/wizz/subagents/wizz-exec-review.md +4 -1
- package/src/modules/wizz/subagents/wizz-exec-sonnet.md +4 -1
- package/src/scripts/__pycache__/resolve_customization.cpython-314.pyc +0 -0
- package/src/scripts/memlog.js +368 -0
- package/src/scripts/resolve_customization.py +124 -15
- package/src/skills-lib/_shared/complexity-signal.md +14 -0
- package/src/skills-lib/wizz-canvas-design/canvas-fonts/InstrumentSerif-OFL.txt +93 -0
- package/src/skills-lib/wizz-huashu-design/references/sfx-library.md +1 -1
- package/src/skills-lib/wizz-huashu-design/scripts/add-music.sh +1 -1
- package/src/skills-lib/wizz-huashu-design/scripts/mix-voiceover.sh +1 -1
- package/src/skills-lib/wizz-impeccable/LICENSE.txt +202 -0
- package/src/skills-lib/wizz-offer-forge/SKILL.md +1 -1
- package/src/skills-lib/wizz-react-components/LICENSE.txt +202 -0
- package/src/skills-lib/wizz-router/SKILL.md +2 -2
- package/src/skills-lib/wizz-supabase-postgres-best-practices/LICENSE +21 -0
- package/src/skills-lib/wizz-taste-skill/SKILL.md +1 -1
- package/src/skills-lib/wizz-tracking-audit/SKILL.md +1 -1
- package/tools/fetch-assets.mjs +70 -38
- package/tools/hooks/README.md +22 -0
- package/tools/hooks/rtk-rewrite.sh +280 -0
- package/tools/hooks/security-defensive-context.js +70 -0
- package/tools/hooks/session-rules.js +368 -0
- package/tools/hooks/wizz-decision-trace.js +389 -0
- package/tools/hooks/wizz-router-enforce.js +258 -0
- package/tools/installer/banner.js +1 -1
- package/tools/installer/commands/doctor.js +124 -0
- package/tools/installer/commands/fetch-assets.js +7 -8
- package/tools/installer/commands/install.js +1 -1
- package/tools/installer/commands/resolve.js +95 -0
- package/tools/installer/core/doctor.js +648 -0
- package/tools/installer/core/hash-cache.js +156 -0
- package/tools/installer/core/help-catalog.js +4 -1
- package/tools/installer/core/hooks-settings.js +178 -0
- package/tools/installer/core/installer.js +297 -15
- package/tools/installer/core/legacy-warnings.js +0 -4
- package/tools/installer/core/manifest-generator.js +121 -43
- package/tools/installer/core/manifest.js +36 -32
- package/tools/installer/core/module-config-writer.js +4 -1
- package/tools/installer/core/python-check.js +60 -63
- package/tools/installer/core/quick-update.js +76 -43
- package/tools/installer/core/resolved-config.js +168 -0
- package/tools/installer/core/resolved-customizations.js +736 -0
- package/tools/installer/core/resolved-includes.js +262 -0
- package/tools/installer/core/resolved-schema.js +148 -0
- package/tools/installer/core/user-file-preservation.js +40 -8
- package/tools/installer/core/wizz-dir.js +117 -0
- package/tools/installer/core/yaml-cache.js +105 -0
- package/tools/installer/fs-native.js +97 -6
- package/tools/installer/ide/_config-driven.js +12 -75
- package/tools/installer/ide/platform-codes.js +111 -16
- package/tools/installer/ide/platform-codes.yaml +45 -100
- package/tools/installer/ide/shared/path-utils.js +6 -208
- package/tools/installer/install-messages.yaml +4 -14
- package/tools/installer/modules/channel-plan.js +15 -2
- package/tools/installer/modules/config-collector.js +762 -0
- package/tools/installer/modules/config-values.js +352 -0
- package/tools/installer/modules/custom-module-manager.js +161 -28
- package/tools/installer/modules/env-vars.js +119 -0
- package/tools/installer/modules/external-manager.js +133 -60
- package/tools/installer/modules/git-cache-utils.js +125 -0
- package/tools/installer/modules/module-catalog.js +565 -0
- package/tools/installer/modules/module-installer.js +618 -0
- package/tools/installer/modules/module-interface.js +86 -0
- package/tools/installer/modules/official-modules.js +98 -2172
- package/tools/installer/modules/pin-spec.js +125 -0
- package/tools/installer/modules/plugin-resolver.js +4 -0
- package/tools/installer/modules/skills-lib.js +3 -6
- package/tools/installer/prompts.js +0 -3
- package/tools/installer/ui.js +89 -54
- package/tools/installer/wizz-cli.js +1 -1
- package/tools/lib/frontmatter.js +139 -0
- package/tools/lib/sync-targets.mjs +49 -0
- package/tools/lib/walk.js +93 -0
- package/wizz-modules.yaml +9 -0
- package/src/scripts/__pycache__/memlog.cpython-313.pyc +0 -0
- package/src/scripts/memlog.py +0 -233
- package/src/scripts/tests/__pycache__/test_memlog.cpython-313-pytest-9.1.1.pyc +0 -0
- package/src/scripts/tests/__pycache__/test_resolve_customization.cpython-313-pytest-9.1.1.pyc +0 -0
- package/src/scripts/tests/test_memlog.py +0 -306
- package/src/skills-lib/wizz-huashu-design/assets/showcases/INDEX.md +0 -115
- package/src/skills-lib/wizz-huashu-design/assets/showcases/cover/cover-build.html +0 -235
- package/src/skills-lib/wizz-huashu-design/assets/showcases/cover/cover-build.png +0 -0
- package/src/skills-lib/wizz-huashu-design/assets/showcases/cover/cover-pentagram.html +0 -229
- package/src/skills-lib/wizz-huashu-design/assets/showcases/cover/cover-pentagram.png +0 -0
- package/src/skills-lib/wizz-huashu-design/assets/showcases/cover/cover-takram.html +0 -288
- package/src/skills-lib/wizz-huashu-design/assets/showcases/cover/cover-takram.png +0 -0
- package/src/skills-lib/wizz-huashu-design/assets/showcases/infographic/infographic-build.html +0 -503
- package/src/skills-lib/wizz-huashu-design/assets/showcases/infographic/infographic-build.png +0 -0
- package/src/skills-lib/wizz-huashu-design/assets/showcases/infographic/infographic-pentagram.html +0 -600
- package/src/skills-lib/wizz-huashu-design/assets/showcases/infographic/infographic-pentagram.png +0 -0
- package/src/skills-lib/wizz-huashu-design/assets/showcases/infographic/infographic-takram.html +0 -670
- package/src/skills-lib/wizz-huashu-design/assets/showcases/infographic/infographic-takram.png +0 -0
- package/src/skills-lib/wizz-huashu-design/assets/showcases/ppt/ppt-build.html +0 -382
- package/src/skills-lib/wizz-huashu-design/assets/showcases/ppt/ppt-build.png +0 -0
- package/src/skills-lib/wizz-huashu-design/assets/showcases/ppt/ppt-pentagram.html +0 -536
- package/src/skills-lib/wizz-huashu-design/assets/showcases/ppt/ppt-pentagram.png +0 -0
- package/src/skills-lib/wizz-huashu-design/assets/showcases/ppt/ppt-takram.html +0 -497
- package/src/skills-lib/wizz-huashu-design/assets/showcases/ppt/ppt-takram.png +0 -0
- package/src/skills-lib/wizz-huashu-design/assets/showcases/website-ai-nav/ainav-build.html +0 -385
- package/src/skills-lib/wizz-huashu-design/assets/showcases/website-ai-nav/ainav-build.png +0 -0
- package/src/skills-lib/wizz-huashu-design/assets/showcases/website-ai-nav/ainav-pentagram.html +0 -422
- package/src/skills-lib/wizz-huashu-design/assets/showcases/website-ai-nav/ainav-pentagram.png +0 -0
- package/src/skills-lib/wizz-huashu-design/assets/showcases/website-ai-nav/ainav-takram.html +0 -499
- package/src/skills-lib/wizz-huashu-design/assets/showcases/website-ai-nav/ainav-takram.png +0 -0
- package/src/skills-lib/wizz-huashu-design/assets/showcases/website-ai-writing/aiwriting-build.html +0 -562
- package/src/skills-lib/wizz-huashu-design/assets/showcases/website-ai-writing/aiwriting-build.png +0 -0
- package/src/skills-lib/wizz-huashu-design/assets/showcases/website-ai-writing/aiwriting-pentagram.html +0 -548
- package/src/skills-lib/wizz-huashu-design/assets/showcases/website-ai-writing/aiwriting-pentagram.png +0 -0
- package/src/skills-lib/wizz-huashu-design/assets/showcases/website-ai-writing/aiwriting-takram.html +0 -696
- package/src/skills-lib/wizz-huashu-design/assets/showcases/website-ai-writing/aiwriting-takram.png +0 -0
- package/src/skills-lib/wizz-huashu-design/assets/showcases/website-devdocs/devdocs-build.html +0 -372
- package/src/skills-lib/wizz-huashu-design/assets/showcases/website-devdocs/devdocs-build.png +0 -0
- package/src/skills-lib/wizz-huashu-design/assets/showcases/website-devdocs/devdocs-pentagram.html +0 -460
- package/src/skills-lib/wizz-huashu-design/assets/showcases/website-devdocs/devdocs-pentagram.png +0 -0
- package/src/skills-lib/wizz-huashu-design/assets/showcases/website-devdocs/devdocs-takram.html +0 -494
- package/src/skills-lib/wizz-huashu-design/assets/showcases/website-devdocs/devdocs-takram.png +0 -0
- package/src/skills-lib/wizz-huashu-design/assets/showcases/website-homepage/homepage-build.html +0 -367
- package/src/skills-lib/wizz-huashu-design/assets/showcases/website-homepage/homepage-build.png +0 -0
- package/src/skills-lib/wizz-huashu-design/assets/showcases/website-homepage/homepage-pentagram.html +0 -368
- package/src/skills-lib/wizz-huashu-design/assets/showcases/website-homepage/homepage-pentagram.png +0 -0
- package/src/skills-lib/wizz-huashu-design/assets/showcases/website-homepage/homepage-takram.html +0 -459
- package/src/skills-lib/wizz-huashu-design/assets/showcases/website-homepage/homepage-takram.png +0 -0
- package/src/skills-lib/wizz-huashu-design/assets/showcases/website-saas/saas-build.html +0 -493
- package/src/skills-lib/wizz-huashu-design/assets/showcases/website-saas/saas-build.png +0 -0
- package/src/skills-lib/wizz-huashu-design/assets/showcases/website-saas/saas-pentagram.html +0 -556
- package/src/skills-lib/wizz-huashu-design/assets/showcases/website-saas/saas-pentagram.png +0 -0
- package/src/skills-lib/wizz-huashu-design/assets/showcases/website-saas/saas-takram.html +0 -604
- package/src/skills-lib/wizz-huashu-design/assets/showcases/website-saas/saas-takram.png +0 -0
- package/tools/installer/file-ops.js +0 -204
- package/tools/installer/ide/shared/skill-manifest.js +0 -57
- package/tools/installer/yaml-format.js +0 -245
- package/web-bundles/README.md +0 -46
- package/web-bundles/brainstorming-coach/INSTRUCTIONS.md +0 -86
- package/web-bundles/brainstorming-coach/SKILL.md +0 -83
- package/web-bundles/brainstorming-coach/brain-methods.csv +0 -62
- package/web-bundles/bundles.json +0 -139
- package/web-bundles/market-and-industry-research/INSTRUCTIONS.md +0 -88
- package/web-bundles/market-and-industry-research/SKILL.md +0 -59
- package/web-bundles/prd-coach/INSTRUCTIONS.md +0 -86
- package/web-bundles/prd-coach/SKILL.md +0 -101
- package/web-bundles/prd-coach/prd-template.md +0 -165
- package/web-bundles/prd-coach/prd-validation-checklist.md +0 -135
- package/web-bundles/prfaq-coach/INSTRUCTIONS.md +0 -86
- package/web-bundles/prfaq-coach/SKILL.md +0 -139
- package/web-bundles/product-brief-coach/INSTRUCTIONS.md +0 -86
- package/web-bundles/product-brief-coach/SKILL.md +0 -113
- package/web-bundles/ux-coach/INSTRUCTIONS.md +0 -92
- package/web-bundles/ux-coach/SKILL.md +0 -187
- package/web-bundles/ux-coach/ux-validation.md +0 -100
- /package/src/modules/lowticket/skills/{lowticket-funil → wizz-lowticket-funil}/references/mapa-do-funil.md +0 -0
- /package/src/modules/lowticket/skills/{lowticket-metodologia → wizz-lowticket-metodologia}/CATALOGO.md +0 -0
- /package/src/modules/lowticket/skills/{lowticket-metodologia → wizz-lowticket-metodologia}/knowledge/01-principios.md +0 -0
- /package/src/modules/lowticket/skills/{lowticket-metodologia → wizz-lowticket-metodologia}/knowledge/02-diagnostico-funil.md +0 -0
- /package/src/modules/lowticket/skills/{lowticket-metodologia → wizz-lowticket-metodologia}/knowledge/03-campanha-bidcap.md +0 -0
- /package/src/modules/lowticket/skills/{lowticket-metodologia → wizz-lowticket-metodologia}/knowledge/04-criativos.md +0 -0
- /package/src/modules/lowticket/skills/{lowticket-metodologia → wizz-lowticket-metodologia}/knowledge/04a-criativos-ia.md +0 -0
- /package/src/modules/lowticket/skills/{lowticket-metodologia → wizz-lowticket-metodologia}/knowledge/04b-criativos-formatos.md +0 -0
- /package/src/modules/lowticket/skills/{lowticket-metodologia → wizz-lowticket-metodologia}/knowledge/05-oferta.md +0 -0
- /package/src/modules/lowticket/skills/{lowticket-metodologia → wizz-lowticket-metodologia}/knowledge/06-pagina-vendas.md +0 -0
- /package/src/modules/lowticket/skills/{lowticket-metodologia → wizz-lowticket-metodologia}/knowledge/06a-instagram.md +0 -0
- /package/src/modules/lowticket/skills/{lowticket-metodologia → wizz-lowticket-metodologia}/knowledge/06b-player-vsl.md +0 -0
- /package/src/modules/lowticket/skills/{lowticket-metodologia → wizz-lowticket-metodologia}/knowledge/07-funil-upsell.md +0 -0
- /package/src/modules/lowticket/skills/{lowticket-metodologia → wizz-lowticket-metodologia}/knowledge/07a-copy-humanizacao.md +0 -0
- /package/src/modules/lowticket/skills/{lowticket-metodologia → wizz-lowticket-metodologia}/knowledge/08-pesquisa-publico.md +0 -0
- /package/src/modules/lowticket/skills/{lowticket-metodologia → wizz-lowticket-metodologia}/knowledge/09-especialista-coproducao.md +0 -0
- /package/src/modules/lowticket/skills/{lowticket-metodologia → wizz-lowticket-metodologia}/knowledge/10-levantar-caixa.md +0 -0
- /package/src/modules/lowticket/skills/{lowticket-metodologia → wizz-lowticket-metodologia}/knowledge/11-checklist-roi.md +0 -0
- /package/src/modules/lowticket/skills/{lowticket-metodologia → wizz-lowticket-metodologia}/knowledge/12-mineracao-ofertas.md +0 -0
- /package/src/modules/lowticket/skills/{lowticket-metodologia → wizz-lowticket-metodologia}/knowledge/12a-mineracao-veredito.md +0 -0
- /package/src/modules/lowticket/skills/{lowticket-metodologia → wizz-lowticket-metodologia}/knowledge/12b-fabrica-de-ofertas.md +0 -0
- /package/src/modules/lowticket/skills/{lowticket-metodologia → wizz-lowticket-metodologia}/knowledge/12c-anatomia-low-ticket.md +0 -0
- /package/src/modules/lowticket/skills/{lowticket-metodologia → wizz-lowticket-metodologia}/knowledge/13-benchmarks-vsl.md +0 -0
- /package/src/modules/lowticket/skills/{lowticket-metodologia → wizz-lowticket-metodologia}/knowledge/14-vocabulario.md +0 -0
- /package/src/modules/lowticket/skills/{lowticket-metodologia → wizz-lowticket-metodologia}/knowledge/15-como-estender.md +0 -0
- /package/src/modules/lowticket/skills/{lowticket-metodologia → wizz-lowticket-metodologia}/knowledge/17-rastreamento.md +0 -0
- /package/src/modules/lowticket/skills/{lowticket-metodologia → wizz-lowticket-metodologia}/knowledge/18-copy-desejo-oferta.md +0 -0
- /package/src/modules/lowticket/skills/{lowticket-metodologia → wizz-lowticket-metodologia}/knowledge/INDEX.md +0 -0
- /package/src/modules/lowticket/skills/{lowticket-metodologia → wizz-lowticket-metodologia}/knowledge/guardrails.md +0 -0
- /package/src/modules/lowticket/skills/{lowticket-metodologia → wizz-lowticket-metodologia}/knowledge/pontos-em-aberto.md +0 -0
- /package/src/modules/lowticket/skills/{lowticket-metodologia → wizz-lowticket-metodologia}/references/swipe-file.md +0 -0
- /package/src/modules/lowticket/skills/{lowticket-pagina → wizz-lowticket-pagina}/references/metas-e-medicao.md +0 -0
- /package/src/modules/lowticket/skills/{lowticket-pagina → wizz-lowticket-pagina}/references/padroes-de-codigo.md +0 -0
- /package/src/modules/lowticket/skills/{lowticket-trafego → wizz-lowticket-trafego}/references/formato-do-diagnostico.md +0 -0
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
// Shared `--pin CODE=TAG@SHA` value parsing, used by BOTH download paths so
|
|
2
|
+
// their pin format and error messages can't diverge:
|
|
3
|
+
// - channel-plan.js (CLI gate — item 8b, auditoria 2026-09-11: a malformed
|
|
4
|
+
// pin must fail here, before any clone runs)
|
|
5
|
+
// - external-manager.js and custom-module-manager.js (post-clone trust
|
|
6
|
+
// check — item 8 fase 2 / item 8c)
|
|
7
|
+
//
|
|
8
|
+
// This module must stay a leaf: it is required by channel-plan.js, which is
|
|
9
|
+
// itself required by external-manager.js — importing anything that pulls
|
|
10
|
+
// prompts/git back in would create a require cycle.
|
|
11
|
+
|
|
12
|
+
// Exactly 40 hex chars — a git full SHA. Short (abbreviated) SHAs are
|
|
13
|
+
// rejected on purpose (item 8b: "prefira rejeitar: simples e seguro"): a
|
|
14
|
+
// prefix compare quietly trusts whatever commit currently sits at that
|
|
15
|
+
// prefix, which is exactly the ambiguity a pin exists to remove.
|
|
16
|
+
const PIN_SHA_PATTERN = /^[0-9a-f]{40}$/i;
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Split a `--pin CODE=<value>` value into its tag and (optional) expected
|
|
20
|
+
* SHA, item 8 fase 2 (auditoria 2026-09-11, EXT-02 / IM-ACH-06). Accepts
|
|
21
|
+
* either:
|
|
22
|
+
* - "TAG" → { tag: 'TAG', expectedSha: null }
|
|
23
|
+
* - "TAG@SHA" → { tag: 'TAG', expectedSha: 'sha' (lowercased) }
|
|
24
|
+
*
|
|
25
|
+
* `channel-plan.js#parsePinSpec` only splits `CODE=<value>` and hands us
|
|
26
|
+
* `<value>` verbatim as an opaque string — it doesn't know about `@SHA`, so
|
|
27
|
+
* that split and this validation both live here. Same posture as
|
|
28
|
+
* `validateShellRef`/`validateCustomRef`: defensive shape check, throws
|
|
29
|
+
* loudly on a malformed value instead of silently degrading to a tag-only
|
|
30
|
+
* pin or forwarding something unchecked into `git`/the GitHub API.
|
|
31
|
+
*
|
|
32
|
+
* @param {string} rawPin - the value after `CODE=` in a --pin flag
|
|
33
|
+
* @returns {{tag: string, expectedSha: string|null}}
|
|
34
|
+
*/
|
|
35
|
+
function parsePinTagAndSha(rawPin) {
|
|
36
|
+
if (typeof rawPin !== 'string' || !rawPin) {
|
|
37
|
+
throw new Error(`Unsafe pin value: ${JSON.stringify(rawPin)}`);
|
|
38
|
+
}
|
|
39
|
+
const atIndex = rawPin.indexOf('@');
|
|
40
|
+
if (atIndex === -1) {
|
|
41
|
+
return { tag: rawPin, expectedSha: null };
|
|
42
|
+
}
|
|
43
|
+
const tag = rawPin.slice(0, atIndex);
|
|
44
|
+
const shaRaw = rawPin.slice(atIndex + 1);
|
|
45
|
+
if (!tag || !PIN_SHA_PATTERN.test(shaRaw)) {
|
|
46
|
+
throw new Error(
|
|
47
|
+
`Invalid --pin value ${JSON.stringify(rawPin)}. Expected TAG or TAG@40-hex-sha, where SHA is the full 40-character hex git commit SHA (e.g. --pin module=v1.7.0@0123456789abcdef0123456789abcdef01234567).`,
|
|
48
|
+
);
|
|
49
|
+
}
|
|
50
|
+
return { tag, expectedSha: shaRaw.toLowerCase() };
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Inverse of parsePinTagAndSha: build the `TAG` or `TAG@SHA` string a
|
|
55
|
+
* `channelOptions.pins` entry is expected to hold, from a tag and an
|
|
56
|
+
* optional expected SHA. Used wherever a pin is rebuilt from stored state
|
|
57
|
+
* (e.g. quick-update rebuilding it from a manifest entry's `version` +
|
|
58
|
+
* `shaRequested` — item 10, review da fase 3 2026-09-11) instead of
|
|
59
|
+
* hand-concatenating `${tag}@${sha}` at each call site.
|
|
60
|
+
* @param {string} tag
|
|
61
|
+
* @param {string|null|undefined} [expectedSha]
|
|
62
|
+
* @returns {string}
|
|
63
|
+
*/
|
|
64
|
+
function formatPinValue(tag, expectedSha) {
|
|
65
|
+
return expectedSha ? `${tag}@${expectedSha}` : tag;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Resolve the effective raw pin ("TAG" or "TAG@SHA") for one clone call:
|
|
70
|
+
* an explicit `options.pinOverride` always wins; otherwise, when the caller
|
|
71
|
+
* passed `options.channelOptions` (parseChannelOptions' output) and a
|
|
72
|
+
* lookup `key`, look it up in `channelOptions.pins`.
|
|
73
|
+
*
|
|
74
|
+
* Bug 8 (review da fase 3, 2026-09-11): custom-module-manager.js's cloneRepo
|
|
75
|
+
* keys this by `parsed.displayName` ("owner/repo", or a local dir's
|
|
76
|
+
* basename) — a custom module's plugin code isn't known until AFTER the
|
|
77
|
+
* clone, so `--pin CODE=...` can't be keyed by plugin code at clone time.
|
|
78
|
+
* See docs/how-to/install-wizz.md.
|
|
79
|
+
*
|
|
80
|
+
* @param {{pinOverride?: string|null, channelOptions?: {pins?: Map<string,string>}}} options
|
|
81
|
+
* @param {string|null|undefined} key
|
|
82
|
+
* @returns {string|null}
|
|
83
|
+
*/
|
|
84
|
+
function resolvePinOverride(options, key) {
|
|
85
|
+
if (options?.pinOverride) return options.pinOverride;
|
|
86
|
+
const fromChannelOptions = key ? options?.channelOptions?.pins?.get(key) : null;
|
|
87
|
+
return fromChannelOptions || null;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* Build the error for a post-clone `TAG@SHA` mismatch (item 8 fase 2 / 8c).
|
|
92
|
+
* Two flavors, picked by `fetchFailed` (bug 4, review da fase 3,
|
|
93
|
+
* 2026-09-11): when the fetch/update that preceded this compare failed
|
|
94
|
+
* (network down, repo moved, our own timeout), the mismatch was only ever
|
|
95
|
+
* checked against a stale cached checkout — the message must say the
|
|
96
|
+
* remote couldn't be reached, not claim the tag moved (that was never
|
|
97
|
+
* verified). Otherwise this ran against a fresh clone, so a real mismatch
|
|
98
|
+
* does mean the tag points somewhere else than expected.
|
|
99
|
+
*
|
|
100
|
+
* Callers remove the (now-untrusted) cache dir themselves before throwing
|
|
101
|
+
* this — building the Error here doesn't touch the filesystem.
|
|
102
|
+
*
|
|
103
|
+
* @param {Object} args
|
|
104
|
+
* @param {string} args.displayName - Human label for the module/source.
|
|
105
|
+
* @param {string} args.tag - The tag half of the pin.
|
|
106
|
+
* @param {string|null} args.resolvedSha - The actual checked-out SHA, if known.
|
|
107
|
+
* @param {string} args.expectedSha - The SHA half of the pin.
|
|
108
|
+
* @param {string} args.pinDisplay - `CODE=TAG@SHA`, echoed in the message.
|
|
109
|
+
* @param {boolean} args.fetchFailed
|
|
110
|
+
* @returns {Error}
|
|
111
|
+
*/
|
|
112
|
+
function buildPinMismatchError({ displayName, tag, resolvedSha, expectedSha, pinDisplay, fetchFailed }) {
|
|
113
|
+
const shaText = resolvedSha || '(desconhecido)';
|
|
114
|
+
if (fetchFailed) {
|
|
115
|
+
return new Error(
|
|
116
|
+
`Não foi possível acessar o repositório remoto para atualizar ${displayName}, e o checkout em cache não corresponde ao pin ` +
|
|
117
|
+
`solicitado (--pin ${pinDisplay}): SHA em cache ${shaText}, esperado ${expectedSha}.`,
|
|
118
|
+
);
|
|
119
|
+
}
|
|
120
|
+
return new Error(
|
|
121
|
+
`Tag '${tag}' aponta para o SHA ${shaText}, esperado ${expectedSha} (--pin ${pinDisplay}); a tag pode ter sido movida no repositório remoto.`,
|
|
122
|
+
);
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
module.exports = { parsePinTagAndSha, formatPinValue, resolvePinOverride, buildPinMismatchError, PIN_SHA_PATTERN };
|
|
@@ -87,6 +87,7 @@ class PluginResolver {
|
|
|
87
87
|
name: moduleData.name || plugin.name,
|
|
88
88
|
version: plugin.version || moduleData.module_version || null,
|
|
89
89
|
description: moduleData.description || plugin.description || '',
|
|
90
|
+
interfaceVersion: moduleData.interface_version,
|
|
90
91
|
strategy: 1,
|
|
91
92
|
pluginName: plugin.name,
|
|
92
93
|
moduleYamlPath,
|
|
@@ -124,6 +125,7 @@ class PluginResolver {
|
|
|
124
125
|
name: moduleData.name || plugin.name,
|
|
125
126
|
version: plugin.version || moduleData.module_version || null,
|
|
126
127
|
description: moduleData.description || plugin.description || '',
|
|
128
|
+
interfaceVersion: moduleData.interface_version,
|
|
127
129
|
strategy: 2,
|
|
128
130
|
pluginName: plugin.name,
|
|
129
131
|
moduleYamlPath,
|
|
@@ -163,6 +165,7 @@ class PluginResolver {
|
|
|
163
165
|
name: moduleData.name || plugin.name,
|
|
164
166
|
version: plugin.version || moduleData.module_version || null,
|
|
165
167
|
description: moduleData.description || plugin.description || '',
|
|
168
|
+
interfaceVersion: moduleData.interface_version,
|
|
166
169
|
strategy: 3,
|
|
167
170
|
pluginName: plugin.name,
|
|
168
171
|
moduleYamlPath,
|
|
@@ -201,6 +204,7 @@ class PluginResolver {
|
|
|
201
204
|
name: moduleData.name || path.basename(skillPath),
|
|
202
205
|
version: plugin.version || moduleData.module_version || null,
|
|
203
206
|
description: moduleData.description || '',
|
|
207
|
+
interfaceVersion: moduleData.interface_version,
|
|
204
208
|
strategy: 4,
|
|
205
209
|
pluginName: plugin.name,
|
|
206
210
|
moduleYamlPath,
|
|
@@ -24,6 +24,7 @@ const path = require('node:path');
|
|
|
24
24
|
const fs = require('../fs-native');
|
|
25
25
|
const yaml = require('yaml');
|
|
26
26
|
const { getProjectRoot, getSourcePath } = require('../project-root');
|
|
27
|
+
const { loadYamlCached } = require('../core/yaml-cache');
|
|
27
28
|
const { resolveAreaEntries } = require('./registry-resolve');
|
|
28
29
|
|
|
29
30
|
/**
|
|
@@ -158,12 +159,8 @@ async function installSkillsLib({ wizzDir, selectedAreas, trackFile = () => {} }
|
|
|
158
159
|
return { copied: 0, skipped: [], registry: false };
|
|
159
160
|
}
|
|
160
161
|
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
registry = yaml.parse(await fs.readFile(srcRegistry, 'utf8'));
|
|
164
|
-
} catch (error) {
|
|
165
|
-
throw new Error(`Failed to parse skills-registry.yaml: ${error.message}`);
|
|
166
|
-
}
|
|
162
|
+
// Memoized: ui.js already parsed this same file during selection (ACH-07).
|
|
163
|
+
const registry = await loadYamlCached(srcRegistry);
|
|
167
164
|
|
|
168
165
|
const ids = resolveSkillIds(registry, selectedAreas);
|
|
169
166
|
const destLib = path.join(wizzDir, 'skills-lib');
|
|
@@ -771,9 +771,7 @@ async function prompt(questions) {
|
|
|
771
771
|
}
|
|
772
772
|
|
|
773
773
|
module.exports = {
|
|
774
|
-
getClack,
|
|
775
774
|
getColor,
|
|
776
|
-
handleCancel,
|
|
777
775
|
intro,
|
|
778
776
|
outro,
|
|
779
777
|
cancel,
|
|
@@ -783,7 +781,6 @@ module.exports = {
|
|
|
783
781
|
select,
|
|
784
782
|
multiselect,
|
|
785
783
|
autocompleteMultiselect,
|
|
786
|
-
autocomplete,
|
|
787
784
|
directory,
|
|
788
785
|
confirm,
|
|
789
786
|
text,
|
package/tools/installer/ui.js
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
const path = require('node:path');
|
|
2
2
|
const os = require('node:os');
|
|
3
3
|
const semver = require('semver');
|
|
4
|
-
const yaml = require('yaml');
|
|
5
4
|
const fs = require('./fs-native');
|
|
6
5
|
const { getProjectRoot } = require('./project-root');
|
|
7
6
|
const installerPackageJson = require('../../package.json');
|
|
@@ -9,6 +8,8 @@ const { CLIUtils } = require('./banner');
|
|
|
9
8
|
const { ExternalModuleManager } = require('./modules/external-manager');
|
|
10
9
|
const { resolveModuleVersion } = require('./modules/version-resolver');
|
|
11
10
|
const { Manifest } = require('./core/manifest');
|
|
11
|
+
const { findWizzDir } = require('./core/installer');
|
|
12
|
+
const { loadYamlCached } = require('./core/yaml-cache');
|
|
12
13
|
const {
|
|
13
14
|
parseChannelOptions,
|
|
14
15
|
buildPlan,
|
|
@@ -17,6 +18,11 @@ const {
|
|
|
17
18
|
bundledTargetWarnings,
|
|
18
19
|
} = require('./modules/channel-plan');
|
|
19
20
|
const channelResolver = require('./modules/channel-resolver');
|
|
21
|
+
// Bug 5 (review da fase 3, 2026-09-11): the interactive "pin to a version"
|
|
22
|
+
// prompt validators below used to reject '@' outright, so a user could never
|
|
23
|
+
// type TAG@SHA at the prompt (only --pin from the CLI could). Validate with
|
|
24
|
+
// the same parser the CLI gate uses instead of a bare tag-chars regex.
|
|
25
|
+
const { parsePinTagAndSha } = require('./modules/pin-spec');
|
|
20
26
|
const { resolveMcps, partitionGloballyConfigured } = require('./modules/mcp-config');
|
|
21
27
|
const { resolveClis, detectClis } = require('./modules/cli-config');
|
|
22
28
|
const prompts = require('./prompts');
|
|
@@ -42,6 +48,35 @@ function formatDisplayVersion(version) {
|
|
|
42
48
|
return trimmed;
|
|
43
49
|
}
|
|
44
50
|
|
|
51
|
+
// Bare tag chars: letters, digits, dots, hyphens, plus, slash. Same shape
|
|
52
|
+
// the interactive picker always accepted; TAG@SHA additionally requires
|
|
53
|
+
// parsePinTagAndSha's 40-hex-SHA half to validate (item 8c/bug 5).
|
|
54
|
+
const PIN_TAG_CHARS_RE = /^[\w.\-+/]+$/;
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Validate a value typed at the interactive "pin to a version" prompt.
|
|
58
|
+
* Accepts a bare tag ("v1.6.0") or TAG@SHA ("v1.6.0@<40-hex-sha>") — the
|
|
59
|
+
* same two forms `--pin CODE=...` accepts on the CLI (pin-spec.js).
|
|
60
|
+
* @param {string} value
|
|
61
|
+
* @returns {string|undefined} Error message, or undefined when valid.
|
|
62
|
+
*/
|
|
63
|
+
function validatePinTagInput(value) {
|
|
64
|
+
const trimmed = String(value || '').trim();
|
|
65
|
+
if (!trimmed) return 'Must be a non-empty tag name (letters, digits, dots, hyphens), optionally TAG@40-hex-sha.';
|
|
66
|
+
if (!trimmed.includes('@')) {
|
|
67
|
+
if (!PIN_TAG_CHARS_RE.test(trimmed)) return 'Must be a non-empty tag name (letters, digits, dots, hyphens).';
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
try {
|
|
71
|
+
const { tag } = parsePinTagAndSha(trimmed);
|
|
72
|
+
if (!PIN_TAG_CHARS_RE.test(tag)) {
|
|
73
|
+
return 'Must be a non-empty tag name (letters, digits, dots, hyphens), optionally TAG@40-hex-sha.';
|
|
74
|
+
}
|
|
75
|
+
} catch (error) {
|
|
76
|
+
return error.message;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
45
80
|
/**
|
|
46
81
|
* Build the display label for a module, showing an upgrade arrow when an
|
|
47
82
|
* installed semver differs from the latest resolvable semver.
|
|
@@ -204,15 +239,15 @@ class UI {
|
|
|
204
239
|
const messageLoader = new MessageLoader();
|
|
205
240
|
await messageLoader.displayStartMessage();
|
|
206
241
|
|
|
207
|
-
// Probe the local Python before any other prompts
|
|
208
|
-
// (
|
|
209
|
-
//
|
|
210
|
-
//
|
|
211
|
-
//
|
|
212
|
-
//
|
|
213
|
-
//
|
|
242
|
+
// Probe the local Python before any other prompts. Since audit item 29
|
|
243
|
+
// (2026-09-12) this is INFORMATIONAL only: Node is the sole prerequisite
|
|
244
|
+
// of the core, and Python buys the user the handful of BMAD skills that
|
|
245
|
+
// ship their own Python scripts. It logs one line, never blocks, and no
|
|
246
|
+
// longer asks for an acknowledgement — there is nothing to acknowledge.
|
|
247
|
+
// The installer runs in the destination environment, so probing PATH
|
|
248
|
+
// here tests the right machine.
|
|
214
249
|
const { checkPythonEnvironment } = require('./core/python-check');
|
|
215
|
-
await checkPythonEnvironment(
|
|
250
|
+
await checkPythonEnvironment();
|
|
216
251
|
|
|
217
252
|
// Parse channel flags (--channel/--all-*/--next=/--pin) once. Warnings
|
|
218
253
|
// are surfaced immediately so the user sees them before any git ops run.
|
|
@@ -254,9 +289,7 @@ class UI {
|
|
|
254
289
|
confirmedDirectory = await this.getConfirmedDirectory();
|
|
255
290
|
}
|
|
256
291
|
|
|
257
|
-
const {
|
|
258
|
-
const installer = new Installer();
|
|
259
|
-
const { wizzDir } = await installer.findWizzDir(confirmedDirectory);
|
|
292
|
+
const { wizzDir } = findWizzDir(confirmedDirectory);
|
|
260
293
|
|
|
261
294
|
// Check if there's an existing WIZZ installation
|
|
262
295
|
const hasExistingInstall = await fs.pathExists(wizzDir);
|
|
@@ -358,7 +391,7 @@ class UI {
|
|
|
358
391
|
|
|
359
392
|
// Resolve custom sources from --custom-source flag
|
|
360
393
|
if (options.customSource) {
|
|
361
|
-
const customCodes = await this._resolveCustomSourcesCli(options.customSource);
|
|
394
|
+
const customCodes = await this._resolveCustomSourcesCli(options.customSource, channelOptions);
|
|
362
395
|
for (const code of customCodes) {
|
|
363
396
|
if (!selectedModules.includes(code)) selectedModules.push(code);
|
|
364
397
|
}
|
|
@@ -460,7 +493,7 @@ class UI {
|
|
|
460
493
|
|
|
461
494
|
// Resolve custom sources from --custom-source flag
|
|
462
495
|
if (options.customSource) {
|
|
463
|
-
const customCodes = await this._resolveCustomSourcesCli(options.customSource);
|
|
496
|
+
const customCodes = await this._resolveCustomSourcesCli(options.customSource, channelOptions);
|
|
464
497
|
for (const code of customCodes) {
|
|
465
498
|
if (!selectedModules.includes(code)) selectedModules.push(code);
|
|
466
499
|
}
|
|
@@ -534,18 +567,19 @@ class UI {
|
|
|
534
567
|
}
|
|
535
568
|
|
|
536
569
|
/**
|
|
537
|
-
* Load and parse skills-registry.yaml from the package root
|
|
570
|
+
* Load and parse skills-registry.yaml from the package root, memoized per
|
|
571
|
+
* absolute path (audit 2026-09-11 ACH-07: this used to be a plain
|
|
572
|
+
* readFileSync + yaml.parse called 3x per install with no cache).
|
|
538
573
|
* A corrupted/unparsable registry still degrades to null (areas/MCPs/CLIs
|
|
539
574
|
* come back empty rather than crashing the install), but that degradation
|
|
540
575
|
* is never silent: it is logged so the failure is diagnosable instead of
|
|
541
576
|
* looking like "nothing to choose from" (audit finding M11).
|
|
542
|
-
* @returns {Object|null} Parsed registry, or null when absent/unreadable
|
|
577
|
+
* @returns {Promise<Object|null>} Parsed registry, or null when absent/unreadable
|
|
543
578
|
*/
|
|
544
|
-
_loadSkillsRegistry() {
|
|
579
|
+
async _loadSkillsRegistry() {
|
|
545
580
|
const registryPath = path.join(getProjectRoot(), 'skills-registry.yaml');
|
|
546
|
-
if (!fs.existsSync(registryPath)) return null;
|
|
547
581
|
try {
|
|
548
|
-
return
|
|
582
|
+
return await loadYamlCached(registryPath);
|
|
549
583
|
} catch (error) {
|
|
550
584
|
console.warn(`⚠ skills-registry.yaml failed to parse (${error.message}). Areas/MCPs/CLIs will be empty until this is fixed.`);
|
|
551
585
|
return null;
|
|
@@ -564,7 +598,7 @@ class UI {
|
|
|
564
598
|
async selectSkillAreas(selectedModules, options = {}) {
|
|
565
599
|
if (!selectedModules.includes('bmm')) return [];
|
|
566
600
|
|
|
567
|
-
const registry = this._loadSkillsRegistry();
|
|
601
|
+
const registry = await this._loadSkillsRegistry();
|
|
568
602
|
if (!registry || !registry.areas) return [];
|
|
569
603
|
const areaKeys = Object.keys(registry.areas);
|
|
570
604
|
if (areaKeys.length === 0) return [];
|
|
@@ -620,7 +654,7 @@ class UI {
|
|
|
620
654
|
async selectMcps(selectedModules, selectedAreas, options = {}) {
|
|
621
655
|
if (!selectedModules.includes('bmm')) return { toWrite: [], toRecommend: [] };
|
|
622
656
|
|
|
623
|
-
const registry = this._loadSkillsRegistry();
|
|
657
|
+
const registry = await this._loadSkillsRegistry();
|
|
624
658
|
let resolved = resolveMcps(registry, selectedAreas);
|
|
625
659
|
if (resolved.length === 0) return { toWrite: [], toRecommend: [] };
|
|
626
660
|
|
|
@@ -702,7 +736,7 @@ class UI {
|
|
|
702
736
|
const empty = { toInstall: [], toRecommend: [], alreadyInstalled: [] };
|
|
703
737
|
if (!selectedModules.includes('bmm')) return empty;
|
|
704
738
|
|
|
705
|
-
const registry = this._loadSkillsRegistry();
|
|
739
|
+
const registry = await this._loadSkillsRegistry();
|
|
706
740
|
const resolved = resolveClis(registry, selectedAreas);
|
|
707
741
|
if (resolved.length === 0) return empty;
|
|
708
742
|
|
|
@@ -849,9 +883,7 @@ class UI {
|
|
|
849
883
|
|
|
850
884
|
async promptToolSelection(projectDir, options = {}) {
|
|
851
885
|
const { ExistingInstall } = require('./core/existing-install');
|
|
852
|
-
const {
|
|
853
|
-
const installer = new Installer();
|
|
854
|
-
const { wizzDir } = await installer.findWizzDir(projectDir || process.cwd());
|
|
886
|
+
const { wizzDir } = findWizzDir(projectDir || process.cwd());
|
|
855
887
|
const existingInstall = await ExistingInstall.detect(wizzDir);
|
|
856
888
|
const configuredIdes = existingInstall.ides;
|
|
857
889
|
|
|
@@ -1084,9 +1116,7 @@ class UI {
|
|
|
1084
1116
|
*/
|
|
1085
1117
|
async getExistingInstallation(directory) {
|
|
1086
1118
|
const { ExistingInstall } = require('./core/existing-install');
|
|
1087
|
-
const {
|
|
1088
|
-
const installer = new Installer();
|
|
1089
|
-
const { wizzDir } = await installer.findWizzDir(directory);
|
|
1119
|
+
const { wizzDir } = findWizzDir(directory);
|
|
1090
1120
|
const existingInstall = await ExistingInstall.detect(wizzDir);
|
|
1091
1121
|
const installedModuleIds = new Set(existingInstall.moduleIds);
|
|
1092
1122
|
const installedModuleVersions = new Map();
|
|
@@ -1236,7 +1266,7 @@ class UI {
|
|
|
1236
1266
|
const installedNonOfficial = [...installedModuleIds].filter((id) => !officialRegistryCodes.has(id));
|
|
1237
1267
|
|
|
1238
1268
|
// Phase 2: Custom URL modules
|
|
1239
|
-
const customSelected = await this._addCustomUrlModules(installedModuleIds);
|
|
1269
|
+
const customSelected = await this._addCustomUrlModules(installedModuleIds, channelOptions);
|
|
1240
1270
|
|
|
1241
1271
|
const allSelected = new Set([...officialSelected, ...customSelected, ...installedNonOfficial]);
|
|
1242
1272
|
|
|
@@ -1361,7 +1391,7 @@ class UI {
|
|
|
1361
1391
|
* @param {Set} installedModuleIds - Currently installed module IDs
|
|
1362
1392
|
* @returns {Array} Selected custom module code strings
|
|
1363
1393
|
*/
|
|
1364
|
-
async _addCustomUrlModules(installedModuleIds = new Set()) {
|
|
1394
|
+
async _addCustomUrlModules(installedModuleIds = new Set(), channelOptions = null) {
|
|
1365
1395
|
const addCustom = await prompts.confirm({
|
|
1366
1396
|
message: 'Do you want to install custom or community modules (Git URL or local path)?',
|
|
1367
1397
|
default: false,
|
|
@@ -1379,8 +1409,16 @@ class UI {
|
|
|
1379
1409
|
placeholder: 'https://github.com/owner/repo or /path/to/module',
|
|
1380
1410
|
validate: (input) => {
|
|
1381
1411
|
if (!input || input.trim() === '') return 'Source is required';
|
|
1382
|
-
|
|
1383
|
-
|
|
1412
|
+
try {
|
|
1413
|
+
const result = customMgr.parseSource(input.trim());
|
|
1414
|
+
return result.isValid ? undefined : result.error;
|
|
1415
|
+
} catch (error) {
|
|
1416
|
+
// parseSource() throws for SSH URLs whose host/owner/repo contain
|
|
1417
|
+
// characters that could not be safely handed to git — surface
|
|
1418
|
+
// that as an inline validation message instead of crashing the
|
|
1419
|
+
// prompt.
|
|
1420
|
+
return error.message;
|
|
1421
|
+
}
|
|
1384
1422
|
},
|
|
1385
1423
|
});
|
|
1386
1424
|
|
|
@@ -1389,7 +1427,13 @@ class UI {
|
|
|
1389
1427
|
|
|
1390
1428
|
let sourceResult;
|
|
1391
1429
|
try {
|
|
1392
|
-
|
|
1430
|
+
// Bug 8 (review da fase 3, 2026-09-11): thread channelOptions through
|
|
1431
|
+
// so a `--pin CODE=TAG@SHA` targeting this source's displayName
|
|
1432
|
+
// (owner/repo, or the local dir basename) is honored and SHA-checked
|
|
1433
|
+
// by cloneRepo — see the pin-lookup block near custom-module-manager.js's
|
|
1434
|
+
// cloneRepo, keyed by parsed.displayName since the plugin code isn't
|
|
1435
|
+
// known until after this clone.
|
|
1436
|
+
sourceResult = await customMgr.resolveSource(sourceInput.trim(), { skipInstall: true, silent: true, channelOptions });
|
|
1393
1437
|
s.stop(sourceResult.parsed.type === 'local' ? 'Local source resolved' : 'Repository cloned');
|
|
1394
1438
|
} catch (error) {
|
|
1395
1439
|
s.error('Failed to resolve source');
|
|
@@ -1541,9 +1585,10 @@ class UI {
|
|
|
1541
1585
|
* Resolve custom sources from --custom-source CLI flag (non-interactive).
|
|
1542
1586
|
* Auto-selects all discovered modules from each source.
|
|
1543
1587
|
* @param {string} sourcesArg - Comma-separated Git URLs or local paths
|
|
1588
|
+
* @param {Object|null} channelOptions - Parsed installer channel options (for --pin CODE=TAG@SHA)
|
|
1544
1589
|
* @returns {Array} Module codes from all resolved sources
|
|
1545
1590
|
*/
|
|
1546
|
-
async _resolveCustomSourcesCli(sourcesArg) {
|
|
1591
|
+
async _resolveCustomSourcesCli(sourcesArg, channelOptions = null) {
|
|
1547
1592
|
const { CustomModuleManager } = require('./modules/custom-module-manager');
|
|
1548
1593
|
const customMgr = new CustomModuleManager();
|
|
1549
1594
|
const allCodes = [];
|
|
@@ -1559,7 +1604,9 @@ class UI {
|
|
|
1559
1604
|
|
|
1560
1605
|
let sourceResult;
|
|
1561
1606
|
try {
|
|
1562
|
-
|
|
1607
|
+
// Bug 8 (review da fase 3, 2026-09-11): see the matching comment in
|
|
1608
|
+
// _addCustomUrlModules — same pin-by-displayName wiring, CLI path.
|
|
1609
|
+
sourceResult = await customMgr.resolveSource(source, { skipInstall: true, silent: true, channelOptions });
|
|
1563
1610
|
s.stop(sourceResult.parsed.type === 'local' ? 'Local source resolved' : 'Repository cloned');
|
|
1564
1611
|
} catch (error) {
|
|
1565
1612
|
s.error(`Failed to resolve ${source}`);
|
|
@@ -1711,9 +1758,7 @@ class UI {
|
|
|
1711
1758
|
const files = await fs.readdir(directory);
|
|
1712
1759
|
if (files.length > 0) {
|
|
1713
1760
|
// Check for any wizz installation (any folder with _config/manifest.yaml)
|
|
1714
|
-
const
|
|
1715
|
-
const installer = new Installer();
|
|
1716
|
-
const wizzResult = await installer.findWizzDir(directory);
|
|
1761
|
+
const wizzResult = findWizzDir(directory);
|
|
1717
1762
|
const hasWizzInstall =
|
|
1718
1763
|
(await fs.pathExists(wizzResult.wizzDir)) && (await fs.pathExists(path.join(wizzResult.wizzDir, '_config', 'manifest.yaml')));
|
|
1719
1764
|
|
|
@@ -1954,9 +1999,7 @@ class UI {
|
|
|
1954
1999
|
*/
|
|
1955
2000
|
async getConfiguredIdes(directory) {
|
|
1956
2001
|
const { ExistingInstall } = require('./core/existing-install');
|
|
1957
|
-
const {
|
|
1958
|
-
const installer = new Installer();
|
|
1959
|
-
const { wizzDir } = await installer.findWizzDir(directory);
|
|
2002
|
+
const { wizzDir } = findWizzDir(directory);
|
|
1960
2003
|
const existingInstall = await ExistingInstall.detect(wizzDir);
|
|
1961
2004
|
return existingInstall.ides;
|
|
1962
2005
|
}
|
|
@@ -2180,12 +2223,8 @@ class UI {
|
|
|
2180
2223
|
channelOptions.nextSet.add(code);
|
|
2181
2224
|
} else if (choice === 'pin') {
|
|
2182
2225
|
const pinValue = await prompts.text({
|
|
2183
|
-
message: `Enter a version tag for '${code}' (e.g. v1.6.0):`,
|
|
2184
|
-
validate:
|
|
2185
|
-
if (!value || !/^[\w.\-+/]+$/.test(String(value).trim())) {
|
|
2186
|
-
return 'Must be a non-empty tag name (letters, digits, dots, hyphens).';
|
|
2187
|
-
}
|
|
2188
|
-
},
|
|
2226
|
+
message: `Enter a version tag for '${code}' (e.g. v1.6.0, or TAG@40-hex-sha to also pin the commit):`,
|
|
2227
|
+
validate: validatePinTagInput,
|
|
2189
2228
|
});
|
|
2190
2229
|
channelOptions.pins.set(code, String(pinValue).trim());
|
|
2191
2230
|
}
|
|
@@ -2312,12 +2351,8 @@ class UI {
|
|
|
2312
2351
|
}
|
|
2313
2352
|
if (choice === 'pin') {
|
|
2314
2353
|
const pinValue = await prompts.text({
|
|
2315
|
-
message: `Enter a version tag for '${code}' (e.g. v1.6.0):`,
|
|
2316
|
-
validate:
|
|
2317
|
-
if (!value || !/^[\w.\-+/]+$/.test(String(value).trim())) {
|
|
2318
|
-
return 'Must be a non-empty tag name (letters, digits, dots, hyphens).';
|
|
2319
|
-
}
|
|
2320
|
-
},
|
|
2354
|
+
message: `Enter a version tag for '${code}' (e.g. v1.6.0, or TAG@40-hex-sha to also pin the commit):`,
|
|
2355
|
+
validate: validatePinTagInput,
|
|
2321
2356
|
});
|
|
2322
2357
|
channelOptions.pins.set(code, String(pinValue).trim());
|
|
2323
2358
|
continue;
|
|
@@ -2429,4 +2464,4 @@ class UI {
|
|
|
2429
2464
|
}
|
|
2430
2465
|
}
|
|
2431
2466
|
|
|
2432
|
-
module.exports = { UI };
|
|
2467
|
+
module.exports = { UI, validatePinTagInput };
|
|
@@ -81,7 +81,7 @@ for (const file of commandFiles) {
|
|
|
81
81
|
}
|
|
82
82
|
|
|
83
83
|
// Set up main program
|
|
84
|
-
program.version(packageJson.version).description('Wizz Method CLI
|
|
84
|
+
program.version(packageJson.version).description('Wizz Method CLI: método de agência orientado por IA');
|
|
85
85
|
|
|
86
86
|
// Register all commands
|
|
87
87
|
for (const [name, cmd] of Object.entries(commands)) {
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
// Parsers de frontmatter compartilhados pelos validadores do repo.
|
|
2
|
+
//
|
|
3
|
+
// M15 (auditoria 2026-07-07): `parseFrontmatter` estava reimplementado em
|
|
4
|
+
// validate-method-refs.js (via `yaml.parse`, estrito) e 2x em
|
|
5
|
+
// validate-skills.js (parser manual linha-a-linha, tolerante). As três
|
|
6
|
+
// variantes têm comportamento DIFERENTE de propósito — cada validador
|
|
7
|
+
// depende de nuances distintas — então esta lib não as funde numa só; ela
|
|
8
|
+
// só para de duplicar a implementação, centralizando as 3 num único lugar
|
|
9
|
+
// com nome próprio para cada uma:
|
|
10
|
+
// - parseFrontmatterYaml: `yaml.parse` real (estrito: só reconhece o
|
|
11
|
+
// fechamento `\n---\n`; um `---` final sem newline devolve null).
|
|
12
|
+
// - parseFrontmatterSimple: parser manual linha-a-linha; ignora linhas
|
|
13
|
+
// indentadas (valores aninhados) e NÃO junta continuações multi-linha.
|
|
14
|
+
// - parseFrontmatterMultiline: parser manual que junta continuações de
|
|
15
|
+
// valor (descriptions que ocupam várias linhas) na mesma chave.
|
|
16
|
+
// parseFrontmatterSimple e parseFrontmatterMultiline aceitam o fechamento
|
|
17
|
+
// tolerante (`---` final sem newline) que parseFrontmatterYaml não aceita —
|
|
18
|
+
// preservando o comportamento exato que validate-skills.js já tinha.
|
|
19
|
+
|
|
20
|
+
const yaml = require('yaml');
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Remove aspas simples/duplas envolvendo o valor, se houver.
|
|
24
|
+
* @param {string} value
|
|
25
|
+
* @returns {string}
|
|
26
|
+
*/
|
|
27
|
+
function stripQuotes(value) {
|
|
28
|
+
if ((value.startsWith("'") && value.endsWith("'")) || (value.startsWith('"') && value.endsWith('"'))) {
|
|
29
|
+
return value.slice(1, -1);
|
|
30
|
+
}
|
|
31
|
+
return value;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Extrai o bloco de frontmatter (texto entre os `---`), sem parsear.
|
|
36
|
+
* @param {string} content - Conteúdo completo do arquivo
|
|
37
|
+
* @param {{lenient?: boolean}} [opts] - `lenient`: aceita também um `---`
|
|
38
|
+
* final sem newline de fechamento (ex.: arquivo termina em `\n---`)
|
|
39
|
+
* @returns {string|null} Bloco de frontmatter, ou null se não houver
|
|
40
|
+
*/
|
|
41
|
+
function frontmatterBlock(content, { lenient = false } = {}) {
|
|
42
|
+
const trimmed = content.trimStart();
|
|
43
|
+
if (!trimmed.startsWith('---')) return null;
|
|
44
|
+
|
|
45
|
+
let end = trimmed.indexOf('\n---\n', 3);
|
|
46
|
+
if (end === -1) {
|
|
47
|
+
if (lenient && trimmed.endsWith('\n---')) {
|
|
48
|
+
end = trimmed.length - 4;
|
|
49
|
+
} else {
|
|
50
|
+
return null;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
return trimmed.slice(3, end);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Parse de frontmatter via YAML real. Fechamento estrito (`\n---\n`); um
|
|
58
|
+
* `---` final sem newline devolve null, igual ao comportamento original de
|
|
59
|
+
* validate-method-refs.js.
|
|
60
|
+
* @param {string} content
|
|
61
|
+
* @returns {Object|null} Objeto parseado, ou null se não houver frontmatter
|
|
62
|
+
* válido (ausente, sem fechamento, ou YAML inválido)
|
|
63
|
+
*/
|
|
64
|
+
function parseFrontmatterYaml(content) {
|
|
65
|
+
const block = frontmatterBlock(content, { lenient: false });
|
|
66
|
+
if (block === null) return null;
|
|
67
|
+
try {
|
|
68
|
+
return yaml.parse(block);
|
|
69
|
+
} catch {
|
|
70
|
+
return null;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Parse manual linha-a-linha: só reconhece pares `chave: valor` na coluna 0;
|
|
76
|
+
* linhas indentadas (valores aninhados) são ignoradas; nenhuma continuação
|
|
77
|
+
* multi-linha é aplicada. Fechamento tolerante (aceita `---` final sem
|
|
78
|
+
* newline).
|
|
79
|
+
* @param {string} content
|
|
80
|
+
* @returns {Object|null} Objeto com pares chave/valor, ou null se não houver
|
|
81
|
+
* frontmatter
|
|
82
|
+
*/
|
|
83
|
+
function parseFrontmatterSimple(content) {
|
|
84
|
+
const block = frontmatterBlock(content, { lenient: true });
|
|
85
|
+
if (block === null) return null;
|
|
86
|
+
|
|
87
|
+
const fmBlock = block.trim();
|
|
88
|
+
if (fmBlock === '') return {};
|
|
89
|
+
|
|
90
|
+
const result = {};
|
|
91
|
+
for (const line of fmBlock.split('\n')) {
|
|
92
|
+
const colonIndex = line.indexOf(':');
|
|
93
|
+
if (colonIndex === -1) continue;
|
|
94
|
+
if (line[0] === ' ' || line[0] === '\t') continue;
|
|
95
|
+
const key = line.slice(0, colonIndex).trim();
|
|
96
|
+
const value = line.slice(colonIndex + 1).trim();
|
|
97
|
+
result[key] = stripQuotes(value);
|
|
98
|
+
}
|
|
99
|
+
return result;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* Parse manual que junta continuações de valor multi-linha (ex.:
|
|
104
|
+
* `description:` que ocupa várias linhas) na mesma chave. Fechamento
|
|
105
|
+
* tolerante (aceita `---` final sem newline). Linhas de comentário YAML
|
|
106
|
+
* (`#`) dentro de uma continuação são ignoradas.
|
|
107
|
+
* @param {string} content
|
|
108
|
+
* @returns {Object|null} Objeto com pares chave/valor, ou null se não houver
|
|
109
|
+
* frontmatter
|
|
110
|
+
*/
|
|
111
|
+
function parseFrontmatterMultiline(content) {
|
|
112
|
+
const block = frontmatterBlock(content, { lenient: true });
|
|
113
|
+
if (block === null) return null;
|
|
114
|
+
|
|
115
|
+
const fmBlock = block.trim();
|
|
116
|
+
if (fmBlock === '') return {};
|
|
117
|
+
|
|
118
|
+
const result = {};
|
|
119
|
+
let currentKey = null;
|
|
120
|
+
let currentValue = '';
|
|
121
|
+
|
|
122
|
+
for (const line of fmBlock.split('\n')) {
|
|
123
|
+
const colonIndex = line.indexOf(':');
|
|
124
|
+
// Nova chave: precisa começar na coluna 0 (sem indentação) e ter ':'.
|
|
125
|
+
if (colonIndex > 0 && line[0] !== ' ' && line[0] !== '\t') {
|
|
126
|
+
if (currentKey !== null) result[currentKey] = stripQuotes(currentValue.trim());
|
|
127
|
+
currentKey = line.slice(0, colonIndex).trim();
|
|
128
|
+
currentValue = line.slice(colonIndex + 1);
|
|
129
|
+
} else if (currentKey !== null) {
|
|
130
|
+
if (line.trimStart().startsWith('#')) continue;
|
|
131
|
+
currentValue += '\n' + line;
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
if (currentKey !== null) result[currentKey] = stripQuotes(currentValue.trim());
|
|
135
|
+
|
|
136
|
+
return result;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
module.exports = { parseFrontmatterYaml, parseFrontmatterSimple, parseFrontmatterMultiline, stripQuotes, frontmatterBlock };
|