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.
- 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 +62 -37
- 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/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,262 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Include expansion for customize.toml layers.
|
|
3
|
+
*
|
|
4
|
+
* Extracted from `resolved-customizations.js` (2026-09-11) to keep that file
|
|
5
|
+
* under the 800-line cap and to give the `_shared/` fallback a home. Kept in
|
|
6
|
+
* lock-step with `src/scripts/resolve_customization.py`: the two resolvers
|
|
7
|
+
* must produce byte-identical JSON, and `test/test-resolved-customizations.js`
|
|
8
|
+
* diffs them on every run.
|
|
9
|
+
*
|
|
10
|
+
* The `_shared/` fallback (bug found 2026-09-11): the verbatim pipeline moves
|
|
11
|
+
* each skill directory OUT of `_wizz/` into the IDE folder, e.g.
|
|
12
|
+
* `.claude/skills/wizz-maestro/customize.toml`, while that file keeps its
|
|
13
|
+
* shipped `include = ["../../_shared/communication-rules.md"]`. From the
|
|
14
|
+
* deployed location that relative path resolves to `.claude/_shared/...`,
|
|
15
|
+
* which does not exist, so every included paragraph was dropped silently.
|
|
16
|
+
* The real shared files live at `<project-root>/_wizz/<module>/_shared/`.
|
|
17
|
+
* So: when the base-relative path is missing AND the include mentions
|
|
18
|
+
* `_shared/`, the segment after the LAST `_shared/` is looked up under
|
|
19
|
+
* `<project-root>/_wizz/<module>/_shared/` for every module that has one,
|
|
20
|
+
* in sorted order, first hit wins. Nothing else is guessed.
|
|
21
|
+
*
|
|
22
|
+
* Containment (hardening, 2026-09-11): when a project root is known, an
|
|
23
|
+
* include whose base-relative path escapes that root (`../../../../x.md`) is
|
|
24
|
+
* refused before it is ever read — a customize.toml must not pull arbitrary
|
|
25
|
+
* files from the user's home or from a sibling checkout into an agent's
|
|
26
|
+
* activation steps. The `_shared/` fallback candidates are built under
|
|
27
|
+
* `<project-root>/_wizz/` by construction, so they always pass. A standalone
|
|
28
|
+
* skill (no project root resolvable) keeps the old unrestricted behaviour —
|
|
29
|
+
* there is no root to be outside of. `resolve_customization.py` implements
|
|
30
|
+
* the identical rule with the identical wording.
|
|
31
|
+
*/
|
|
32
|
+
|
|
33
|
+
const path = require('node:path');
|
|
34
|
+
const nodeFs = require('node:fs');
|
|
35
|
+
const { WIZZ_FOLDER_NAME } = require('../ide/shared/path-utils');
|
|
36
|
+
|
|
37
|
+
const INCLUDE_TARGET_FIELD = 'activation_steps_append';
|
|
38
|
+
const SHARED_DIR_NAME = '_shared';
|
|
39
|
+
|
|
40
|
+
// Keys that JavaScript treats specially on assignment: writing
|
|
41
|
+
// `obj.__proto__ = x` walks the Object.prototype setter (mutating the
|
|
42
|
+
// prototype chain) instead of creating an own property, so `[agent.__proto__]`
|
|
43
|
+
// in a customize.toml silently disappeared from the snapshot. smol-toml
|
|
44
|
+
// itself parses into null-prototype objects, so the only unsafe step was
|
|
45
|
+
// ours — every write goes through `safeSet`.
|
|
46
|
+
const DANGEROUS_KEYS = new Set(['__proto__', 'constructor', 'prototype']);
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Define `key` on `target` as a plain own data property, bypassing the
|
|
50
|
+
* `__proto__` setter and any inherited accessor. Parity with Python dicts,
|
|
51
|
+
* where these are ordinary keys.
|
|
52
|
+
*/
|
|
53
|
+
function safeSet(target, key, value) {
|
|
54
|
+
if (DANGEROUS_KEYS.has(key)) {
|
|
55
|
+
Object.defineProperty(target, key, { value, writable: true, enumerable: true, configurable: true });
|
|
56
|
+
} else {
|
|
57
|
+
target[key] = value;
|
|
58
|
+
}
|
|
59
|
+
return target;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
function hasOwn(obj, key) {
|
|
63
|
+
return Object.prototype.hasOwnProperty.call(obj, key);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
function isPlainObject(value) {
|
|
67
|
+
return value !== null && typeof value === 'object' && !Array.isArray(value);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
function isFile(absPath) {
|
|
71
|
+
try {
|
|
72
|
+
return nodeFs.statSync(absPath).isFile();
|
|
73
|
+
} catch {
|
|
74
|
+
return false;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Split an included markdown file into instruction strings: blocks
|
|
80
|
+
* separated by a blank line, internal newlines collapsed to single
|
|
81
|
+
* spaces, blocks made only of `#` lines dropped. Python
|
|
82
|
+
* `_split_include_paragraphs` parity.
|
|
83
|
+
*/
|
|
84
|
+
function splitIncludeParagraphs(text) {
|
|
85
|
+
const paragraphs = [];
|
|
86
|
+
for (const block of text.trim().split(/\n\s*\n/)) {
|
|
87
|
+
const lines = block
|
|
88
|
+
.split('\n')
|
|
89
|
+
.map((line) => line.trim())
|
|
90
|
+
.filter((line) => line.length > 0);
|
|
91
|
+
if (lines.every((line) => line.startsWith('#'))) continue;
|
|
92
|
+
paragraphs.push(lines.join(' '));
|
|
93
|
+
}
|
|
94
|
+
return paragraphs;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* Absolute candidates for an include whose base-relative path is missing.
|
|
99
|
+
* Empty unless `relPath` mentions `_shared/` and a project root is known.
|
|
100
|
+
* Deterministic: modules sorted by name, first existing hit wins upstream.
|
|
101
|
+
* Python `_shared_fallback_candidates` parity.
|
|
102
|
+
* @param {string} relPath - the include as written in the TOML
|
|
103
|
+
* @param {string|null} projectRoot
|
|
104
|
+
* @returns {string[]}
|
|
105
|
+
*/
|
|
106
|
+
function sharedFallbackCandidates(relPath, projectRoot) {
|
|
107
|
+
if (!projectRoot || typeof relPath !== 'string') return [];
|
|
108
|
+
const posix = relPath.split('\\').join('/');
|
|
109
|
+
const marker = `${SHARED_DIR_NAME}/`;
|
|
110
|
+
const index = posix.lastIndexOf(marker);
|
|
111
|
+
if (index === -1) return [];
|
|
112
|
+
const segment = posix.slice(index + marker.length);
|
|
113
|
+
const parts = segment.split('/');
|
|
114
|
+
if (segment.length === 0 || parts.some((part) => part === '' || part === '..' || part === '.')) return [];
|
|
115
|
+
|
|
116
|
+
const wizzRoot = path.join(projectRoot, WIZZ_FOLDER_NAME);
|
|
117
|
+
let modules;
|
|
118
|
+
try {
|
|
119
|
+
modules = nodeFs
|
|
120
|
+
.readdirSync(wizzRoot, { withFileTypes: true })
|
|
121
|
+
.filter((entry) => entry.isDirectory())
|
|
122
|
+
.map((entry) => entry.name)
|
|
123
|
+
.sort();
|
|
124
|
+
} catch {
|
|
125
|
+
return [];
|
|
126
|
+
}
|
|
127
|
+
const candidates = [];
|
|
128
|
+
for (const name of modules) {
|
|
129
|
+
const sharedDir = path.join(wizzRoot, name, SHARED_DIR_NAME);
|
|
130
|
+
let stat;
|
|
131
|
+
try {
|
|
132
|
+
stat = nodeFs.statSync(sharedDir);
|
|
133
|
+
} catch {
|
|
134
|
+
continue;
|
|
135
|
+
}
|
|
136
|
+
if (!stat.isDirectory()) continue;
|
|
137
|
+
candidates.push(path.join(sharedDir, ...parts));
|
|
138
|
+
}
|
|
139
|
+
return candidates;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
* True when the base-relative include escapes the project root. Lexical
|
|
144
|
+
* (`path.resolve` normalizes `..` without touching the filesystem), so a
|
|
145
|
+
* missing file is judged the same way an existing one is. No project root →
|
|
146
|
+
* never outside. Python `_is_outside_project_root` parity.
|
|
147
|
+
* @param {string} baseDir
|
|
148
|
+
* @param {string} relPath
|
|
149
|
+
* @param {string|null} projectRoot
|
|
150
|
+
* @returns {boolean}
|
|
151
|
+
*/
|
|
152
|
+
function isOutsideProjectRoot(baseDir, relPath, projectRoot) {
|
|
153
|
+
if (!projectRoot) return false;
|
|
154
|
+
const primary = path.resolve(baseDir, relPath);
|
|
155
|
+
const rel = path.relative(path.resolve(projectRoot), primary);
|
|
156
|
+
if (rel === '') return false;
|
|
157
|
+
return rel === '..' || rel.startsWith(`..${path.sep}`) || path.isAbsolute(rel);
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
/** The one escaped-include sentence, worded identically in both resolvers. */
|
|
161
|
+
function outsideRootMessage(relPath, skillName) {
|
|
162
|
+
return `include outside the project root, skipping: "${relPath}" (skill: ${skillName || '?'})`;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
/**
|
|
166
|
+
* Absolute path of the file an `include` entry actually points at, or null.
|
|
167
|
+
* Base-relative first, then the `_shared/` fallback. Python
|
|
168
|
+
* `_find_include_file` parity.
|
|
169
|
+
*/
|
|
170
|
+
function findIncludeFile(baseDir, relPath, projectRoot) {
|
|
171
|
+
const primary = path.resolve(baseDir, relPath);
|
|
172
|
+
if (isFile(primary)) return primary;
|
|
173
|
+
for (const candidate of sharedFallbackCandidates(relPath, projectRoot)) {
|
|
174
|
+
if (isFile(candidate)) return candidate;
|
|
175
|
+
}
|
|
176
|
+
return null;
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
/** The one missing-include sentence, worded identically in both resolvers. */
|
|
180
|
+
function missingIncludeMessage(relPath, skillName, primary) {
|
|
181
|
+
return `include not found, skipping: "${relPath}" (skill: ${skillName || '?'}; tried ${primary} and every ${WIZZ_FOLDER_NAME}/*/${SHARED_DIR_NAME}/)`;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
/**
|
|
185
|
+
* Expand `include = [...]` in any table: each referenced file's
|
|
186
|
+
* paragraphs are PREPENDED onto that table's `activation_steps_append`
|
|
187
|
+
* (created if absent), the `include` key itself removed, recursion into
|
|
188
|
+
* nested tables. Paths resolve relative to the declaring TOML's
|
|
189
|
+
* directory, with the `_shared/` fallback above when that misses.
|
|
190
|
+
* Missing/unreadable files warn and are skipped (fail-open).
|
|
191
|
+
* Python `resolve_includes` parity.
|
|
192
|
+
*
|
|
193
|
+
* @param {object} data
|
|
194
|
+
* @param {string} baseDir - directory of the TOML that declared the include
|
|
195
|
+
* @param {string[]} warnings - sink for fail-open warnings
|
|
196
|
+
* @param {string[]} [inputs] - optional sink: every include file actually
|
|
197
|
+
* read is pushed here (absolute path, the FALLBACK path when that is what
|
|
198
|
+
* was used) so the caller can hash it into `_resolved/.index.json`.
|
|
199
|
+
* @param {{projectRoot?: string, skillName?: string}} [context]
|
|
200
|
+
*/
|
|
201
|
+
function resolveIncludes(data, baseDir, warnings, inputs, context = {}) {
|
|
202
|
+
if (!isPlainObject(data)) return data;
|
|
203
|
+
const projectRoot = context.projectRoot || null;
|
|
204
|
+
const skillName = context.skillName || '';
|
|
205
|
+
|
|
206
|
+
const includedParagraphs = [];
|
|
207
|
+
if (Array.isArray(data.include)) {
|
|
208
|
+
for (const relPath of data.include) {
|
|
209
|
+
if (typeof relPath !== 'string') {
|
|
210
|
+
warnings.push(`include entries must be strings, got: ${JSON.stringify(relPath)}`);
|
|
211
|
+
continue;
|
|
212
|
+
}
|
|
213
|
+
if (isOutsideProjectRoot(baseDir, relPath, projectRoot)) {
|
|
214
|
+
warnings.push(outsideRootMessage(relPath, skillName));
|
|
215
|
+
continue;
|
|
216
|
+
}
|
|
217
|
+
const fullPath = findIncludeFile(baseDir, relPath, projectRoot);
|
|
218
|
+
let text = null;
|
|
219
|
+
if (fullPath === null) {
|
|
220
|
+
warnings.push(missingIncludeMessage(relPath, skillName, path.resolve(baseDir, relPath)));
|
|
221
|
+
} else {
|
|
222
|
+
try {
|
|
223
|
+
text = nodeFs.readFileSync(fullPath, 'utf8');
|
|
224
|
+
} catch {
|
|
225
|
+
warnings.push(`include not readable, skipping: ${fullPath}`);
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
if (text !== null) {
|
|
229
|
+
if (inputs) inputs.push(fullPath);
|
|
230
|
+
includedParagraphs.push(...splitIncludeParagraphs(text));
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
} else if ('include' in data) {
|
|
234
|
+
warnings.push(`'include' must be an array of strings, got: ${JSON.stringify(data.include)}`);
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
const result = {};
|
|
238
|
+
for (const [key, value] of Object.entries(data)) {
|
|
239
|
+
if (key === 'include') continue;
|
|
240
|
+
safeSet(result, key, isPlainObject(value) ? resolveIncludes(value, baseDir, warnings, inputs, context) : value);
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
if (includedParagraphs.length > 0) {
|
|
244
|
+
const existing = Array.isArray(result[INCLUDE_TARGET_FIELD]) ? result[INCLUDE_TARGET_FIELD] : [];
|
|
245
|
+
result[INCLUDE_TARGET_FIELD] = [...includedParagraphs, ...existing];
|
|
246
|
+
}
|
|
247
|
+
return result;
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
module.exports = {
|
|
251
|
+
resolveIncludes,
|
|
252
|
+
splitIncludeParagraphs,
|
|
253
|
+
sharedFallbackCandidates,
|
|
254
|
+
findIncludeFile,
|
|
255
|
+
isOutsideProjectRoot,
|
|
256
|
+
outsideRootMessage,
|
|
257
|
+
safeSet,
|
|
258
|
+
hasOwn,
|
|
259
|
+
isPlainObject,
|
|
260
|
+
INCLUDE_TARGET_FIELD,
|
|
261
|
+
SHARED_DIR_NAME,
|
|
262
|
+
};
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Closed key sets for `customize.toml` (audit item 24, 2026-09-11).
|
|
3
|
+
*
|
|
4
|
+
* Extracted from `resolved-customizations.js` (2026-09-11) to keep that file
|
|
5
|
+
* under the 800-line cap. Validation only: nothing here writes, parses or
|
|
6
|
+
* merges — it takes ONE parsed layer and reports the keys no code consumes.
|
|
7
|
+
*
|
|
8
|
+
* "additionalProperties: false" in spirit. The BASE layer (shipped,
|
|
9
|
+
* code-reviewed) is exempt: it may legitimately carry LLM-only fields
|
|
10
|
+
* (door/rel/not_when-style prose the agents read but no code consumes) and
|
|
11
|
+
* new experimental fields. TEAM/USER layers are user-authored, where a typo'd
|
|
12
|
+
* key (`persistant_facts`) merges into silence today — deepMerge applies it,
|
|
13
|
+
* nothing reads it, the user believes the knob turned. Each unknown key there
|
|
14
|
+
* is a warning (not an error: fail-open, the snapshot is still written).
|
|
15
|
+
* `include` is the documented extension point and is validated by
|
|
16
|
+
* `resolveIncludes`.
|
|
17
|
+
*/
|
|
18
|
+
|
|
19
|
+
const { isPlainObject } = require('./resolved-includes');
|
|
20
|
+
|
|
21
|
+
const WORKFLOW_KEYS = new Set([
|
|
22
|
+
// steps & facts
|
|
23
|
+
'activation_steps_prepend',
|
|
24
|
+
'activation_steps_append',
|
|
25
|
+
'persistent_facts',
|
|
26
|
+
'on_complete',
|
|
27
|
+
'include',
|
|
28
|
+
// output & templates
|
|
29
|
+
'output_dir',
|
|
30
|
+
'output_folder_name',
|
|
31
|
+
'run_folder_pattern',
|
|
32
|
+
'ux_output_path',
|
|
33
|
+
'prd_template',
|
|
34
|
+
'prd_output_path',
|
|
35
|
+
'validation_report_template',
|
|
36
|
+
'validation_checklist_template',
|
|
37
|
+
'spec_template',
|
|
38
|
+
'spec_filename',
|
|
39
|
+
'spec_output_path',
|
|
40
|
+
'spine_template',
|
|
41
|
+
'spine_output_path',
|
|
42
|
+
'brief_template',
|
|
43
|
+
'brief_output_path',
|
|
44
|
+
'case_file_template',
|
|
45
|
+
'case_file_subdir',
|
|
46
|
+
'case_file_filename',
|
|
47
|
+
'forge_output_path',
|
|
48
|
+
'methods_file',
|
|
49
|
+
'brain_methods',
|
|
50
|
+
// examples & handoffs
|
|
51
|
+
'design_md_examples',
|
|
52
|
+
'experience_md_examples',
|
|
53
|
+
'design_handoffs',
|
|
54
|
+
'external_sources',
|
|
55
|
+
'external_handoffs',
|
|
56
|
+
'finalize_reviewers',
|
|
57
|
+
'creative_tools',
|
|
58
|
+
'doc_standards',
|
|
59
|
+
// techniques & preferences
|
|
60
|
+
'favorite_techniques',
|
|
61
|
+
'additional_techniques',
|
|
62
|
+
'preferences',
|
|
63
|
+
'additional_methods',
|
|
64
|
+
// party mode
|
|
65
|
+
'default_party',
|
|
66
|
+
'party_mode',
|
|
67
|
+
'party_memory',
|
|
68
|
+
'memory_dir',
|
|
69
|
+
'party_members',
|
|
70
|
+
'party_groups',
|
|
71
|
+
// review layers (wizz-code-review, wizz-quick-dev): arrays of tables whose
|
|
72
|
+
// item keys are validated against REVIEW_LAYER_KEYS below.
|
|
73
|
+
'review_layers',
|
|
74
|
+
'oneshot_review_layers',
|
|
75
|
+
]);
|
|
76
|
+
const PARTY_MEMBER_KEYS = new Set(['code', 'name', 'icon', 'title', 'persona', 'capabilities', 'model']);
|
|
77
|
+
const PARTY_GROUP_KEYS = new Set(['id', 'name', 'scene', 'members', 'memory']);
|
|
78
|
+
// Exactly the keys the 8 shipped `[[workflow.*review_layers]]` entries use
|
|
79
|
+
// (src/bmm-skills/4-implementation/wizz-code-review + wizz-quick-dev).
|
|
80
|
+
const REVIEW_LAYER_KEYS = new Set(['id', 'name', 'instruction', 'when']);
|
|
81
|
+
// The only top-level keys any of the 47 shipped customize.toml carry. A
|
|
82
|
+
// top-level typo (`[workflw]`) or a stray scalar merged into silence before.
|
|
83
|
+
const TOP_LEVEL_KEYS = new Set(['workflow', 'agent', 'include']);
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* Collect unknown keys under `[workflow]`: unknown fields by name, and for
|
|
87
|
+
* the arrays-of-tables we own (party members/groups, review layers) the
|
|
88
|
+
* unknown keys of each item.
|
|
89
|
+
* @returns {string[]} dotted paths
|
|
90
|
+
*/
|
|
91
|
+
function findUnknownWorkflowKeys(workflow) {
|
|
92
|
+
const unknown = [];
|
|
93
|
+
for (const [k2, v2] of Object.entries(workflow)) {
|
|
94
|
+
const wfPath = `workflow.${k2}`;
|
|
95
|
+
if (!WORKFLOW_KEYS.has(k2)) {
|
|
96
|
+
unknown.push(wfPath);
|
|
97
|
+
continue;
|
|
98
|
+
}
|
|
99
|
+
if (!Array.isArray(v2) || v2.length === 0 || !v2.every((it) => isPlainObject(it))) continue;
|
|
100
|
+
const allowed =
|
|
101
|
+
k2 === 'party_members'
|
|
102
|
+
? PARTY_MEMBER_KEYS
|
|
103
|
+
: k2 === 'party_groups'
|
|
104
|
+
? PARTY_GROUP_KEYS
|
|
105
|
+
: k2.includes('review_layers')
|
|
106
|
+
? REVIEW_LAYER_KEYS
|
|
107
|
+
: null;
|
|
108
|
+
if (!allowed) continue;
|
|
109
|
+
for (const item of v2) {
|
|
110
|
+
for (const k3 of Object.keys(item)) {
|
|
111
|
+
if (!allowed.has(k3)) unknown.push(`${wfPath}[].${k3}`);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
return unknown;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* Walk a loaded TOML layer and collect unknown keys: unknown TOP-level
|
|
120
|
+
* tables/scalars (anything outside `workflow`, `agent`, `include`) plus the
|
|
121
|
+
* `[workflow]` fields and array-of-table item keys. `[agent]` is prose the
|
|
122
|
+
* LLM reads, not a code-consumed schema, so its keys are open by design;
|
|
123
|
+
* `include` is validated by resolveIncludes.
|
|
124
|
+
* @param {object} data - a single layer, as parsed (never a merged tree)
|
|
125
|
+
* @returns {string[]} dotted paths (caller prefixes with layer info)
|
|
126
|
+
*/
|
|
127
|
+
function findUnknownKeys(data) {
|
|
128
|
+
const unknown = [];
|
|
129
|
+
if (!isPlainObject(data)) return unknown;
|
|
130
|
+
for (const [key, value] of Object.entries(data)) {
|
|
131
|
+
if (!TOP_LEVEL_KEYS.has(key)) {
|
|
132
|
+
unknown.push(key);
|
|
133
|
+
continue;
|
|
134
|
+
}
|
|
135
|
+
if (key === 'workflow' && isPlainObject(value)) unknown.push(...findUnknownWorkflowKeys(value));
|
|
136
|
+
}
|
|
137
|
+
return unknown;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
module.exports = {
|
|
141
|
+
findUnknownKeys,
|
|
142
|
+
findUnknownWorkflowKeys,
|
|
143
|
+
WORKFLOW_KEYS,
|
|
144
|
+
PARTY_MEMBER_KEYS,
|
|
145
|
+
PARTY_GROUP_KEYS,
|
|
146
|
+
REVIEW_LAYER_KEYS,
|
|
147
|
+
TOP_LEVEL_KEYS,
|
|
148
|
+
};
|
|
@@ -39,6 +39,13 @@ async function detectCustomFiles(wizzDir, existingFilesManifest, { manifest }) {
|
|
|
39
39
|
manifestHasHashes = existingFilesManifest.some((f) => f.hash);
|
|
40
40
|
}
|
|
41
41
|
|
|
42
|
+
// Persistent stat → hash cache (audit item 23, written by
|
|
43
|
+
// manifest-generator alongside files-manifest.csv). Fail-open: absent or
|
|
44
|
+
// corrupt cache = every file falls through to the full hash below.
|
|
45
|
+
const { loadHashCache, getCachedHash } = require('./hash-cache');
|
|
46
|
+
const hashCache = await loadHashCache(path.join(wizzDir, '_config'));
|
|
47
|
+
const relPathOf = (fullPath) => path.relative(wizzDir, fullPath).replaceAll('\\', '/');
|
|
48
|
+
|
|
42
49
|
// Build map of previously installed files from files-manifest.csv with their hashes
|
|
43
50
|
const installedFilesMap = new Map();
|
|
44
51
|
for (const fileEntry of existingFilesManifest) {
|
|
@@ -97,6 +104,15 @@ async function detectCustomFiles(wizzDir, existingFilesManifest, { manifest }) {
|
|
|
97
104
|
continue;
|
|
98
105
|
}
|
|
99
106
|
|
|
107
|
+
// Skip _resolved/ — generated snapshots of resolved customizations
|
|
108
|
+
// (_wizz/_resolved/<skill>.json + .index.json, item 19), gitignored,
|
|
109
|
+
// not in the manifest, regenerated at update. Same treatment as
|
|
110
|
+
// _config/ above, minus the exception: these are pure build output,
|
|
111
|
+
// never something a user hand-edits.
|
|
112
|
+
if (relativePath.startsWith('_resolved/') || relativePath.startsWith('_resolved\\')) {
|
|
113
|
+
continue;
|
|
114
|
+
}
|
|
115
|
+
|
|
100
116
|
if (wizzMemoryPaths.some((mp) => relativePath === mp || relativePath.startsWith(mp + '/'))) {
|
|
101
117
|
continue;
|
|
102
118
|
}
|
|
@@ -114,14 +130,30 @@ async function detectCustomFiles(wizzDir, existingFilesManifest, { manifest }) {
|
|
|
114
130
|
customFiles.push(fullPath);
|
|
115
131
|
}
|
|
116
132
|
} else if (manifestHasHashes && fileInfo.hash) {
|
|
117
|
-
// File in manifest with hash - check if it was modified
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
133
|
+
// File in manifest with hash - check if it was modified.
|
|
134
|
+
// Incremental (audit item 23): consult the persistent
|
|
135
|
+
// size+mtime → hash cache first; a stat match proves the file
|
|
136
|
+
// is byte-identical to the last install, skipping the read
|
|
137
|
+
// entirely. Cache miss falls through to the full hash.
|
|
138
|
+
let unchangedByCache = false;
|
|
139
|
+
try {
|
|
140
|
+
const stat = await fs.stat(fullPath);
|
|
141
|
+
const cachedHash = getCachedHash(hashCache, relPathOf(fullPath), stat);
|
|
142
|
+
if (cachedHash !== null) {
|
|
143
|
+
unchangedByCache = true;
|
|
144
|
+
}
|
|
145
|
+
} catch {
|
|
146
|
+
// stat failed — hash below will handle the missing file
|
|
147
|
+
}
|
|
148
|
+
if (!unchangedByCache) {
|
|
149
|
+
const currentHash = await manifest.calculateFileHash(fullPath);
|
|
150
|
+
if (currentHash && currentHash !== fileInfo.hash) {
|
|
151
|
+
// Hash changed = file was modified
|
|
152
|
+
modifiedFiles.push({
|
|
153
|
+
path: fullPath,
|
|
154
|
+
relativePath: fileInfo.relativePath,
|
|
155
|
+
});
|
|
156
|
+
}
|
|
125
157
|
}
|
|
126
158
|
}
|
|
127
159
|
}
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Resolução do diretório de instalação `_wizz/` — dono único (item 20,
|
|
3
|
+
* auditoria 2026-09-11).
|
|
4
|
+
*
|
|
5
|
+
* Antes deste módulo havia quatro `findWizzDir` espalhados
|
|
6
|
+
* (core/installer.js, modules/module-catalog.js, ide/_config-driven.js e
|
|
7
|
+
* tools/migrate-custom-module-paths.js) e eles NÃO eram equivalentes: dois
|
|
8
|
+
* devolviam `null` quando o diretório não existe, um varria o projeto atrás
|
|
9
|
+
* de `<dir>/_config/manifest.yaml` (instalação V6+ com nome de pasta
|
|
10
|
+
* customizado) e um era só um `path.join`. Em vez de apagar comportamento, as
|
|
11
|
+
* quatro variantes moram aqui, nomeadas pelo que cada uma promete; os callers
|
|
12
|
+
* passam a importar a que já usavam.
|
|
13
|
+
*
|
|
14
|
+
* Módulo folha de propósito: além de `node:path` só importa `fs-native` e o
|
|
15
|
+
* `path-utils` do IDE (que por sua vez não importa nada), então não pode
|
|
16
|
+
* entrar em ciclo de require.
|
|
17
|
+
*/
|
|
18
|
+
|
|
19
|
+
const path = require('node:path');
|
|
20
|
+
const fs = require('../fs-native');
|
|
21
|
+
const { WIZZ_FOLDER_NAME } = require('../ide/shared/path-utils');
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Pure helper: compute the `_wizz` directory path for a project. No I/O, no
|
|
25
|
+
* instance state — callers that only need this path-join should call it
|
|
26
|
+
* directly instead of constructing a full `Installer` (which also builds an
|
|
27
|
+
* ExternalModuleManager, Manifest, IdeManager, ...) just to reach it (audit
|
|
28
|
+
* 2026-09-11, IC-F03).
|
|
29
|
+
* @param {string} projectDir - Project directory
|
|
30
|
+
* @returns {{wizzDir: string}}
|
|
31
|
+
*/
|
|
32
|
+
function findWizzDir(projectDir) {
|
|
33
|
+
return { wizzDir: path.join(projectDir, WIZZ_FOLDER_NAME) };
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* The same path as `findWizzDir`, unwrapped. For callers that want the string
|
|
38
|
+
* and not the `{ wizzDir }` envelope.
|
|
39
|
+
* @param {string} projectDir - Project directory
|
|
40
|
+
* @returns {string}
|
|
41
|
+
*/
|
|
42
|
+
function wizzDirPath(projectDir) {
|
|
43
|
+
return path.join(projectDir, WIZZ_FOLDER_NAME);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* `_wizz/` path when it already exists on disk, else null. Used by the IDE
|
|
48
|
+
* handlers' `detect()`, where "no install here" must stay distinguishable
|
|
49
|
+
* from "install at this path".
|
|
50
|
+
* @param {string} projectDir - Project directory
|
|
51
|
+
* @returns {Promise<string|null>} Path to wizz dir or null
|
|
52
|
+
*/
|
|
53
|
+
async function findExistingWizzDir(projectDir) {
|
|
54
|
+
const wizzDir = path.join(projectDir, WIZZ_FOLDER_NAME);
|
|
55
|
+
return (await fs.pathExists(wizzDir)) ? wizzDir : null;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Synchronous variant of `findExistingWizzDir`, for the one-shot migration
|
|
60
|
+
* scripts that run outside the installer's async pipeline.
|
|
61
|
+
* @param {string} [projectDir] - Project directory (defaults to cwd)
|
|
62
|
+
* @returns {string|null} Path to wizz dir or null
|
|
63
|
+
*/
|
|
64
|
+
function findExistingWizzDirSync(projectDir = process.cwd()) {
|
|
65
|
+
const wizzDir = path.join(projectDir, WIZZ_FOLDER_NAME);
|
|
66
|
+
return fs.existsSync(wizzDir) ? wizzDir : null;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Locate the wizz installation directory of a project by its V6+ marker.
|
|
71
|
+
*
|
|
72
|
+
* V6+ installations can use ANY folder name but ALWAYS have
|
|
73
|
+
* `_config/manifest.yaml`, so this scans the project's direct children for
|
|
74
|
+
* that file instead of assuming `_wizz`. Falls back to `<projectDir>/wizz`
|
|
75
|
+
* (the historical default of this code path — note: no leading underscore,
|
|
76
|
+
* unlike WIZZ_FOLDER_NAME) when nothing is found, which is what new
|
|
77
|
+
* installations get.
|
|
78
|
+
* @param {string} projectDir - Project directory
|
|
79
|
+
* @returns {Promise<string>} Path to wizz directory
|
|
80
|
+
*/
|
|
81
|
+
async function detectWizzDir(projectDir) {
|
|
82
|
+
// Check if project directory exists
|
|
83
|
+
if (!(await fs.pathExists(projectDir))) {
|
|
84
|
+
// Project doesn't exist yet, return default
|
|
85
|
+
return path.join(projectDir, 'wizz');
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
// V6+ strategy: Look for ANY directory with _config/manifest.yaml
|
|
89
|
+
// This is the definitive marker of a V6+ installation
|
|
90
|
+
try {
|
|
91
|
+
const entries = await fs.readdir(projectDir, { withFileTypes: true });
|
|
92
|
+
for (const entry of entries) {
|
|
93
|
+
if (entry.isDirectory()) {
|
|
94
|
+
const manifestPath = path.join(projectDir, entry.name, '_config', 'manifest.yaml');
|
|
95
|
+
if (await fs.pathExists(manifestPath)) {
|
|
96
|
+
// Found a V6+ installation
|
|
97
|
+
return path.join(projectDir, entry.name);
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
} catch {
|
|
102
|
+
// Ignore errors, fall through to default
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
// No V6+ installation found, return default
|
|
106
|
+
// This will be used for new installations
|
|
107
|
+
return path.join(projectDir, 'wizz');
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
module.exports = {
|
|
111
|
+
WIZZ_FOLDER_NAME,
|
|
112
|
+
findWizzDir,
|
|
113
|
+
wizzDirPath,
|
|
114
|
+
findExistingWizzDir,
|
|
115
|
+
findExistingWizzDirSync,
|
|
116
|
+
detectWizzDir,
|
|
117
|
+
};
|