wizz-method 1.4.1 → 1.5.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/README.md +6 -4
- package/package.json +39 -3
- package/skills-registry.yaml +102 -7
- package/src/bmm-skills/4-implementation/wizz-code-review/SKILL.md +2 -0
- package/src/bmm-skills/4-implementation/wizz-quick-dev/SKILL.md +5 -2
- package/src/core-skills/_shared/handoff-protocol.md +61 -0
- package/src/core-skills/wizz-customize/SKILL.md +2 -2
- package/src/core-skills/wizz-party-mode/references/mode-agent-team.md +1 -1
- package/src/core-skills/wizz-party-mode/references/mode-subagent.md +1 -1
- package/src/core-skills/wizz-review-adversarial-general/SKILL.md +2 -0
- package/src/modules/wizz/README.md +3 -3
- package/src/modules/wizz/_shared/communication-rules.md +13 -0
- package/src/modules/wizz/_shared/encerramento.md +2 -2
- package/src/modules/wizz/agents/wizz-ads/customize.toml +5 -3
- package/src/modules/wizz/agents/wizz-copy/customize.toml +5 -3
- package/src/modules/wizz/agents/wizz-designer/SKILL.md +2 -2
- package/src/modules/wizz/agents/wizz-designer/customize.toml +6 -4
- package/src/modules/wizz/agents/wizz-growth/customize.toml +11 -3
- package/src/modules/wizz/agents/wizz-maestro/SKILL.md +9 -5
- package/src/modules/wizz/agents/wizz-maestro/customize.toml +5 -7
- package/src/modules/wizz/agents/wizz-memoria/customize.toml +2 -4
- package/src/modules/wizz/agents/wizz-qa/SKILL.md +5 -5
- package/src/modules/wizz/agents/wizz-qa/customize.toml +9 -7
- package/src/modules/wizz/agents/wizz-seo/customize.toml +5 -3
- package/src/modules/wizz/agents/wizz-social/customize.toml +9 -8
- package/src/modules/wizz/module.yaml +1 -1
- package/src/modules/wizz/overrides/wizz-agent-analyst.toml +4 -5
- package/src/modules/wizz/overrides/wizz-agent-architect.toml +11 -3
- package/src/modules/wizz/overrides/wizz-agent-dev.toml +6 -4
- package/src/modules/wizz/overrides/wizz-agent-pm.toml +4 -2
- package/src/modules/wizz/overrides/wizz-agent-tech-writer.toml +3 -5
- package/src/modules/wizz/overrides/wizz-agent-ux-designer.toml +4 -2
- package/src/modules/wizz/scripts/wizz-init.mjs +3 -1
- package/src/scripts/__pycache__/resolve_customization.cpython-314.pyc +0 -0
- package/src/scripts/memlog.py +9 -0
- package/src/scripts/resolve_customization.py +93 -3
- package/src/skills-lib/adversarial-reviewer/SKILL.md +2 -0
- package/src/skills-lib/algorithmic-art/SKILL.md +29 -369
- package/src/skills-lib/algorithmic-art/references/interactive-artifact.md +139 -0
- package/src/skills-lib/algorithmic-art/references/p5js-implementation.md +121 -0
- package/src/skills-lib/algorithmic-art/references/philosophy-creation.md +88 -0
- package/src/skills-lib/canvas-design/SKILL.md +9 -38
- package/src/skills-lib/canvas-design/references/canvas-execution.md +21 -0
- package/src/skills-lib/canvas-design/references/philosophy-examples.md +25 -0
- package/src/skills-lib/cerebro/SKILL.md +8 -273
- package/src/skills-lib/cerebro/references/comandos-pesquisa-e-sync.md +44 -0
- package/src/skills-lib/cerebro/references/comandos-rotina-e-captura.md +94 -0
- package/src/skills-lib/cerebro/references/comandos-sessao.md +122 -0
- package/src/skills-lib/content-strategy/SKILL.md +12 -316
- package/src/skills-lib/content-strategy/references/content-types.md +52 -0
- package/src/skills-lib/content-strategy/references/ideation-sources.md +78 -0
- package/src/skills-lib/content-strategy/references/pillars-and-keywords.md +78 -0
- package/src/skills-lib/content-strategy/references/prioritization-and-output.md +57 -0
- package/src/skills-lib/decision-maker/SKILL.md +13 -466
- package/src/skills-lib/decision-maker/references/commands-and-edge-cases.md +40 -0
- package/src/skills-lib/decision-maker/references/output-format.md +161 -0
- package/src/skills-lib/decision-maker/references/references-and-extraction.md +129 -0
- package/src/skills-lib/decision-maker/references/six-decisions.md +122 -0
- package/src/skills-lib/decision-maker/references/wizz-method-handoff.md +22 -0
- package/src/skills-lib/find-skills/SKILL.md +9 -6
- package/src/skills-lib/form-cro/SKILL.md +12 -390
- package/src/skills-lib/form-cro/references/experiments.md +73 -0
- package/src/skills-lib/form-cro/references/field-optimization.md +92 -0
- package/src/skills-lib/form-cro/references/flow-and-errors.md +71 -0
- package/src/skills-lib/form-cro/references/measurement-output.md +41 -0
- package/src/skills-lib/form-cro/references/trust-and-form-types.md +54 -0
- package/src/skills-lib/graphify/SKILL.md +2 -20
- package/src/skills-lib/huashu-design/SKILL.md +42 -596
- package/src/skills-lib/huashu-design/references/anti-slop-principles.md +62 -0
- package/src/skills-lib/huashu-design/references/audio-design-rules.md +1 -1
- package/src/skills-lib/huashu-design/references/cross-agent-adaptation.md +14 -0
- package/src/skills-lib/huashu-design/references/design-direction-fallback.md +113 -0
- package/src/skills-lib/huashu-design/references/exception-handling.md +18 -0
- package/src/skills-lib/huashu-design/references/fact-verification.md +36 -0
- package/src/skills-lib/huashu-design/references/ios-prototype.md +146 -0
- package/src/skills-lib/huashu-design/references/sfx-library.md +7 -0
- package/src/skills-lib/huashu-design/references/starter-components.md +24 -0
- package/src/skills-lib/huashu-design/references/video-export.md +1 -1
- package/src/skills-lib/huashu-design/references/watermark-policy.md +23 -0
- package/src/skills-lib/huashu-design/scripts/add-music.sh +12 -1
- package/src/skills-lib/huashu-design/scripts/mix-voiceover.sh +11 -0
- package/src/skills-lib/humanizer/SKILL.md +23 -431
- package/src/skills-lib/humanizer/references/ai-writing-patterns.md +314 -0
- package/src/skills-lib/humanizer/references/full-example.md +72 -0
- package/src/skills-lib/humanizer/references/personality-and-soul.md +36 -0
- package/src/skills-lib/impeccable/SKILL.md +37 -153
- package/src/skills-lib/impeccable/references/design-rules.md +95 -0
- package/src/skills-lib/impeccable/references/pin-unpin-and-hooks.md +17 -0
- package/src/skills-lib/impeccable/references/routing-rules.md +28 -0
- package/src/skills-lib/implementation-planner/SKILL.md +22 -529
- package/src/skills-lib/implementation-planner/references/folder-structure-and-dependencies.md +132 -0
- package/src/skills-lib/implementation-planner/references/handoff-template.md +34 -0
- package/src/skills-lib/implementation-planner/references/implementation-phases.md +54 -0
- package/src/skills-lib/implementation-planner/references/implementation-types.md +28 -0
- package/src/skills-lib/implementation-planner/references/motion-path-implementation.md +57 -0
- package/src/skills-lib/implementation-planner/references/output-templates.md +92 -0
- package/src/skills-lib/implementation-planner/references/performance-plan.md +52 -0
- package/src/skills-lib/inicio-de-projeto/SKILL.md +4 -224
- package/src/skills-lib/inicio-de-projeto/references/implementacao-api-forms.md +112 -0
- package/src/skills-lib/inicio-de-projeto/references/padroes-arquiteturais-e-pastas.md +71 -0
- package/src/skills-lib/inicio-de-projeto/references/seguranca-e-regras-codigo.md +26 -0
- package/src/skills-lib/launch-strategy/SKILL.md +9 -311
- package/src/skills-lib/launch-strategy/references/five-phase-approach.md +76 -0
- package/src/skills-lib/launch-strategy/references/launch-checklist.md +34 -0
- package/src/skills-lib/launch-strategy/references/orb-framework.md +76 -0
- package/src/skills-lib/launch-strategy/references/post-launch-and-ongoing.md +64 -0
- package/src/skills-lib/launch-strategy/references/product-hunt-strategy.md +52 -0
- package/src/skills-lib/marketing-psychology/SKILL.md +18 -401
- package/src/skills-lib/marketing-psychology/references/design-and-delivery-models.md +56 -0
- package/src/skills-lib/marketing-psychology/references/foundational-thinking-models.md +76 -0
- package/src/skills-lib/marketing-psychology/references/growth-and-scaling-models.md +46 -0
- package/src/skills-lib/marketing-psychology/references/influencing-behavior.md +71 -0
- package/src/skills-lib/marketing-psychology/references/pricing-psychology.md +31 -0
- package/src/skills-lib/marketing-psychology/references/understanding-buyers.md +116 -0
- package/src/skills-lib/motion-3d-director/SKILL.md +23 -370
- package/src/skills-lib/motion-3d-director/references/image-to-video-workflow.md +166 -0
- package/src/skills-lib/motion-3d-director/references/motion-paths.md +119 -0
- package/src/skills-lib/motion-3d-director/references/performance-and-handoff.md +51 -0
- package/src/skills-lib/popup-cro/SKILL.md +11 -414
- package/src/skills-lib/popup-cro/references/design-copy-compliance.md +81 -0
- package/src/skills-lib/popup-cro/references/experiments.md +82 -0
- package/src/skills-lib/popup-cro/references/rules-measurement-output.md +87 -0
- package/src/skills-lib/popup-cro/references/triggers-and-popup-types.md +108 -0
- package/src/skills-lib/signup-flow-cro/SKILL.md +13 -321
- package/src/skills-lib/signup-flow-cro/references/experiments.md +72 -0
- package/src/skills-lib/signup-flow-cro/references/field-optimization.md +49 -0
- package/src/skills-lib/signup-flow-cro/references/flow-structure.md +38 -0
- package/src/skills-lib/signup-flow-cro/references/measurement-output-patterns.md +62 -0
- package/src/skills-lib/signup-flow-cro/references/trust-and-post-submit.md +40 -0
- package/src/skills-lib/taste-redesign/SKILL.md +10 -146
- package/src/skills-lib/taste-redesign/references/design-audit.md +120 -0
- package/src/skills-lib/taste-redesign/references/upgrade-techniques.md +31 -0
- package/src/skills-lib/ui-ux-pro-max/SKILL.md +9 -353
- package/src/skills-lib/ui-ux-pro-max/references/common-rules-checklist.md +76 -0
- package/src/skills-lib/ui-ux-pro-max/references/rules-quick-reference.md +70 -0
- package/src/skills-lib/ui-ux-pro-max/references/search-reference.md +45 -0
- package/src/skills-lib/ui-ux-pro-max/references/workflow-guide.md +157 -0
- package/src/skills-lib/web-security/SKILL.md +13 -187
- package/src/skills-lib/web-security/references/checklist-deploy.md +52 -0
- package/src/skills-lib/web-security/references/headers-rate-limit-cors.md +78 -0
- package/src/skills-lib/web-security/references/owasp-top5-detalhado.md +51 -0
- package/src/skills-lib/wizz-router/SKILL.md +20 -9
- package/src/skills-lib/wizz-router/references/auditoria-360.md +4 -4
- package/src/skills-lib/wizz-router/references/routing-table-flat.md +15 -15
- package/tools/fetch-assets.mjs +277 -0
- package/tools/installer/commands/fetch-assets.js +71 -0
- package/tools/installer/commands/install.js +35 -3
- package/tools/installer/commands/trace-report.js +131 -0
- package/tools/installer/core/config.js +9 -0
- package/tools/installer/core/help-catalog.js +181 -0
- package/tools/installer/core/install-paths.js +48 -3
- package/tools/installer/core/installer.js +253 -618
- package/tools/installer/core/manifest-generator.js +8 -1
- package/tools/installer/core/manifest.js +67 -22
- package/tools/installer/core/module-config-writer.js +110 -0
- package/tools/installer/core/preflight-tools-check.js +82 -0
- package/tools/installer/core/quick-update.js +209 -0
- package/tools/installer/core/user-file-preservation.js +250 -0
- package/tools/installer/modules/channel-resolver.js +34 -2
- package/tools/installer/modules/cli-config.js +127 -34
- package/tools/installer/modules/deps-cache.js +28 -1
- package/tools/installer/modules/env-vars.js +446 -0
- package/tools/installer/modules/external-manager.js +40 -6
- package/tools/installer/modules/mcp-config.js +180 -37
- package/tools/installer/modules/module-help-schema.js +2 -1
- package/tools/installer/modules/official-modules.js +1 -1
- package/tools/installer/modules/registry-resolve.js +74 -0
- package/tools/installer/modules/skills-lib.js +11 -15
- package/tools/installer/ui.js +71 -5
- package/wizz-modules.yaml +15 -5
- package/.claude-plugin/marketplace.json +0 -80
- package/AGENTS.md +0 -12
- package/build/artifacts/llms-full.txt +0 -4049
- package/build/artifacts/llms.txt +0 -28
- package/build/site/404.html +0 -55
- package/build/site/_astro/MobileTableOfContents.astro_astro_type_script_index_0_lang.hwBsy0Mo.js +0 -1
- package/build/site/_astro/Search.astro_astro_type_script_index_0_lang.cjYDvRdi.js +0 -1
- package/build/site/_astro/TableOfContents.astro_astro_type_script_index_0_lang.FuRcXuRY.js +0 -1
- package/build/site/_astro/ec.0vx5m.js +0 -3
- package/build/site/_astro/ec.v4551.css +0 -1
- package/build/site/_astro/index.DdjI3lF_.css +0 -1
- package/build/site/_astro/page.B1D-nYk3.js +0 -1
- package/build/site/_astro/print.DNXP8c50.css +0 -1
- package/build/site/_astro/ui-core.D_Lfcn_I.js +0 -2
- package/build/site/diagrams/checkpoint-preview-diagram-fr.webp +0 -0
- package/build/site/diagrams/checkpoint-preview-diagram.png +0 -0
- package/build/site/diagrams/quick-dev-diagram-fr.webp +0 -0
- package/build/site/diagrams/quick-dev-diagram.png +0 -0
- package/build/site/explanation/advanced-elicitation/index.html +0 -105
- package/build/site/explanation/adversarial-review/index.html +0 -109
- package/build/site/explanation/analysis-phase/index.html +0 -129
- package/build/site/explanation/brainstorming/index.html +0 -92
- package/build/site/explanation/checkpoint-preview/index.html +0 -121
- package/build/site/explanation/established-projects-faq/index.html +0 -107
- package/build/site/explanation/forensic-investigation/index.html +0 -167
- package/build/site/explanation/named-agents/index.html +0 -187
- package/build/site/explanation/party-mode/index.html +0 -256
- package/build/site/explanation/preventing-agent-conflicts/index.html +0 -185
- package/build/site/explanation/project-context/index.html +0 -198
- package/build/site/explanation/quick-dev/index.html +0 -113
- package/build/site/explanation/web-bundles/index.html +0 -178
- package/build/site/explanation/why-solutioning-matters/index.html +0 -168
- package/build/site/how-to/customize-wizz/index.html +0 -277
- package/build/site/how-to/established-projects/index.html +0 -165
- package/build/site/how-to/expand-wizz-for-your-org/index.html +0 -245
- package/build/site/how-to/get-answers-about-wizz/index.html +0 -129
- package/build/site/how-to/install-custom-modules/index.html +0 -197
- package/build/site/how-to/install-wizz/index.html +0 -330
- package/build/site/how-to/non-interactive-installation/index.html +0 -73
- package/build/site/how-to/project-context/index.html +0 -141
- package/build/site/how-to/quick-fixes/index.html +0 -122
- package/build/site/how-to/shard-large-documents/index.html +0 -103
- package/build/site/how-to/upgrade-to-v6/index.html +0 -185
- package/build/site/how-to/use-web-bundles/index.html +0 -99
- package/build/site/img/wizz-dark.png +0 -0
- package/build/site/img/wizz-light.png +0 -0
- package/build/site/index.html +0 -128
- package/build/site/llms-full.txt +0 -4049
- package/build/site/llms.txt +0 -28
- package/build/site/pagefind/fragment/en_175de32.pf_fragment +0 -0
- package/build/site/pagefind/fragment/en_24258fb.pf_fragment +0 -0
- package/build/site/pagefind/fragment/en_24f53a6.pf_fragment +0 -0
- package/build/site/pagefind/fragment/en_27ba8f9.pf_fragment +0 -0
- package/build/site/pagefind/fragment/en_296ddb9.pf_fragment +0 -0
- package/build/site/pagefind/fragment/en_2b5aa5c.pf_fragment +0 -0
- package/build/site/pagefind/fragment/en_49047e0.pf_fragment +0 -0
- package/build/site/pagefind/fragment/en_4a187d2.pf_fragment +0 -0
- package/build/site/pagefind/fragment/en_514725b.pf_fragment +0 -0
- package/build/site/pagefind/fragment/en_583316f.pf_fragment +0 -0
- package/build/site/pagefind/fragment/en_6465dfb.pf_fragment +0 -0
- package/build/site/pagefind/fragment/en_67825a4.pf_fragment +0 -0
- package/build/site/pagefind/fragment/en_82aec61.pf_fragment +0 -0
- package/build/site/pagefind/fragment/en_85dcebf.pf_fragment +0 -0
- package/build/site/pagefind/fragment/en_887ce56.pf_fragment +0 -0
- package/build/site/pagefind/fragment/en_89a1a7a.pf_fragment +0 -0
- package/build/site/pagefind/fragment/en_8ade291.pf_fragment +0 -0
- package/build/site/pagefind/fragment/en_8c11f8a.pf_fragment +0 -0
- package/build/site/pagefind/fragment/en_8c1bde3.pf_fragment +0 -0
- package/build/site/pagefind/fragment/en_92d7cc7.pf_fragment +0 -0
- package/build/site/pagefind/fragment/en_94bfc21.pf_fragment +0 -0
- package/build/site/pagefind/fragment/en_9b57d7d.pf_fragment +0 -0
- package/build/site/pagefind/fragment/en_ab62b53.pf_fragment +0 -0
- package/build/site/pagefind/fragment/en_b0d23ee.pf_fragment +0 -0
- package/build/site/pagefind/fragment/en_ba9fb37.pf_fragment +0 -0
- package/build/site/pagefind/fragment/en_bb113eb.pf_fragment +0 -0
- package/build/site/pagefind/fragment/en_bfc56b6.pf_fragment +0 -0
- package/build/site/pagefind/fragment/en_c6d9e48.pf_fragment +0 -0
- package/build/site/pagefind/fragment/en_cdd772f.pf_fragment +0 -0
- package/build/site/pagefind/fragment/en_cdd885c.pf_fragment +0 -0
- package/build/site/pagefind/fragment/en_cefed6a.pf_fragment +0 -0
- package/build/site/pagefind/fragment/en_d890205.pf_fragment +0 -0
- package/build/site/pagefind/fragment/en_da351b7.pf_fragment +0 -0
- package/build/site/pagefind/fragment/en_ea289f9.pf_fragment +0 -0
- package/build/site/pagefind/fragment/en_f1c3711.pf_fragment +0 -0
- package/build/site/pagefind/index/en_5b9d8c6.pf_index +0 -0
- package/build/site/pagefind/index/en_868614c.pf_index +0 -0
- package/build/site/pagefind/index/en_e4f9bff.pf_index +0 -0
- package/build/site/pagefind/pagefind-entry.json +0 -1
- package/build/site/pagefind/pagefind-highlight.js +0 -1064
- package/build/site/pagefind/pagefind-modular-ui.css +0 -214
- package/build/site/pagefind/pagefind-modular-ui.js +0 -8
- package/build/site/pagefind/pagefind-ui.css +0 -1
- package/build/site/pagefind/pagefind-ui.js +0 -2
- package/build/site/pagefind/pagefind.en_4e69d7f053.pf_meta +0 -0
- package/build/site/pagefind/pagefind.js +0 -6
- package/build/site/pagefind/wasm.en.pagefind +0 -0
- package/build/site/pagefind/wasm.unknown.pagefind +0 -0
- package/build/site/reference/agents/index.html +0 -168
- package/build/site/reference/commands/index.html +0 -254
- package/build/site/reference/core-tools/index.html +0 -384
- package/build/site/reference/modules/index.html +0 -132
- package/build/site/reference/testing/index.html +0 -218
- package/build/site/reference/workflow-map/index.html +0 -266
- package/build/site/roadmap/index.html +0 -77
- package/build/site/robots.txt +0 -37
- package/build/site/sitemap-0.xml +0 -1
- package/build/site/sitemap-index.xml +0 -1
- package/build/site/tutorials/getting-started/index.html +0 -386
- package/build/site/wizz-icon-orange.svg +0 -7
- package/build/site/workflow-map-diagram-fr.html +0 -375
- package/build/site/workflow-map-diagram.html +0 -375
- package/evals/bmm-skills/wizz-product-brief/evals.json +0 -237
- package/evals/bmm-skills/wizz-product-brief/files/branfield-memo.md +0 -46
- package/evals/bmm-skills/wizz-product-brief/files/forkbird-brief/addendum.md +0 -40
- package/evals/bmm-skills/wizz-product-brief/files/forkbird-brief/brief.md +0 -56
- package/evals/bmm-skills/wizz-product-brief/files/forkbird-brief/decision-log.md +0 -27
- package/evals/bmm-skills/wizz-product-brief/files/meridian-mobility-report.md +0 -116
- package/evals/bmm-skills/wizz-product-brief/files/mossridge-brief/addendum.md +0 -41
- package/evals/bmm-skills/wizz-product-brief/files/mossridge-brief/brief.md +0 -57
- package/evals/bmm-skills/wizz-product-brief/files/mossridge-brief/decision-log.md +0 -29
- package/evals/bmm-skills/wizz-product-brief/files/pantry-bridge-interviews.md +0 -90
- package/evals/bmm-skills/wizz-product-brief/files/q2-brainstorm.md +0 -101
- package/evals/bmm-skills/wizz-product-brief/triggers.json +0 -18
- package/evals/routing/dataset.json +0 -290
- package/evals/routing/run-routing-eval.mjs +0 -89
- package/src/skills-lib/canvas-design/canvas-fonts/ArsenalSC-Regular.ttf +0 -0
- package/src/skills-lib/canvas-design/canvas-fonts/BigShoulders-Bold.ttf +0 -0
- package/src/skills-lib/canvas-design/canvas-fonts/BigShoulders-Regular.ttf +0 -0
- package/src/skills-lib/canvas-design/canvas-fonts/Boldonse-Regular.ttf +0 -0
- package/src/skills-lib/canvas-design/canvas-fonts/BricolageGrotesque-Bold.ttf +0 -0
- package/src/skills-lib/canvas-design/canvas-fonts/BricolageGrotesque-Regular.ttf +0 -0
- package/src/skills-lib/canvas-design/canvas-fonts/CrimsonPro-Bold.ttf +0 -0
- package/src/skills-lib/canvas-design/canvas-fonts/CrimsonPro-Italic.ttf +0 -0
- package/src/skills-lib/canvas-design/canvas-fonts/CrimsonPro-Regular.ttf +0 -0
- package/src/skills-lib/canvas-design/canvas-fonts/DMMono-Regular.ttf +0 -0
- package/src/skills-lib/canvas-design/canvas-fonts/EricaOne-Regular.ttf +0 -0
- package/src/skills-lib/canvas-design/canvas-fonts/GeistMono-Bold.ttf +0 -0
- package/src/skills-lib/canvas-design/canvas-fonts/GeistMono-Regular.ttf +0 -0
- package/src/skills-lib/canvas-design/canvas-fonts/Gloock-Regular.ttf +0 -0
- package/src/skills-lib/canvas-design/canvas-fonts/IBMPlexMono-Bold.ttf +0 -0
- package/src/skills-lib/canvas-design/canvas-fonts/IBMPlexMono-Regular.ttf +0 -0
- package/src/skills-lib/canvas-design/canvas-fonts/IBMPlexSerif-Bold.ttf +0 -0
- package/src/skills-lib/canvas-design/canvas-fonts/IBMPlexSerif-BoldItalic.ttf +0 -0
- package/src/skills-lib/canvas-design/canvas-fonts/IBMPlexSerif-Italic.ttf +0 -0
- package/src/skills-lib/canvas-design/canvas-fonts/IBMPlexSerif-Regular.ttf +0 -0
- package/src/skills-lib/canvas-design/canvas-fonts/InstrumentSans-Bold.ttf +0 -0
- package/src/skills-lib/canvas-design/canvas-fonts/InstrumentSans-BoldItalic.ttf +0 -0
- package/src/skills-lib/canvas-design/canvas-fonts/InstrumentSans-Italic.ttf +0 -0
- package/src/skills-lib/canvas-design/canvas-fonts/InstrumentSans-Regular.ttf +0 -0
- package/src/skills-lib/canvas-design/canvas-fonts/InstrumentSerif-Italic.ttf +0 -0
- package/src/skills-lib/canvas-design/canvas-fonts/InstrumentSerif-Regular.ttf +0 -0
- package/src/skills-lib/canvas-design/canvas-fonts/Italiana-Regular.ttf +0 -0
- package/src/skills-lib/canvas-design/canvas-fonts/JetBrainsMono-Bold.ttf +0 -0
- package/src/skills-lib/canvas-design/canvas-fonts/JetBrainsMono-Regular.ttf +0 -0
- package/src/skills-lib/canvas-design/canvas-fonts/Jura-Light.ttf +0 -0
- package/src/skills-lib/canvas-design/canvas-fonts/Jura-Medium.ttf +0 -0
- package/src/skills-lib/canvas-design/canvas-fonts/LibreBaskerville-Regular.ttf +0 -0
- package/src/skills-lib/canvas-design/canvas-fonts/Lora-Bold.ttf +0 -0
- package/src/skills-lib/canvas-design/canvas-fonts/Lora-BoldItalic.ttf +0 -0
- package/src/skills-lib/canvas-design/canvas-fonts/Lora-Italic.ttf +0 -0
- package/src/skills-lib/canvas-design/canvas-fonts/Lora-Regular.ttf +0 -0
- package/src/skills-lib/canvas-design/canvas-fonts/NationalPark-Bold.ttf +0 -0
- package/src/skills-lib/canvas-design/canvas-fonts/NationalPark-Regular.ttf +0 -0
- package/src/skills-lib/canvas-design/canvas-fonts/NothingYouCouldDo-Regular.ttf +0 -0
- package/src/skills-lib/canvas-design/canvas-fonts/Outfit-Bold.ttf +0 -0
- package/src/skills-lib/canvas-design/canvas-fonts/Outfit-Regular.ttf +0 -0
- package/src/skills-lib/canvas-design/canvas-fonts/PixelifySans-Medium.ttf +0 -0
- package/src/skills-lib/canvas-design/canvas-fonts/PoiretOne-Regular.ttf +0 -0
- package/src/skills-lib/canvas-design/canvas-fonts/RedHatMono-Bold.ttf +0 -0
- package/src/skills-lib/canvas-design/canvas-fonts/RedHatMono-Regular.ttf +0 -0
- package/src/skills-lib/canvas-design/canvas-fonts/Silkscreen-Regular.ttf +0 -0
- package/src/skills-lib/canvas-design/canvas-fonts/SmoochSans-Medium.ttf +0 -0
- package/src/skills-lib/canvas-design/canvas-fonts/Tektur-Medium.ttf +0 -0
- package/src/skills-lib/canvas-design/canvas-fonts/Tektur-Regular.ttf +0 -0
- package/src/skills-lib/canvas-design/canvas-fonts/WorkSans-Bold.ttf +0 -0
- package/src/skills-lib/canvas-design/canvas-fonts/WorkSans-BoldItalic.ttf +0 -0
- package/src/skills-lib/canvas-design/canvas-fonts/WorkSans-Italic.ttf +0 -0
- package/src/skills-lib/canvas-design/canvas-fonts/WorkSans-Regular.ttf +0 -0
- package/src/skills-lib/canvas-design/canvas-fonts/YoungSerif-Regular.ttf +0 -0
- package/src/skills-lib/huashu-design/assets/bgm-ad.mp3 +0 -0
- package/src/skills-lib/huashu-design/assets/bgm-educational-alt.mp3 +0 -0
- package/src/skills-lib/huashu-design/assets/bgm-educational.mp3 +0 -0
- package/src/skills-lib/huashu-design/assets/bgm-tech.mp3 +0 -0
- package/src/skills-lib/huashu-design/assets/bgm-tutorial-alt.mp3 +0 -0
- package/src/skills-lib/huashu-design/assets/bgm-tutorial.mp3 +0 -0
- package/src/skills-lib/huashu-design/assets/sfx/container/card-flip.mp3 +0 -0
- package/src/skills-lib/huashu-design/assets/sfx/container/card-snap.mp3 +0 -0
- package/src/skills-lib/huashu-design/assets/sfx/container/modal-open.mp3 +0 -0
- package/src/skills-lib/huashu-design/assets/sfx/container/stack-collapse.mp3 +0 -0
- package/src/skills-lib/huashu-design/assets/sfx/feedback/achievement.mp3 +0 -0
- package/src/skills-lib/huashu-design/assets/sfx/feedback/error-tone.mp3 +0 -0
- package/src/skills-lib/huashu-design/assets/sfx/feedback/notification-pop.mp3 +0 -0
- package/src/skills-lib/huashu-design/assets/sfx/feedback/success-chime.mp3 +0 -0
- package/src/skills-lib/huashu-design/assets/sfx/impact/brand-stamp.mp3 +0 -0
- package/src/skills-lib/huashu-design/assets/sfx/impact/drop-thud.mp3 +0 -0
- package/src/skills-lib/huashu-design/assets/sfx/impact/logo-reveal-v2.mp3 +0 -0
- package/src/skills-lib/huashu-design/assets/sfx/impact/logo-reveal.mp3 +0 -0
- package/src/skills-lib/huashu-design/assets/sfx/keyboard/delete-key.mp3 +0 -0
- package/src/skills-lib/huashu-design/assets/sfx/keyboard/enter.mp3 +0 -0
- package/src/skills-lib/huashu-design/assets/sfx/keyboard/space-tap.mp3 +0 -0
- package/src/skills-lib/huashu-design/assets/sfx/keyboard/type-fast.mp3 +0 -0
- package/src/skills-lib/huashu-design/assets/sfx/keyboard/type.mp3 +0 -0
- package/src/skills-lib/huashu-design/assets/sfx/magic/ai-process.mp3 +0 -0
- package/src/skills-lib/huashu-design/assets/sfx/magic/sparkle.mp3 +0 -0
- package/src/skills-lib/huashu-design/assets/sfx/magic/transform.mp3 +0 -0
- package/src/skills-lib/huashu-design/assets/sfx/progress/complete-done.mp3 +0 -0
- package/src/skills-lib/huashu-design/assets/sfx/progress/generate-start.mp3 +0 -0
- package/src/skills-lib/huashu-design/assets/sfx/progress/loading-tick.mp3 +0 -0
- package/src/skills-lib/huashu-design/assets/sfx/terminal/command-execute.mp3 +0 -0
- package/src/skills-lib/huashu-design/assets/sfx/terminal/cursor-blink.mp3 +0 -0
- package/src/skills-lib/huashu-design/assets/sfx/terminal/output-appear.mp3 +0 -0
- package/src/skills-lib/huashu-design/assets/sfx/transition/dissolve.mp3 +0 -0
- package/src/skills-lib/huashu-design/assets/sfx/transition/slide-in.mp3 +0 -0
- package/src/skills-lib/huashu-design/assets/sfx/transition/swipe-horizontal.mp3 +0 -0
- package/src/skills-lib/huashu-design/assets/sfx/transition/whoosh-fast.mp3 +0 -0
- package/src/skills-lib/huashu-design/assets/sfx/transition/whoosh.mp3 +0 -0
- package/src/skills-lib/huashu-design/assets/sfx/ui/click-soft.mp3 +0 -0
- package/src/skills-lib/huashu-design/assets/sfx/ui/click.mp3 +0 -0
- package/src/skills-lib/huashu-design/assets/sfx/ui/focus.mp3 +0 -0
- package/src/skills-lib/huashu-design/assets/sfx/ui/hover-subtle.mp3 +0 -0
- package/src/skills-lib/huashu-design/assets/sfx/ui/tap-finger.mp3 +0 -0
- package/src/skills-lib/huashu-design/assets/sfx/ui/toggle-on.mp3 +0 -0
- package/src/squads/README.md +0 -39
- package/src/squads/advisory-board/README.md +0 -34
- package/src/squads/advisory-board/agents/board-chair.md +0 -161
- package/src/squads/advisory-board/agents/brene-brown.md +0 -296
- package/src/squads/advisory-board/agents/charlie-munger.md +0 -590
- package/src/squads/advisory-board/agents/derek-sivers.md +0 -268
- package/src/squads/advisory-board/agents/naval-ravikant.md +0 -251
- package/src/squads/advisory-board/agents/patrick-lencioni.md +0 -394
- package/src/squads/advisory-board/agents/peter-thiel.md +0 -269
- package/src/squads/advisory-board/agents/ray-dalio.md +0 -567
- package/src/squads/advisory-board/agents/reid-hoffman.md +0 -278
- package/src/squads/advisory-board/agents/simon-sinek.md +0 -291
- package/src/squads/advisory-board/agents/yvon-chouinard.md +0 -275
- package/src/squads/advisory-board/squad.yaml +0 -50
- package/src/squads/brand-squad/README.md +0 -60
- package/src/squads/brand-squad/agents/al-ries.md +0 -175
- package/src/squads/brand-squad/agents/alina-wheeler.md +0 -184
- package/src/squads/brand-squad/agents/archetype-consultant.md +0 -215
- package/src/squads/brand-squad/agents/brand-chief.md +0 -158
- package/src/squads/brand-squad/agents/byron-sharp.md +0 -169
- package/src/squads/brand-squad/agents/david-aaker.md +0 -166
- package/src/squads/brand-squad/agents/denise-yohn.md +0 -172
- package/src/squads/brand-squad/agents/domain-scout.md +0 -135
- package/src/squads/brand-squad/agents/donald-miller.md +0 -179
- package/src/squads/brand-squad/agents/emily-heyward.md +0 -147
- package/src/squads/brand-squad/agents/jean-noel-kapferer.md +0 -189
- package/src/squads/brand-squad/agents/kevin-keller.md +0 -199
- package/src/squads/brand-squad/agents/marty-neumeier.md +0 -170
- package/src/squads/brand-squad/agents/miller-sticky-brand.md +0 -180
- package/src/squads/brand-squad/agents/naming-strategist.md +0 -171
- package/src/squads/brand-squad/squad.yaml +0 -117
- package/src/squads/c-level-squad/README.md +0 -29
- package/src/squads/c-level-squad/agents/caio-architect.md +0 -235
- package/src/squads/c-level-squad/agents/cio-engineer.md +0 -209
- package/src/squads/c-level-squad/agents/cmo-architect.md +0 -208
- package/src/squads/c-level-squad/agents/coo-orchestrator.md +0 -193
- package/src/squads/c-level-squad/agents/cto-architect.md +0 -194
- package/src/squads/c-level-squad/agents/vision-chief.md +0 -201
- package/src/squads/c-level-squad/squad.yaml +0 -45
- package/src/squads/claude-code-mastery/README.md +0 -146
- package/src/squads/claude-code-mastery/agents/claude-mastery-chief.md +0 -554
- package/src/squads/claude-code-mastery/agents/config-engineer.md +0 -865
- package/src/squads/claude-code-mastery/agents/hooks-architect.md +0 -1013
- package/src/squads/claude-code-mastery/agents/mcp-integrator.md +0 -791
- package/src/squads/claude-code-mastery/agents/project-integrator.md +0 -1196
- package/src/squads/claude-code-mastery/agents/roadmap-sentinel.md +0 -931
- package/src/squads/claude-code-mastery/agents/skill-craftsman.md +0 -1250
- package/src/squads/claude-code-mastery/agents/swarm-orchestrator.md +0 -1008
- package/src/squads/copy-squad/README.md +0 -65
- package/src/squads/copy-squad/agents/andre-chaperon.md +0 -206
- package/src/squads/copy-squad/agents/ben-settle.md +0 -194
- package/src/squads/copy-squad/agents/claude-hopkins.md +0 -182
- package/src/squads/copy-squad/agents/clayton-makepeace.md +0 -225
- package/src/squads/copy-squad/agents/copy-chief.md +0 -166
- package/src/squads/copy-squad/agents/dan-kennedy.md +0 -202
- package/src/squads/copy-squad/agents/dan-koe.md +0 -223
- package/src/squads/copy-squad/agents/david-deutsch.md +0 -197
- package/src/squads/copy-squad/agents/david-ogilvy.md +0 -198
- package/src/squads/copy-squad/agents/eugene-schwartz.md +0 -238
- package/src/squads/copy-squad/agents/frank-kern.md +0 -195
- package/src/squads/copy-squad/agents/gary-bencivenga.md +0 -197
- package/src/squads/copy-squad/agents/gary-halbert.md +0 -219
- package/src/squads/copy-squad/agents/jim-rutz.md +0 -193
- package/src/squads/copy-squad/agents/joe-sugarman.md +0 -234
- package/src/squads/copy-squad/agents/john-carlton.md +0 -203
- package/src/squads/copy-squad/agents/jon-benson.md +0 -196
- package/src/squads/copy-squad/agents/parris-lampropoulos.md +0 -188
- package/src/squads/copy-squad/agents/robert-collier.md +0 -183
- package/src/squads/copy-squad/agents/russell-brunson.md +0 -229
- package/src/squads/copy-squad/agents/ry-schwartz.md +0 -185
- package/src/squads/copy-squad/agents/stefan-georgi.md +0 -188
- package/src/squads/copy-squad/agents/todd-brown.md +0 -171
- package/src/squads/copy-squad/squad.yaml +0 -87
- package/src/squads/cybersecurity/README.md +0 -38
- package/src/squads/cybersecurity/agents/busterer.md +0 -108
- package/src/squads/cybersecurity/agents/cartographer.md +0 -114
- package/src/squads/cybersecurity/agents/chris-sanders.md +0 -205
- package/src/squads/cybersecurity/agents/command-generator.md +0 -121
- package/src/squads/cybersecurity/agents/cyber-chief.md +0 -120
- package/src/squads/cybersecurity/agents/dirber.md +0 -111
- package/src/squads/cybersecurity/agents/fuzzer.md +0 -121
- package/src/squads/cybersecurity/agents/georgia-weidman.md +0 -178
- package/src/squads/cybersecurity/agents/jim-manico.md +0 -182
- package/src/squads/cybersecurity/agents/marcus-carey.md +0 -200
- package/src/squads/cybersecurity/agents/omar-santos.md +0 -206
- package/src/squads/cybersecurity/agents/peter-kim.md +0 -179
- package/src/squads/cybersecurity/agents/ripper.md +0 -121
- package/src/squads/cybersecurity/agents/rogue.md +0 -116
- package/src/squads/cybersecurity/agents/shannon-runner.md +0 -108
- package/src/squads/cybersecurity/squad.yaml +0 -56
- package/src/squads/data-squad/README.md +0 -30
- package/src/squads/data-squad/agents/avinash-kaushik.md +0 -268
- package/src/squads/data-squad/agents/data-chief.md +0 -167
- package/src/squads/data-squad/agents/david-spinks.md +0 -277
- package/src/squads/data-squad/agents/nick-mehta.md +0 -294
- package/src/squads/data-squad/agents/peter-fader.md +0 -246
- package/src/squads/data-squad/agents/sean-ellis.md +0 -303
- package/src/squads/data-squad/agents/wes-kao.md +0 -268
- package/src/squads/data-squad/squad.yaml +0 -46
- package/src/squads/design-squad/README.md +0 -31
- package/src/squads/design-squad/agents/brad-frost.md +0 -185
- package/src/squads/design-squad/agents/dan-mall.md +0 -178
- package/src/squads/design-squad/agents/dave-malouf.md +0 -198
- package/src/squads/design-squad/agents/design-chief.md +0 -109
- package/src/squads/design-squad/agents/design-system-architect.md +0 -109
- package/src/squads/design-squad/agents/ui-engineer.md +0 -102
- package/src/squads/design-squad/agents/ux-designer.md +0 -105
- package/src/squads/design-squad/agents/visual-generator.md +0 -108
- package/src/squads/design-squad/squad.yaml +0 -48
- package/src/squads/hormozi-squad/README.md +0 -39
- package/src/squads/hormozi-squad/agents/hormozi-ads.md +0 -159
- package/src/squads/hormozi-squad/agents/hormozi-advisor.md +0 -178
- package/src/squads/hormozi-squad/agents/hormozi-audit.md +0 -178
- package/src/squads/hormozi-squad/agents/hormozi-chief.md +0 -111
- package/src/squads/hormozi-squad/agents/hormozi-closer.md +0 -179
- package/src/squads/hormozi-squad/agents/hormozi-content.md +0 -166
- package/src/squads/hormozi-squad/agents/hormozi-copy.md +0 -152
- package/src/squads/hormozi-squad/agents/hormozi-hooks.md +0 -177
- package/src/squads/hormozi-squad/agents/hormozi-launch.md +0 -160
- package/src/squads/hormozi-squad/agents/hormozi-leads.md +0 -198
- package/src/squads/hormozi-squad/agents/hormozi-models.md +0 -191
- package/src/squads/hormozi-squad/agents/hormozi-offers.md +0 -197
- package/src/squads/hormozi-squad/agents/hormozi-pricing.md +0 -151
- package/src/squads/hormozi-squad/agents/hormozi-retention.md +0 -166
- package/src/squads/hormozi-squad/agents/hormozi-scale.md +0 -175
- package/src/squads/hormozi-squad/agents/hormozi-workshop.md +0 -160
- package/src/squads/hormozi-squad/squad.yaml +0 -60
- package/src/squads/movement/README.md +0 -29
- package/src/squads/movement/agents/analista-de-impacto.md +0 -350
- package/src/squads/movement/agents/estrategista-de-ciclo.md +0 -301
- package/src/squads/movement/agents/fenomenologo.md +0 -169
- package/src/squads/movement/agents/identitario.md +0 -265
- package/src/squads/movement/agents/manifestador.md +0 -279
- package/src/squads/movement/agents/movement-architect.md +0 -210
- package/src/squads/movement/agents/movement-chief.md +0 -135
- package/src/squads/movement/squad.yaml +0 -45
- package/src/squads/storytelling/README.md +0 -35
- package/src/squads/storytelling/agents/blake-snyder.md +0 -225
- package/src/squads/storytelling/agents/dan-harmon.md +0 -167
- package/src/squads/storytelling/agents/joseph-campbell.md +0 -184
- package/src/squads/storytelling/agents/keith-johnstone.md +0 -157
- package/src/squads/storytelling/agents/kindra-hall.md +0 -162
- package/src/squads/storytelling/agents/marshall-ganz.md +0 -167
- package/src/squads/storytelling/agents/matthew-dicks.md +0 -152
- package/src/squads/storytelling/agents/nancy-duarte.md +0 -154
- package/src/squads/storytelling/agents/oren-klaff.md +0 -166
- package/src/squads/storytelling/agents/park-howell.md +0 -152
- package/src/squads/storytelling/agents/shawn-coyne.md +0 -208
- package/src/squads/storytelling/agents/story-chief.md +0 -155
- package/src/squads/storytelling/squad.yaml +0 -52
- package/src/squads/traffic-masters/README.md +0 -39
- package/src/squads/traffic-masters/agents/ad-midas.md +0 -149
- package/src/squads/traffic-masters/agents/ads-analyst.md +0 -135
- package/src/squads/traffic-masters/agents/creative-analyst.md +0 -142
- package/src/squads/traffic-masters/agents/depesh-mandalia.md +0 -174
- package/src/squads/traffic-masters/agents/fiscal.md +0 -144
- package/src/squads/traffic-masters/agents/kasim-aslam.md +0 -158
- package/src/squads/traffic-masters/agents/media-buyer.md +0 -159
- package/src/squads/traffic-masters/agents/molly-pittman.md +0 -185
- package/src/squads/traffic-masters/agents/nicholas-kusmich.md +0 -157
- package/src/squads/traffic-masters/agents/pedro-sobral.md +0 -158
- package/src/squads/traffic-masters/agents/performance-analyst.md +0 -135
- package/src/squads/traffic-masters/agents/pixel-specialist.md +0 -144
- package/src/squads/traffic-masters/agents/ralph-burns.md +0 -163
- package/src/squads/traffic-masters/agents/scale-optimizer.md +0 -144
- package/src/squads/traffic-masters/agents/tom-breeze.md +0 -175
- package/src/squads/traffic-masters/agents/traffic-chief.md +0 -97
- package/src/squads/traffic-masters/squad.yaml +0 -59
- package/tools/bundle-web-bundles.js +0 -117
- package/tools/format-workflow-md.js +0 -263
- package/tools/hooks/README.md +0 -17
- package/tools/hooks/security-defensive-context.js +0 -70
- package/tools/hooks/session-rules.js +0 -38
- package/tools/hooks/wizz-router-enforce.js +0 -188
- package/tools/javascript-conventions.md +0 -5
- package/tools/migrate-custom-module-paths.js +0 -124
- package/tools/skill-validator.md +0 -368
- package/tools/sync-global.mjs +0 -84
- package/tools/validate-sidebar-order.js +0 -388
- package/tools/validate-skills.js +0 -708
- package/tools/validate-svg-changes.sh +0 -356
- /package/tools/installer/{cli-utils.js → banner.js} +0 -0
|
@@ -3,23 +3,26 @@ const fs = require('../fs-native');
|
|
|
3
3
|
const { Manifest } = require('./manifest');
|
|
4
4
|
const { OfficialModules } = require('../modules/official-modules');
|
|
5
5
|
const { installSkillsLib } = require('../modules/skills-lib');
|
|
6
|
-
const { writeMcpConfig, renderAddCommand, prepareMcps } = require('../modules/mcp-config');
|
|
6
|
+
const { writeMcpConfig, renderAddCommand, prepareMcps, partitionAlreadyConfigured } = require('../modules/mcp-config');
|
|
7
|
+
const { promptMissingEnvVars } = require('../modules/env-vars');
|
|
7
8
|
const { installClis, renderInstallCommand } = require('../modules/cli-config');
|
|
8
|
-
const { writeDepsCache } = require('../modules/deps-cache');
|
|
9
|
+
const { writeDepsCache, readPreviousMcpPins } = require('../modules/deps-cache');
|
|
9
10
|
const { IdeManager } = require('../ide/manager');
|
|
10
11
|
const { FileOps } = require('../file-ops');
|
|
11
12
|
const { Config } = require('./config');
|
|
12
|
-
const { getProjectRoot, getSourcePath } = require('../project-root');
|
|
13
13
|
const { ManifestGenerator } = require('./manifest-generator');
|
|
14
14
|
const prompts = require('../prompts');
|
|
15
15
|
const { WIZZ_FOLDER_NAME } = require('../ide/shared/path-utils');
|
|
16
16
|
const { InstallPaths } = require('./install-paths');
|
|
17
17
|
const { ExternalModuleManager } = require('../modules/external-manager');
|
|
18
18
|
const { resolveModuleVersion } = require('../modules/version-resolver');
|
|
19
|
-
const { MODULE_HELP_CSV_HEADER } = require('../modules/module-help-schema');
|
|
20
19
|
|
|
21
20
|
const { ExistingInstall } = require('./existing-install');
|
|
22
21
|
const { warnPreNativeSkillsLegacy } = require('./legacy-warnings');
|
|
22
|
+
const userFilePreservation = require('./user-file-preservation');
|
|
23
|
+
const moduleConfigWriter = require('./module-config-writer');
|
|
24
|
+
const helpCatalog = require('./help-catalog');
|
|
25
|
+
const quickUpdateModule = require('./quick-update');
|
|
23
26
|
|
|
24
27
|
class Installer {
|
|
25
28
|
constructor() {
|
|
@@ -40,12 +43,33 @@ class Installer {
|
|
|
40
43
|
*/
|
|
41
44
|
async install(originalConfig) {
|
|
42
45
|
let updateState = null;
|
|
46
|
+
// Fresh installs (A14, atomic install): the writing pipeline runs against
|
|
47
|
+
// a sibling `_wizz.tmp-<pid>/` scaffold and only gets renamed into
|
|
48
|
+
// `_wizz/` after `generateManifests` succeeds. Tracked here (outside the
|
|
49
|
+
// try's local scope) so the outer catch can remove an orphaned tmp dir
|
|
50
|
+
// without ever touching a real `_wizz/` — cleared the moment the swap
|
|
51
|
+
// actually happens, so a later best-effort failure (e.g. IDE setup) never
|
|
52
|
+
// deletes a now-valid install.
|
|
53
|
+
let freshInstallTmpDir = null;
|
|
43
54
|
|
|
44
55
|
try {
|
|
45
56
|
const config = Config.build(originalConfig);
|
|
46
|
-
|
|
57
|
+
|
|
58
|
+
// Detect BEFORE creating any scaffold — a plain, read-only check
|
|
59
|
+
// against the path _wizz/ would live at, untouched by InstallPaths.
|
|
60
|
+
// This decides tmp-vs-real for InstallPaths.create below; detecting
|
|
61
|
+
// after paths creation (as before A14) meant the real `_wizz/` was
|
|
62
|
+
// already force-created as a side effect even for a first-time
|
|
63
|
+
// install, which is exactly the corruption window this task closes.
|
|
64
|
+
const projectRootCandidate = path.resolve(config.directory);
|
|
65
|
+
const realWizzDirCandidate = path.join(projectRootCandidate, WIZZ_FOLDER_NAME);
|
|
66
|
+
const existingInstall = await ExistingInstall.detect(realWizzDirCandidate);
|
|
67
|
+
const isFreshInstall = !existingInstall.installed;
|
|
68
|
+
|
|
69
|
+
let paths = await InstallPaths.create(config, { useTmp: isFreshInstall });
|
|
70
|
+
if (isFreshInstall) freshInstallTmpDir = paths.wizzDir;
|
|
71
|
+
|
|
47
72
|
const officialModules = await OfficialModules.build(config, paths);
|
|
48
|
-
const existingInstall = await ExistingInstall.detect(paths.wizzDir);
|
|
49
73
|
|
|
50
74
|
try {
|
|
51
75
|
await warnPreNativeSkillsLegacy({
|
|
@@ -87,7 +111,7 @@ class Installer {
|
|
|
87
111
|
|
|
88
112
|
const allModules = config.modules || [];
|
|
89
113
|
|
|
90
|
-
await this._installAndConfigure(
|
|
114
|
+
const configureResult = await this._installAndConfigure(
|
|
91
115
|
config,
|
|
92
116
|
originalConfig,
|
|
93
117
|
paths,
|
|
@@ -97,6 +121,13 @@ class Installer {
|
|
|
97
121
|
officialModules,
|
|
98
122
|
previousSkillManifestRows,
|
|
99
123
|
);
|
|
124
|
+
// Fresh installs got promoted from the tmp scaffold to the real
|
|
125
|
+
// `_wizz/` inside _installAndConfigure (right after generateManifests
|
|
126
|
+
// succeeded) — pick up the rewritten paths so every step below
|
|
127
|
+
// (IDE setup, cleanup, summary) reads/writes the real location, and
|
|
128
|
+
// the outer catch stops treating this as an orphaned tmp dir.
|
|
129
|
+
paths = configureResult.paths;
|
|
130
|
+
if (configureResult.swapped) freshInstallTmpDir = null;
|
|
100
131
|
|
|
101
132
|
await this._setupIdes(config, allModules, paths, addResult, previousSkillIds);
|
|
102
133
|
|
|
@@ -114,14 +145,30 @@ class Installer {
|
|
|
114
145
|
customFiles: restoreResult.customFiles.length > 0 ? restoreResult.customFiles : undefined,
|
|
115
146
|
modifiedFiles: restoreResult.modifiedFiles.length > 0 ? restoreResult.modifiedFiles : undefined,
|
|
116
147
|
preInstallVersions,
|
|
148
|
+
traceEnabled: config.traceEnabled,
|
|
117
149
|
});
|
|
118
150
|
|
|
151
|
+
// Some steps (IDE setup, global skills/MCP/CLI provisioning) are
|
|
152
|
+
// best-effort and record their outcome in `results` instead of
|
|
153
|
+
// throwing, so one broken IDE or MCP never aborts the rest of the
|
|
154
|
+
// install. That used to mean a real per-step failure was invisible to
|
|
155
|
+
// the caller: `success` was always true and the CLI always exited 0.
|
|
156
|
+
// Surface it structurally instead: 'error' rows (hard failures, e.g.
|
|
157
|
+
// a suspended/broken IDE setup) flip success to false; 'warn' rows
|
|
158
|
+
// (recoverable, e.g. a single MCP whose setup script failed) keep
|
|
159
|
+
// success true but are still counted so CI/automation can detect
|
|
160
|
+
// "succeeded with warnings" without parsing log text (see M24).
|
|
161
|
+
const errorCount = results.filter((r) => r.status === 'error').length;
|
|
162
|
+
const warningCount = results.filter((r) => r.status === 'warn').length;
|
|
163
|
+
|
|
119
164
|
return {
|
|
120
|
-
success:
|
|
165
|
+
success: errorCount === 0,
|
|
121
166
|
path: paths.wizzDir,
|
|
122
167
|
modules: config.modules,
|
|
123
168
|
ides: config.ides,
|
|
124
169
|
projectDir: paths.projectRoot,
|
|
170
|
+
errors: errorCount,
|
|
171
|
+
warnings: warningCount,
|
|
125
172
|
};
|
|
126
173
|
} catch (error) {
|
|
127
174
|
await prompts.log.error('Installation failed');
|
|
@@ -134,6 +181,12 @@ class Installer {
|
|
|
134
181
|
if (updateState?.tempModifiedBackupDir && (await fs.pathExists(updateState.tempModifiedBackupDir))) {
|
|
135
182
|
await fs.remove(updateState.tempModifiedBackupDir);
|
|
136
183
|
}
|
|
184
|
+
// A14: a fresh install that never reached the tmp→real swap leaves
|
|
185
|
+
// only the orphaned `_wizz.tmp-<pid>/` scaffold behind — remove just
|
|
186
|
+
// that, never the real `_wizz/` (which never existed on this path).
|
|
187
|
+
if (freshInstallTmpDir && (await fs.pathExists(freshInstallTmpDir))) {
|
|
188
|
+
await fs.remove(freshInstallTmpDir);
|
|
189
|
+
}
|
|
137
190
|
} catch {
|
|
138
191
|
// Best-effort cleanup — don't mask the original error
|
|
139
192
|
}
|
|
@@ -229,6 +282,12 @@ class Installer {
|
|
|
229
282
|
const moduleConfigs = officialModules.moduleConfigs;
|
|
230
283
|
|
|
231
284
|
const dirResults = { createdDirs: [], movedDirs: [], createdWdsFolders: [] };
|
|
285
|
+
// Set true inside configTask the moment the A14 tmp→real swap actually
|
|
286
|
+
// runs, so the return value below tells `install()` precisely when it's
|
|
287
|
+
// safe to stop treating the tmp scaffold as something to clean up on
|
|
288
|
+
// failure — never inferred from path shape (updates and fresh-but-
|
|
289
|
+
// never-swapped both have `paths.isTmp === false` for different reasons).
|
|
290
|
+
let swapped = false;
|
|
232
291
|
|
|
233
292
|
const installTasks = [];
|
|
234
293
|
|
|
@@ -294,6 +353,19 @@ class Installer {
|
|
|
294
353
|
const configTask = {
|
|
295
354
|
title: 'Generating configurations',
|
|
296
355
|
task: async (message) => {
|
|
356
|
+
// A14 (atomic fresh install): `.mcp.json` lives outside `_wizz/`, at
|
|
357
|
+
// the project root. For a fresh install it must not be mutated until
|
|
358
|
+
// AFTER the tmp→real swap below (right after generateManifests
|
|
359
|
+
// succeeds) — writing it earlier would leave a mutated `.mcp.json`
|
|
360
|
+
// even when the install as a whole later fails and the tmp scaffold
|
|
361
|
+
// gets thrown away. `writeMcpConfig` below runs in `dryRun` mode in
|
|
362
|
+
// that case (same merge computation, no disk write) so the log
|
|
363
|
+
// lines/results and the `pinHashes` fed to `writeDepsCache` stay
|
|
364
|
+
// identical to today; the real write happens once, right after the
|
|
365
|
+
// swap. Updates (paths.isTmp === false) are out of scope for this
|
|
366
|
+
// task and keep writing inline, as before.
|
|
367
|
+
let pendingMcpWrite = null;
|
|
368
|
+
|
|
297
369
|
await this.generateModuleConfigs(paths.wizzDir, moduleConfigs);
|
|
298
370
|
addResult('Configurations', 'ok', 'generated');
|
|
299
371
|
|
|
@@ -322,6 +394,7 @@ class Installer {
|
|
|
322
394
|
}
|
|
323
395
|
} catch (error) {
|
|
324
396
|
await prompts.log.warn(`Falha ao instalar skills globais: ${error.message}`);
|
|
397
|
+
addResult('Global skills', 'warn', error.message);
|
|
325
398
|
}
|
|
326
399
|
|
|
327
400
|
// Configure recommended MCP servers for the chosen areas. The user's
|
|
@@ -330,23 +403,62 @@ class Installer {
|
|
|
330
403
|
// the rest. Additive + placeholder-secret, so it never clobbers config
|
|
331
404
|
// or leaks tokens; a failure warns and never aborts the install.
|
|
332
405
|
const mcpPlan = config.mcpPlan || { toWrite: [], toRecommend: [] };
|
|
406
|
+
let mcpPinHashes = {};
|
|
333
407
|
try {
|
|
334
408
|
const toWrite = mcpPlan.toWrite || [];
|
|
335
409
|
if (toWrite.length > 0) {
|
|
336
410
|
message('Configuring MCP servers...');
|
|
337
|
-
//
|
|
338
|
-
//
|
|
339
|
-
//
|
|
340
|
-
//
|
|
341
|
-
//
|
|
342
|
-
//
|
|
343
|
-
//
|
|
411
|
+
// Every resolved MCP goes through prepareMcps (DETECT→INSTALL→
|
|
412
|
+
// VERIFY→RESOLVE) — including ids already present in .mcp.json.
|
|
413
|
+
// A13 needs the RESOLVED server (setup-bearing entries like
|
|
414
|
+
// scrapling get their command rewritten to an absolute path) to
|
|
415
|
+
// hash-compare against what's on disk; comparing against the raw
|
|
416
|
+
// registry command would always "look changed" for those. This
|
|
417
|
+
// is still cheap for an already-installed binary: prepareMcp is
|
|
418
|
+
// detect-first, so only a genuinely missing binary pays for the
|
|
419
|
+
// network-heavy install/post_install steps.
|
|
344
420
|
const { ready: mcpsReady, failed: mcpsFailed } = await prepareMcps({ mcps: toWrite });
|
|
345
421
|
for (const f of mcpsFailed) {
|
|
346
422
|
await prompts.log.warn(
|
|
347
423
|
`MCP ${f.id} não pôde ser preparado (${f.error}). Config NÃO escrita para evitar ENOENT — instale manualmente e adicione depois com \`claude mcp add\`.`,
|
|
348
424
|
);
|
|
349
425
|
}
|
|
426
|
+
if (mcpsFailed.length > 0) {
|
|
427
|
+
addResult('MCP servers', 'warn', `falharam: ${mcpsFailed.map((f) => f.id).join(', ')}`);
|
|
428
|
+
}
|
|
429
|
+
|
|
430
|
+
// Env var assistance (3.3, design em _audit parte 3 seção E):
|
|
431
|
+
// before writing .mcp.json, detect missing `${VAR}`
|
|
432
|
+
// placeholders in the servers about to be written and — only
|
|
433
|
+
// when interactive (never --yes/no-TTY, E1/E5) — offer to fill
|
|
434
|
+
// them, persisting into `.claude/settings.local.json` (the only
|
|
435
|
+
// place confirmed to reach the MCP subprocess's env; C7). Runs
|
|
436
|
+
// on `mcpsReady` (never `toRecommend`) and skips any id already
|
|
437
|
+
// present in `.mcp.json` — its vars are moot, the additive
|
|
438
|
+
// merge below ignores that server entirely. A dedicated
|
|
439
|
+
// try/catch so a failure here only warns and never blocks the
|
|
440
|
+
// `.mcp.json` write that follows (own principle of this
|
|
441
|
+
// feature: never fail the install over a skipped/failed var).
|
|
442
|
+
try {
|
|
443
|
+
const { toPrepare: mcpsForEnvVars } = await partitionAlreadyConfigured({
|
|
444
|
+
projectDir: paths.projectRoot,
|
|
445
|
+
mcps: mcpsReady,
|
|
446
|
+
});
|
|
447
|
+
const envInteractive = !config.skipPrompts && !!process.stdin.isTTY;
|
|
448
|
+
await promptMissingEnvVars(mcpsForEnvVars, {
|
|
449
|
+
projectDir: paths.projectRoot,
|
|
450
|
+
interactive: envInteractive,
|
|
451
|
+
});
|
|
452
|
+
} catch (error) {
|
|
453
|
+
await prompts.log.warn(`Falha ao configurar env vars dos MCPs: ${error.message}`);
|
|
454
|
+
addResult('MCP env vars', 'warn', error.message);
|
|
455
|
+
}
|
|
456
|
+
|
|
457
|
+
// A13 ("merge aditivo congela pins para sempre"): read the pin
|
|
458
|
+
// hashes the LAST install recorded so writeMcpConfig can tell an
|
|
459
|
+
// untouched block (safe to auto-update the pin) from a
|
|
460
|
+
// user-customized one (never overwritten, only warned about).
|
|
461
|
+
const previousPins = await readPreviousMcpPins(paths.wizzDir);
|
|
350
462
|
// Intentionally NOT tracked in installedFiles: .mcp.json is a
|
|
351
463
|
// shared, user-owned config we merge into (it may hold the user's
|
|
352
464
|
// own servers). Tracking it would expose it to uninstall removal
|
|
@@ -354,12 +466,33 @@ class Installer {
|
|
|
354
466
|
const mcpResult = await writeMcpConfig({
|
|
355
467
|
projectDir: paths.projectRoot,
|
|
356
468
|
mcps: mcpsReady,
|
|
469
|
+
previousPins,
|
|
470
|
+
dryRun: paths.isTmp,
|
|
357
471
|
});
|
|
472
|
+
if (paths.isTmp) {
|
|
473
|
+
// Real write deferred until after the tmp→real swap (see the
|
|
474
|
+
// comment at the top of this task and step 4/README below).
|
|
475
|
+
pendingMcpWrite = { mcpsReady, previousPins };
|
|
476
|
+
}
|
|
477
|
+
mcpPinHashes = mcpResult.pinHashes || {};
|
|
358
478
|
if (mcpResult.added.length > 0) {
|
|
359
479
|
addResult('MCP servers', 'ok', `${mcpResult.added.join(', ')} → .mcp.json`);
|
|
360
480
|
}
|
|
481
|
+
const pinUpdated = mcpResult.pinUpdated || [];
|
|
482
|
+
if (pinUpdated.length > 0) {
|
|
483
|
+
await prompts.log.info(
|
|
484
|
+
`MCPs com pin atualizado (bloco não havia sido customizado): ${pinUpdated.map((u) => u.id).join(', ')}`,
|
|
485
|
+
);
|
|
486
|
+
addResult('MCP servers', 'ok', `pin atualizado: ${pinUpdated.map((u) => u.id).join(', ')}`);
|
|
487
|
+
}
|
|
488
|
+
const pinCustomized = mcpResult.pinCustomized || [];
|
|
489
|
+
if (pinCustomized.length > 0) {
|
|
490
|
+
await prompts.log.warn(
|
|
491
|
+
`Há atualização de pin disponível para ${pinCustomized.map((c) => c.id).join(', ')}, mas o bloco no .mcp.json foi customizado (diferente do que o installer escreveu) — mantido intacto. Atualize manualmente se quiser o pin novo.`,
|
|
492
|
+
);
|
|
493
|
+
}
|
|
361
494
|
if (mcpResult.skipped.length > 0) {
|
|
362
|
-
await prompts.log.info(`MCPs já presentes no .mcp.json (mantidos): ${mcpResult.skipped.join(', ')}`);
|
|
495
|
+
await prompts.log.info(`MCPs já presentes e atualizados no .mcp.json (mantidos): ${mcpResult.skipped.join(', ')}`);
|
|
363
496
|
}
|
|
364
497
|
}
|
|
365
498
|
const toRecommend = mcpPlan.toRecommend || [];
|
|
@@ -375,6 +508,7 @@ class Installer {
|
|
|
375
508
|
}
|
|
376
509
|
} catch (error) {
|
|
377
510
|
await prompts.log.warn(`Falha ao configurar MCPs: ${error.message}`);
|
|
511
|
+
addResult('MCP servers', 'warn', error.message);
|
|
378
512
|
}
|
|
379
513
|
|
|
380
514
|
// Install/recommend the CLIs the agents shell out to (agent-browser,
|
|
@@ -401,6 +535,15 @@ class Installer {
|
|
|
401
535
|
`Falha ao instalar CLI ${f.id}: ${f.error}. Rode manualmente: ${renderInstallCommand(toInstall.find((c) => c.id === f.id) || {})}`,
|
|
402
536
|
);
|
|
403
537
|
}
|
|
538
|
+
if (cliResult.failed.length > 0) {
|
|
539
|
+
addResult('CLIs', 'warn', `falharam: ${cliResult.failed.map((f) => f.id).join(', ')}`);
|
|
540
|
+
}
|
|
541
|
+
// M14: verify failure never aborts (CLIs are opt-in) — just a
|
|
542
|
+
// clear warning that the tool cloned/installed but a runtime
|
|
543
|
+
// dependency might still be missing.
|
|
544
|
+
for (const w of cliResult.warnings || []) {
|
|
545
|
+
await prompts.log.warn(`CLI ${w.id} instalado, mas ${w.warning}`);
|
|
546
|
+
}
|
|
404
547
|
}
|
|
405
548
|
const toRecommend = cliPlan.toRecommend || [];
|
|
406
549
|
if (toRecommend.length > 0) {
|
|
@@ -409,6 +552,7 @@ class Installer {
|
|
|
409
552
|
}
|
|
410
553
|
} catch (error) {
|
|
411
554
|
await prompts.log.warn(`Falha ao configurar CLIs: ${error.message}`);
|
|
555
|
+
addResult('CLIs', 'warn', error.message);
|
|
412
556
|
}
|
|
413
557
|
|
|
414
558
|
// Persist a project-local cache of the skill dependencies (CLIs +
|
|
@@ -422,7 +566,10 @@ class Installer {
|
|
|
422
566
|
wizzDir: paths.wizzDir,
|
|
423
567
|
selectedAreas: config.selectedAreas || [],
|
|
424
568
|
cliPlan: config.cliPlan || {},
|
|
425
|
-
|
|
569
|
+
// pinHashes (A13) is the writeMcpConfig result computed above,
|
|
570
|
+
// not part of the config-time plan — merged in here so the
|
|
571
|
+
// NEXT install's readPreviousMcpPins() can see it.
|
|
572
|
+
mcpPlan: { ...config.mcpPlan, pinHashes: mcpPinHashes },
|
|
426
573
|
trackFile: (p) => this.installedFiles.add(p),
|
|
427
574
|
});
|
|
428
575
|
if (depsResult.wrote) {
|
|
@@ -430,7 +577,16 @@ class Installer {
|
|
|
430
577
|
}
|
|
431
578
|
} catch (error) {
|
|
432
579
|
await prompts.log.warn(`Falha ao gravar cache de dependências: ${error.message}`);
|
|
580
|
+
addResult('Skill deps cache', 'warn', error.message);
|
|
433
581
|
}
|
|
582
|
+
} else if (config.isQuickUpdate() && (config.modules || []).includes('bmm')) {
|
|
583
|
+
// Gate above only runs for fresh installs / Modify. Quick Update
|
|
584
|
+
// preserves settings and skips provisioning entirely, so say it
|
|
585
|
+
// explicitly instead of leaving the user to notice by absence
|
|
586
|
+
// (see project memory: "atualizei e não veio skill").
|
|
587
|
+
await prompts.log.info(
|
|
588
|
+
'Quick Update: skills globais, MCPs e CLIs não foram alterados. Rode install e escolha "Modify Wizz Installation" para instalar itens novos.',
|
|
589
|
+
);
|
|
434
590
|
}
|
|
435
591
|
|
|
436
592
|
message('Generating manifests...');
|
|
@@ -456,7 +612,44 @@ class Installer {
|
|
|
456
612
|
ides: config.ides || [],
|
|
457
613
|
preservedModules: modulesForCsvPreserve,
|
|
458
614
|
moduleConfigs,
|
|
615
|
+
// A14: wizzDir is still the tmp scaffold at this point for a fresh
|
|
616
|
+
// install (swap happens right below, after this call succeeds) —
|
|
617
|
+
// skill-manifest.csv must embed the REAL folder name regardless,
|
|
618
|
+
// or every skill path recorded in it (read later by IDE setup,
|
|
619
|
+
// post-swap) would point at a `_wizz.tmp-<pid>/` dir that no
|
|
620
|
+
// longer exists. `paths.realWizzDir` is set by InstallPaths.create
|
|
621
|
+
// for both tmp and non-tmp installs; guarded here because some
|
|
622
|
+
// tests hand-roll a minimal `paths` stand-in without it, in which
|
|
623
|
+
// case falling back to generateManifests' own default (basename of
|
|
624
|
+
// wizzDir) is exactly the pre-A14 behavior.
|
|
625
|
+
wizzFolderName: paths.realWizzDir ? path.basename(paths.realWizzDir) : undefined,
|
|
459
626
|
});
|
|
627
|
+
|
|
628
|
+
// A14 atomic swap: generateManifests just succeeded, so the tmp
|
|
629
|
+
// scaffold now has a valid manifest.yaml — promote it to the real
|
|
630
|
+
// `_wizz/` in one same-filesystem rename. Anything that threw above
|
|
631
|
+
// this line (module copy, configs, global skills, MCP prepare, CLI
|
|
632
|
+
// install, deps cache, or generateManifests itself) never reaches
|
|
633
|
+
// here, so `install()`'s catch finds only the orphaned tmp dir and
|
|
634
|
+
// the real `_wizz/` never existed. No-op for updates (paths.isTmp
|
|
635
|
+
// is false; they were never given a tmp scaffold).
|
|
636
|
+
if (paths.isTmp) {
|
|
637
|
+
await fs.rename(paths.wizzDir, paths.realWizzDir);
|
|
638
|
+
paths = paths.toReal();
|
|
639
|
+
swapped = true;
|
|
640
|
+
}
|
|
641
|
+
|
|
642
|
+
// Perform the .mcp.json write deferred above, now that the swap
|
|
643
|
+
// succeeded. No-op when nothing was staged (non-wizz install, no
|
|
644
|
+
// areas selected, or an update that already wrote inline).
|
|
645
|
+
if (pendingMcpWrite) {
|
|
646
|
+
await writeMcpConfig({
|
|
647
|
+
projectDir: paths.projectRoot,
|
|
648
|
+
mcps: pendingMcpWrite.mcpsReady,
|
|
649
|
+
previousPins: pendingMcpWrite.previousPins,
|
|
650
|
+
});
|
|
651
|
+
}
|
|
652
|
+
|
|
460
653
|
await this._appendPreservedSkillManifestRows(paths.wizzDir, previousSkillManifestRows, preservedModules);
|
|
461
654
|
|
|
462
655
|
// Apply post-install --set TOML patches. Runs after writeCentralConfig
|
|
@@ -500,6 +693,11 @@ class Installer {
|
|
|
500
693
|
}
|
|
501
694
|
|
|
502
695
|
await prompts.tasks([configTask]);
|
|
696
|
+
|
|
697
|
+
// `paths` may have been reassigned above (fresh install: tmp → real,
|
|
698
|
+
// see the A14 swap inside configTask) — return it so `install()` picks
|
|
699
|
+
// up the real location for every step that runs after this returns.
|
|
700
|
+
return { paths, swapped };
|
|
503
701
|
}
|
|
504
702
|
|
|
505
703
|
/**
|
|
@@ -577,7 +775,8 @@ class Installer {
|
|
|
577
775
|
const entries = await fs.readdir(current);
|
|
578
776
|
if (entries.length > 0) break;
|
|
579
777
|
await fs.rmdir(current);
|
|
580
|
-
} catch {
|
|
778
|
+
} catch (error) {
|
|
779
|
+
await prompts.log.warn(`Warning: could not remove empty directory ${current}: ${error.message}`);
|
|
581
780
|
break;
|
|
582
781
|
}
|
|
583
782
|
current = path.dirname(current);
|
|
@@ -648,66 +847,7 @@ class Installer {
|
|
|
648
847
|
* @returns {Object} { customFiles, modifiedFiles } — lists of restored files
|
|
649
848
|
*/
|
|
650
849
|
async _restoreUserFiles(paths, updateState) {
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
if (!updateState || (updateState.customFiles.length === 0 && updateState.modifiedFiles.length === 0)) {
|
|
654
|
-
return noFiles;
|
|
655
|
-
}
|
|
656
|
-
|
|
657
|
-
let restoredCustomFiles = [];
|
|
658
|
-
let restoredModifiedFiles = [];
|
|
659
|
-
|
|
660
|
-
await prompts.tasks([
|
|
661
|
-
{
|
|
662
|
-
title: 'Finalizing installation',
|
|
663
|
-
task: async (message) => {
|
|
664
|
-
if (updateState.customFiles.length > 0) {
|
|
665
|
-
message(`Restoring ${updateState.customFiles.length} custom files...`);
|
|
666
|
-
|
|
667
|
-
for (const originalPath of updateState.customFiles) {
|
|
668
|
-
const relativePath = path.relative(paths.wizzDir, originalPath);
|
|
669
|
-
const backupPath = path.join(updateState.tempBackupDir, relativePath);
|
|
670
|
-
|
|
671
|
-
if (await fs.pathExists(backupPath)) {
|
|
672
|
-
await fs.ensureDir(path.dirname(originalPath));
|
|
673
|
-
await fs.copy(backupPath, originalPath, { overwrite: true });
|
|
674
|
-
}
|
|
675
|
-
}
|
|
676
|
-
|
|
677
|
-
if (updateState.tempBackupDir && (await fs.pathExists(updateState.tempBackupDir))) {
|
|
678
|
-
await fs.remove(updateState.tempBackupDir);
|
|
679
|
-
}
|
|
680
|
-
|
|
681
|
-
restoredCustomFiles = updateState.customFiles;
|
|
682
|
-
}
|
|
683
|
-
|
|
684
|
-
if (updateState.modifiedFiles.length > 0) {
|
|
685
|
-
restoredModifiedFiles = updateState.modifiedFiles;
|
|
686
|
-
|
|
687
|
-
if (updateState.tempModifiedBackupDir && (await fs.pathExists(updateState.tempModifiedBackupDir))) {
|
|
688
|
-
message(`Restoring ${restoredModifiedFiles.length} modified files as .bak...`);
|
|
689
|
-
|
|
690
|
-
for (const modifiedFile of restoredModifiedFiles) {
|
|
691
|
-
const relativePath = path.relative(paths.wizzDir, modifiedFile.path);
|
|
692
|
-
const tempBackupPath = path.join(updateState.tempModifiedBackupDir, relativePath);
|
|
693
|
-
const bakPath = modifiedFile.path + '.bak';
|
|
694
|
-
|
|
695
|
-
if (await fs.pathExists(tempBackupPath)) {
|
|
696
|
-
await fs.ensureDir(path.dirname(bakPath));
|
|
697
|
-
await fs.copy(tempBackupPath, bakPath, { overwrite: true });
|
|
698
|
-
}
|
|
699
|
-
}
|
|
700
|
-
|
|
701
|
-
await fs.remove(updateState.tempModifiedBackupDir);
|
|
702
|
-
}
|
|
703
|
-
}
|
|
704
|
-
|
|
705
|
-
return 'Installation finalized';
|
|
706
|
-
},
|
|
707
|
-
},
|
|
708
|
-
]);
|
|
709
|
-
|
|
710
|
-
return { customFiles: restoredCustomFiles, modifiedFiles: restoredModifiedFiles };
|
|
850
|
+
return userFilePreservation.restoreUserFiles(paths, updateState);
|
|
711
851
|
}
|
|
712
852
|
|
|
713
853
|
/**
|
|
@@ -758,34 +898,7 @@ class Installer {
|
|
|
758
898
|
* @returns {Object} { tempBackupDir, tempModifiedBackupDir } — undefined if no files
|
|
759
899
|
*/
|
|
760
900
|
async _backupUserFiles(paths, customFiles, modifiedFiles) {
|
|
761
|
-
|
|
762
|
-
let tempModifiedBackupDir;
|
|
763
|
-
|
|
764
|
-
if (customFiles.length > 0) {
|
|
765
|
-
tempBackupDir = path.join(paths.projectRoot, '_wizz-custom-backup-temp');
|
|
766
|
-
await fs.ensureDir(tempBackupDir);
|
|
767
|
-
|
|
768
|
-
for (const customFile of customFiles) {
|
|
769
|
-
const relativePath = path.relative(paths.wizzDir, customFile);
|
|
770
|
-
const backupPath = path.join(tempBackupDir, relativePath);
|
|
771
|
-
await fs.ensureDir(path.dirname(backupPath));
|
|
772
|
-
await fs.copy(customFile, backupPath);
|
|
773
|
-
}
|
|
774
|
-
}
|
|
775
|
-
|
|
776
|
-
if (modifiedFiles.length > 0) {
|
|
777
|
-
tempModifiedBackupDir = path.join(paths.projectRoot, '_wizz-modified-backup-temp');
|
|
778
|
-
await fs.ensureDir(tempModifiedBackupDir);
|
|
779
|
-
|
|
780
|
-
for (const modifiedFile of modifiedFiles) {
|
|
781
|
-
const relativePath = path.relative(paths.wizzDir, modifiedFile.path);
|
|
782
|
-
const tempBackupPath = path.join(tempModifiedBackupDir, relativePath);
|
|
783
|
-
await fs.ensureDir(path.dirname(tempBackupPath));
|
|
784
|
-
await fs.copy(modifiedFile.path, tempBackupPath, { overwrite: true });
|
|
785
|
-
}
|
|
786
|
-
}
|
|
787
|
-
|
|
788
|
-
return { tempBackupDir, tempModifiedBackupDir };
|
|
901
|
+
return userFilePreservation.backupUserFiles(paths, customFiles, modifiedFiles);
|
|
789
902
|
}
|
|
790
903
|
|
|
791
904
|
/**
|
|
@@ -966,115 +1079,7 @@ class Installer {
|
|
|
966
1079
|
* @returns {Object} Object with customFiles and modifiedFiles arrays
|
|
967
1080
|
*/
|
|
968
1081
|
async detectCustomFiles(wizzDir, existingFilesManifest) {
|
|
969
|
-
|
|
970
|
-
const modifiedFiles = [];
|
|
971
|
-
|
|
972
|
-
// Memory subtrees (v6.1: _wizz/_memory, current: _wizz/memory) hold
|
|
973
|
-
// per-user runtime data generated by agents with sidecars. These files
|
|
974
|
-
// aren't installer-managed and must never be reported as "custom" or
|
|
975
|
-
// "modified" — they're user state, not user overrides.
|
|
976
|
-
const wizzMemoryPaths = ['_memory', 'memory'];
|
|
977
|
-
|
|
978
|
-
// Check if the manifest has hashes - if not, we can't detect modifications
|
|
979
|
-
let manifestHasHashes = false;
|
|
980
|
-
if (existingFilesManifest && existingFilesManifest.length > 0) {
|
|
981
|
-
manifestHasHashes = existingFilesManifest.some((f) => f.hash);
|
|
982
|
-
}
|
|
983
|
-
|
|
984
|
-
// Build map of previously installed files from files-manifest.csv with their hashes
|
|
985
|
-
const installedFilesMap = new Map();
|
|
986
|
-
for (const fileEntry of existingFilesManifest) {
|
|
987
|
-
if (fileEntry.path) {
|
|
988
|
-
const absolutePath = path.join(wizzDir, fileEntry.path);
|
|
989
|
-
installedFilesMap.set(path.normalize(absolutePath), {
|
|
990
|
-
hash: fileEntry.hash,
|
|
991
|
-
relativePath: fileEntry.path,
|
|
992
|
-
});
|
|
993
|
-
}
|
|
994
|
-
}
|
|
995
|
-
|
|
996
|
-
// Recursively scan wizzDir for all files
|
|
997
|
-
const scanDirectory = async (dir) => {
|
|
998
|
-
try {
|
|
999
|
-
const entries = await fs.readdir(dir, { withFileTypes: true });
|
|
1000
|
-
for (const entry of entries) {
|
|
1001
|
-
const fullPath = path.join(dir, entry.name);
|
|
1002
|
-
|
|
1003
|
-
if (entry.isDirectory()) {
|
|
1004
|
-
// Skip certain directories
|
|
1005
|
-
if (entry.name === 'node_modules' || entry.name === '.git') {
|
|
1006
|
-
continue;
|
|
1007
|
-
}
|
|
1008
|
-
await scanDirectory(fullPath);
|
|
1009
|
-
} else if (entry.isFile()) {
|
|
1010
|
-
const normalizedPath = path.normalize(fullPath);
|
|
1011
|
-
const fileInfo = installedFilesMap.get(normalizedPath);
|
|
1012
|
-
|
|
1013
|
-
// Skip certain system files that are auto-generated
|
|
1014
|
-
const relativePath = path.relative(wizzDir, fullPath);
|
|
1015
|
-
const fileName = path.basename(fullPath);
|
|
1016
|
-
|
|
1017
|
-
// Skip _config directory EXCEPT for modified agent customizations
|
|
1018
|
-
if (relativePath.startsWith('_config/') || relativePath.startsWith('_config\\')) {
|
|
1019
|
-
// Special handling for .customize.yaml files - only preserve if modified
|
|
1020
|
-
if (relativePath.includes('/agents/') && fileName.endsWith('.customize.yaml')) {
|
|
1021
|
-
// Check if the customization file has been modified from manifest
|
|
1022
|
-
const manifestPath = path.join(wizzDir, '_config', 'manifest.yaml');
|
|
1023
|
-
if (await fs.pathExists(manifestPath)) {
|
|
1024
|
-
const crypto = require('node:crypto');
|
|
1025
|
-
const currentContent = await fs.readFile(fullPath, 'utf8');
|
|
1026
|
-
const currentHash = crypto.createHash('sha256').update(currentContent).digest('hex');
|
|
1027
|
-
|
|
1028
|
-
const yaml = require('yaml');
|
|
1029
|
-
const manifestContent = await fs.readFile(manifestPath, 'utf8');
|
|
1030
|
-
const manifestData = yaml.parse(manifestContent);
|
|
1031
|
-
const originalHash = manifestData.agentCustomizations?.[relativePath];
|
|
1032
|
-
|
|
1033
|
-
// Only add to customFiles if hash differs (user modified)
|
|
1034
|
-
if (originalHash && currentHash !== originalHash) {
|
|
1035
|
-
customFiles.push(fullPath);
|
|
1036
|
-
}
|
|
1037
|
-
}
|
|
1038
|
-
}
|
|
1039
|
-
continue;
|
|
1040
|
-
}
|
|
1041
|
-
|
|
1042
|
-
if (wizzMemoryPaths.some((mp) => relativePath === mp || relativePath.startsWith(mp + '/'))) {
|
|
1043
|
-
continue;
|
|
1044
|
-
}
|
|
1045
|
-
|
|
1046
|
-
// Skip config.yaml files - these are regenerated on each install/update
|
|
1047
|
-
if (fileName === 'config.yaml') {
|
|
1048
|
-
continue;
|
|
1049
|
-
}
|
|
1050
|
-
|
|
1051
|
-
if (!fileInfo) {
|
|
1052
|
-
// File not in manifest = custom file
|
|
1053
|
-
// EXCEPT: Agent .md files in module folders are generated files, not custom
|
|
1054
|
-
// Only treat .md files under _config/agents/ as custom
|
|
1055
|
-
if (!(fileName.endsWith('.md') && relativePath.includes('/agents/') && !relativePath.startsWith('_config/'))) {
|
|
1056
|
-
customFiles.push(fullPath);
|
|
1057
|
-
}
|
|
1058
|
-
} else if (manifestHasHashes && fileInfo.hash) {
|
|
1059
|
-
// File in manifest with hash - check if it was modified
|
|
1060
|
-
const currentHash = await this.manifest.calculateFileHash(fullPath);
|
|
1061
|
-
if (currentHash && currentHash !== fileInfo.hash) {
|
|
1062
|
-
// Hash changed = file was modified
|
|
1063
|
-
modifiedFiles.push({
|
|
1064
|
-
path: fullPath,
|
|
1065
|
-
relativePath: fileInfo.relativePath,
|
|
1066
|
-
});
|
|
1067
|
-
}
|
|
1068
|
-
}
|
|
1069
|
-
}
|
|
1070
|
-
}
|
|
1071
|
-
} catch {
|
|
1072
|
-
// Ignore errors scanning directories
|
|
1073
|
-
}
|
|
1074
|
-
};
|
|
1075
|
-
|
|
1076
|
-
await scanDirectory(wizzDir);
|
|
1077
|
-
return { customFiles, modifiedFiles };
|
|
1082
|
+
return userFilePreservation.detectCustomFiles(wizzDir, existingFilesManifest, { manifest: this.manifest });
|
|
1078
1083
|
}
|
|
1079
1084
|
|
|
1080
1085
|
/**
|
|
@@ -1083,93 +1088,7 @@ class Installer {
|
|
|
1083
1088
|
* @param {Object} moduleConfigs - Collected configuration values
|
|
1084
1089
|
*/
|
|
1085
1090
|
async generateModuleConfigs(wizzDir, moduleConfigs) {
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
// Extract core config values to share with other modules
|
|
1089
|
-
const coreConfig = moduleConfigs.core || {};
|
|
1090
|
-
|
|
1091
|
-
// Get all installed module directories
|
|
1092
|
-
const entries = await fs.readdir(wizzDir, { withFileTypes: true });
|
|
1093
|
-
const nonModuleDirs = new Set(['_config', '_memory', 'memory', 'docs', 'scripts', 'custom']);
|
|
1094
|
-
const installedModules = entries.filter((entry) => entry.isDirectory() && !nonModuleDirs.has(entry.name)).map((entry) => entry.name);
|
|
1095
|
-
|
|
1096
|
-
// Generate config.yaml for each installed module
|
|
1097
|
-
for (const moduleName of installedModules) {
|
|
1098
|
-
const modulePath = path.join(wizzDir, moduleName);
|
|
1099
|
-
|
|
1100
|
-
// Get module-specific config or use empty object if none
|
|
1101
|
-
const config = moduleConfigs[moduleName] || {};
|
|
1102
|
-
|
|
1103
|
-
if (await fs.pathExists(modulePath)) {
|
|
1104
|
-
const configPath = path.join(modulePath, 'config.yaml');
|
|
1105
|
-
|
|
1106
|
-
// Create header
|
|
1107
|
-
const packageJson = require(path.join(getProjectRoot(), 'package.json'));
|
|
1108
|
-
const header = `# ${moduleName.toUpperCase()} Module Configuration
|
|
1109
|
-
# Generated by Wizz Method installer
|
|
1110
|
-
# Version: ${packageJson.version}
|
|
1111
|
-
# Date: ${new Date().toISOString()}
|
|
1112
|
-
|
|
1113
|
-
`;
|
|
1114
|
-
|
|
1115
|
-
// For non-core modules, add core config values directly
|
|
1116
|
-
let finalConfig = { ...config };
|
|
1117
|
-
let coreSection = '';
|
|
1118
|
-
|
|
1119
|
-
if (moduleName !== 'core' && coreConfig && Object.keys(coreConfig).length > 0) {
|
|
1120
|
-
// Add core values directly to the module config
|
|
1121
|
-
// These will be available for reference in the module
|
|
1122
|
-
finalConfig = {
|
|
1123
|
-
...config,
|
|
1124
|
-
...coreConfig, // Spread core config values directly into the module config
|
|
1125
|
-
};
|
|
1126
|
-
|
|
1127
|
-
// Create a comment section to identify core values
|
|
1128
|
-
coreSection = '\n# Core Configuration Values\n';
|
|
1129
|
-
}
|
|
1130
|
-
|
|
1131
|
-
// Clean the config to remove any non-serializable values (like functions)
|
|
1132
|
-
const cleanConfig = structuredClone(finalConfig);
|
|
1133
|
-
|
|
1134
|
-
// Convert config to YAML
|
|
1135
|
-
let yamlContent = yaml.stringify(cleanConfig, {
|
|
1136
|
-
indent: 2,
|
|
1137
|
-
lineWidth: 0,
|
|
1138
|
-
minContentWidth: 0,
|
|
1139
|
-
});
|
|
1140
|
-
|
|
1141
|
-
// If we have core values, reorganize the YAML to group them with their comment
|
|
1142
|
-
if (coreSection && moduleName !== 'core') {
|
|
1143
|
-
// Split the YAML into lines
|
|
1144
|
-
const lines = yamlContent.split('\n');
|
|
1145
|
-
const moduleConfigLines = [];
|
|
1146
|
-
const coreConfigLines = [];
|
|
1147
|
-
|
|
1148
|
-
// Separate module-specific and core config lines
|
|
1149
|
-
for (const line of lines) {
|
|
1150
|
-
const key = line.split(':')[0].trim();
|
|
1151
|
-
if (Object.prototype.hasOwnProperty.call(coreConfig, key)) {
|
|
1152
|
-
coreConfigLines.push(line);
|
|
1153
|
-
} else {
|
|
1154
|
-
moduleConfigLines.push(line);
|
|
1155
|
-
}
|
|
1156
|
-
}
|
|
1157
|
-
|
|
1158
|
-
// Rebuild YAML with module config first, then core config with comment
|
|
1159
|
-
yamlContent = moduleConfigLines.join('\n');
|
|
1160
|
-
if (coreConfigLines.length > 0) {
|
|
1161
|
-
yamlContent += coreSection + coreConfigLines.join('\n');
|
|
1162
|
-
}
|
|
1163
|
-
}
|
|
1164
|
-
|
|
1165
|
-
// Write the clean config file with POSIX-compliant final newline
|
|
1166
|
-
const content = header + yamlContent;
|
|
1167
|
-
await fs.writeFile(configPath, content.endsWith('\n') ? content : content + '\n', 'utf8');
|
|
1168
|
-
|
|
1169
|
-
// Track the config file in installedFiles
|
|
1170
|
-
this.installedFiles.add(configPath);
|
|
1171
|
-
}
|
|
1172
|
-
}
|
|
1091
|
+
return moduleConfigWriter.generateModuleConfigs(wizzDir, moduleConfigs, { trackFile: (p) => this.installedFiles.add(p) });
|
|
1173
1092
|
}
|
|
1174
1093
|
|
|
1175
1094
|
/**
|
|
@@ -1179,118 +1098,14 @@ class Installer {
|
|
|
1179
1098
|
* @param {string} wizzDir - WIZZ installation directory
|
|
1180
1099
|
* @param {Array<Object>} _agentEntries - Unused; retained for call-site compatibility
|
|
1181
1100
|
*/
|
|
1182
|
-
async mergeModuleHelpCatalogs(wizzDir,
|
|
1183
|
-
|
|
1184
|
-
const headerRow = MODULE_HELP_CSV_HEADER;
|
|
1185
|
-
const COLUMN_COUNT = 13;
|
|
1186
|
-
const PHASE_INDEX = 7;
|
|
1187
|
-
|
|
1188
|
-
// Get all installed module directories
|
|
1189
|
-
const entries = await fs.readdir(wizzDir, { withFileTypes: true });
|
|
1190
|
-
const nonModuleDirs = new Set(['_config', '_memory', 'memory', 'docs', 'scripts', 'custom']);
|
|
1191
|
-
const installedModules = entries.filter((entry) => entry.isDirectory() && !nonModuleDirs.has(entry.name)).map((entry) => entry.name);
|
|
1192
|
-
|
|
1193
|
-
// Add core module to scan (it's installed at root level as _config, but we check src/core-skills)
|
|
1194
|
-
const coreModulePath = getSourcePath('core-skills');
|
|
1195
|
-
const modulePaths = new Map();
|
|
1196
|
-
|
|
1197
|
-
// Map all module source paths
|
|
1198
|
-
if (await fs.pathExists(coreModulePath)) {
|
|
1199
|
-
modulePaths.set('core', coreModulePath);
|
|
1200
|
-
}
|
|
1201
|
-
|
|
1202
|
-
// Map installed module paths
|
|
1203
|
-
for (const moduleName of installedModules) {
|
|
1204
|
-
const modulePath = path.join(wizzDir, moduleName);
|
|
1205
|
-
modulePaths.set(moduleName, modulePath);
|
|
1206
|
-
}
|
|
1207
|
-
|
|
1208
|
-
// Scan each module for module-help.csv
|
|
1209
|
-
for (const [moduleName, modulePath] of modulePaths) {
|
|
1210
|
-
const helpFilePath = path.join(modulePath, 'module-help.csv');
|
|
1211
|
-
|
|
1212
|
-
if (await fs.pathExists(helpFilePath)) {
|
|
1213
|
-
try {
|
|
1214
|
-
const content = await fs.readFile(helpFilePath, 'utf8');
|
|
1215
|
-
const lines = content.split('\n').filter((line) => line.trim() && !line.startsWith('#'));
|
|
1216
|
-
|
|
1217
|
-
let headerWarned = false;
|
|
1218
|
-
for (const line of lines) {
|
|
1219
|
-
// Header row: warn on drift from canonical schema, then skip.
|
|
1220
|
-
// Data rows are loaded positionally regardless, so the warning
|
|
1221
|
-
// is advisory — the maintainer should rename their columns.
|
|
1222
|
-
if (line.startsWith('module,')) {
|
|
1223
|
-
if (!headerWarned && line.trim() !== headerRow) {
|
|
1224
|
-
await prompts.log.warn(
|
|
1225
|
-
` ${moduleName}/module-help.csv header does not match canonical schema. ` +
|
|
1226
|
-
`Expected: ${headerRow} | Found: ${line.trim()} | Data loaded positionally.`,
|
|
1227
|
-
);
|
|
1228
|
-
headerWarned = true;
|
|
1229
|
-
}
|
|
1230
|
-
continue;
|
|
1231
|
-
}
|
|
1232
|
-
|
|
1233
|
-
// Parse the line - handle quoted fields with commas
|
|
1234
|
-
const columns = this.parseCSVLine(line);
|
|
1235
|
-
if (columns.length < COLUMN_COUNT - 1) continue;
|
|
1236
|
-
|
|
1237
|
-
// Pad short rows; truncate over-long rows
|
|
1238
|
-
const padded = columns.slice(0, COLUMN_COUNT);
|
|
1239
|
-
while (padded.length < COLUMN_COUNT) padded.push('');
|
|
1240
|
-
|
|
1241
|
-
// If module column is empty, fill with this module's name
|
|
1242
|
-
// (core stays empty so its rows render as universal tools)
|
|
1243
|
-
if ((!padded[0] || padded[0].trim() === '') && moduleName !== 'core') {
|
|
1244
|
-
padded[0] = moduleName;
|
|
1245
|
-
}
|
|
1246
|
-
|
|
1247
|
-
allRows.push(padded.map((c) => this.escapeCSVField(c)).join(','));
|
|
1248
|
-
}
|
|
1249
|
-
|
|
1250
|
-
if (process.env.WIZZ_VERBOSE_INSTALL === 'true') {
|
|
1251
|
-
await prompts.log.message(` Merged module-help from: ${moduleName}`);
|
|
1252
|
-
}
|
|
1253
|
-
} catch (error) {
|
|
1254
|
-
await prompts.log.warn(` Warning: Failed to read module-help.csv from ${moduleName}: ${error.message}`);
|
|
1255
|
-
}
|
|
1256
|
-
}
|
|
1257
|
-
}
|
|
1258
|
-
|
|
1259
|
-
// Sort by module, then phase. Stable sort preserves authored order within a phase.
|
|
1260
|
-
const decorated = allRows.map((row, index) => ({ row, index, cols: this.parseCSVLine(row) }));
|
|
1261
|
-
decorated.sort((a, b) => {
|
|
1262
|
-
const moduleA = (a.cols[0] || '').toLowerCase();
|
|
1263
|
-
const moduleB = (b.cols[0] || '').toLowerCase();
|
|
1264
|
-
if (moduleA !== moduleB) return moduleA.localeCompare(moduleB);
|
|
1265
|
-
|
|
1266
|
-
const phaseA = a.cols[PHASE_INDEX] || '';
|
|
1267
|
-
const phaseB = b.cols[PHASE_INDEX] || '';
|
|
1268
|
-
if (phaseA !== phaseB) return phaseA.localeCompare(phaseB);
|
|
1269
|
-
|
|
1270
|
-
return a.index - b.index;
|
|
1271
|
-
});
|
|
1272
|
-
const sortedRows = decorated.map((d) => d.row);
|
|
1273
|
-
|
|
1274
|
-
// Write merged catalog
|
|
1275
|
-
const outputDir = path.join(wizzDir, '_config');
|
|
1276
|
-
await fs.ensureDir(outputDir);
|
|
1277
|
-
const outputPath = path.join(outputDir, 'wizz-help.csv');
|
|
1278
|
-
|
|
1279
|
-
const mergedContent = [headerRow, ...sortedRows].join('\n');
|
|
1280
|
-
await fs.writeFile(outputPath, mergedContent, 'utf8');
|
|
1281
|
-
|
|
1282
|
-
// Track the installed file
|
|
1283
|
-
this.installedFiles.add(outputPath);
|
|
1284
|
-
|
|
1285
|
-
if (process.env.WIZZ_VERBOSE_INSTALL === 'true') {
|
|
1286
|
-
await prompts.log.message(` Generated wizz-help.csv: ${sortedRows.length} workflows`);
|
|
1287
|
-
}
|
|
1101
|
+
async mergeModuleHelpCatalogs(wizzDir, agentEntries = []) {
|
|
1102
|
+
return helpCatalog.mergeModuleHelpCatalogs(wizzDir, agentEntries, { trackFile: (p) => this.installedFiles.add(p) });
|
|
1288
1103
|
}
|
|
1289
1104
|
|
|
1290
1105
|
/**
|
|
1291
1106
|
* Render a consolidated install summary using prompts.note()
|
|
1292
1107
|
* @param {Array} results - Array of {step, status: 'ok'|'error'|'warn', detail}
|
|
1293
|
-
* @param {Object} context - {wizzDir, modules, ides, customFiles, modifiedFiles}
|
|
1108
|
+
* @param {Object} context - {wizzDir, modules, ides, customFiles, modifiedFiles, traceEnabled}
|
|
1294
1109
|
*/
|
|
1295
1110
|
async renderInstallSummary(results, context = {}) {
|
|
1296
1111
|
const color = await prompts.getColor();
|
|
@@ -1362,6 +1177,19 @@ class Installer {
|
|
|
1362
1177
|
lines.push(` ${color.yellow(`Modified files backed up (.bak): ${context.modifiedFiles.length}`)}`);
|
|
1363
1178
|
}
|
|
1364
1179
|
|
|
1180
|
+
// 3.8-E1: mention the routing-trace opt-in choice. `traceEnabled` is
|
|
1181
|
+
// `null` when the question was never asked (quick-update/update, or a
|
|
1182
|
+
// module set without bmm) — that case is intentionally silent instead of
|
|
1183
|
+
// misreporting an unasked question as "desligado".
|
|
1184
|
+
if (context.traceEnabled === true) {
|
|
1185
|
+
lines.push(
|
|
1186
|
+
` ${color.cyan('Medidor de roteamento: ligado')} (WIZZ_TRACE=1 em .claude/settings.local.json)`,
|
|
1187
|
+
` Para desligar: remova "WIZZ_TRACE" de .claude/settings.local.json (ou defina "0")`,
|
|
1188
|
+
);
|
|
1189
|
+
} else if (context.traceEnabled === false) {
|
|
1190
|
+
lines.push(` Medidor de roteamento: desligado (rode o install de novo para ligar)`);
|
|
1191
|
+
}
|
|
1192
|
+
|
|
1365
1193
|
// Next steps
|
|
1366
1194
|
lines.push(
|
|
1367
1195
|
'',
|
|
@@ -1385,172 +1213,7 @@ class Installer {
|
|
|
1385
1213
|
* @returns {Object} Update result
|
|
1386
1214
|
*/
|
|
1387
1215
|
async quickUpdate(config) {
|
|
1388
|
-
|
|
1389
|
-
const { wizzDir } = await this.findWizzDir(projectDir);
|
|
1390
|
-
|
|
1391
|
-
// Check if wizz directory exists
|
|
1392
|
-
if (!(await fs.pathExists(wizzDir))) {
|
|
1393
|
-
throw new Error(`Wizz not installed at ${wizzDir}. Use regular install for first-time setup.`);
|
|
1394
|
-
}
|
|
1395
|
-
|
|
1396
|
-
// Detect existing installation
|
|
1397
|
-
const existingInstall = await ExistingInstall.detect(wizzDir);
|
|
1398
|
-
const installedModules = existingInstall.moduleIds;
|
|
1399
|
-
const configuredIdes = existingInstall.ides;
|
|
1400
|
-
const projectRoot = path.dirname(wizzDir);
|
|
1401
|
-
|
|
1402
|
-
// Get available modules (what we have source for)
|
|
1403
|
-
const availableModulesData = await new OfficialModules().listAvailable();
|
|
1404
|
-
const availableModules = [...availableModulesData.modules];
|
|
1405
|
-
|
|
1406
|
-
// Add external official modules to available modules
|
|
1407
|
-
const externalModules = await this.externalModuleManager.listAvailable();
|
|
1408
|
-
for (const externalModule of externalModules) {
|
|
1409
|
-
if (installedModules.includes(externalModule.code) && !availableModules.some((m) => m.id === externalModule.code)) {
|
|
1410
|
-
availableModules.push({
|
|
1411
|
-
id: externalModule.code,
|
|
1412
|
-
name: externalModule.name,
|
|
1413
|
-
isExternal: true,
|
|
1414
|
-
fromExternal: true,
|
|
1415
|
-
});
|
|
1416
|
-
}
|
|
1417
|
-
}
|
|
1418
|
-
|
|
1419
|
-
// Add installed custom modules to available modules
|
|
1420
|
-
const { CustomModuleManager } = require('../modules/custom-module-manager');
|
|
1421
|
-
const customMgr = new CustomModuleManager();
|
|
1422
|
-
for (const moduleId of installedModules) {
|
|
1423
|
-
if (!availableModules.some((m) => m.id === moduleId)) {
|
|
1424
|
-
const customSource = await customMgr.findModuleSourceByCode(moduleId, { wizzDir });
|
|
1425
|
-
if (customSource) {
|
|
1426
|
-
availableModules.push({
|
|
1427
|
-
id: moduleId,
|
|
1428
|
-
name: moduleId,
|
|
1429
|
-
isExternal: true,
|
|
1430
|
-
fromCustom: true,
|
|
1431
|
-
});
|
|
1432
|
-
}
|
|
1433
|
-
}
|
|
1434
|
-
}
|
|
1435
|
-
|
|
1436
|
-
const availableModuleIds = new Set(availableModules.map((m) => m.id));
|
|
1437
|
-
|
|
1438
|
-
// Only update modules that are BOTH installed AND available (we have source for)
|
|
1439
|
-
const modulesToUpdate = installedModules.filter((id) => availableModuleIds.has(id));
|
|
1440
|
-
const skippedModules = installedModules.filter((id) => !availableModuleIds.has(id));
|
|
1441
|
-
|
|
1442
|
-
if (skippedModules.length > 0) {
|
|
1443
|
-
await prompts.log.warn(`Skipping ${skippedModules.length} module(s) - no source available: ${skippedModules.join(', ')}`);
|
|
1444
|
-
}
|
|
1445
|
-
|
|
1446
|
-
// Build channel options from the existing manifest FIRST so the config
|
|
1447
|
-
// collector below (which triggers external-module clones via
|
|
1448
|
-
// findModuleSource) knows each module's recorded channel and doesn't
|
|
1449
|
-
// silently redecide it. Without this, modules previously on 'next' or
|
|
1450
|
-
// 'pinned' would trigger a stable-channel tag lookup at config-collection
|
|
1451
|
-
// time, burning GitHub API quota and potentially failing.
|
|
1452
|
-
const manifestData = await this.manifest.read(wizzDir);
|
|
1453
|
-
const channelOptions = { global: null, nextSet: new Set(), pins: new Map(), warnings: [] };
|
|
1454
|
-
if (manifestData?.modulesDetailed) {
|
|
1455
|
-
const { fetchStableTags, classifyUpgrade, parseGitHubRepo } = require('../modules/channel-resolver');
|
|
1456
|
-
for (const entry of manifestData.modulesDetailed) {
|
|
1457
|
-
if (!entry?.name || !entry?.channel) continue;
|
|
1458
|
-
if (entry.channel === 'pinned' && entry.version) {
|
|
1459
|
-
channelOptions.pins.set(entry.name, entry.version);
|
|
1460
|
-
continue;
|
|
1461
|
-
}
|
|
1462
|
-
if (entry.channel === 'next') {
|
|
1463
|
-
channelOptions.nextSet.add(entry.name);
|
|
1464
|
-
continue;
|
|
1465
|
-
}
|
|
1466
|
-
// Stable: classify the available upgrade. Patches and minors fall
|
|
1467
|
-
// through (stable default picks up the top tag). A major upgrade
|
|
1468
|
-
// requires opt-in, so under quick-update's non-interactive semantics
|
|
1469
|
-
// we pin to the current version to prevent a silent breaking jump.
|
|
1470
|
-
if (entry.channel === 'stable' && entry.version && entry.repoUrl) {
|
|
1471
|
-
const parsed = parseGitHubRepo(entry.repoUrl);
|
|
1472
|
-
if (!parsed) continue;
|
|
1473
|
-
try {
|
|
1474
|
-
const tags = await fetchStableTags(parsed.owner, parsed.repo);
|
|
1475
|
-
if (tags.length === 0) continue;
|
|
1476
|
-
const topTag = tags[0].tag;
|
|
1477
|
-
const cls = classifyUpgrade(entry.version, topTag);
|
|
1478
|
-
if (cls === 'major') {
|
|
1479
|
-
channelOptions.pins.set(entry.name, entry.version);
|
|
1480
|
-
await prompts.log.warn(
|
|
1481
|
-
`${entry.name} ${entry.version} → ${topTag} is a new major release; staying on ${entry.version}. ` +
|
|
1482
|
-
`Run \`wizz install\` (Modify) with \`--pin ${entry.name}=${topTag}\` to accept.`,
|
|
1483
|
-
);
|
|
1484
|
-
}
|
|
1485
|
-
} catch (error) {
|
|
1486
|
-
// Tag lookup failed (offline, rate-limited). Stay on the current
|
|
1487
|
-
// version rather than guessing — the existing cache is already
|
|
1488
|
-
// at that ref, so re-using it keeps the install stable.
|
|
1489
|
-
channelOptions.pins.set(entry.name, entry.version);
|
|
1490
|
-
await prompts.log.warn(`Could not check ${entry.name} for updates (${error.message}); staying on ${entry.version}.`);
|
|
1491
|
-
}
|
|
1492
|
-
}
|
|
1493
|
-
}
|
|
1494
|
-
}
|
|
1495
|
-
|
|
1496
|
-
// Load existing configs and collect new fields (if any)
|
|
1497
|
-
await prompts.log.info('Checking for new configuration options...');
|
|
1498
|
-
const quickModules = new OfficialModules({ channelOptions });
|
|
1499
|
-
await quickModules.loadExistingConfig(projectDir);
|
|
1500
|
-
|
|
1501
|
-
let promptedForNewFields = false;
|
|
1502
|
-
|
|
1503
|
-
const corePrompted = await quickModules.collectModuleConfigQuick('core', projectDir, true);
|
|
1504
|
-
if (corePrompted) {
|
|
1505
|
-
promptedForNewFields = true;
|
|
1506
|
-
}
|
|
1507
|
-
|
|
1508
|
-
for (const moduleName of modulesToUpdate) {
|
|
1509
|
-
if (moduleName === 'core') continue; // Already collected above
|
|
1510
|
-
const modulePrompted = await quickModules.collectModuleConfigQuick(moduleName, projectDir, true);
|
|
1511
|
-
if (modulePrompted) {
|
|
1512
|
-
promptedForNewFields = true;
|
|
1513
|
-
}
|
|
1514
|
-
}
|
|
1515
|
-
|
|
1516
|
-
if (!promptedForNewFields) {
|
|
1517
|
-
await prompts.log.success('All configuration is up to date, no new options to configure');
|
|
1518
|
-
}
|
|
1519
|
-
|
|
1520
|
-
quickModules.collectedConfig._meta = {
|
|
1521
|
-
version: require(path.join(getProjectRoot(), 'package.json')).version,
|
|
1522
|
-
installDate: new Date().toISOString(),
|
|
1523
|
-
lastModified: new Date().toISOString(),
|
|
1524
|
-
};
|
|
1525
|
-
|
|
1526
|
-
// Build config and delegate to install()
|
|
1527
|
-
const installConfig = {
|
|
1528
|
-
directory: projectDir,
|
|
1529
|
-
modules: modulesToUpdate,
|
|
1530
|
-
ides: configuredIdes,
|
|
1531
|
-
coreConfig: quickModules.collectedConfig.core,
|
|
1532
|
-
moduleConfigs: quickModules.collectedConfig,
|
|
1533
|
-
// Forward `--set` overrides so the post-install patch step
|
|
1534
|
-
// (`applySetOverrides`) runs at the end of quick-update too. The
|
|
1535
|
-
// installer.install path applies them after writeCentralConfig.
|
|
1536
|
-
setOverrides: config.setOverrides || {},
|
|
1537
|
-
actionType: 'install',
|
|
1538
|
-
_quickUpdate: true,
|
|
1539
|
-
_preserveModules: skippedModules,
|
|
1540
|
-
_existingModules: installedModules,
|
|
1541
|
-
channelOptions,
|
|
1542
|
-
};
|
|
1543
|
-
|
|
1544
|
-
await this.install(installConfig);
|
|
1545
|
-
|
|
1546
|
-
return {
|
|
1547
|
-
success: true,
|
|
1548
|
-
moduleCount: modulesToUpdate.length,
|
|
1549
|
-
hadNewFields: promptedForNewFields,
|
|
1550
|
-
modules: modulesToUpdate,
|
|
1551
|
-
skippedModules: skippedModules,
|
|
1552
|
-
ides: configuredIdes,
|
|
1553
|
-
};
|
|
1216
|
+
return quickUpdateModule.quickUpdate(this, config);
|
|
1554
1217
|
}
|
|
1555
1218
|
|
|
1556
1219
|
/**
|
|
@@ -1703,8 +1366,8 @@ class Installer {
|
|
|
1703
1366
|
// Strip {project-root}/ prefix if present
|
|
1704
1367
|
return config.output_folder.replace(/^\{project-root\}[/\\]/, '');
|
|
1705
1368
|
}
|
|
1706
|
-
} catch {
|
|
1707
|
-
|
|
1369
|
+
} catch (error) {
|
|
1370
|
+
await prompts.log.warn(`Warning: could not read ${bmmConfigPath}: ${error.message}`);
|
|
1708
1371
|
}
|
|
1709
1372
|
}
|
|
1710
1373
|
|
|
@@ -1721,13 +1384,13 @@ class Installer {
|
|
|
1721
1384
|
if (config && config.output_folder) {
|
|
1722
1385
|
return config.output_folder.replace(/^\{project-root\}[/\\]/, '');
|
|
1723
1386
|
}
|
|
1724
|
-
} catch {
|
|
1725
|
-
|
|
1387
|
+
} catch (error) {
|
|
1388
|
+
await prompts.log.warn(`Warning: could not read ${configPath}: ${error.message}`);
|
|
1726
1389
|
}
|
|
1727
1390
|
}
|
|
1728
1391
|
}
|
|
1729
|
-
} catch {
|
|
1730
|
-
|
|
1392
|
+
} catch (error) {
|
|
1393
|
+
await prompts.log.warn(`Warning: could not scan ${wizzDir} for module configs: ${error.message}`);
|
|
1731
1394
|
}
|
|
1732
1395
|
|
|
1733
1396
|
// Default fallback
|
|
@@ -1735,54 +1398,26 @@ class Installer {
|
|
|
1735
1398
|
}
|
|
1736
1399
|
|
|
1737
1400
|
/**
|
|
1738
|
-
* Parse a CSV line, handling quoted fields
|
|
1401
|
+
* Parse a CSV line, handling quoted fields.
|
|
1402
|
+
* Thin wrapper — see `core/help-catalog.js` for the implementation and the
|
|
1403
|
+
* M15 rationale (auditoria 2026-07-07) on why this delegates to
|
|
1404
|
+
* `csv-parse/sync`.
|
|
1739
1405
|
* @param {string} line - CSV line to parse
|
|
1740
1406
|
* @returns {Array} Array of field values
|
|
1741
1407
|
*/
|
|
1742
1408
|
parseCSVLine(line) {
|
|
1743
|
-
|
|
1744
|
-
let current = '';
|
|
1745
|
-
let inQuotes = false;
|
|
1746
|
-
|
|
1747
|
-
for (let i = 0; i < line.length; i++) {
|
|
1748
|
-
const char = line[i];
|
|
1749
|
-
const nextChar = line[i + 1];
|
|
1750
|
-
|
|
1751
|
-
if (char === '"') {
|
|
1752
|
-
if (inQuotes && nextChar === '"') {
|
|
1753
|
-
// Escaped quote
|
|
1754
|
-
current += '"';
|
|
1755
|
-
i++; // Skip next quote
|
|
1756
|
-
} else {
|
|
1757
|
-
// Toggle quote mode
|
|
1758
|
-
inQuotes = !inQuotes;
|
|
1759
|
-
}
|
|
1760
|
-
} else if (char === ',' && !inQuotes) {
|
|
1761
|
-
result.push(current);
|
|
1762
|
-
current = '';
|
|
1763
|
-
} else {
|
|
1764
|
-
current += char;
|
|
1765
|
-
}
|
|
1766
|
-
}
|
|
1767
|
-
result.push(current);
|
|
1768
|
-
return result;
|
|
1409
|
+
return helpCatalog.parseCSVLine(line);
|
|
1769
1410
|
}
|
|
1770
1411
|
|
|
1771
1412
|
/**
|
|
1772
|
-
* Escape a CSV field if it contains special characters
|
|
1413
|
+
* Escape a CSV field if it contains special characters.
|
|
1414
|
+
* Thin wrapper — see `core/help-catalog.js` for the implementation and the
|
|
1415
|
+
* M15 rationale (auditoria 2026-07-07) on why this stays manual.
|
|
1773
1416
|
* @param {string} field - Field value to escape
|
|
1774
1417
|
* @returns {string} Escaped field
|
|
1775
1418
|
*/
|
|
1776
1419
|
escapeCSVField(field) {
|
|
1777
|
-
|
|
1778
|
-
return '';
|
|
1779
|
-
}
|
|
1780
|
-
const str = String(field);
|
|
1781
|
-
// If field contains comma, quote, or newline, wrap in quotes and escape inner quotes
|
|
1782
|
-
if (str.includes(',') || str.includes('"') || str.includes('\n')) {
|
|
1783
|
-
return `"${str.replaceAll('"', '""')}"`;
|
|
1784
|
-
}
|
|
1785
|
-
return str;
|
|
1420
|
+
return helpCatalog.escapeCSVField(field);
|
|
1786
1421
|
}
|
|
1787
1422
|
}
|
|
1788
1423
|
|