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,368 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* memlog — an append-only memory log: LLM-optimal working memory for a skill.
|
|
3
|
+
*
|
|
4
|
+
* A memlog is the dense, chronological record of everything that mattered in a piece of
|
|
5
|
+
* work — every item the user generated or accepted — kept minimal like human memory: only
|
|
6
|
+
* what's important, never bloated. It persists ACROSS sessions, so a fresh session can
|
|
7
|
+
* load it and continue. It is NOT a deliverable; downstream artifacts (a brief, a PRD, a
|
|
8
|
+
* deck, a report) are *derived* from it on demand. The host skill supplies the vocabulary
|
|
9
|
+
* by how it calls `append` — the tool stays neutral.
|
|
10
|
+
*
|
|
11
|
+
* It is a FLAT log: there are no sections or grouping. Every entry is one line, recorded
|
|
12
|
+
* at the END in the order it happened. The chronology itself is the structure — an event
|
|
13
|
+
* like "started technique X" is just another entry, same as an idea or an insight.
|
|
14
|
+
*
|
|
15
|
+
* Three invariants make it trustworthy:
|
|
16
|
+
*
|
|
17
|
+
* 1. Append-only, chronological. Entries land at the end, in the order they happen.
|
|
18
|
+
* Nothing is ever inserted backward, reordered, edited, or removed. There is no
|
|
19
|
+
* edit or delete subcommand by design; history is never rewritten.
|
|
20
|
+
* 2. Write-only / blind. Every command is an atomic, context-free write and echoes the
|
|
21
|
+
* new state as one line of JSON, so the caller never re-reads the file mid-session.
|
|
22
|
+
* The one time the file is read is on resume — and the caller reads it itself, not
|
|
23
|
+
* via this script.
|
|
24
|
+
* 3. No lifecycle status. A memory log has no "complete" flag. Whether the work is done,
|
|
25
|
+
* blocked, or paused is itself a fact that happened, so it is recorded as an entry
|
|
26
|
+
* (e.g. `append --type event --text "session complete"`), never as frontmatter the
|
|
27
|
+
* log would have to mutate.
|
|
28
|
+
*
|
|
29
|
+
* Atomicity: every write goes to a temp file, is flushed and fsync'd, then atomically
|
|
30
|
+
* renamed over the target, so a crash never leaves a half-written entry. Concurrent
|
|
31
|
+
* writers serialize on an O_EXCL lock file next to the memlog.
|
|
32
|
+
*
|
|
33
|
+
* Known limitation (by design, not a bug): there is no compaction, archival, or size
|
|
34
|
+
* cap. Append-only + no lifecycle status (invariant 3 above) means a `.memlog.md` grows
|
|
35
|
+
* without bound for the life of the workspace. If that ever becomes a real problem, the
|
|
36
|
+
* fix is a new host-skill-driven step, not a change to this script's invariants.
|
|
37
|
+
*
|
|
38
|
+
* The file shape (.memlog.md):
|
|
39
|
+
*
|
|
40
|
+
* ---
|
|
41
|
+
* topic: Onboarding flow for a budgeting app
|
|
42
|
+
* goal: lift week-1 retention
|
|
43
|
+
* updated: 2026-06-07T14:22
|
|
44
|
+
* ---
|
|
45
|
+
*
|
|
46
|
+
* - (note) user picked techniques: SCAMPER, then Six Thinking Hats
|
|
47
|
+
* - (technique) started SCAMPER
|
|
48
|
+
* - (idea) skip the signup wall: let people try with sample data first
|
|
49
|
+
* - (event) session complete
|
|
50
|
+
*
|
|
51
|
+
* Each entry may carry an optional `--type` — what KIND it is (idea, insight, question,
|
|
52
|
+
* decision, direction, assumption, gap, note, event, …) — and an optional `--by` naming
|
|
53
|
+
* who it came from (e.g. `user`, `coach`). Both render into one short inline tag:
|
|
54
|
+
* `(idea)`, `(idea by user)`, `(by coach)`. Omit them for a plain note. The host skill
|
|
55
|
+
* names the vocabulary; the script does not enforce one.
|
|
56
|
+
*
|
|
57
|
+
* Commands:
|
|
58
|
+
* init (--workspace DIR | --path FILE) [--field k=v ...] create the memlog (errors if it exists)
|
|
59
|
+
* append (--workspace DIR | --path FILE) --text STR [--type T] [--by W] append one entry at the end
|
|
60
|
+
* set (--workspace DIR | --path FILE) --key K --value V set/replace a frontmatter field
|
|
61
|
+
*
|
|
62
|
+
* Addressing: `--workspace` is the run folder, and the memlog is always
|
|
63
|
+
* {workspace}/.memlog.md. `--path` points straight at the memlog file instead.
|
|
64
|
+
*
|
|
65
|
+
* Zero dependencies on purpose: this file is copied verbatim to
|
|
66
|
+
* `{project-root}/_wizz/scripts/memlog.js` at install time, where there is no
|
|
67
|
+
* node_modules of any kind. Only `node:*` builtins may be required here.
|
|
68
|
+
*
|
|
69
|
+
* Node port of the former memlog.py (audit item 29, 2026-09-12): Node is now the only
|
|
70
|
+
* prerequisite of the Wizz core.
|
|
71
|
+
*/
|
|
72
|
+
|
|
73
|
+
'use strict';
|
|
74
|
+
|
|
75
|
+
const fs = require('node:fs');
|
|
76
|
+
const path = require('node:path');
|
|
77
|
+
|
|
78
|
+
const MEMLOG = '.memlog.md';
|
|
79
|
+
const LOCK_TIMEOUT_MS = 5000;
|
|
80
|
+
const LOCK_RETRY_MS = 50;
|
|
81
|
+
// A lock older than this belonged to a process that died mid-write; reclaim it
|
|
82
|
+
// instead of making every later caller wait out the full timeout.
|
|
83
|
+
const LOCK_STALE_MS = 30_000;
|
|
84
|
+
|
|
85
|
+
const EXIT_OK = 0;
|
|
86
|
+
const EXIT_RUNTIME = 1;
|
|
87
|
+
const EXIT_USAGE = 2;
|
|
88
|
+
|
|
89
|
+
// ─── helpers ───
|
|
90
|
+
|
|
91
|
+
/** Local timestamp in the frontmatter's `updated` format (YYYY-MM-DDTHH:MM). */
|
|
92
|
+
function now() {
|
|
93
|
+
const d = new Date();
|
|
94
|
+
const pad = (n) => String(n).padStart(2, '0');
|
|
95
|
+
return `${d.getFullYear()}-${pad(d.getMonth() + 1)}-${pad(d.getDate())}T${pad(d.getHours())}:${pad(d.getMinutes())}`;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/** Block the current thread for `ms` without a dependency and without a busy spin. */
|
|
99
|
+
function sleepSync(ms) {
|
|
100
|
+
Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, ms);
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/** Python's str.splitlines(): split on newlines and drop the empty tail a final \n leaves. */
|
|
104
|
+
function splitLines(text) {
|
|
105
|
+
const lines = text.split(/\r\n|\n|\r/);
|
|
106
|
+
if (lines.at(-1) === '') lines.pop();
|
|
107
|
+
return lines;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
// ─── locking ───
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* Take an exclusive lock on `lockFile` (O_EXCL create), retrying until LOCK_TIMEOUT_MS.
|
|
114
|
+
* @param {string} lockFile
|
|
115
|
+
* @returns {number} open file descriptor for the lock
|
|
116
|
+
*/
|
|
117
|
+
function acquireLock(lockFile) {
|
|
118
|
+
fs.mkdirSync(path.dirname(lockFile), { recursive: true });
|
|
119
|
+
const start = Date.now();
|
|
120
|
+
while (Date.now() - start < LOCK_TIMEOUT_MS) {
|
|
121
|
+
try {
|
|
122
|
+
return fs.openSync(lockFile, 'wx');
|
|
123
|
+
} catch (error) {
|
|
124
|
+
if (error.code !== 'EEXIST') throw error;
|
|
125
|
+
reclaimIfStale(lockFile);
|
|
126
|
+
sleepSync(LOCK_RETRY_MS);
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
throw new Error(
|
|
130
|
+
`Falha ao adquirir lock de ${lockFile} após ${LOCK_TIMEOUT_MS / 1000}s. ` + 'Outro processo pode estar gravando o arquivo de memória.',
|
|
131
|
+
);
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
/** Delete a lock left behind by a crashed writer (older than LOCK_STALE_MS). */
|
|
135
|
+
function reclaimIfStale(lockFile) {
|
|
136
|
+
try {
|
|
137
|
+
if (Date.now() - fs.statSync(lockFile).mtimeMs > LOCK_STALE_MS) fs.unlinkSync(lockFile);
|
|
138
|
+
} catch {
|
|
139
|
+
// Gone already, or not ours to clean up: the retry loop handles both.
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
/** Release the lock: close the descriptor and remove the lock file. */
|
|
144
|
+
function releaseLock(fd, lockFile) {
|
|
145
|
+
try {
|
|
146
|
+
fs.closeSync(fd);
|
|
147
|
+
} catch {
|
|
148
|
+
// Already closed.
|
|
149
|
+
}
|
|
150
|
+
try {
|
|
151
|
+
fs.unlinkSync(lockFile);
|
|
152
|
+
} catch {
|
|
153
|
+
// Another writer already reclaimed it as stale.
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
// ─── file shape ───
|
|
158
|
+
|
|
159
|
+
/** The memlog file, from either addressing mode: {workspace}/.memlog.md or an explicit --path. */
|
|
160
|
+
function resolveTarget(args) {
|
|
161
|
+
return args.path ? path.normalize(args.path) : path.join(args.workspace, MEMLOG);
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
/**
|
|
165
|
+
* Return [frontmatter Map in source order, body string]. Frontmatter is plain key: value.
|
|
166
|
+
* The closing fence is the first line that is *exactly* `---`, so a `---` inside a field
|
|
167
|
+
* value (topic/goal are free user text) never truncates the frontmatter.
|
|
168
|
+
* @param {string} text
|
|
169
|
+
* @returns {[Map<string, string>, string]}
|
|
170
|
+
*/
|
|
171
|
+
function split(text) {
|
|
172
|
+
const lines = splitLines(text);
|
|
173
|
+
if (lines.length === 0 || lines[0] !== '---') throw new Error('.memlog.md has no frontmatter');
|
|
174
|
+
const end = lines.findIndex((line, i) => i >= 1 && line === '---');
|
|
175
|
+
if (end === -1) throw new Error('.memlog.md frontmatter is not terminated');
|
|
176
|
+
const meta = new Map();
|
|
177
|
+
for (const line of lines.slice(1, end)) {
|
|
178
|
+
const at = line.indexOf(':');
|
|
179
|
+
if (at === -1) continue;
|
|
180
|
+
meta.set(line.slice(0, at).trim(), line.slice(at + 1).trim());
|
|
181
|
+
}
|
|
182
|
+
return [
|
|
183
|
+
meta,
|
|
184
|
+
lines
|
|
185
|
+
.slice(end + 1)
|
|
186
|
+
.join('\n')
|
|
187
|
+
.replace(/^\n+/, ''),
|
|
188
|
+
];
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
/**
|
|
192
|
+
* Render frontmatter + body back to the file shape.
|
|
193
|
+
* Newlines in values are neutralized so a multi-line field can't break the fence on re-read.
|
|
194
|
+
*/
|
|
195
|
+
function render(meta, body) {
|
|
196
|
+
const fm = [...meta].map(([k, v]) => `${k}: ${splitLines(String(v)).join(' ')}`).join('\n');
|
|
197
|
+
return `---\n${fm}\n---\n\n${body.replace(/\n+$/, '')}\n`;
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
/** Stamp `updated` and keep it last so the field order stays predictable. */
|
|
201
|
+
function touch(meta) {
|
|
202
|
+
meta.delete('updated');
|
|
203
|
+
meta.set('updated', now());
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
/** Temp + write + fsync + atomic rename, so a crash never half-writes an entry. */
|
|
207
|
+
function writeAtomic(target, text) {
|
|
208
|
+
const tmp = `${target}.tmp`;
|
|
209
|
+
const fd = fs.openSync(tmp, 'w');
|
|
210
|
+
try {
|
|
211
|
+
fs.writeFileSync(fd, text, 'utf8');
|
|
212
|
+
fs.fsyncSync(fd);
|
|
213
|
+
} finally {
|
|
214
|
+
fs.closeSync(fd);
|
|
215
|
+
}
|
|
216
|
+
fs.renameSync(tmp, target);
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
function entryCount(body) {
|
|
220
|
+
return splitLines(body).filter((line) => line.startsWith('- ')).length;
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
/** Echo new state so the caller never re-reads the file to know where it stands. */
|
|
224
|
+
function ack(target, body) {
|
|
225
|
+
process.stdout.write(`${JSON.stringify({ ok: true, memlog: target, entries: entryCount(body) })}\n`);
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
/** Read and parse the memlog, turning a missing file into a friendly usage error. */
|
|
229
|
+
function readMemlog(target) {
|
|
230
|
+
let text;
|
|
231
|
+
try {
|
|
232
|
+
text = fs.readFileSync(target, 'utf8');
|
|
233
|
+
} catch (error) {
|
|
234
|
+
if (error.code === 'ENOENT') {
|
|
235
|
+
throw new UsageError(`${target} does not exist; run \`init\` before append/set`);
|
|
236
|
+
}
|
|
237
|
+
throw new Error(`failed to read ${target}: ${error.message}`);
|
|
238
|
+
}
|
|
239
|
+
return split(text);
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
// ─── commands ───
|
|
243
|
+
|
|
244
|
+
class UsageError extends Error {}
|
|
245
|
+
|
|
246
|
+
function cmdInit(args) {
|
|
247
|
+
const target = resolveTarget(args);
|
|
248
|
+
if (fs.existsSync(target)) {
|
|
249
|
+
throw new UsageError(`${target} already exists; use append/set to update it`);
|
|
250
|
+
}
|
|
251
|
+
fs.mkdirSync(path.dirname(target), { recursive: true });
|
|
252
|
+
const meta = new Map();
|
|
253
|
+
for (const pair of args.field) {
|
|
254
|
+
const at = pair.indexOf('=');
|
|
255
|
+
if (at === -1) throw new UsageError(`--field expects key=value, got '${pair}'`);
|
|
256
|
+
meta.set(pair.slice(0, at).trim(), pair.slice(at + 1).trim());
|
|
257
|
+
}
|
|
258
|
+
touch(meta);
|
|
259
|
+
writeAtomic(target, render(meta, ''));
|
|
260
|
+
ack(target, '');
|
|
261
|
+
return EXIT_OK;
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
/** Build one entry line: `- (type by who) text`, with the tag omitted when both are absent. */
|
|
265
|
+
function entryLine(args) {
|
|
266
|
+
const text = args.text.trim().split(/\s+/).filter(Boolean).join(' ');
|
|
267
|
+
let label = args.type || '';
|
|
268
|
+
if (args.by) label = `${label} by ${args.by}`.trim(); // attribution: "(idea by user)" / "(by coach)"
|
|
269
|
+
return `- ${label ? `(${label}) ` : ''}${text}`;
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
/** Run `mutate(meta, body)` under the lock and write the result atomically. */
|
|
273
|
+
function withLockedMemlog(target, mutate) {
|
|
274
|
+
const lockFile = `${target}.lock`;
|
|
275
|
+
const fd = acquireLock(lockFile);
|
|
276
|
+
try {
|
|
277
|
+
const [meta, body] = readMemlog(target);
|
|
278
|
+
const nextBody = mutate(meta, body);
|
|
279
|
+
touch(meta);
|
|
280
|
+
writeAtomic(target, render(meta, nextBody));
|
|
281
|
+
ack(target, nextBody);
|
|
282
|
+
return EXIT_OK;
|
|
283
|
+
} finally {
|
|
284
|
+
releaseLock(fd, lockFile);
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
function cmdAppend(args) {
|
|
289
|
+
const target = resolveTarget(args);
|
|
290
|
+
return withLockedMemlog(target, (_meta, body) => {
|
|
291
|
+
const entry = entryLine(args);
|
|
292
|
+
return body.trim() ? `${body.replace(/\n+$/, '')}\n${entry}` : entry; // always at the end
|
|
293
|
+
});
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
function cmdSet(args) {
|
|
297
|
+
const target = resolveTarget(args);
|
|
298
|
+
return withLockedMemlog(target, (meta, body) => {
|
|
299
|
+
meta.set(args.key, args.value);
|
|
300
|
+
return body;
|
|
301
|
+
});
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
// ─── CLI ───
|
|
305
|
+
|
|
306
|
+
const COMMANDS = {
|
|
307
|
+
init: { run: cmdInit, flags: { field: 'many' }, required: [] },
|
|
308
|
+
append: { run: cmdAppend, flags: { text: 'one', type: 'one', by: 'one' }, required: ['text'] },
|
|
309
|
+
set: { run: cmdSet, flags: { key: 'one', value: 'one' }, required: ['key', 'value'] },
|
|
310
|
+
};
|
|
311
|
+
|
|
312
|
+
const USAGE = 'usage: memlog.js {init,append,set} (--workspace DIR | --path FILE) [options]';
|
|
313
|
+
|
|
314
|
+
/**
|
|
315
|
+
* Parse argv for one subcommand. Throws UsageError on anything argparse would reject.
|
|
316
|
+
* @param {string[]} argv
|
|
317
|
+
* @returns {{spec: object, args: object}}
|
|
318
|
+
*/
|
|
319
|
+
function parseArgs(argv) {
|
|
320
|
+
const [name, ...rest] = argv;
|
|
321
|
+
const spec = Object.prototype.hasOwnProperty.call(COMMANDS, name) ? COMMANDS[name] : null;
|
|
322
|
+
if (!spec) throw new UsageError(`invalid choice: '${name ?? ''}' (choose from init, append, set)`);
|
|
323
|
+
const flags = { workspace: 'one', path: 'one', ...spec.flags };
|
|
324
|
+
const args = { field: [] };
|
|
325
|
+
for (let i = 0; i < rest.length; i++) {
|
|
326
|
+
const key = rest[i].startsWith('--') ? rest[i].slice(2) : null;
|
|
327
|
+
const kind = key && Object.prototype.hasOwnProperty.call(flags, key) ? flags[key] : null;
|
|
328
|
+
if (!kind) throw new UsageError(`unrecognized argument: ${rest[i]}`);
|
|
329
|
+
const value = rest[++i];
|
|
330
|
+
if (value === undefined) throw new UsageError(`argument --${key}: expected one argument`);
|
|
331
|
+
if (kind === 'many') args[key].push(value);
|
|
332
|
+
else args[key] = value;
|
|
333
|
+
}
|
|
334
|
+
// Mutually exclusive AND required: exactly one of the two must be present.
|
|
335
|
+
if (Boolean(args.workspace) === Boolean(args.path)) {
|
|
336
|
+
throw new UsageError('one of the arguments --workspace --path is required (and not both)');
|
|
337
|
+
}
|
|
338
|
+
for (const required of spec.required) {
|
|
339
|
+
if (args[required] === undefined) throw new UsageError(`the following arguments are required: --${required}`);
|
|
340
|
+
}
|
|
341
|
+
return { spec, args };
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
/**
|
|
345
|
+
* Entry point. Returns the process exit code instead of throwing, so callers
|
|
346
|
+
* (tests included) can assert on it.
|
|
347
|
+
* @param {string[]} argv - argv without node and script
|
|
348
|
+
* @returns {number}
|
|
349
|
+
*/
|
|
350
|
+
function main(argv) {
|
|
351
|
+
try {
|
|
352
|
+
const { spec, args } = parseArgs(argv);
|
|
353
|
+
return spec.run(args);
|
|
354
|
+
} catch (error) {
|
|
355
|
+
if (error instanceof UsageError) {
|
|
356
|
+
process.stderr.write(`${USAGE}\nerror: ${error.message}\n`);
|
|
357
|
+
return EXIT_USAGE;
|
|
358
|
+
}
|
|
359
|
+
process.stderr.write(`error: ${error.message}\n`);
|
|
360
|
+
return EXIT_RUNTIME;
|
|
361
|
+
}
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
if (require.main === module) {
|
|
365
|
+
process.exitCode = main(process.argv.slice(2));
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
module.exports = { main, split, render, entryCount, MEMLOG };
|
|
@@ -46,6 +46,20 @@ Optional `include` (aditivo, opcional):
|
|
|
46
46
|
include files warn to stderr and are skipped (fail-open, matching the
|
|
47
47
|
rest of this resolver); they never abort resolution. A toml with no
|
|
48
48
|
`include` key resolves exactly as before this feature existed.
|
|
49
|
+
|
|
50
|
+
`_shared/` fallback: after `wizz install` the skill directory is moved
|
|
51
|
+
out of `_wizz/` into the IDE folder (`.claude/skills/<skill>/`), so a
|
|
52
|
+
shipped `include = ["../../_shared/x.md"]` no longer resolves. When the
|
|
53
|
+
base-relative path is missing AND the include mentions `_shared/`, the
|
|
54
|
+
segment after the LAST `_shared/` is looked up under
|
|
55
|
+
`<project-root>/_wizz/<module>/_shared/` for every module that has one,
|
|
56
|
+
modules sorted by name, first hit wins.
|
|
57
|
+
|
|
58
|
+
Containment: when a project root is known, an include whose base-relative
|
|
59
|
+
path escapes that root (`../../../../outside.md`) is refused with a warning
|
|
60
|
+
before it is read. The `_shared/` fallback candidates live under
|
|
61
|
+
`<project-root>/_wizz/` by construction, so they always pass. A standalone
|
|
62
|
+
skill with no resolvable project root keeps the unrestricted behaviour.
|
|
49
63
|
"""
|
|
50
64
|
|
|
51
65
|
import argparse
|
|
@@ -67,6 +81,8 @@ except ImportError:
|
|
|
67
81
|
|
|
68
82
|
_MISSING = object()
|
|
69
83
|
_KEYED_MERGE_FIELDS = ("code", "id")
|
|
84
|
+
_WIZZ_FOLDER_NAME = "_wizz"
|
|
85
|
+
_SHARED_DIR_NAME = "_shared"
|
|
70
86
|
|
|
71
87
|
|
|
72
88
|
def find_project_root(start: Path):
|
|
@@ -114,19 +130,90 @@ _INCLUDE_TARGET_FIELD = "activation_steps_append"
|
|
|
114
130
|
|
|
115
131
|
def _read_include_file(path: Path):
|
|
116
132
|
"""Read an include file's raw text. Returns None (and warns to stderr)
|
|
117
|
-
when the file is
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
sys.stderr.write(f"warning: include not found, skipping: {path}\n")
|
|
122
|
-
return None
|
|
133
|
+
when the file is unreadable, so a broken include never aborts
|
|
134
|
+
resolution — same fail-open philosophy as the optional team/user layers
|
|
135
|
+
above. Existence (and the `_shared/` fallback) is `_find_include_file`'s
|
|
136
|
+
job."""
|
|
123
137
|
try:
|
|
124
138
|
return path.read_text(encoding="utf-8")
|
|
125
139
|
except OSError as error:
|
|
126
|
-
sys.stderr.write(f"warning:
|
|
140
|
+
sys.stderr.write(f"warning: include not readable, skipping: {path}: {error}\n")
|
|
127
141
|
return None
|
|
128
142
|
|
|
129
143
|
|
|
144
|
+
def _shared_fallback_candidates(rel_path: str, project_root):
|
|
145
|
+
"""Absolute candidates for an include whose base-relative path is missing.
|
|
146
|
+
|
|
147
|
+
The verbatim install pipeline moves each skill directory OUT of `_wizz/`
|
|
148
|
+
into the IDE folder (`.claude/skills/<skill>/customize.toml`) while the
|
|
149
|
+
file keeps its shipped `include = ["../../_shared/x.md"]`. From there that
|
|
150
|
+
resolves to `.claude/_shared/x.md`, which does not exist, and every
|
|
151
|
+
included paragraph was dropped silently. The real shared files live at
|
|
152
|
+
`<project-root>/_wizz/<module>/_shared/`. So: take the segment after the
|
|
153
|
+
LAST `_shared/` in the include and look for it under every module directly
|
|
154
|
+
under `_wizz/` that has a `_shared/` folder, modules sorted by name (first
|
|
155
|
+
hit wins upstream). Nothing else is guessed: an include without `_shared/`
|
|
156
|
+
gets no fallback. Mirror of `sharedFallbackCandidates` in
|
|
157
|
+
tools/installer/core/resolved-includes.js."""
|
|
158
|
+
if project_root is None or not isinstance(rel_path, str):
|
|
159
|
+
return []
|
|
160
|
+
posix = rel_path.replace("\\", "/")
|
|
161
|
+
marker = _SHARED_DIR_NAME + "/"
|
|
162
|
+
index = posix.rfind(marker)
|
|
163
|
+
if index == -1:
|
|
164
|
+
return []
|
|
165
|
+
segment = posix[index + len(marker):]
|
|
166
|
+
parts = segment.split("/")
|
|
167
|
+
if not segment or any(part in ("", "..", ".") for part in parts):
|
|
168
|
+
return []
|
|
169
|
+
|
|
170
|
+
wizz_root = project_root / _WIZZ_FOLDER_NAME
|
|
171
|
+
try:
|
|
172
|
+
modules = sorted(entry.name for entry in wizz_root.iterdir() if entry.is_dir())
|
|
173
|
+
except OSError:
|
|
174
|
+
return []
|
|
175
|
+
candidates = []
|
|
176
|
+
for name in modules:
|
|
177
|
+
shared_dir = wizz_root / name / _SHARED_DIR_NAME
|
|
178
|
+
if not shared_dir.is_dir():
|
|
179
|
+
continue
|
|
180
|
+
candidates.append(shared_dir.joinpath(*parts))
|
|
181
|
+
return candidates
|
|
182
|
+
|
|
183
|
+
|
|
184
|
+
def _is_outside_project_root(base_dir: Path, rel_path: str, project_root):
|
|
185
|
+
"""True when the base-relative include escapes the project root.
|
|
186
|
+
|
|
187
|
+
Hardening (2026-09-11): a customize.toml must not pull arbitrary files
|
|
188
|
+
from the user's home or from a sibling checkout into an agent's
|
|
189
|
+
activation steps, so `include = ["../../../../outside.md"]` is refused
|
|
190
|
+
before it is ever read. The `_shared/` fallback candidates are built
|
|
191
|
+
under `<project-root>/_wizz/` by construction and always pass. When no
|
|
192
|
+
project root is resolvable (standalone skill) there is nothing to be
|
|
193
|
+
outside of and the old unrestricted behaviour stands. Mirror of
|
|
194
|
+
`isOutsideProjectRoot` in tools/installer/core/resolved-includes.js."""
|
|
195
|
+
if project_root is None:
|
|
196
|
+
return False
|
|
197
|
+
primary = (base_dir / rel_path).resolve()
|
|
198
|
+
try:
|
|
199
|
+
primary.relative_to(Path(project_root).resolve())
|
|
200
|
+
except ValueError:
|
|
201
|
+
return True
|
|
202
|
+
return False
|
|
203
|
+
|
|
204
|
+
|
|
205
|
+
def _find_include_file(base_dir: Path, rel_path: str, project_root):
|
|
206
|
+
"""Absolute path the include actually points at, or None. Base-relative
|
|
207
|
+
first, then the `_shared/` fallback above."""
|
|
208
|
+
primary = (base_dir / rel_path).resolve()
|
|
209
|
+
if primary.is_file():
|
|
210
|
+
return primary
|
|
211
|
+
for candidate in _shared_fallback_candidates(rel_path, project_root):
|
|
212
|
+
if candidate.is_file():
|
|
213
|
+
return candidate
|
|
214
|
+
return None
|
|
215
|
+
|
|
216
|
+
|
|
130
217
|
def _split_include_paragraphs(text: str):
|
|
131
218
|
"""Split an included markdown file into instruction strings.
|
|
132
219
|
|
|
@@ -144,7 +231,7 @@ def _split_include_paragraphs(text: str):
|
|
|
144
231
|
return paragraphs
|
|
145
232
|
|
|
146
233
|
|
|
147
|
-
def resolve_includes(data, base_dir: Path):
|
|
234
|
+
def resolve_includes(data, base_dir: Path, project_root=None, skill_name: str = ""):
|
|
148
235
|
"""Expand `include = [...]` keys found in any table of `data`.
|
|
149
236
|
|
|
150
237
|
Purely additive: a table without `include` comes back unchanged. When
|
|
@@ -163,7 +250,22 @@ def resolve_includes(data, base_dir: Path):
|
|
|
163
250
|
if not isinstance(rel_path, str):
|
|
164
251
|
sys.stderr.write(f"warning: include entries must be strings, got: {rel_path!r}\n")
|
|
165
252
|
continue
|
|
166
|
-
|
|
253
|
+
if _is_outside_project_root(base_dir, rel_path, project_root):
|
|
254
|
+
sys.stderr.write(
|
|
255
|
+
f'warning: include outside the project root, skipping: "{rel_path}" '
|
|
256
|
+
f"(skill: {skill_name or '?'})\n"
|
|
257
|
+
)
|
|
258
|
+
continue
|
|
259
|
+
target = _find_include_file(base_dir, rel_path, project_root)
|
|
260
|
+
if target is None:
|
|
261
|
+
primary = (base_dir / rel_path).resolve()
|
|
262
|
+
sys.stderr.write(
|
|
263
|
+
f'warning: include not found, skipping: "{rel_path}" '
|
|
264
|
+
f"(skill: {skill_name or '?'}; tried {primary} and every "
|
|
265
|
+
f"{_WIZZ_FOLDER_NAME}/*/{_SHARED_DIR_NAME}/)\n"
|
|
266
|
+
)
|
|
267
|
+
continue
|
|
268
|
+
text = _read_include_file(target)
|
|
167
269
|
if text is not None:
|
|
168
270
|
included_paragraphs.extend(_split_include_paragraphs(text))
|
|
169
271
|
elif "include" in data:
|
|
@@ -173,7 +275,9 @@ def resolve_includes(data, base_dir: Path):
|
|
|
173
275
|
for key, value in data.items():
|
|
174
276
|
if key == "include":
|
|
175
277
|
continue
|
|
176
|
-
result[key] =
|
|
278
|
+
result[key] = (
|
|
279
|
+
resolve_includes(value, base_dir, project_root, skill_name) if isinstance(value, dict) else value
|
|
280
|
+
)
|
|
177
281
|
|
|
178
282
|
if included_paragraphs:
|
|
179
283
|
existing = result.get(_INCLUDE_TARGET_FIELD, [])
|
|
@@ -294,20 +398,25 @@ def main():
|
|
|
294
398
|
skill_name = skill_dir.name
|
|
295
399
|
defaults_path = skill_dir / "customize.toml"
|
|
296
400
|
|
|
297
|
-
defaults = resolve_includes(load_toml(defaults_path, required=True), defaults_path.parent)
|
|
298
|
-
|
|
299
401
|
# Prefer the project that contains this skill. Only fall back to cwd if
|
|
300
402
|
# the skill isn't inside a recognizable project tree (unusual but possible
|
|
301
403
|
# for standalone skills invoked directly). Using cwd first is unsafe when
|
|
302
404
|
# an ancestor of cwd happens to have a stray _wizz/ from another project.
|
|
405
|
+
# Resolved BEFORE the base layer: the `_shared/` include fallback needs it.
|
|
303
406
|
project_root = find_project_root(skill_dir) or find_project_root(Path.cwd())
|
|
304
407
|
|
|
408
|
+
defaults = resolve_includes(
|
|
409
|
+
load_toml(defaults_path, required=True), defaults_path.parent, project_root, skill_name
|
|
410
|
+
)
|
|
411
|
+
|
|
305
412
|
team = {}
|
|
306
413
|
user = {}
|
|
307
414
|
if project_root:
|
|
308
|
-
custom_dir = project_root /
|
|
309
|
-
team = resolve_includes(load_toml(custom_dir / f"{skill_name}.toml"), custom_dir)
|
|
310
|
-
user = resolve_includes(
|
|
415
|
+
custom_dir = project_root / _WIZZ_FOLDER_NAME / "custom"
|
|
416
|
+
team = resolve_includes(load_toml(custom_dir / f"{skill_name}.toml"), custom_dir, project_root, skill_name)
|
|
417
|
+
user = resolve_includes(
|
|
418
|
+
load_toml(custom_dir / f"{skill_name}.user.toml"), custom_dir, project_root, skill_name
|
|
419
|
+
)
|
|
311
420
|
|
|
312
421
|
merged = deep_merge(defaults, team)
|
|
313
422
|
merged = deep_merge(merged, user)
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
# Sinal de complexidade (fonte única)
|
|
2
|
+
#
|
|
3
|
+
# Lido por wizz-router (SKILL.md), wizz-maestro (SKILL.md) e wizz-quick-dev
|
|
4
|
+
# (SKILL.md) como a FONTE CANÔNICA do parágrafo de regra abaixo. As SKILL.md
|
|
5
|
+
# não fazem include automático dele (skills são pastas autocontidas copiadas
|
|
6
|
+
# verbatim), então editar aqui NÃO propaga sozinho — quem editar este
|
|
7
|
+
# parágrafo precisa replicar a mudança manualmente nas 3 SKILL.md (PT-BR
|
|
8
|
+
# idêntico (após a normalização do teste: backticks, prefixo wizz-, "(você)") em wizz-router/wizz-maestro; tradução em inglês em
|
|
9
|
+
# wizz-quick-dev). `test/test-dispatch-rule-consistency.js` compara o texto
|
|
10
|
+
# do bloco (não só os números) contra as 3 cópias e falha em qualquer
|
|
11
|
+
# divergência de wording, não só de limiar.
|
|
12
|
+
# ---
|
|
13
|
+
|
|
14
|
+
Regra de dispatch: SE 2+ áreas → maestro, sempre. SENÃO conte os 3 fatores restantes (multi-passo, precisa planejar, gera artefato memorável); 2+ fatores → maestro. A cláusula de área decide sozinha, sem somar com mais nada.
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
Copyright 2022 The Instrument Serif Project Authors (https://github.com/Instrument/instrument-serif)
|
|
2
|
+
|
|
3
|
+
This Font Software is licensed under the SIL Open Font License, Version 1.1.
|
|
4
|
+
This license is copied below, and is also available with a FAQ at:
|
|
5
|
+
https://openfontlicense.org
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
-----------------------------------------------------------
|
|
9
|
+
SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
|
|
10
|
+
-----------------------------------------------------------
|
|
11
|
+
|
|
12
|
+
PREAMBLE
|
|
13
|
+
The goals of the Open Font License (OFL) are to stimulate worldwide
|
|
14
|
+
development of collaborative font projects, to support the font creation
|
|
15
|
+
efforts of academic and linguistic communities, and to provide a free and
|
|
16
|
+
open framework in which fonts may be shared and improved in partnership
|
|
17
|
+
with others.
|
|
18
|
+
|
|
19
|
+
The OFL allows the licensed fonts to be used, studied, modified and
|
|
20
|
+
redistributed freely as long as they are not sold by themselves. The
|
|
21
|
+
fonts, including any derivative works, can be bundled, embedded,
|
|
22
|
+
redistributed and/or sold with any software provided that any reserved
|
|
23
|
+
names are not used by derivative works. The fonts and derivatives,
|
|
24
|
+
however, cannot be released under any other type of license. The
|
|
25
|
+
requirement for fonts to remain under this license does not apply
|
|
26
|
+
to any document created using the fonts or their derivatives.
|
|
27
|
+
|
|
28
|
+
DEFINITIONS
|
|
29
|
+
"Font Software" refers to the set of files released by the Copyright
|
|
30
|
+
Holder(s) under this license and clearly marked as such. This may
|
|
31
|
+
include source files, build scripts and documentation.
|
|
32
|
+
|
|
33
|
+
"Reserved Font Name" refers to any names specified as such after the
|
|
34
|
+
copyright statement(s).
|
|
35
|
+
|
|
36
|
+
"Original Version" refers to the collection of Font Software components as
|
|
37
|
+
distributed by the Copyright Holder(s).
|
|
38
|
+
|
|
39
|
+
"Modified Version" refers to any derivative made by adding to, deleting,
|
|
40
|
+
or substituting -- in part or in whole -- any of the components of the
|
|
41
|
+
Original Version, by changing formats or by porting the Font Software to a
|
|
42
|
+
new environment.
|
|
43
|
+
|
|
44
|
+
"Author" refers to any designer, engineer, programmer, technical
|
|
45
|
+
writer or other person who contributed to the Font Software.
|
|
46
|
+
|
|
47
|
+
PERMISSION & CONDITIONS
|
|
48
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
|
49
|
+
a copy of the Font Software, to use, study, copy, merge, embed, modify,
|
|
50
|
+
redistribute, and sell modified and unmodified copies of the Font
|
|
51
|
+
Software, subject to the following conditions:
|
|
52
|
+
|
|
53
|
+
1) Neither the Font Software nor any of its individual components,
|
|
54
|
+
in Original or Modified Versions, may be sold by itself.
|
|
55
|
+
|
|
56
|
+
2) Original or Modified Versions of the Font Software may be bundled,
|
|
57
|
+
redistributed and/or sold with any software, provided that each copy
|
|
58
|
+
contains the above copyright notice and this license. These can be
|
|
59
|
+
included either as stand-alone text files, human-readable headers or
|
|
60
|
+
in the appropriate machine-readable metadata fields within text or
|
|
61
|
+
binary files as long as those fields can be easily viewed by the user.
|
|
62
|
+
|
|
63
|
+
3) No Modified Version of the Font Software may use the Reserved Font
|
|
64
|
+
Name(s) unless explicit written permission is granted by the corresponding
|
|
65
|
+
Copyright Holder. This restriction only applies to the primary font name as
|
|
66
|
+
presented to the users.
|
|
67
|
+
|
|
68
|
+
4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
|
|
69
|
+
Software shall not be used to promote, endorse or advertise any
|
|
70
|
+
Modified Version, except to acknowledge the contribution(s) of the
|
|
71
|
+
Copyright Holder(s) and the Author(s) or with their explicit written
|
|
72
|
+
permission.
|
|
73
|
+
|
|
74
|
+
5) The Font Software, modified or unmodified, in part or in whole,
|
|
75
|
+
must be distributed entirely under this license, and must not be
|
|
76
|
+
distributed under any other license. The requirement for fonts to
|
|
77
|
+
remain under this license does not apply to any document created
|
|
78
|
+
using the Font Software.
|
|
79
|
+
|
|
80
|
+
TERMINATION
|
|
81
|
+
This license becomes null and void if any of the above conditions are
|
|
82
|
+
not met.
|
|
83
|
+
|
|
84
|
+
DISCLAIMER
|
|
85
|
+
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
86
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
|
|
87
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
|
|
88
|
+
OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
|
|
89
|
+
COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
|
90
|
+
INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
|
|
91
|
+
DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
|
92
|
+
FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
|
|
93
|
+
OTHER DEALINGS IN THE FONT SOFTWARE.
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
> 仓库和已下载的缓存中)。用某个 SFX 前先 `ls assets/sfx/<category>/` 确认文件存在;
|
|
13
13
|
> 缺失就跑 `npx --yes wizz-method fetch-assets --bundle huashu-audio --dest
|
|
14
14
|
> assets`(路径相对本 skill 根目录)。离线时手动下载
|
|
15
|
-
> `https://
|
|
15
|
+
> `npx wizz-method fetch-assets --bundle huashu-audio` (2 partes em `https://wizz-assets.junior-aec.workers.dev/huashu-audio-1.tar.gz` e `.../huashu-audio-2.tar.gz`)
|
|
16
16
|
> 解压到 `assets/`,能力不受影响,只是首次用要等下载。
|
|
17
17
|
|
|
18
18
|
---
|