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,389 @@
|
|
|
1
|
+
// wizz-decision-trace.js — Stop event hook (v1)
|
|
2
|
+
//
|
|
3
|
+
// Fonte de verdade: wizz-method/tools/hooks/. Instalar em ~/.claude/hooks via
|
|
4
|
+
// `npm run sync:global` (nunca editar a cópia global direto — ela é
|
|
5
|
+
// substituída pelo sync).
|
|
6
|
+
//
|
|
7
|
+
// Fecha a lacuna "o trace grava o que foi INJETADO, não o que foi OBEDECIDO":
|
|
8
|
+
// tools/hooks/wizz-router-enforce.js (UserPromptSubmit) já grava, opt-in via
|
|
9
|
+
// WIZZ_TRACE=1, qual contexto de roteamento foi injetado no prompt. Mas
|
|
10
|
+
// injetar não é obedecer — o agente pode ignorar a dica. Para medir a
|
|
11
|
+
// decisão de fato tomada, todo agente wizz emite, no fecho de um pedido
|
|
12
|
+
// roteado (ver src/modules/wizz/_shared/encerramento.md), 1 linha marcador:
|
|
13
|
+
//
|
|
14
|
+
// 🧭 {"rota":"agent:designer","sel":["wizz-canvas-design"],"desc":[["hyperframes","motivo"]],"gate":"ok","repetiria":true}
|
|
15
|
+
//
|
|
16
|
+
// Este hook roda no evento Stop (fim da resposta do assistant). Ele lê o
|
|
17
|
+
// transcript apontado por `transcript_path` no payload do hook, pega a
|
|
18
|
+
// ÚLTIMA mensagem do assistant, extrai a última ocorrência do marcador 🧭 e
|
|
19
|
+
// appenda uma linha `{"type":"decision",...}` no MESMO arquivo usado pelo
|
|
20
|
+
// enforce (~/.claude/wizz-trace.jsonl, honrando WIZZ_TRACE_FILE) — os dois
|
|
21
|
+
// hooks compartilham o mesmo JSONL, distinguível pelo campo `type`
|
|
22
|
+
// ("decision" aqui; as linhas do enforce não têm esse campo).
|
|
23
|
+
//
|
|
24
|
+
// Opt-in: só faz algo com WIZZ_TRACE=1 (mesma convenção do enforce); senão
|
|
25
|
+
// sai 0 sem tocar em disco nem ler o transcript. Nem todo pedido é roteado
|
|
26
|
+
// (marcador ausente é normal, não é erro) e o marcador é telemetria: falha
|
|
27
|
+
// em QUALQUER etapa (payload inválido, transcript ilegível, JSON do marcador
|
|
28
|
+
// quebrado) sai 0 em silêncio — este hook nunca pode bloquear ou derrubar a
|
|
29
|
+
// sessão.
|
|
30
|
+
//
|
|
31
|
+
// P1 da auditoria 360° (medir aderência à escada de modelos): no MESMO passe
|
|
32
|
+
// de leitura do transcript, quando há marcador de decisão no turno, também
|
|
33
|
+
// varre o turno atual em busca de invocação de subagente wizz-exec-*
|
|
34
|
+
// (Task/Agent com subagent_type contendo "wizz-exec") e appenda uma segunda
|
|
35
|
+
// linha `{"type":"ladder",...}` no mesmo JSONL — mesmas garantias de
|
|
36
|
+
// opt-in/fail-silent/custo-zero. Só medição, nenhum enforcement novo.
|
|
37
|
+
//
|
|
38
|
+
// RT-H4 da auditoria 2026-09-11 (item 12, Fase 2): em sessão longa, reler o
|
|
39
|
+
// transcript inteiro a cada `Stop` é O(n) por turno (custo cresce quadrático
|
|
40
|
+
// ao longo da sessão). Correção: um offset em bytes por transcript, salvo em
|
|
41
|
+
// `wizz-trace.offsets.json` ao lado do trace file (mesmo diretório de
|
|
42
|
+
// `getTraceFile()`, então honra `WIZZ_TRACE_FILE`). A cada Stop, lê só os
|
|
43
|
+
// bytes novos desde o offset salvo (ver `readTranscriptDelta`):
|
|
44
|
+
// - transcript encolheu (offset > tamanho atual — sessão nova reusando o
|
|
45
|
+
// mesmo path, ou arquivo truncado) → recomeça do zero;
|
|
46
|
+
// - última linha do delta sem `\n` no final (escrita em andamento, JSON
|
|
47
|
+
// cortado no meio) → não avança o offset além do último `\n` completo;
|
|
48
|
+
// tenta de novo no próximo Stop;
|
|
49
|
+
// - efeito colateral bom: como só processa bytes NOVOS, um turno sem
|
|
50
|
+
// conteúdo novo desde o último Stop não pode reemitir o marcador de um
|
|
51
|
+
// turno já registrado — dedup vem de graça do próprio offset, sem
|
|
52
|
+
// precisar de um mecanismo separado.
|
|
53
|
+
// O arquivo de offsets é podado a cada escrita (entradas cujo transcript já
|
|
54
|
+
// não existe mais são removidas; teto de 50 entradas, mais recentes
|
|
55
|
+
// primeiro) e escrito de forma atômica (tmp + rename). Mesma política de
|
|
56
|
+
// erro do hook: qualquer falha aqui (arquivo de offsets corrompido, disco
|
|
57
|
+
// cheio, permissão) nunca derruba o hook — fail-silent, volta a reler tudo.
|
|
58
|
+
|
|
59
|
+
const fs = require('node:fs');
|
|
60
|
+
const path = require('node:path');
|
|
61
|
+
const os = require('node:os');
|
|
62
|
+
|
|
63
|
+
// Captura, na mesma linha do marcador, do `{` até o último `}` daquela
|
|
64
|
+
// linha. Suficiente porque o marcador é sempre um objeto JSON plano — `desc`
|
|
65
|
+
// usa array de arrays (`[...]`), nunca objetos aninhados — então o último
|
|
66
|
+
// `}` da linha é sempre o fechamento do próprio marcador.
|
|
67
|
+
const MARKER_LINE_RE = /🧭\s*(\{[\s\S]*\})\s*$/;
|
|
68
|
+
|
|
69
|
+
// Detecta invocação de subagente da escada de modelos: tool_use de
|
|
70
|
+
// Task/Agent cujo subagent_type (ou campo equivalente) contém "wizz-exec"
|
|
71
|
+
// (case-insensitive — cobre wizz-exec-haiku/sonnet/opus/review).
|
|
72
|
+
const EXEC_NAME_RE = /wizz-exec/i;
|
|
73
|
+
|
|
74
|
+
function isTraceEnabled() {
|
|
75
|
+
return process.env.WIZZ_TRACE === '1';
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
function getTraceFile() {
|
|
79
|
+
return process.env.WIZZ_TRACE_FILE || path.join(os.homedir(), '.claude', 'wizz-trace.jsonl');
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
// Concatena todos os blocos `type: "text"` do conteúdo de uma mensagem de
|
|
83
|
+
// assistant (o array `content` mistura text/tool_use/thinking/etc. — só nos
|
|
84
|
+
// interessa texto).
|
|
85
|
+
function extractAssistantText(entry) {
|
|
86
|
+
const content = entry && entry.message && entry.message.content;
|
|
87
|
+
if (!Array.isArray(content)) return '';
|
|
88
|
+
return content
|
|
89
|
+
.filter((block) => block && block.type === 'text' && typeof block.text === 'string')
|
|
90
|
+
.map((block) => block.text)
|
|
91
|
+
.join('\n');
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
// Lê o transcript (JSONL, 1 mensagem por linha) e devolve o array de
|
|
95
|
+
// entradas já parseadas. Linhas corrompidas são ignoradas (fail-open). Passe
|
|
96
|
+
// único de leitura do disco — tanto o marcador de decisão quanto a detecção
|
|
97
|
+
// de execs da escada de modelos partem deste mesmo array em memória.
|
|
98
|
+
function readTranscriptEntries(transcriptPath) {
|
|
99
|
+
const raw = fs.readFileSync(transcriptPath, 'utf8');
|
|
100
|
+
return parseJsonlText(raw);
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
// Parseia texto JSONL (1 objeto por linha) em array de entradas. Linhas
|
|
104
|
+
// corrompidas/vazias são ignoradas (fail-open) — usado tanto pela leitura
|
|
105
|
+
// completa (`readTranscriptEntries`, mantida por compat/testes) quanto pela
|
|
106
|
+
// leitura incremental (`readTranscriptDelta`).
|
|
107
|
+
function parseJsonlText(text) {
|
|
108
|
+
const entries = [];
|
|
109
|
+
for (const line of text.split('\n')) {
|
|
110
|
+
const trimmed = line.trim();
|
|
111
|
+
if (!trimmed) continue;
|
|
112
|
+
try {
|
|
113
|
+
entries.push(JSON.parse(trimmed));
|
|
114
|
+
} catch {
|
|
115
|
+
continue; // linha corrompida — ignora, não derruba a leitura
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
return entries;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
const MAX_OFFSET_ENTRIES = 50;
|
|
122
|
+
|
|
123
|
+
// Arquivo de offsets fica no MESMO diretório do trace file — assim honra
|
|
124
|
+
// WIZZ_TRACE_FILE automaticamente sem precisar de uma env var própria.
|
|
125
|
+
function getOffsetsFile() {
|
|
126
|
+
return path.join(path.dirname(getTraceFile()), 'wizz-trace.offsets.json');
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
// Lê o arquivo de offsets. Fail-open: ausente, JSON inválido, ou formato
|
|
130
|
+
// inesperado → lista vazia (equivalente a "nunca lemos nenhum transcript
|
|
131
|
+
// antes", reprocessa tudo do zero pros transcripts em questão).
|
|
132
|
+
function loadOffsets() {
|
|
133
|
+
try {
|
|
134
|
+
const raw = fs.readFileSync(getOffsetsFile(), 'utf8');
|
|
135
|
+
const data = JSON.parse(raw);
|
|
136
|
+
if (!data || !Array.isArray(data.entries)) return [];
|
|
137
|
+
return data.entries.filter((e) => e && typeof e.path === 'string' && Number.isFinite(e.offset) && e.offset >= 0);
|
|
138
|
+
} catch {
|
|
139
|
+
return [];
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
// Persiste a lista de offsets de forma atômica (tmp + rename no mesmo
|
|
144
|
+
// diretório). Antes de escrever: poda entradas órfãs (transcript que já não
|
|
145
|
+
// existe mais em disco) e limita ao teto de MAX_OFFSET_ENTRIES (a lista já
|
|
146
|
+
// chega ordenada mais-recente-primeiro por `upsertOffset`). Fail-silent —
|
|
147
|
+
// nunca lança; se a escrita falhar, o próximo Stop simplesmente relê tudo de
|
|
148
|
+
// novo pros transcripts afetados (mesma política de erro do resto do hook).
|
|
149
|
+
function saveOffsets(entries) {
|
|
150
|
+
try {
|
|
151
|
+
const alive = entries.filter((e) => {
|
|
152
|
+
try {
|
|
153
|
+
return fs.existsSync(e.path);
|
|
154
|
+
} catch {
|
|
155
|
+
return false;
|
|
156
|
+
}
|
|
157
|
+
});
|
|
158
|
+
const capped = alive.slice(0, MAX_OFFSET_ENTRIES);
|
|
159
|
+
const offsetsFile = getOffsetsFile();
|
|
160
|
+
const dir = path.dirname(offsetsFile);
|
|
161
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
162
|
+
const tmpFile = path.join(dir, `.wizz-trace.offsets.${process.pid}.${Date.now()}.tmp`);
|
|
163
|
+
fs.writeFileSync(tmpFile, JSON.stringify({ entries: capped }));
|
|
164
|
+
fs.renameSync(tmpFile, offsetsFile);
|
|
165
|
+
} catch {
|
|
166
|
+
// arquivo de offsets nunca pode derrubar o hook
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
// Devolve uma nova lista com a entrada de `transcriptPath` movida (ou
|
|
171
|
+
// inserida) na FRENTE — mantém a lista ordenada mais-recente-primeiro, que é
|
|
172
|
+
// a ordem que `saveOffsets` usa pra decidir quem poda quando passa do teto.
|
|
173
|
+
function upsertOffset(entries, transcriptPath, offset) {
|
|
174
|
+
const key = path.resolve(transcriptPath);
|
|
175
|
+
const rest = entries.filter((e) => path.resolve(e.path) !== key);
|
|
176
|
+
return [{ path: key, offset, ts: new Date().toISOString() }, ...rest];
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
function getStoredOffset(entries, transcriptPath) {
|
|
180
|
+
const key = path.resolve(transcriptPath);
|
|
181
|
+
const found = entries.find((e) => path.resolve(e.path) === key);
|
|
182
|
+
return found ? found.offset : 0;
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
// Lê só os bytes NOVOS do transcript desde `storedOffset`. Devolve
|
|
186
|
+
// `{ entries, newOffset }`:
|
|
187
|
+
// - `entries`: já parseadas (linhas corrompidas ignoradas, fail-open),
|
|
188
|
+
// só as do delta lido nesta chamada;
|
|
189
|
+
// - `newOffset`: até onde dá pra avançar com segurança.
|
|
190
|
+
//
|
|
191
|
+
// Duas garantias de robustez (RT-H4):
|
|
192
|
+
// 1. Transcript encolheu (storedOffset > tamanho atual — sessão nova
|
|
193
|
+
// reusando o mesmo path, ou arquivo truncado) → relê do zero.
|
|
194
|
+
// 2. Delta termina no meio de uma linha (sem `\n` final — escrita em
|
|
195
|
+
// andamento) → não avança o offset além do último `\n` completo; a
|
|
196
|
+
// leitura seguinte relê esse trecho junto com o resto que faltava.
|
|
197
|
+
// Corte feito nos BYTES crus (0x0A), não na string decodificada: `\n`
|
|
198
|
+
// nunca aparece como parte de uma sequência UTF-8 multibyte (bytes de
|
|
199
|
+
// continuação/liderança nunca valem 0x0A), então cortar ali nunca
|
|
200
|
+
// quebra um caractere multibyte ao meio.
|
|
201
|
+
function readTranscriptDelta(transcriptPath, storedOffset) {
|
|
202
|
+
const size = fs.statSync(transcriptPath).size;
|
|
203
|
+
const startOffset = storedOffset > size ? 0 : storedOffset;
|
|
204
|
+
|
|
205
|
+
if (startOffset >= size) {
|
|
206
|
+
return { entries: [], newOffset: startOffset };
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
const length = size - startOffset;
|
|
210
|
+
const buffer = Buffer.alloc(length);
|
|
211
|
+
const fd = fs.openSync(transcriptPath, 'r');
|
|
212
|
+
let bytesRead = 0;
|
|
213
|
+
try {
|
|
214
|
+
bytesRead = fs.readSync(fd, buffer, 0, length, startOffset);
|
|
215
|
+
} finally {
|
|
216
|
+
fs.closeSync(fd);
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
const lastNewline = buffer.lastIndexOf(0x0a, bytesRead - 1);
|
|
220
|
+
if (lastNewline === -1) {
|
|
221
|
+
// Nenhuma linha completa neste delta — não avança, tenta de novo depois.
|
|
222
|
+
return { entries: [], newOffset: startOffset };
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
const usable = buffer.subarray(0, lastNewline + 1);
|
|
226
|
+
const newOffset = startOffset + usable.length;
|
|
227
|
+
const entries = parseJsonlText(usable.toString('utf8'));
|
|
228
|
+
return { entries, newOffset };
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
// Devolve o texto da ÚLTIMA mensagem de assistant entre as entradas dadas;
|
|
232
|
+
// '' se não houver nenhuma.
|
|
233
|
+
function lastAssistantText(entries) {
|
|
234
|
+
let lastText = '';
|
|
235
|
+
for (const entry of entries) {
|
|
236
|
+
if (entry && entry.type === 'assistant') {
|
|
237
|
+
const text = extractAssistantText(entry);
|
|
238
|
+
if (text) lastText = text;
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
return lastText;
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
// Varre só o TURNO ATUAL (entradas depois da última mensagem de `user`) em
|
|
245
|
+
// busca de tool_use de Task/Agent cujo subagent_type contenha "wizz-exec".
|
|
246
|
+
// Execs de turnos anteriores não contam — o objetivo é medir a escada de
|
|
247
|
+
// modelos usada NESTE pedido, não o histórico acumulado da sessão.
|
|
248
|
+
function extractExecInvocations(entries) {
|
|
249
|
+
let lastUserIndex = -1;
|
|
250
|
+
for (const [i, entry] of entries.entries()) {
|
|
251
|
+
if (entry && entry.type === 'user') lastUserIndex = i;
|
|
252
|
+
}
|
|
253
|
+
const currentTurn = entries.slice(lastUserIndex + 1);
|
|
254
|
+
|
|
255
|
+
const execs = [];
|
|
256
|
+
for (const entry of currentTurn) {
|
|
257
|
+
if (!entry || entry.type !== 'assistant') continue;
|
|
258
|
+
const content = entry.message && entry.message.content;
|
|
259
|
+
if (!Array.isArray(content)) continue;
|
|
260
|
+
for (const block of content) {
|
|
261
|
+
if (!block || block.type !== 'tool_use') continue;
|
|
262
|
+
if (block.name !== 'Task' && block.name !== 'Agent') continue;
|
|
263
|
+
const input = block.input || {};
|
|
264
|
+
const candidate = input.subagent_type || input.subagentType || input.agent || block.name;
|
|
265
|
+
if (typeof candidate === 'string' && EXEC_NAME_RE.test(candidate)) {
|
|
266
|
+
execs.push(candidate);
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
return execs;
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
// Extrai a última ocorrência do marcador 🧭 {...} num texto e devolve o
|
|
274
|
+
// objeto já parseado, ou `null` se o marcador estiver ausente ou o JSON for
|
|
275
|
+
// inválido.
|
|
276
|
+
function extractDecision(text) {
|
|
277
|
+
if (!text) return null;
|
|
278
|
+
const lines = text.split('\n');
|
|
279
|
+
let lastRaw = null;
|
|
280
|
+
for (const line of lines) {
|
|
281
|
+
const match = MARKER_LINE_RE.exec(line);
|
|
282
|
+
if (match) lastRaw = match[1];
|
|
283
|
+
}
|
|
284
|
+
if (!lastRaw) return null;
|
|
285
|
+
try {
|
|
286
|
+
return JSON.parse(lastRaw);
|
|
287
|
+
} catch {
|
|
288
|
+
return null;
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
// Appenda 1 linha JSON no trace file. Fail-silent — nunca lança.
|
|
293
|
+
function appendDecision(entry) {
|
|
294
|
+
try {
|
|
295
|
+
fs.appendFileSync(getTraceFile(), JSON.stringify(entry) + '\n');
|
|
296
|
+
} catch {
|
|
297
|
+
// trace nunca pode derrubar o hook
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
function runHook() {
|
|
302
|
+
let input = '';
|
|
303
|
+
const stdinTimeout = setTimeout(() => process.exit(0), 3000);
|
|
304
|
+
process.stdin.setEncoding('utf8');
|
|
305
|
+
process.stdin.on('data', (chunk) => (input += chunk));
|
|
306
|
+
process.stdin.on('end', () => {
|
|
307
|
+
clearTimeout(stdinTimeout);
|
|
308
|
+
try {
|
|
309
|
+
// Custo zero quando desligado: nem chega a tocar no payload/transcript.
|
|
310
|
+
if (!isTraceEnabled()) {
|
|
311
|
+
process.exit(0);
|
|
312
|
+
return;
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
const payload = JSON.parse(input);
|
|
316
|
+
const transcriptPath = payload.transcript_path;
|
|
317
|
+
if (!transcriptPath || !fs.existsSync(transcriptPath)) {
|
|
318
|
+
process.exit(0);
|
|
319
|
+
return;
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
// RT-H4: lê só o delta desde o offset salvo (não o transcript inteiro)
|
|
323
|
+
// e já persiste o offset avançado antes de decidir se há marcador —
|
|
324
|
+
// um turno sem marcador (pedido não roteado, caso comum) não pode
|
|
325
|
+
// forçar releitura do mesmo trecho no próximo Stop.
|
|
326
|
+
const offsetsBefore = loadOffsets();
|
|
327
|
+
const storedOffset = getStoredOffset(offsetsBefore, transcriptPath);
|
|
328
|
+
const { entries, newOffset } = readTranscriptDelta(transcriptPath, storedOffset);
|
|
329
|
+
saveOffsets(upsertOffset(offsetsBefore, transcriptPath, newOffset));
|
|
330
|
+
|
|
331
|
+
const lastText = lastAssistantText(entries);
|
|
332
|
+
const decision = extractDecision(lastText);
|
|
333
|
+
if (!decision) {
|
|
334
|
+
process.exit(0); // nem todo pedido é roteado — ausência é normal
|
|
335
|
+
return;
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
const ts = new Date().toISOString();
|
|
339
|
+
const sessionId = payload.session_id || null;
|
|
340
|
+
|
|
341
|
+
appendDecision({
|
|
342
|
+
ts,
|
|
343
|
+
type: 'decision',
|
|
344
|
+
session: sessionId,
|
|
345
|
+
decision,
|
|
346
|
+
});
|
|
347
|
+
|
|
348
|
+
// Mesmo turno, mesmo passe de leitura: registra a escada de modelos
|
|
349
|
+
// (quais wizz-exec-* foram invocados neste pedido roteado, se algum).
|
|
350
|
+
const execs = extractExecInvocations(entries);
|
|
351
|
+
appendDecision({
|
|
352
|
+
ts,
|
|
353
|
+
type: 'ladder',
|
|
354
|
+
sessionId,
|
|
355
|
+
execs,
|
|
356
|
+
rota: decision.rota || null,
|
|
357
|
+
});
|
|
358
|
+
|
|
359
|
+
process.exit(0);
|
|
360
|
+
} catch {
|
|
361
|
+
// Falha em silêncio em qualquer etapa — nunca bloqueia a sessão.
|
|
362
|
+
process.exit(0);
|
|
363
|
+
}
|
|
364
|
+
});
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
if (require.main === module) {
|
|
368
|
+
runHook();
|
|
369
|
+
} else {
|
|
370
|
+
module.exports = {
|
|
371
|
+
isTraceEnabled,
|
|
372
|
+
getTraceFile,
|
|
373
|
+
extractAssistantText,
|
|
374
|
+
readTranscriptEntries,
|
|
375
|
+
lastAssistantText,
|
|
376
|
+
extractDecision,
|
|
377
|
+
extractExecInvocations,
|
|
378
|
+
appendDecision,
|
|
379
|
+
runHook,
|
|
380
|
+
// RT-H4: offset persistido (item 12, Fase 2)
|
|
381
|
+
getOffsetsFile,
|
|
382
|
+
loadOffsets,
|
|
383
|
+
saveOffsets,
|
|
384
|
+
upsertOffset,
|
|
385
|
+
getStoredOffset,
|
|
386
|
+
readTranscriptDelta,
|
|
387
|
+
MAX_OFFSET_ENTRIES,
|
|
388
|
+
};
|
|
389
|
+
}
|
|
@@ -0,0 +1,258 @@
|
|
|
1
|
+
// wizz-router-enforce.js — UserPromptSubmit hook (v2)
|
|
2
|
+
//
|
|
3
|
+
// Fonte de verdade: wizz-method/tools/hooks/. Instalar em ~/.claude/hooks via
|
|
4
|
+
// `npm run sync:global` (nunca editar a cópia global direto — ela é substituída).
|
|
5
|
+
//
|
|
6
|
+
// v2 (2026-07): detecta projeto Wizz (_wizz/ no cwd ou ancestrais) e injeta uma
|
|
7
|
+
// dica CURTA de delegação direta (maestro/agente da área) em vez do mandato
|
|
8
|
+
// completo do router. Fora de projeto Wizz mantém o router, também em versão
|
|
9
|
+
// curta. Injeção caiu de ~250 para ~50-70 tokens por prompt.
|
|
10
|
+
//
|
|
11
|
+
// Advisory-only: nunca bloqueia o prompt; falha em silêncio.
|
|
12
|
+
//
|
|
13
|
+
// Observabilidade (opt-in, custo zero quando desligado):
|
|
14
|
+
// - WIZZ_TRACE=1 grava uma linha JSON por decisão em ~/.claude/wizz-trace.jsonl
|
|
15
|
+
// (override: WIZZ_TRACE_FILE). Trace é sempre fail-silent — nunca derruba o hook.
|
|
16
|
+
// - Fallback de roteamento (tabela flat ausente no global, install de projeto
|
|
17
|
+
// Wizz incompleto) emite 1 warning em stderr, independente do trace estar
|
|
18
|
+
// ligado. Custo: 1 fs.existsSync por prompt não-trivial.
|
|
19
|
+
|
|
20
|
+
const fs = require('node:fs');
|
|
21
|
+
const path = require('node:path');
|
|
22
|
+
const os = require('node:os');
|
|
23
|
+
|
|
24
|
+
// "Abridores" triviais: saudação, confirmação/reação curta, pergunta pura de
|
|
25
|
+
// status, frase de suporte pessoal. Casam só o INÍCIO do prompt — o que vem
|
|
26
|
+
// depois é avaliado à parte via MAX_LEFTOVER_WORDS logo abaixo. Isso corrige o
|
|
27
|
+
// achado RT-H1 da auditoria de 2026-09-11 (_audit/2026-09-11-anexos/03-runtime.md):
|
|
28
|
+
// antes, essas regexes casavam só o prefixo e qualquer coisa depois (mesmo um
|
|
29
|
+
// pedido real e substancial, ex. "sim, e também refatora o módulo de auth")
|
|
30
|
+
// era engolida como trivial junto.
|
|
31
|
+
// Nota: "tá"/"está" terminam em vogal acentuada, e o \w do JS (sem flag /u)
|
|
32
|
+
// não considera acento como caractere de palavra — um \b logo depois falha
|
|
33
|
+
// (nenhum dos dois lados conta como "palavra"). Por isso a entrada de status
|
|
34
|
+
// abaixo não fecha com \b (a checagem de sobra via MAX_LEFTOVER_WORDS já
|
|
35
|
+
// garante que não vira prefixo solto de uma palavra maior).
|
|
36
|
+
const OPENER_PATTERNS = [
|
|
37
|
+
// Conversa pura / saudações / reação sem pedido
|
|
38
|
+
/^(oi|ol[aá]|hey|hi|hello|tudo bem|bom dia|boa tarde|boa noite|obrigad[oa]|valeu|vlw|ok|okay|certo|perfeito|show|massa|legal|beleza)\b/i,
|
|
39
|
+
// Resposta a pergunta do próprio router — evita re-injetar no follow-up
|
|
40
|
+
/^(sim|n[aã]o|todas|nenhuma|cancela|dispara?\s+(todas|ambas|essas|todas\s+as\s+skills)|pode|vai|continua|[12]|y|n)\b/i,
|
|
41
|
+
// Perguntas puras de status / o que foi feito
|
|
42
|
+
/^(o que foi feito|qual o status|me conta|como (t[aá]|est[aá]|ficou|ficaram)|me mostra|explica)/i,
|
|
43
|
+
// Frase de suporte/estado pessoal ("esqueci a senha") — informacional, não é tarefa
|
|
44
|
+
/^esqueci\b/i,
|
|
45
|
+
];
|
|
46
|
+
|
|
47
|
+
// Marcadores de edição pontual/trivial em QUALQUER posição do prompt — não são
|
|
48
|
+
// "resposta curta", são um tipo de pedido que já é trivial por conteúdo
|
|
49
|
+
// (typo, rename, linha específica), então continuam casando como substring.
|
|
50
|
+
const MARKER_PATTERNS = [
|
|
51
|
+
/\btypo\b/i,
|
|
52
|
+
/\bcorrige?\s+(esse|este|o|a)?\s*typo\b/i,
|
|
53
|
+
/\brename\s+(a\s+)?(vari[aá]vel|fun[cç][aã]o|arquivo|classe|m[eé]todo)\b/i,
|
|
54
|
+
/\brenomei[ao]\s+(a\s+)?(vari[aá]vel|fun[cç][aã]o|arquivo|classe|m[eé]todo)\b/i,
|
|
55
|
+
// Rename no formato "rebatiza/renomeia X para Y" (objeto é nome próprio, não termo técnico)
|
|
56
|
+
/\b(rename|renomeia|renomear|renomeou|rebatiza|rebatizar|rebatizou)\b.*\bpara\b/i,
|
|
57
|
+
// Edição pontual apontando linha específica ("troca X por Y na linha 42")
|
|
58
|
+
/\bna linha \d+\b/i,
|
|
59
|
+
];
|
|
60
|
+
|
|
61
|
+
// Depois de casar um abridor, quantas palavras de sobra ainda contam como a
|
|
62
|
+
// mesma reação curta ("tudo bem?", "o resultado", "pode") em vez de um pedido
|
|
63
|
+
// novo emendado ("e também refatora o módulo de auth", 7 palavras de sobra).
|
|
64
|
+
const MAX_LEFTOVER_WORDS = 2;
|
|
65
|
+
|
|
66
|
+
// Remove pontuação/conectivo solto nas bordas da sobra antes de contar
|
|
67
|
+
// palavras — "ok, pode" deixa a sobra ", pode" -> "pode".
|
|
68
|
+
function normalizeLeftover(text) {
|
|
69
|
+
return text.replace(/^[\s,;:.!-]+/, '').replace(/[\s.,!?;:…-]+$/u, '');
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
function countWords(text) {
|
|
73
|
+
const trimmed = text.trim();
|
|
74
|
+
return trimmed ? trimmed.split(/\s+/).length : 0;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
function isTrivial(prompt) {
|
|
78
|
+
const trimmed = String(prompt || '').trim();
|
|
79
|
+
if (!trimmed) return true;
|
|
80
|
+
|
|
81
|
+
// Slash command — já roteado explicitamente
|
|
82
|
+
if (trimmed.startsWith('/')) return true;
|
|
83
|
+
|
|
84
|
+
// Pergunta de 1 palavra só ("link?", "cadê?") — informacional, sem pedido de trabalho
|
|
85
|
+
if (/^\S+\?$/.test(trimmed)) return true;
|
|
86
|
+
|
|
87
|
+
for (const pattern of MARKER_PATTERNS) {
|
|
88
|
+
if (pattern.test(trimmed)) return true;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
for (const pattern of OPENER_PATTERNS) {
|
|
92
|
+
const match = pattern.exec(trimmed);
|
|
93
|
+
if (!match) continue;
|
|
94
|
+
const leftover = normalizeLeftover(trimmed.slice(match[0].length));
|
|
95
|
+
if (countWords(leftover) <= MAX_LEFTOVER_WORDS) return true;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
// Sem heurística de tamanho para o prompt inteiro: um prompt curto e
|
|
99
|
+
// ambíguo que NÃO começa com abridor (ex.: "e o funil?", "melhora isso")
|
|
100
|
+
// não é trivial por padrão. Custo de injetar contexto à toa é ~50-70
|
|
101
|
+
// tokens; custo de deixar um pedido real escapar do roteamento é alto (ver
|
|
102
|
+
// bug de 2026-08-19 e o RT-H1 acima). Só os abridores + sobra curta, ou os
|
|
103
|
+
// marcadores de conteúdo, marcam trivial.
|
|
104
|
+
return false;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
// Sobe no máximo 8 níveis procurando _wizz/ (projeto Wizz instalado).
|
|
108
|
+
function findWizzRoot(startDir) {
|
|
109
|
+
let dir = startDir;
|
|
110
|
+
for (let i = 0; i < 8 && dir; i++) {
|
|
111
|
+
try {
|
|
112
|
+
if (fs.existsSync(path.join(dir, '_wizz'))) return dir;
|
|
113
|
+
} catch {
|
|
114
|
+
return null;
|
|
115
|
+
}
|
|
116
|
+
const parent = path.dirname(dir);
|
|
117
|
+
if (parent === dir) return null;
|
|
118
|
+
dir = parent;
|
|
119
|
+
}
|
|
120
|
+
return null;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
function buildContext(isWizzProject) {
|
|
124
|
+
if (isWizzProject) {
|
|
125
|
+
return (
|
|
126
|
+
'🎛️ Projeto Wizz: NÃO invoque wizz-router. 2+ áreas → sempre Skill `wizz-maestro`. ' +
|
|
127
|
+
'1 área: 2+ fatores (multi-passo, planejar, artefato memorável) → `wizz-maestro`; ' +
|
|
128
|
+
'senão → Skill do agente da área (ex: wizz-designer, wizz-quick-dev). ' +
|
|
129
|
+
'Personas são skills, não subagent_type; Agent usa tipos disponíveis wizz-exec-*. Trivial → direto.'
|
|
130
|
+
);
|
|
131
|
+
}
|
|
132
|
+
return (
|
|
133
|
+
'🎛️ Pedido não-trivial: invoque a Skill `wizz-router` antes de agir para ' +
|
|
134
|
+
'mapear skills/MCPs (liste candidatas via AskUserQuestion e confirme). ' +
|
|
135
|
+
'Exceção: edição trivial de 1 linha e conversa pura.'
|
|
136
|
+
);
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
function isTraceEnabled() {
|
|
140
|
+
return process.env.WIZZ_TRACE === '1';
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
function getTraceFile() {
|
|
144
|
+
return process.env.WIZZ_TRACE_FILE || path.join(os.homedir(), '.claude', 'wizz-trace.jsonl');
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
// Grava 1 linha JSON por decisão quando WIZZ_TRACE=1. Append-only,
|
|
148
|
+
// fail-silent, e não faz nada (nem chega a serializar) quando desligado —
|
|
149
|
+
// custo zero no caminho comum.
|
|
150
|
+
function traceLine(entry) {
|
|
151
|
+
if (!isTraceEnabled()) return;
|
|
152
|
+
try {
|
|
153
|
+
fs.appendFileSync(getTraceFile(), JSON.stringify(entry) + '\n');
|
|
154
|
+
} catch {
|
|
155
|
+
// trace nunca pode derrubar o hook
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
function getGlobalSkillsDir() {
|
|
160
|
+
return process.env.WIZZ_GLOBAL_SKILLS_DIR || path.join(os.homedir(), '.claude', 'skills');
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
// Verifica se os artefatos de que o roteamento depende de fato existem.
|
|
164
|
+
// Devolve uma lista de avisos legíveis (vazia = tudo ok); nunca lança.
|
|
165
|
+
function checkFallbackWarnings(isWizzProject, wizzRoot) {
|
|
166
|
+
const warnings = [];
|
|
167
|
+
try {
|
|
168
|
+
if (isWizzProject) {
|
|
169
|
+
const configPath = path.join(wizzRoot, '_wizz', 'config.toml');
|
|
170
|
+
if (!fs.existsSync(configPath)) {
|
|
171
|
+
warnings.push(`_wizz/config.toml não encontrado em ${wizzRoot} (install de projeto Wizz incompleto?)`);
|
|
172
|
+
}
|
|
173
|
+
} else {
|
|
174
|
+
const flatTablePath = path.join(getGlobalSkillsDir(), 'wizz-router', 'references', 'routing-table-flat.md');
|
|
175
|
+
if (!fs.existsSync(flatTablePath)) {
|
|
176
|
+
warnings.push(`routing-table-flat.md não encontrada em ${flatTablePath} — rode "npm run sync:global" no repo wizz-method`);
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
} catch {
|
|
180
|
+
// fail-silent — checagem de fallback nunca bloqueia o prompt
|
|
181
|
+
}
|
|
182
|
+
return warnings;
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
// Warning visível mesmo com trace desligado: fallback de roteamento é raro
|
|
186
|
+
// e sinaliza um bug de sincronização (ex.: o próprio C1 da auditoria), então
|
|
187
|
+
// vale a pena aparecer em stderr independente de WIZZ_TRACE.
|
|
188
|
+
function emitFallbackWarnings(warnings) {
|
|
189
|
+
for (const warning of warnings) {
|
|
190
|
+
try {
|
|
191
|
+
process.stderr.write(`[wizz-router-enforce] fallback: ${warning}\n`);
|
|
192
|
+
} catch {
|
|
193
|
+
// fail-silent
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
function runHook() {
|
|
199
|
+
let input = '';
|
|
200
|
+
const stdinTimeout = setTimeout(() => process.exit(0), 3000);
|
|
201
|
+
process.stdin.setEncoding('utf8');
|
|
202
|
+
process.stdin.on('data', (chunk) => (input += chunk));
|
|
203
|
+
process.stdin.on('end', () => {
|
|
204
|
+
clearTimeout(stdinTimeout);
|
|
205
|
+
try {
|
|
206
|
+
const data = JSON.parse(input);
|
|
207
|
+
const prompt = data.prompt || '';
|
|
208
|
+
const trivial = !prompt || isTrivial(prompt);
|
|
209
|
+
if (trivial) {
|
|
210
|
+
traceLine({ ts: new Date().toISOString(), isTrivial: true, mode: null });
|
|
211
|
+
process.exit(0);
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
const cwd = data.cwd || process.cwd();
|
|
215
|
+
const wizzRoot = findWizzRoot(cwd);
|
|
216
|
+
const isWizzProject = Boolean(wizzRoot);
|
|
217
|
+
const context = buildContext(isWizzProject);
|
|
218
|
+
|
|
219
|
+
const warnings = checkFallbackWarnings(isWizzProject, wizzRoot);
|
|
220
|
+
if (warnings.length > 0) emitFallbackWarnings(warnings);
|
|
221
|
+
|
|
222
|
+
traceLine({
|
|
223
|
+
ts: new Date().toISOString(),
|
|
224
|
+
isTrivial: false,
|
|
225
|
+
mode: isWizzProject ? 'wizz' : 'flat',
|
|
226
|
+
contextInjected: context,
|
|
227
|
+
warnings,
|
|
228
|
+
});
|
|
229
|
+
|
|
230
|
+
const output = {
|
|
231
|
+
hookSpecificOutput: {
|
|
232
|
+
hookEventName: 'UserPromptSubmit',
|
|
233
|
+
additionalContext: context,
|
|
234
|
+
},
|
|
235
|
+
};
|
|
236
|
+
process.stdout.write(JSON.stringify(output));
|
|
237
|
+
} catch {
|
|
238
|
+
// Falha em silêncio — nunca bloquear o prompt
|
|
239
|
+
process.exit(0);
|
|
240
|
+
}
|
|
241
|
+
});
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
if (require.main === module) {
|
|
245
|
+
runHook();
|
|
246
|
+
} else {
|
|
247
|
+
module.exports = {
|
|
248
|
+
isTrivial,
|
|
249
|
+
buildContext,
|
|
250
|
+
findWizzRoot,
|
|
251
|
+
isTraceEnabled,
|
|
252
|
+
getTraceFile,
|
|
253
|
+
traceLine,
|
|
254
|
+
getGlobalSkillsDir,
|
|
255
|
+
checkFallbackWarnings,
|
|
256
|
+
emitFallbackWarnings,
|
|
257
|
+
};
|
|
258
|
+
}
|
|
@@ -29,7 +29,7 @@ const CLIUtils = {
|
|
|
29
29
|
|
|
30
30
|
const logoLines = termWidth >= 95 ? logoWide : logoNarrow;
|
|
31
31
|
const logo = logoLines.map((line) => color.blue(line)).join('\n');
|
|
32
|
-
const tagline = color.white('
|
|
32
|
+
const tagline = color.white(' Método de agência orientado por IA\n © Wizz! comms. · method.wizzcomms.com');
|
|
33
33
|
|
|
34
34
|
await prompts.box(`${logo}\n${tagline}`, '', {
|
|
35
35
|
contentAlign: 'center',
|