wizz-method 2.13.0 → 2.15.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/THIRD-PARTY-NOTICES.md +2 -0
- package/package.json +10 -3
- package/skills-registry.yaml +30 -25
- package/src/bmm-skills/1-analysis/research/wizz-domain-research/customize.toml +4 -3
- package/src/bmm-skills/1-analysis/research/wizz-market-research/customize.toml +4 -3
- package/src/bmm-skills/1-analysis/research/wizz-technical-research/customize.toml +3 -1
- package/src/bmm-skills/1-analysis/wizz-agent-analyst/customize.toml +3 -1
- package/src/bmm-skills/1-analysis/wizz-agent-tech-writer/customize.toml +4 -3
- package/src/bmm-skills/1-analysis/wizz-document-project/customize.toml +4 -3
- package/src/bmm-skills/1-analysis/wizz-prfaq/customize.toml +4 -3
- package/src/bmm-skills/1-analysis/wizz-product-brief/customize.toml +5 -6
- package/src/bmm-skills/2-plan-workflows/wizz-agent-pm/customize.toml +3 -1
- package/src/bmm-skills/2-plan-workflows/wizz-agent-ux-designer/customize.toml +3 -1
- package/src/bmm-skills/2-plan-workflows/wizz-create-prd/customize.toml +4 -3
- package/src/bmm-skills/2-plan-workflows/wizz-edit-prd/customize.toml +4 -3
- package/src/bmm-skills/2-plan-workflows/wizz-prd/customize.toml +5 -6
- package/src/bmm-skills/2-plan-workflows/wizz-ux/customize.toml +4 -3
- package/src/bmm-skills/2-plan-workflows/wizz-validate-prd/customize.toml +4 -3
- package/src/bmm-skills/3-solutioning/wizz-agent-architect/customize.toml +3 -1
- package/src/bmm-skills/3-solutioning/wizz-architecture/customize.toml +5 -6
- package/src/bmm-skills/3-solutioning/wizz-check-implementation-readiness/customize.toml +4 -3
- package/src/bmm-skills/3-solutioning/wizz-create-architecture/customize.toml +4 -3
- package/src/bmm-skills/3-solutioning/wizz-create-epics-and-stories/customize.toml +4 -3
- package/src/bmm-skills/3-solutioning/wizz-generate-project-context/steps/step-03-complete.md +7 -0
- package/src/bmm-skills/4-implementation/wizz-agent-dev/customize.toml +3 -1
- package/src/bmm-skills/4-implementation/wizz-checkpoint-preview/customize.toml +4 -3
- package/src/bmm-skills/4-implementation/wizz-code-review/customize.toml +4 -3
- package/src/bmm-skills/4-implementation/wizz-code-review/steps/step-03-triage.md +23 -14
- package/src/bmm-skills/4-implementation/wizz-code-review/steps/step-04-present.md +2 -2
- package/src/bmm-skills/4-implementation/wizz-correct-course/customize.toml +4 -3
- package/src/bmm-skills/4-implementation/wizz-create-story/customize.toml +4 -3
- package/src/bmm-skills/4-implementation/wizz-dev-story/customize.toml +4 -3
- package/src/bmm-skills/4-implementation/wizz-investigate/customize.toml +4 -3
- package/src/bmm-skills/4-implementation/wizz-qa-generate-e2e-tests/customize.toml +4 -3
- package/src/bmm-skills/4-implementation/wizz-quick-dev/SKILL.md +1 -1
- package/src/bmm-skills/4-implementation/wizz-quick-dev/customize.toml +4 -3
- package/src/bmm-skills/4-implementation/wizz-quick-dev/spec-template.md +6 -0
- package/src/bmm-skills/4-implementation/wizz-quick-dev/step-04-review.md +27 -16
- package/src/bmm-skills/4-implementation/wizz-quick-dev/step-oneshot.md +27 -6
- package/src/bmm-skills/4-implementation/wizz-retrospective/customize.toml +4 -3
- package/src/bmm-skills/4-implementation/wizz-sprint-planning/customize.toml +4 -3
- package/src/bmm-skills/4-implementation/wizz-sprint-status/customize.toml +4 -3
- package/src/core-skills/wizz-brainstorming/customize.toml +5 -6
- package/src/core-skills/wizz-brainstorming/scripts/brain.py +19 -0
- package/src/core-skills/wizz-brainstorming/scripts/tests/test_brain.py +33 -0
- package/src/core-skills/wizz-forge-idea/scripts/resolve_personas.py +3 -1
- package/src/core-skills/wizz-forge-idea/scripts/tests/test_resolve_personas.py +21 -0
- package/src/core-skills/wizz-help/SKILL.md +5 -3
- package/src/core-skills/wizz-party-mode/customize.toml +5 -4
- package/src/core-skills/wizz-party-mode/scripts/resolve_party.py +3 -1
- package/src/core-skills/wizz-party-mode/scripts/tests/test_resolve_party.py +21 -0
- package/src/core-skills/wizz-spec/customize.toml +4 -5
- package/src/modules/wizz/_shared/model-ladder.md +4 -4
- package/src/modules/wizz/agents/wizz-designer/SKILL.md +1 -1
- package/src/modules/wizz/agents/wizz-maestro/SKILL.md +1 -1
- package/src/modules/wizz/subagents/opencode/wizz-exec-review.md +2 -2
- package/src/modules/wizz/subagents/opencode/wizz-exec-standard.md +2 -2
- package/src/modules/wizz/subagents/opencode/wizz-exec-strong.md +2 -2
- package/src/modules/wizz/subagents/spec.yaml +3 -3
- package/src/scripts/resolve_config.py +8 -0
- package/src/scripts/resolve_customization.py +24 -3
- package/src/scripts/tests/test_resolve_config.py +42 -0
- package/src/scripts/tests/test_resolve_customization.py +45 -0
- package/src/skills-lib/_shared/complexity-signal.md +1 -1
- package/src/skills-lib/ctc-align/SKILL.md +1 -1
- package/src/skills-lib/wizz-agent-browser/SKILL.md +5 -0
- package/src/skills-lib/wizz-design-needs/SKILL.md +1 -1
- package/src/skills-lib/wizz-huashu-design/scripts/html2pptx.js +902 -1061
- package/src/skills-lib/wizz-humanizer/README.md +134 -71
- package/src/skills-lib/wizz-humanizer/SKILL.md +51 -37
- package/src/skills-lib/wizz-humanizer/references/ai-writing-patterns.md +208 -190
- package/src/skills-lib/wizz-premium-landing-ui-researcher/SKILL.md +1 -1
- package/src/skills-lib/wizz-router/SKILL.md +1 -1
- package/src/skills-lib/wizz-ui-component-curator/SKILL.md +22 -2
- package/tools/installer/core/doctor.js +31 -1
- package/tools/installer/core/installer.js +32 -0
- package/tools/installer/core/project-instructions.js +199 -0
- package/src/bmm-skills/3-solutioning/wizz-architecture/scripts/__pycache__/lint_spine.cpython-313.pyc +0 -0
- package/src/bmm-skills/3-solutioning/wizz-architecture/scripts/tests/__pycache__/test_lint_spine.cpython-313-pytest-9.1.1.pyc +0 -0
- package/src/bmm-skills/4-implementation/wizz-retrospective/scripts/__pycache__/sprint_status.cpython-313.pyc +0 -0
- package/src/bmm-skills/4-implementation/wizz-retrospective/scripts/tests/__pycache__/test_git_evidence.cpython-313-pytest-9.1.1.pyc +0 -0
- package/src/bmm-skills/4-implementation/wizz-retrospective/scripts/tests/__pycache__/test_sprint_status.cpython-313-pytest-9.1.1.pyc +0 -0
- package/src/bmm-skills/4-implementation/wizz-sprint-planning/scripts/__pycache__/sprint_plan.cpython-313.pyc +0 -0
- package/src/bmm-skills/4-implementation/wizz-sprint-planning/scripts/tests/__pycache__/test_sprint_plan.cpython-313-pytest-9.1.1.pyc +0 -0
- package/src/core-skills/wizz-advanced-elicitation/scripts/__pycache__/pick_methods.cpython-313.pyc +0 -0
- package/src/core-skills/wizz-advanced-elicitation/scripts/tests/__pycache__/test_pick_methods.cpython-313-pytest-9.1.1.pyc +0 -0
- package/src/core-skills/wizz-brainstorming/scripts/__pycache__/brain.cpython-313.pyc +0 -0
- package/src/core-skills/wizz-brainstorming/scripts/tests/__pycache__/test_brain.cpython-313-pytest-9.1.1.pyc +0 -0
- package/src/core-skills/wizz-brainstorming/scripts/tests/__pycache__/test_brain.cpython-314.pyc +0 -0
- package/src/core-skills/wizz-customize/scripts/__pycache__/list_customizable_skills.cpython-313.pyc +0 -0
- package/src/core-skills/wizz-customize/scripts/tests/__pycache__/test_list_customizable_skills.cpython-313-pytest-9.1.1.pyc +0 -0
- package/src/core-skills/wizz-forge-idea/scripts/__pycache__/resolve_personas.cpython-313.pyc +0 -0
- package/src/core-skills/wizz-forge-idea/scripts/__pycache__/resolve_personas.cpython-314.pyc +0 -0
- package/src/core-skills/wizz-forge-idea/scripts/tests/__pycache__/test_resolve_personas.cpython-313-pytest-9.1.1.pyc +0 -0
- package/src/core-skills/wizz-forge-idea/scripts/tests/__pycache__/test_resolve_personas.cpython-314.pyc +0 -0
- package/src/core-skills/wizz-party-mode/scripts/__pycache__/resolve_party.cpython-313.pyc +0 -0
- package/src/core-skills/wizz-party-mode/scripts/__pycache__/resolve_party.cpython-314.pyc +0 -0
- package/src/core-skills/wizz-party-mode/scripts/tests/__pycache__/test_resolve_party.cpython-313-pytest-9.1.1.pyc +0 -0
- package/src/core-skills/wizz-party-mode/scripts/tests/__pycache__/test_resolve_party.cpython-314.pyc +0 -0
- package/src/scripts/__pycache__/resolve_customization.cpython-314.pyc +0 -0
- package/src/skills-lib/wizz-huashu-design/package-lock.json +0 -846
- package/src/skills-lib/wizz-humanizer/WARP.md +0 -53
- package/src/skills-lib/wizz-humanizer/references/full-example.md +0 -72
- package/src/skills-lib/wizz-humanizer/references/personality-and-soul.md +0 -36
- package/src/skills-lib/wizz-react-components/package-lock.json +0 -231
- package/src/skills-lib/wizz-supabase-postgres-best-practices/CLAUDE.md +0 -68
- package/src/skills-lib/wizz-ui-ux-pro-max/scripts/__pycache__/core.cpython-314.pyc +0 -0
- package/src/skills-lib/wizz-ui-ux-pro-max/scripts/__pycache__/design_system.cpython-314.pyc +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: wizz-ui-component-curator
|
|
3
|
-
description: analyze an existing frontend project, infer its visual style and product tone, then research and recommend compatible UI components and effects from public component catalogs, registries and source repositories. use when the user wants help choosing components, effects, sections, or visual patterns that fit an existing project — especially hero effects, cards, buttons, testimonials, pricing sections, navigation, or any interactive pattern. trigger whenever the user wants to add a UI element and wants Claude to study the project first before suggesting options. always inspect the codebase and exact component sources, provide evidence and plan before editing.
|
|
3
|
+
description: analyze an existing frontend project, infer its visual style and product tone, then research and recommend compatible UI components and effects from public component catalogs, registries and source repositories. use when the user wants help choosing components, effects, sections, or visual patterns that fit an existing project or dashboard — especially hero effects, cards, buttons, hovers, loading animations, testimonials, pricing sections, navigation, or any interactive pattern. trigger whenever the user wants to add a UI element and wants Claude to study the project first before suggesting options. always inspect the codebase and exact component sources, provide evidence and plan before editing.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# Overview
|
|
@@ -19,6 +19,8 @@ Act as a UI curator with taste and restraint — not a gallery explorer. Optimiz
|
|
|
19
19
|
|
|
20
20
|
If `{output_folder}/design-state.yaml` exists, the need being worked is already written there: take its `query`, `budget.fontes` and `floor` instead of improvising them, honour the `proibidos` block, and write the result back under `discoveries` with the `need` id. If the request does not match any open need, say so before researching: an unplanned need is either a gap in the map (go back to `wizz-design-needs`) or scope creep.
|
|
21
21
|
|
|
22
|
+
Not there? Look before deciding it does not exist: `find . -name design-state.yaml -not -path '*/node_modules/*'`. A map found anywhere else is still the map: use it, and tell the user it is off-place (it belongs in `{output_folder}`).
|
|
23
|
+
|
|
22
24
|
With no state file, continue normally.
|
|
23
25
|
|
|
24
26
|
## 1. Read and infer the style DNA
|
|
@@ -38,7 +40,9 @@ Do not ask the user to describe the style unless the project has no inspectable
|
|
|
38
40
|
|
|
39
41
|
## 2. Search and inspect public sources
|
|
40
42
|
|
|
41
|
-
Start with existing project components. Then search
|
|
43
|
+
Start with existing project components. Then search the public sources. The full authorized list (React Bits, Cult UI, Ali Imam, Watermelon, StyleUI, Skiper UI, Bklit UI, Componentry, shadcn/ui, plus the reference galleries) lives in one place: [component-sources](../wizz-premium-landing-ui-researcher/references/component-sources.md). Read it instead of relying on memory. Compare at least two suitable sources per need.
|
|
44
|
+
|
|
45
|
+
Use whatever search tools the session has: web search (Exa when configured, WebSearch otherwise), WebFetch, scrapling, and `agent-browser` to watch hover and motion live. A tool that errors or hangs is not the end of the research: record the failure, move to the next tool, and never stop without reporting what was and was not checked.
|
|
42
46
|
|
|
43
47
|
Open the exact demo and source file/registry item. Check the actual imports, license, dependencies, stack variant and revision; use current official documentation (Context7 when available) for API compatibility. Inspect animation/interaction in the available browser; label static-only inspection honestly. If a source fails, record the failure and continue elsewhere.
|
|
44
48
|
|
|
@@ -68,6 +72,22 @@ Send the exact candidate links and recommendation. If the user authorized implem
|
|
|
68
72
|
|
|
69
73
|
---
|
|
70
74
|
|
|
75
|
+
## Dashboard and app panels
|
|
76
|
+
|
|
77
|
+
A panel is used every day, so the bar is different from a landing page: motion that delights once tires on the tenth visit. When the project is a dashboard, admin or operational panel, cover these categories (only the ones the request or the map opens):
|
|
78
|
+
|
|
79
|
+
- loading: skeleton, spinner, route progress, branded loader
|
|
80
|
+
- action feedback: toast, confirmation, undo, a discreet success state
|
|
81
|
+
- numbers: animated counter, sparkline, gauge, KPI card
|
|
82
|
+
- lists and queues: enter/exit animation, swipe actions on mobile
|
|
83
|
+
- navigation: sidebar, command menu, tooltip, dock
|
|
84
|
+
- surfaces: hover states, border glow, spotlight, subtle background
|
|
85
|
+
- empty states, charts and form controls
|
|
86
|
+
|
|
87
|
+
For each candidate, judge "does it tire with daily use", reduced-motion support and weight. Reject landing-page effects that do not serve a task.
|
|
88
|
+
|
|
89
|
+
---
|
|
90
|
+
|
|
71
91
|
# Consistency rules
|
|
72
92
|
|
|
73
93
|
If there is tension between the most impressive option and the best-fitting option: **choose the one that fits.**
|
|
@@ -25,7 +25,7 @@ const { HOOK_DEFS, isOurHookCommand } = require('./hooks-settings');
|
|
|
25
25
|
const { classifyPython, PYTHON_ONLY_SKILLS } = require('./python-check');
|
|
26
26
|
|
|
27
27
|
// Piso de versão do rtk que o hook rtk-rewrite.sh exige para `rtk rewrite`
|
|
28
|
-
// (o registry pin do CLI é mais alto, 0.
|
|
28
|
+
// (o registry pin do CLI é mais alto, 0.50.0, e é aplicado pelo detectClis
|
|
29
29
|
// no install; aqui reportamos o piso que quebra o hook hoje).
|
|
30
30
|
const RTK_HOOK_FLOOR = '0.23.0';
|
|
31
31
|
|
|
@@ -464,6 +464,28 @@ async function currentInputHash({ projectDir, relPath, skill, sources, fileExist
|
|
|
464
464
|
* @param {object} [options.deps] - checkers injetáveis (ver chamadas abaixo)
|
|
465
465
|
* @returns {Promise<{results: Array<{check, status, detail}>, exitCode: number, hasError: boolean}>}
|
|
466
466
|
*/
|
|
467
|
+
/**
|
|
468
|
+
* CLAUDE.md/AGENTS.md: bloco Wizz presente e sem regra legada fora dele.
|
|
469
|
+
* Sem o bloco, um CLAUDE.md antigo vence as regras do Wizz (2026-09-30).
|
|
470
|
+
* @returns {Promise<{check: 'instructions', status: 'ok'|'warn', detail: string}>}
|
|
471
|
+
*/
|
|
472
|
+
async function checkProjectInstructions({ projectDir, fileExists, readFile }) {
|
|
473
|
+
const { INSTRUCTION_FILES, BLOCK_BEGIN, scanLegacy } = require('./project-instructions');
|
|
474
|
+
const problems = [];
|
|
475
|
+
let seen = 0;
|
|
476
|
+
for (const name of INSTRUCTION_FILES) {
|
|
477
|
+
const file = path.join(projectDir, name);
|
|
478
|
+
if (!(await fileExists(file))) continue;
|
|
479
|
+
seen += 1;
|
|
480
|
+
const text = await readFile(file);
|
|
481
|
+
if (!text.includes(BLOCK_BEGIN)) problems.push(`${name} sem o bloco Wizz no topo (rode wizz install)`);
|
|
482
|
+
for (const f of scanLegacy(text)) problems.push(`${name}:${f.line} ${f.why}: ${f.snippet}`);
|
|
483
|
+
}
|
|
484
|
+
if (seen === 0) return { check: 'instructions', status: 'ok', detail: 'Sem CLAUDE.md/AGENTS.md no projeto.' };
|
|
485
|
+
if (problems.length === 0) return { check: 'instructions', status: 'ok', detail: 'Bloco Wizz presente, nenhuma regra legada.' };
|
|
486
|
+
return { check: 'instructions', status: 'warn', detail: problems.join('\n') };
|
|
487
|
+
}
|
|
488
|
+
|
|
467
489
|
async function runDoctor(options = {}) {
|
|
468
490
|
const deps = options.deps || {};
|
|
469
491
|
const {
|
|
@@ -578,6 +600,13 @@ async function runDoctor(options = {}) {
|
|
|
578
600
|
});
|
|
579
601
|
}
|
|
580
602
|
|
|
603
|
+
// 7) instructions — CLAUDE.md/AGENTS.md com bloco Wizz e sem regra legada.
|
|
604
|
+
if (skip.includes('instructions')) {
|
|
605
|
+
results.push({ check: 'instructions', status: 'ok', detail: 'pulado.' });
|
|
606
|
+
} else if (wizzDir) {
|
|
607
|
+
results.push(await checkProjectInstructions({ projectDir, fileExists, readFile }));
|
|
608
|
+
}
|
|
609
|
+
|
|
581
610
|
const hasError = results.some((r) => r.status === 'error');
|
|
582
611
|
return { results, exitCode: hasError ? 1 : 0, hasError };
|
|
583
612
|
}
|
|
@@ -631,6 +660,7 @@ function safeReadJson(file) {
|
|
|
631
660
|
}
|
|
632
661
|
|
|
633
662
|
module.exports = {
|
|
663
|
+
checkProjectInstructions,
|
|
634
664
|
CHECKS,
|
|
635
665
|
RTK_HOOK_FLOOR,
|
|
636
666
|
extractVersion,
|
|
@@ -20,6 +20,7 @@ const { buildHookEntries, filterHooksRegisteredGlobally, mergeHooksIntoSettings
|
|
|
20
20
|
|
|
21
21
|
const { ExistingInstall } = require('./existing-install');
|
|
22
22
|
const { warnPreNativeSkillsLegacy } = require('./legacy-warnings');
|
|
23
|
+
const { applyProjectInstructions, removeProjectInstructions } = require('./project-instructions');
|
|
23
24
|
const userFilePreservation = require('./user-file-preservation');
|
|
24
25
|
const moduleConfigWriter = require('./module-config-writer');
|
|
25
26
|
const helpCatalog = require('./help-catalog');
|
|
@@ -808,6 +809,11 @@ class Installer {
|
|
|
808
809
|
addResult('Hooks settings', 'ok', `${pendingHooksSettingsWrite.count} hook(s) → .claude/settings.json${skippedDetail}`);
|
|
809
810
|
}
|
|
810
811
|
|
|
812
|
+
// Bloco gerenciado no CLAUDE.md/AGENTS.md (2026-09-30): sem ele, um
|
|
813
|
+
// CLAUDE.md antigo vence as regras do Wizz, que chegam só por hook.
|
|
814
|
+
// Depois do swap pelo mesmo motivo do settings.json: vive fora de _wizz/.
|
|
815
|
+
await this._applyProjectInstructions(paths, config, addResult);
|
|
816
|
+
|
|
811
817
|
await this._appendPreservedSkillManifestRows(paths.wizzDir, previousSkillManifestRows, preservedModules);
|
|
812
818
|
|
|
813
819
|
// Apply post-install --set TOML patches. Runs after writeCentralConfig
|
|
@@ -1223,6 +1229,31 @@ class Installer {
|
|
|
1223
1229
|
* @param {string} file
|
|
1224
1230
|
* @returns {Promise<{settings: object, invalidJson: boolean}>}
|
|
1225
1231
|
*/
|
|
1232
|
+
async _applyProjectInstructions(paths, config, addResult) {
|
|
1233
|
+
if (!(await fs.pathExists(path.join(paths.wizzDir, 'wizz')))) return;
|
|
1234
|
+
try {
|
|
1235
|
+
const results = await applyProjectInstructions({
|
|
1236
|
+
projectRoot: paths.projectRoot,
|
|
1237
|
+
fs,
|
|
1238
|
+
createIfMissing: (config.ides || []).includes('claude-code'),
|
|
1239
|
+
});
|
|
1240
|
+
for (const r of results) {
|
|
1241
|
+
const name = path.basename(r.file);
|
|
1242
|
+
const legacy = r.findings.length > 0 ? `, ${r.findings.length} trecho(s) legado(s) marcados` : '';
|
|
1243
|
+
addResult('Project instructions', r.findings.length > 0 ? 'warn' : 'ok', `bloco Wizz no topo de ${name}${legacy}`);
|
|
1244
|
+
}
|
|
1245
|
+
const totalLegacy = results.reduce((n, r) => n + r.findings.length, 0);
|
|
1246
|
+
if (totalLegacy > 0) {
|
|
1247
|
+
await prompts.log.warn(
|
|
1248
|
+
`${totalLegacy} regra(s) antiga(s) no CLAUDE.md/AGENTS.md (GSD, superpowers, BMAD puro ou modelo aposentado). O bloco Wizz no topo tem prioridade, mas vale limpar: rode wizz doctor para ver as linhas.`,
|
|
1249
|
+
);
|
|
1250
|
+
}
|
|
1251
|
+
} catch (error) {
|
|
1252
|
+
await prompts.log.warn(`Falha ao gravar o bloco Wizz no CLAUDE.md/AGENTS.md: ${error.message}`);
|
|
1253
|
+
addResult('Project instructions', 'warn', error.message);
|
|
1254
|
+
}
|
|
1255
|
+
}
|
|
1256
|
+
|
|
1226
1257
|
async _readSettingsJson(file) {
|
|
1227
1258
|
if (!(await fs.pathExists(file))) return { settings: {}, invalidJson: false };
|
|
1228
1259
|
try {
|
|
@@ -1600,6 +1631,7 @@ class Installer {
|
|
|
1600
1631
|
// 2. IDE CLEANUP (before _wizz/ deletion so configs are accessible)
|
|
1601
1632
|
if (options.removeIdeConfigs !== false) {
|
|
1602
1633
|
await this.uninstallIdeConfigs(projectDir, existingInstall, { silent: options.silent });
|
|
1634
|
+
await removeProjectInstructions({ projectRoot: projectDir, fs });
|
|
1603
1635
|
removed.ideConfigs = true;
|
|
1604
1636
|
}
|
|
1605
1637
|
|
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
// project-instructions.js — bloco gerenciado no CLAUDE.md/AGENTS.md do projeto.
|
|
2
|
+
//
|
|
3
|
+
// Motivo (2026-09-30): o Claude Code carrega o CLAUDE.md do projeto como
|
|
4
|
+
// instrução de projeto (prioridade alta), enquanto as regras do Wizz chegam
|
|
5
|
+
// por hook e skill (contexto extra, prioridade menor). Num projeto que já
|
|
6
|
+
// tinha CLAUDE.md antigo (GSD, superpowers, BMAD puro, modelos aposentados),
|
|
7
|
+
// a regra velha vencia a nova. O installer agora grava um bloco no TOPO do
|
|
8
|
+
// arquivo dizendo que o Wizz vence em conflito e listando os trechos legados
|
|
9
|
+
// detectados. Nada fora do bloco é apagado ou reescrito.
|
|
10
|
+
//
|
|
11
|
+
// Lógica pura (texto → texto) + um aplicador fino com fs injetável, para os
|
|
12
|
+
// testes não dependerem de disco real.
|
|
13
|
+
|
|
14
|
+
const path = require('node:path');
|
|
15
|
+
const fsp = require('node:fs/promises');
|
|
16
|
+
|
|
17
|
+
const BLOCK_BEGIN = '<!-- wizz:begin -->';
|
|
18
|
+
const BLOCK_END = '<!-- wizz:end -->';
|
|
19
|
+
const INSTRUCTION_FILES = ['CLAUDE.md', 'AGENTS.md'];
|
|
20
|
+
|
|
21
|
+
// IDs de modelo aposentados. Compartilhado com tools/validate-model-ids.mjs.
|
|
22
|
+
// claude-haiku-4-5 continua atual (não há Haiku mais novo em 2026-09-30).
|
|
23
|
+
// `claude-(opus|sonnet)-5` sem sufixo foi trocado por 5-5; o lookahead evita
|
|
24
|
+
// casar o próprio `-5-5`.
|
|
25
|
+
const RETIRED_MODEL_RE =
|
|
26
|
+
/\bclaude-(?:instant|2|3|3-5|3-7)(?:-[a-z0-9]+)*\b|\bclaude-(?:opus|sonnet)-4(?:-\d+)?\b|\bclaude-(?:opus|sonnet)-5\b(?!-)/gi;
|
|
27
|
+
|
|
28
|
+
const LEGACY_RULES = [
|
|
29
|
+
{ id: 'gsd', re: /\bGSD\b|get-shit-done|\/gsd[:-]/, why: 'GSD foi substituído pelas fases e checkpoints do Wizz Method' },
|
|
30
|
+
{ id: 'superpowers', re: /\bsuperpowers\b/i, why: 'superpowers foi substituído pelo Wizz Method' },
|
|
31
|
+
{
|
|
32
|
+
id: 'bmad',
|
|
33
|
+
re: /_bmad\/|\/bmad[-:]|\bbmad-(?:master|agent|method|help)\b/i,
|
|
34
|
+
why: 'comandos e pastas do BMAD puro viraram wizz-* e _wizz/',
|
|
35
|
+
},
|
|
36
|
+
{ id: 'modelo-aposentado', re: RETIRED_MODEL_RE, why: 'ID de modelo aposentado; a escada do Wizz usa os apelidos atuais' },
|
|
37
|
+
];
|
|
38
|
+
|
|
39
|
+
const MAX_SNIPPET = 120;
|
|
40
|
+
|
|
41
|
+
// project-context.md (2026-09-30, porte do BMAD 6.12 #2750): em vez de cada
|
|
42
|
+
// skill procurar o arquivo em toda ativação (persistent_facts), o bloco
|
|
43
|
+
// importa uma vez por sessão. Busca rasa, pulando pastas de dependência/build.
|
|
44
|
+
const CONTEXT_FILE = 'project-context.md';
|
|
45
|
+
const CONTEXT_MAX_DEPTH = 4;
|
|
46
|
+
const CONTEXT_SKIP_DIRS = new Set(['node_modules', '.git', '_wizz', '.claude', 'build', 'dist', '.next', 'vendor', '.venv']);
|
|
47
|
+
|
|
48
|
+
/** Caminho relativo (posix) do project-context.md mais raso, ou null. */
|
|
49
|
+
async function findProjectContext(projectRoot) {
|
|
50
|
+
let level = [projectRoot];
|
|
51
|
+
for (let depth = 0; depth <= CONTEXT_MAX_DEPTH && level.length > 0; depth++) {
|
|
52
|
+
const next = [];
|
|
53
|
+
for (const dir of level.sort()) {
|
|
54
|
+
let entries;
|
|
55
|
+
try {
|
|
56
|
+
entries = await fsp.readdir(dir, { withFileTypes: true });
|
|
57
|
+
} catch {
|
|
58
|
+
continue;
|
|
59
|
+
}
|
|
60
|
+
if (entries.some((e) => e.isFile() && e.name === CONTEXT_FILE)) {
|
|
61
|
+
return path.relative(projectRoot, path.join(dir, CONTEXT_FILE)).split(path.sep).join('/');
|
|
62
|
+
}
|
|
63
|
+
for (const e of entries) if (e.isDirectory() && !CONTEXT_SKIP_DIRS.has(e.name)) next.push(path.join(dir, e.name));
|
|
64
|
+
}
|
|
65
|
+
level = next;
|
|
66
|
+
}
|
|
67
|
+
return null;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/** Linha de contexto por arquivo: CLAUDE.md importa com @; AGENTS.md só aponta. */
|
|
71
|
+
function contextLine(fileName, contextPath) {
|
|
72
|
+
if (!contextPath) return null;
|
|
73
|
+
return fileName === 'CLAUDE.md'
|
|
74
|
+
? `Contexto do projeto (regras de stack e padrões, importado uma vez por sessão):\n@${contextPath}`
|
|
75
|
+
: `- Contexto do projeto: leia \`${contextPath}\` antes de implementar (regras de stack e padrões).`;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/** Separa o bloco gerenciado do resto do arquivo. */
|
|
79
|
+
function splitManagedBlock(text) {
|
|
80
|
+
const start = text.indexOf(BLOCK_BEGIN);
|
|
81
|
+
const end = text.indexOf(BLOCK_END);
|
|
82
|
+
if (start === -1 || end === -1 || end < start) return { block: null, rest: text };
|
|
83
|
+
const after = text.slice(end + BLOCK_END.length).replace(/^\r?\n+/, '');
|
|
84
|
+
return { block: text.slice(start, end + BLOCK_END.length), rest: text.slice(0, start) + after };
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* Procura regras legadas no texto, pulando as linhas do bloco gerenciado.
|
|
89
|
+
* `line` é a linha real no arquivo (1-based), para o doctor apontar.
|
|
90
|
+
* @returns {{id: string, line: number, snippet: string, why: string}[]}
|
|
91
|
+
*/
|
|
92
|
+
function scanLegacy(text) {
|
|
93
|
+
const findings = [];
|
|
94
|
+
let inBlock = false;
|
|
95
|
+
for (const [i, line] of text.split(/\r?\n/).entries()) {
|
|
96
|
+
if (line.includes(BLOCK_BEGIN)) inBlock = true;
|
|
97
|
+
if (inBlock) {
|
|
98
|
+
if (line.includes(BLOCK_END)) inBlock = false;
|
|
99
|
+
continue;
|
|
100
|
+
}
|
|
101
|
+
const rule = LEGACY_RULES.find((r) => new RegExp(r.re.source, r.re.flags.replace('g', '')).test(line));
|
|
102
|
+
if (rule) findings.push({ id: rule.id, line: i + 1, snippet: line.trim().slice(0, MAX_SNIPPET), why: rule.why });
|
|
103
|
+
}
|
|
104
|
+
return findings;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
/** Monta o bloco. Sem número de linha: o próprio bloco desloca as linhas. */
|
|
108
|
+
function renderManagedBlock(findings = [], context = null) {
|
|
109
|
+
const lines = [
|
|
110
|
+
BLOCK_BEGIN,
|
|
111
|
+
'<!-- Gerenciado pelo Wizz Method: o install reescreve este bloco. Edite fora dele. -->',
|
|
112
|
+
'## Wizz Method: estas regras têm prioridade',
|
|
113
|
+
'',
|
|
114
|
+
'Este projeto usa o Wizz Method (`_wizz/`). Se alguma instrução deste arquivo, fora deste bloco, contradizer o Wizz Method, vale o Wizz Method.',
|
|
115
|
+
'',
|
|
116
|
+
'- Pedido não trivial: uma área vai para o agente da área; duas ou mais áreas vão para o `wizz-maestro`. Edição trivial de 1 linha e conversa executam direto.',
|
|
117
|
+
'- Planejamento, TDD, checkpoints e review seguem o Wizz Method. Não usar GSD, superpowers nem os comandos antigos do BMAD (`/bmad-*`, `_bmad/`).',
|
|
118
|
+
'- Modelos seguem a escada do Wizz (`wizz-exec-mechanical`, `-standard`, `-strong`, `-ultra`, `-review`), que usa os apelidos atuais. Ignore IDs de modelo fixos deste arquivo.',
|
|
119
|
+
];
|
|
120
|
+
if (context) lines.push('', ...context.split('\n'));
|
|
121
|
+
if (findings.length > 0) {
|
|
122
|
+
lines.push('', 'Trechos legados detectados abaixo (não valem mais; `wizz doctor` lista de novo):');
|
|
123
|
+
for (const f of findings) lines.push(`- \`${f.snippet.replaceAll('`', "'")}\` (${f.why})`);
|
|
124
|
+
}
|
|
125
|
+
lines.push(BLOCK_END);
|
|
126
|
+
return lines.join('\n');
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
/** Insere ou substitui o bloco no topo. Idempotente. */
|
|
130
|
+
function upsertManagedBlock(text, context = null) {
|
|
131
|
+
const { rest } = splitManagedBlock(text);
|
|
132
|
+
const findings = scanLegacy(rest);
|
|
133
|
+
const block = renderManagedBlock(findings, context);
|
|
134
|
+
const body = rest.replace(/^\s+/, '');
|
|
135
|
+
return { text: body ? `${block}\n\n${body}` : `${block}\n`, findings };
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
/** Remove o bloco (uninstall). Devolve o texto intacto se não houver bloco. */
|
|
139
|
+
function removeManagedBlock(text) {
|
|
140
|
+
return splitManagedBlock(text).rest;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
/**
|
|
144
|
+
* Aplica o bloco nos arquivos de instrução que existem na raiz do projeto.
|
|
145
|
+
* Sem nenhum dos dois, cria CLAUDE.md só se `createIfMissing`.
|
|
146
|
+
* Com project-context.md no projeto, o bloco importa (CLAUDE.md) ou aponta (AGENTS.md) para ele.
|
|
147
|
+
* @returns {Promise<{file: string, changed: boolean, findings: object[]}[]>}
|
|
148
|
+
*/
|
|
149
|
+
async function applyProjectInstructions({ projectRoot, fs, createIfMissing = false }) {
|
|
150
|
+
const results = [];
|
|
151
|
+
const targets = [];
|
|
152
|
+
for (const name of INSTRUCTION_FILES) {
|
|
153
|
+
const file = path.join(projectRoot, name);
|
|
154
|
+
if (await fs.pathExists(file)) targets.push(file);
|
|
155
|
+
}
|
|
156
|
+
if (targets.length === 0 && createIfMissing) targets.push(path.join(projectRoot, 'CLAUDE.md'));
|
|
157
|
+
|
|
158
|
+
const contextPath = await findProjectContext(projectRoot);
|
|
159
|
+
for (const file of targets) {
|
|
160
|
+
const before = (await fs.pathExists(file)) ? await fs.readFile(file, 'utf8') : '';
|
|
161
|
+
const { text, findings } = upsertManagedBlock(before, contextLine(path.basename(file), contextPath));
|
|
162
|
+
const changed = text !== before;
|
|
163
|
+
if (changed) await fs.writeFile(file, text, 'utf8');
|
|
164
|
+
results.push({ file, changed, findings });
|
|
165
|
+
}
|
|
166
|
+
return results;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
/** Tira o bloco dos arquivos de instrução (uninstall). */
|
|
170
|
+
async function removeProjectInstructions({ projectRoot, fs }) {
|
|
171
|
+
const removed = [];
|
|
172
|
+
for (const name of INSTRUCTION_FILES) {
|
|
173
|
+
const file = path.join(projectRoot, name);
|
|
174
|
+
if (!(await fs.pathExists(file))) continue;
|
|
175
|
+
const before = await fs.readFile(file, 'utf8');
|
|
176
|
+
const after = removeManagedBlock(before);
|
|
177
|
+
if (after !== before) {
|
|
178
|
+
await fs.writeFile(file, after, 'utf8');
|
|
179
|
+
removed.push(file);
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
return removed;
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
module.exports = {
|
|
186
|
+
BLOCK_BEGIN,
|
|
187
|
+
BLOCK_END,
|
|
188
|
+
INSTRUCTION_FILES,
|
|
189
|
+
findProjectContext,
|
|
190
|
+
contextLine,
|
|
191
|
+
RETIRED_MODEL_RE,
|
|
192
|
+
splitManagedBlock,
|
|
193
|
+
scanLegacy,
|
|
194
|
+
renderManagedBlock,
|
|
195
|
+
upsertManagedBlock,
|
|
196
|
+
removeManagedBlock,
|
|
197
|
+
applyProjectInstructions,
|
|
198
|
+
removeProjectInstructions,
|
|
199
|
+
};
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
package/src/core-skills/wizz-advanced-elicitation/scripts/__pycache__/pick_methods.cpython-313.pyc
DELETED
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
package/src/core-skills/wizz-brainstorming/scripts/tests/__pycache__/test_brain.cpython-314.pyc
DELETED
|
Binary file
|
package/src/core-skills/wizz-customize/scripts/__pycache__/list_customizable_skills.cpython-313.pyc
DELETED
|
Binary file
|
|
Binary file
|
package/src/core-skills/wizz-forge-idea/scripts/__pycache__/resolve_personas.cpython-313.pyc
DELETED
|
Binary file
|
package/src/core-skills/wizz-forge-idea/scripts/__pycache__/resolve_personas.cpython-314.pyc
DELETED
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
package/src/core-skills/wizz-party-mode/scripts/tests/__pycache__/test_resolve_party.cpython-314.pyc
DELETED
|
Binary file
|
|
Binary file
|