wizz-method 2.18.0 → 2.19.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/package.json +5 -3
- package/removals.txt +10 -0
- package/skills-registry.yaml +50 -38
- package/src/bmm-skills/1-analysis/wizz-set-feature/SKILL.md +9 -9
- package/src/bmm-skills/4-implementation/wizz-create-story/SKILL.md +1 -1
- package/src/bmm-skills/4-implementation/wizz-dev-story/SKILL.md +1 -1
- package/src/bmm-skills/4-implementation/wizz-qa-generate-e2e-tests/SKILL.md +1 -1
- package/src/bmm-skills/4-implementation/wizz-qa-generate-e2e-tests/checklist.md +1 -1
- package/src/bmm-skills/4-implementation/wizz-quick-dev/SKILL.md +1 -1
- package/src/bmm-skills/4-implementation/wizz-sprint-status/SKILL.md +5 -5
- package/src/bmm-skills/module-help.csv +1 -1
- package/src/bmm-skills/module.yaml +1 -1
- package/src/core-skills/_shared/handoff-protocol.md +2 -2
- package/src/modules/lowticket/skills/wizz-lowticket-funil/SKILL.md +1 -1
- package/src/modules/lowticket/skills/wizz-lowticket-guia/SKILL.md +1 -1
- package/src/modules/lowticket/skills/wizz-lowticket-metodologia/SKILL.md +1 -1
- package/src/modules/lowticket/skills/wizz-lowticket-minerador/SKILL.md +1 -1
- package/src/modules/lowticket/skills/wizz-lowticket-pagina/SKILL.md +1 -1
- package/src/modules/lowticket/skills/wizz-lowticket-trafego/SKILL.md +1 -1
- package/src/modules/wizz/_shared/cerebro.md +7 -7
- package/src/modules/wizz/_shared/communication-rules.md +1 -1
- package/src/modules/wizz/_shared/encerramento.md +4 -3
- package/src/modules/wizz/_shared/organizacao.md +8 -4
- package/src/modules/wizz/_shared/token-economy.md +1 -1
- package/src/modules/wizz/_shared/video-pipeline.md +4 -4
- package/src/modules/wizz/agents/wizz-ads/SKILL.md +4 -1
- package/src/modules/wizz/agents/wizz-ads/customize.toml +12 -3
- package/src/modules/wizz/agents/wizz-ads/knowledge/playbook.md +36 -0
- package/src/modules/wizz/agents/wizz-copy/SKILL.md +4 -1
- package/src/modules/wizz/agents/wizz-copy/customize.toml +2 -3
- package/src/modules/wizz/agents/wizz-copy/knowledge/playbook.md +34 -0
- package/src/modules/wizz/agents/wizz-designer/SKILL.md +2 -2
- package/src/modules/wizz/agents/wizz-designer/customize.toml +2 -3
- package/src/modules/wizz/agents/wizz-growth/SKILL.md +4 -1
- package/src/modules/wizz/agents/wizz-growth/customize.toml +33 -4
- package/src/modules/wizz/agents/wizz-growth/knowledge/playbook.md +39 -0
- package/src/modules/wizz/agents/wizz-maestro/SKILL.md +6 -8
- package/src/modules/wizz/agents/wizz-maestro/customize.toml +2 -3
- package/src/modules/wizz/agents/wizz-memoria/SKILL.md +7 -7
- package/src/modules/wizz/agents/wizz-memoria/customize.toml +5 -6
- package/src/modules/wizz/agents/wizz-qa/SKILL.md +5 -6
- package/src/modules/wizz/agents/wizz-qa/customize.toml +3 -4
- package/src/modules/wizz/agents/wizz-seo/SKILL.md +4 -1
- package/src/modules/wizz/agents/wizz-seo/customize.toml +2 -3
- package/src/modules/wizz/agents/wizz-seo/knowledge/playbook.md +31 -0
- package/src/modules/wizz/agents/wizz-social/SKILL.md +3 -3
- package/src/modules/wizz/agents/wizz-social/customize.toml +2 -3
- package/src/modules/wizz/overrides/wizz-agent-analyst.toml +2 -2
- package/src/modules/wizz/overrides/wizz-agent-architect.toml +3 -3
- package/src/modules/wizz/overrides/wizz-agent-dev.toml +3 -3
- package/src/modules/wizz/overrides/wizz-agent-pm.toml +2 -2
- package/src/modules/wizz/overrides/wizz-agent-tech-writer.toml +2 -2
- package/src/modules/wizz/overrides/wizz-agent-ux-designer.toml +2 -2
- package/src/skills-lib/_shared/complexity-signal.md +8 -9
- package/src/skills-lib/_shared/dispatch-rule.yaml +21 -0
- package/src/skills-lib/{cerebro → wizz-cerebro}/SKILL.md +1 -1
- package/src/skills-lib/{ctc-align → wizz-ctc-align}/SKILL.md +1 -1
- package/src/skills-lib/{enhance-prompt → wizz-enhance-prompt}/SKILL.md +1 -1
- package/src/skills-lib/{find-skills → wizz-find-skills}/SKILL.md +1 -1
- package/src/skills-lib/wizz-huashu-design/references/sfx-library.md +1 -1
- package/src/skills-lib/wizz-huashu-design/scripts/add-music.sh +1 -1
- package/src/skills-lib/wizz-huashu-design/scripts/html2pptx.js +45 -37
- package/src/skills-lib/wizz-huashu-design/scripts/mix-voiceover.sh +1 -1
- package/src/skills-lib/wizz-huashu-design/scripts/narrate-pipeline.mjs +11 -5
- package/src/skills-lib/wizz-huashu-design/scripts/test_scripts.py +209 -0
- package/src/skills-lib/wizz-huashu-design/scripts/tts-doubao.mjs +42 -28
- package/src/skills-lib/wizz-ig-profile-optimizer/SKILL.md +1 -1
- package/src/skills-lib/wizz-inicio-de-projeto/SKILL.md +1 -1
- package/src/skills-lib/wizz-launch-readiness/SKILL.md +7 -7
- package/src/skills-lib/wizz-launch-readiness/references/02-seguranca.md +3 -3
- package/src/skills-lib/wizz-launch-readiness/references/03-seo-descoberta.md +5 -5
- package/src/skills-lib/wizz-launch-readiness/references/04-analytics-medicao.md +1 -1
- package/src/skills-lib/wizz-launch-readiness/references/05-conteudo-prova-social.md +6 -6
- package/src/skills-lib/wizz-launch-readiness/references/06-legal-lgpd.md +1 -1
- package/src/skills-lib/wizz-launch-readiness/references/08-fusao-priorizacao.md +1 -1
- package/src/skills-lib/wizz-offer-forge/SKILL.md +3 -3
- package/src/skills-lib/{pesquisa-de-publico-do-piva → wizz-pesquisa-de-publico-do-piva}/README.md +1 -1
- package/src/skills-lib/{pesquisa-de-publico-do-piva → wizz-pesquisa-de-publico-do-piva}/SKILL.md +1 -1
- package/src/skills-lib/wizz-router/SKILL.md +3 -3
- package/src/skills-lib/wizz-router/references/routing-table-flat.md +9 -9
- package/src/skills-lib/{security-audit-pentest → wizz-security-audit-pentest}/SKILL.md +1 -1
- package/src/skills-lib/{site-launch-kit → wizz-site-launch-kit}/SKILL.md +1 -1
- package/src/skills-lib/wizz-video-effects/SKILL.md +3 -3
- package/src/skills-lib/wizz-video-effects/references/data-contract.md +3 -3
- package/src/skills-lib/wizz-video-effects/scripts/fill_breaths.py +15 -1
- package/src/skills-lib/wizz-video-effects/scripts/test_fill_breaths.py +20 -0
- package/src/skills-lib/wizz-video-styles/SKILL.md +2 -2
- package/src/skills-lib/wizz-video-styles/data/recipes.json +32 -1
- package/src/skills-lib/wizz-video-styles/data/references.json +211 -1
- package/src/skills-lib/wizz-video-styles/data/styles.json +54 -0
- package/src/skills-lib/wizz-video-styles/references/generated-prompts.md +13 -3
- package/src/skills-lib/wizz-video-styles/references/style-picker.md +4 -2
- package/src/skills-lib/wizz-video-styles/references/styles/ui-morph.md +68 -0
- package/src/skills-lib/wizz-video-styles/scripts/analyze.sh +21 -9
- package/src/skills-lib/wizz-video-styles/scripts/references.mjs +1 -0
- package/src/skills-lib/wizz-web-security/SKILL.md +1 -1
- package/tools/fetch-assets.mjs +1 -1
- package/tools/hooks/README.md +18 -14
- package/tools/hooks/rtk-rewrite.js +95 -0
- package/tools/hooks/security-defensive-context.js +17 -1
- package/tools/hooks/session-rules.js +25 -5
- package/tools/hooks/wizz-arrumar.js +126 -12
- package/tools/hooks/wizz-artifact-guard.js +41 -7
- package/tools/hooks/wizz-cerebro-lib.js +239 -0
- package/tools/hooks/wizz-close-reminder.js +124 -0
- package/tools/hooks/wizz-debug-lib.js +55 -0
- package/tools/hooks/wizz-decision-trace.js +19 -2
- package/tools/hooks/wizz-feature.js +20 -4
- package/tools/hooks/wizz-router-enforce.js +30 -13
- package/tools/installer/command-text.js +243 -0
- package/tools/installer/commands/catalog.js +2 -0
- package/tools/installer/commands/doctor.js +10 -12
- package/tools/installer/commands/fetch-assets.js +5 -5
- package/tools/installer/commands/install.js +6 -7
- package/tools/installer/commands/resolve.js +17 -17
- package/tools/installer/commands/trace-report.js +40 -37
- package/tools/installer/core/doctor.js +60 -55
- package/tools/installer/core/hooks-settings.js +88 -14
- package/tools/installer/core/hooks-smoke.js +134 -0
- package/tools/installer/core/installer.js +61 -52
- package/tools/installer/core/quick-update.js +2 -3
- package/tools/installer/install-text.js +201 -0
- package/tools/installer/modules/channel-plan.js +2 -2
- package/tools/installer/modules/env-vars.js +5 -6
- package/tools/installer/modules/skills-lib.js +1 -1
- package/tools/installer/ui.js +17 -9
- /package/src/skills-lib/{cerebro → wizz-cerebro}/references/comandos-pesquisa-e-memoria.md +0 -0
- /package/src/skills-lib/{cerebro → wizz-cerebro}/references/comandos-rotina-e-captura.md +0 -0
- /package/src/skills-lib/{cerebro → wizz-cerebro}/references/comandos-sessao.md +0 -0
- /package/src/skills-lib/{ctc-align → wizz-ctc-align}/scripts/align.py +0 -0
- /package/src/skills-lib/{enhance-prompt → wizz-enhance-prompt}/README.md +0 -0
- /package/src/skills-lib/{enhance-prompt → wizz-enhance-prompt}/references/KEYWORDS.md +0 -0
- /package/src/skills-lib/{pesquisa-de-publico-do-piva → wizz-pesquisa-de-publico-do-piva}/assets/template.html +0 -0
- /package/src/skills-lib/{pesquisa-de-publico-do-piva → wizz-pesquisa-de-publico-do-piva}/prompts.md +0 -0
- /package/src/skills-lib/{security-audit-pentest → wizz-security-audit-pentest}/references/stage-1-validacao-entrada.md +0 -0
- /package/src/skills-lib/{security-audit-pentest → wizz-security-audit-pentest}/references/stage-2-autorizacao.md +0 -0
- /package/src/skills-lib/{security-audit-pentest → wizz-security-audit-pentest}/references/stage-3-abuso-volume.md +0 -0
- /package/src/skills-lib/{security-audit-pentest → wizz-security-audit-pentest}/references/stage-4-vazamento-resposta.md +0 -0
- /package/src/skills-lib/{security-audit-pentest → wizz-security-audit-pentest}/references/stage-5-fusao-plano.md +0 -0
- /package/src/skills-lib/{site-launch-kit → wizz-site-launch-kit}/references/01-cta-principal.md +0 -0
- /package/src/skills-lib/{site-launch-kit → wizz-site-launch-kit}/references/02-barra-fixa-mobile.md +0 -0
- /package/src/skills-lib/{site-launch-kit → wizz-site-launch-kit}/references/03-tempo-de-resposta.md +0 -0
- /package/src/skills-lib/{site-launch-kit → wizz-site-launch-kit}/references/04-prova-social.md +0 -0
- /package/src/skills-lib/{site-launch-kit → wizz-site-launch-kit}/references/05-faq-decisao.md +0 -0
- /package/src/skills-lib/{site-launch-kit → wizz-site-launch-kit}/references/06-imagens-reais.md +0 -0
- /package/src/skills-lib/{site-launch-kit → wizz-site-launch-kit}/references/07-endereco-como-chegar.md +0 -0
- /package/src/skills-lib/{site-launch-kit → wizz-site-launch-kit}/references/08-titles.md +0 -0
- /package/src/skills-lib/{site-launch-kit → wizz-site-launch-kit}/references/09-open-graph.md +0 -0
- /package/src/skills-lib/{site-launch-kit → wizz-site-launch-kit}/references/10-breadcrumbs.md +0 -0
- /package/src/skills-lib/{site-launch-kit → wizz-site-launch-kit}/references/11-alt-text.md +0 -0
- /package/src/skills-lib/{site-launch-kit → wizz-site-launch-kit}/references/12-schema-local.md +0 -0
- /package/src/skills-lib/{site-launch-kit → wizz-site-launch-kit}/references/13-robots-sitemap.md +0 -0
- /package/src/skills-lib/{site-launch-kit → wizz-site-launch-kit}/references/14-privacidade-termos.md +0 -0
- /package/src/skills-lib/{site-launch-kit → wizz-site-launch-kit}/references/15-medicao.md +0 -0
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
"""Testes (unittest, stdlib) das partes puras de fetch_images.py e verify.py.
|
|
2
|
+
|
|
3
|
+
Rede e browser ficam de fora: a API da Wikimedia e o download são trocados por
|
|
4
|
+
mocks. Rodam via `python3 -m unittest discover` (test/test-python-skills.js).
|
|
5
|
+
"""
|
|
6
|
+
import contextlib
|
|
7
|
+
import io
|
|
8
|
+
import os
|
|
9
|
+
import sys
|
|
10
|
+
import tempfile
|
|
11
|
+
import unittest
|
|
12
|
+
from unittest import mock
|
|
13
|
+
|
|
14
|
+
sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
|
|
15
|
+
|
|
16
|
+
import fetch_images # noqa: E402
|
|
17
|
+
import verify # noqa: E402
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
class FakeResponse:
|
|
21
|
+
"""Resposta mínima de urlopen usada como context manager."""
|
|
22
|
+
|
|
23
|
+
def __init__(self, payload=b"IMG"):
|
|
24
|
+
self._payload = payload
|
|
25
|
+
|
|
26
|
+
def __enter__(self):
|
|
27
|
+
return self
|
|
28
|
+
|
|
29
|
+
def __exit__(self, *exc):
|
|
30
|
+
return False
|
|
31
|
+
|
|
32
|
+
def read(self):
|
|
33
|
+
return self._payload
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
def page(title, thumb=None, url=None, lic="CC BY-SA 4.0", artist="<a href='x'>Ana</a> Silva"):
|
|
37
|
+
info = {
|
|
38
|
+
"descriptionurl": "https://commons.example/" + title,
|
|
39
|
+
"extmetadata": {"LicenseShortName": {"value": lic}, "Artist": {"value": artist}},
|
|
40
|
+
}
|
|
41
|
+
if thumb:
|
|
42
|
+
info["thumburl"] = thumb
|
|
43
|
+
if url:
|
|
44
|
+
info["url"] = url
|
|
45
|
+
return {"title": title, "imageinfo": [info]}
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
class SafeNameTest(unittest.TestCase):
|
|
49
|
+
def test_replaces_unsafe_chars(self):
|
|
50
|
+
self.assertEqual(fetch_images._safe("Petronas Towers/KL"), "Petronas_Towers_KL")
|
|
51
|
+
|
|
52
|
+
def test_keeps_word_chars_dash_dot(self):
|
|
53
|
+
self.assertEqual(fetch_images._safe("a-b.c_d"), "a-b.c_d")
|
|
54
|
+
|
|
55
|
+
def test_truncates_to_60(self):
|
|
56
|
+
self.assertEqual(len(fetch_images._safe("x" * 200)), 60)
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
class FetchTest(unittest.TestCase):
|
|
60
|
+
def setUp(self):
|
|
61
|
+
self.tmp = tempfile.TemporaryDirectory()
|
|
62
|
+
self.addCleanup(self.tmp.cleanup)
|
|
63
|
+
self.out = self.tmp.name
|
|
64
|
+
|
|
65
|
+
def run_fetch(self, pages, query="Langkawi beach", count=2, width=1600, urlopen=None):
|
|
66
|
+
data = {"query": {"pages": pages}}
|
|
67
|
+
stack = contextlib.ExitStack()
|
|
68
|
+
stack.enter_context(mock.patch.object(fetch_images, "_api_get", return_value=data))
|
|
69
|
+
opener = urlopen or (lambda req, timeout=0: FakeResponse())
|
|
70
|
+
stack.enter_context(mock.patch.object(fetch_images.urllib.request, "urlopen", side_effect=opener))
|
|
71
|
+
with stack:
|
|
72
|
+
buf = io.StringIO()
|
|
73
|
+
with contextlib.redirect_stdout(buf), contextlib.redirect_stderr(io.StringIO()):
|
|
74
|
+
got = fetch_images.fetch(query, self.out, count, width)
|
|
75
|
+
return got, buf.getvalue()
|
|
76
|
+
|
|
77
|
+
def test_downloads_thumb_and_prints_license_and_clean_artist(self):
|
|
78
|
+
pages = {"1": page("File:Beach one.jpg", thumb="https://up.example/t/beach.jpg?x=1")}
|
|
79
|
+
got, out = self.run_fetch(pages)
|
|
80
|
+
self.assertEqual(len(got), 1)
|
|
81
|
+
self.assertTrue(os.path.exists(got[0]))
|
|
82
|
+
self.assertTrue(got[0].startswith(self.out))
|
|
83
|
+
self.assertTrue(got[0].endswith(".jpg"), "extensão vem da URL sem a query string")
|
|
84
|
+
self.assertIn("CC BY-SA 4.0", out)
|
|
85
|
+
self.assertIn("Ana Silva", out)
|
|
86
|
+
self.assertNotIn("<a", out, "tags HTML do autor são removidas")
|
|
87
|
+
self.assertIn("https://commons.example/File:Beach one.jpg", out)
|
|
88
|
+
|
|
89
|
+
def test_filename_has_query_and_title_without_file_prefix(self):
|
|
90
|
+
got, _ = self.run_fetch({"1": page("File:Nice view.png", thumb="https://up.example/x.png")}, query="Petronas Towers")
|
|
91
|
+
name = os.path.basename(got[0])
|
|
92
|
+
self.assertTrue(name.startswith("Petronas_Towers_"), name)
|
|
93
|
+
self.assertNotIn("File_", name)
|
|
94
|
+
self.assertTrue(name.endswith(".png"))
|
|
95
|
+
|
|
96
|
+
def test_falls_back_to_url_when_no_thumb_and_default_ext_jpg(self):
|
|
97
|
+
got, _ = self.run_fetch({"1": page("File:a", url="https://up.example/noext")})
|
|
98
|
+
self.assertEqual(len(got), 1)
|
|
99
|
+
self.assertTrue(got[0].endswith(".jpg"))
|
|
100
|
+
|
|
101
|
+
def test_skips_pages_without_any_image_url(self):
|
|
102
|
+
got, _ = self.run_fetch({"1": page("File:nada")})
|
|
103
|
+
self.assertEqual(got, [])
|
|
104
|
+
|
|
105
|
+
def test_respects_count(self):
|
|
106
|
+
pages = {str(i): page(f"File:img{i}.jpg", thumb=f"https://up.example/{i}.jpg") for i in range(5)}
|
|
107
|
+
got, _ = self.run_fetch(pages, count=2)
|
|
108
|
+
self.assertEqual(len(got), 2)
|
|
109
|
+
|
|
110
|
+
def test_missing_metadata_uses_question_mark(self):
|
|
111
|
+
bare = {"title": "File:x.jpg", "imageinfo": [{"thumburl": "https://up.example/x.jpg"}]}
|
|
112
|
+
_, out = self.run_fetch({"1": bare})
|
|
113
|
+
self.assertIn("| ? | ?", out)
|
|
114
|
+
|
|
115
|
+
def test_api_failure_returns_empty_list(self):
|
|
116
|
+
with mock.patch.object(fetch_images, "_api_get", side_effect=OSError("boom")):
|
|
117
|
+
with contextlib.redirect_stderr(io.StringIO()) as err:
|
|
118
|
+
got = fetch_images.fetch("q", self.out, 2, 800)
|
|
119
|
+
self.assertEqual(got, [])
|
|
120
|
+
self.assertIn("FAIL search", err.getvalue())
|
|
121
|
+
|
|
122
|
+
def test_no_pages_returns_empty_and_warns(self):
|
|
123
|
+
with mock.patch.object(fetch_images, "_api_get", return_value={"query": {}}):
|
|
124
|
+
with contextlib.redirect_stderr(io.StringIO()) as err:
|
|
125
|
+
got = fetch_images.fetch("q", self.out, 2, 800)
|
|
126
|
+
self.assertEqual(got, [])
|
|
127
|
+
self.assertIn("EMPTY", err.getvalue())
|
|
128
|
+
|
|
129
|
+
def test_download_failure_is_skipped_not_fatal(self):
|
|
130
|
+
def opener(req, timeout=0):
|
|
131
|
+
raise OSError("download caiu")
|
|
132
|
+
|
|
133
|
+
got, _ = self.run_fetch({"1": page("File:a.jpg", thumb="https://up.example/a.jpg")}, urlopen=opener)
|
|
134
|
+
self.assertEqual(got, [])
|
|
135
|
+
|
|
136
|
+
def test_requests_send_compliant_user_agent_and_width(self):
|
|
137
|
+
seen = {}
|
|
138
|
+
|
|
139
|
+
def fake_api(params):
|
|
140
|
+
seen.update(params)
|
|
141
|
+
return {"query": {"pages": {}}}
|
|
142
|
+
|
|
143
|
+
with mock.patch.object(fetch_images, "_api_get", side_effect=fake_api):
|
|
144
|
+
with contextlib.redirect_stderr(io.StringIO()):
|
|
145
|
+
fetch_images.fetch("Georgetown", self.out, 3, 1200)
|
|
146
|
+
self.assertEqual(seen["gsrsearch"], "Georgetown")
|
|
147
|
+
self.assertEqual(seen["gsrlimit"], 3)
|
|
148
|
+
self.assertEqual(seen["iiurlwidth"], 1200)
|
|
149
|
+
self.assertEqual(seen["gsrnamespace"], 6)
|
|
150
|
+
self.assertIn("huashu-design", fetch_images.UA)
|
|
151
|
+
|
|
152
|
+
def test_module_clears_proxy_env(self):
|
|
153
|
+
for key in ("ALL_PROXY", "HTTP_PROXY", "HTTPS_PROXY", "http_proxy", "https_proxy", "all_proxy"):
|
|
154
|
+
self.assertNotIn(key, os.environ)
|
|
155
|
+
|
|
156
|
+
|
|
157
|
+
class MainTest(unittest.TestCase):
|
|
158
|
+
def run_main(self, argv, fetch_result):
|
|
159
|
+
with mock.patch.object(sys, "argv", ["fetch_images.py", *argv]):
|
|
160
|
+
with mock.patch.object(fetch_images, "fetch", return_value=fetch_result) as fetch:
|
|
161
|
+
with contextlib.redirect_stdout(io.StringIO()), contextlib.redirect_stderr(io.StringIO()):
|
|
162
|
+
try:
|
|
163
|
+
fetch_images.main()
|
|
164
|
+
code = None
|
|
165
|
+
except SystemExit as exc:
|
|
166
|
+
code = exc.code
|
|
167
|
+
return code, fetch
|
|
168
|
+
|
|
169
|
+
def test_exit_1_when_nothing_downloaded(self):
|
|
170
|
+
with tempfile.TemporaryDirectory() as tmp:
|
|
171
|
+
code, _ = self.run_main(["--query", "a", "b", "--out", os.path.join(tmp, "img")], [])
|
|
172
|
+
self.assertEqual(code, 1)
|
|
173
|
+
|
|
174
|
+
def test_success_creates_out_dir_and_passes_defaults(self):
|
|
175
|
+
with tempfile.TemporaryDirectory() as tmp:
|
|
176
|
+
out = os.path.join(tmp, "novo", "img")
|
|
177
|
+
code, fetch = self.run_main(["--query", "a", "b", "--out", out], ["f.jpg"])
|
|
178
|
+
self.assertIsNone(code)
|
|
179
|
+
self.assertTrue(os.path.isdir(out))
|
|
180
|
+
self.assertEqual(fetch.call_count, 2, "um fetch por query")
|
|
181
|
+
fetch.assert_any_call("a", out, 2, 1600)
|
|
182
|
+
|
|
183
|
+
def test_custom_count_and_width(self):
|
|
184
|
+
with tempfile.TemporaryDirectory() as tmp:
|
|
185
|
+
out = os.path.join(tmp, "img")
|
|
186
|
+
_, fetch = self.run_main(["--query", "x", "--out", out, "--count", "4", "--width", "800"], ["f"])
|
|
187
|
+
fetch.assert_called_once_with("x", out, 4, 800)
|
|
188
|
+
|
|
189
|
+
def test_requires_query_and_out(self):
|
|
190
|
+
with mock.patch.object(sys, "argv", ["fetch_images.py"]):
|
|
191
|
+
with contextlib.redirect_stderr(io.StringIO()):
|
|
192
|
+
with self.assertRaises(SystemExit) as ctx:
|
|
193
|
+
fetch_images.main()
|
|
194
|
+
self.assertEqual(ctx.exception.code, 2)
|
|
195
|
+
|
|
196
|
+
|
|
197
|
+
class ParseViewportTest(unittest.TestCase):
|
|
198
|
+
def test_parses_width_x_height(self):
|
|
199
|
+
self.assertEqual(verify.parse_viewport("1440x900"), {"width": 1440, "height": 900})
|
|
200
|
+
self.assertEqual(verify.parse_viewport("375x667"), {"width": 375, "height": 667})
|
|
201
|
+
|
|
202
|
+
def test_rejects_malformed(self):
|
|
203
|
+
for bad in ("1440", "axb", "1x2x3", ""):
|
|
204
|
+
with self.assertRaises(ValueError, msg=bad):
|
|
205
|
+
verify.parse_viewport(bad)
|
|
206
|
+
|
|
207
|
+
|
|
208
|
+
if __name__ == "__main__":
|
|
209
|
+
unittest.main()
|
|
@@ -28,8 +28,7 @@ import { randomUUID } from 'node:crypto';
|
|
|
28
28
|
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
29
29
|
const SKILL_ROOT = path.resolve(__dirname, '..');
|
|
30
30
|
|
|
31
|
-
function loadEnv() {
|
|
32
|
-
const envPath = path.join(SKILL_ROOT, '.env');
|
|
31
|
+
function loadEnv(envPath = path.join(SKILL_ROOT, '.env')) {
|
|
33
32
|
if (!fs.existsSync(envPath)) return;
|
|
34
33
|
const text = fs.readFileSync(envPath, 'utf8');
|
|
35
34
|
for (const line of text.split('\n')) {
|
|
@@ -45,7 +44,6 @@ function loadEnv() {
|
|
|
45
44
|
if (!(key in process.env)) process.env[key] = val;
|
|
46
45
|
}
|
|
47
46
|
}
|
|
48
|
-
loadEnv();
|
|
49
47
|
|
|
50
48
|
function parseArgs(argv) {
|
|
51
49
|
const args = { speed: '1.0', encoding: 'mp3' };
|
|
@@ -90,16 +88,9 @@ function getDuration(filePath) {
|
|
|
90
88
|
}
|
|
91
89
|
}
|
|
92
90
|
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
const endpoint = process.env.DOUBAO_TTS_ENDPOINT || 'https://openspeech.bytedance.com/api/v1/tts';
|
|
97
|
-
const voiceId = voice || process.env.DOUBAO_TTS_VOICE_ID;
|
|
98
|
-
|
|
99
|
-
if (!apiKey) throw new Error('缺 DOUBAO_TTS_API_KEY(检查 .env)');
|
|
100
|
-
if (!voiceId) throw new Error('缺 DOUBAO_TTS_VOICE_ID(检查 .env 或用 --voice 传)');
|
|
101
|
-
|
|
102
|
-
const body = {
|
|
91
|
+
/** Corpo da requisição à API do Doubao (puro, sem rede). */
|
|
92
|
+
function buildTtsBody({ cluster, voiceId, encoding, speed, text, reqid = randomUUID() }) {
|
|
93
|
+
return {
|
|
103
94
|
app: { cluster },
|
|
104
95
|
user: { uid: 'wizz-huashu-design' },
|
|
105
96
|
audio: {
|
|
@@ -108,11 +99,36 @@ async function tts({ text, voice, speed, encoding }) {
|
|
|
108
99
|
speed_ratio: parseFloat(speed),
|
|
109
100
|
},
|
|
110
101
|
request: {
|
|
111
|
-
reqid
|
|
102
|
+
reqid,
|
|
112
103
|
text,
|
|
113
104
|
operation: 'query',
|
|
114
105
|
},
|
|
115
106
|
};
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/** Valida a resposta JSON do Doubao e devolve o áudio decodificado (Buffer). */
|
|
110
|
+
function parseTtsResponse(json) {
|
|
111
|
+
// 豆包标准返回:{ code, message, data: "<base64 audio>", ... }
|
|
112
|
+
// code === 3000 表示成功
|
|
113
|
+
if (json.code !== undefined && json.code !== 3000) {
|
|
114
|
+
throw new Error(`API 返回错误 code=${json.code} msg=${json.message || JSON.stringify(json)}`);
|
|
115
|
+
}
|
|
116
|
+
if (!json.data) {
|
|
117
|
+
throw new Error(`API 响应无 data 字段:${JSON.stringify(json).slice(0, 500)}`);
|
|
118
|
+
}
|
|
119
|
+
return Buffer.from(json.data, 'base64');
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
async function tts({ text, voice, speed, encoding }) {
|
|
123
|
+
const apiKey = process.env.DOUBAO_TTS_API_KEY;
|
|
124
|
+
const cluster = process.env.DOUBAO_TTS_CLUSTER || 'volcano_icl';
|
|
125
|
+
const endpoint = process.env.DOUBAO_TTS_ENDPOINT || 'https://openspeech.bytedance.com/api/v1/tts';
|
|
126
|
+
const voiceId = voice || process.env.DOUBAO_TTS_VOICE_ID;
|
|
127
|
+
|
|
128
|
+
if (!apiKey) throw new Error('缺 DOUBAO_TTS_API_KEY(检查 .env)');
|
|
129
|
+
if (!voiceId) throw new Error('缺 DOUBAO_TTS_VOICE_ID(检查 .env 或用 --voice 传)');
|
|
130
|
+
|
|
131
|
+
const body = buildTtsBody({ cluster, voiceId, encoding, speed, text });
|
|
116
132
|
|
|
117
133
|
const res = await fetch(endpoint, {
|
|
118
134
|
method: 'POST',
|
|
@@ -128,16 +144,7 @@ async function tts({ text, voice, speed, encoding }) {
|
|
|
128
144
|
throw new Error(`HTTP ${res.status}: ${errText.slice(0, 500)}`);
|
|
129
145
|
}
|
|
130
146
|
|
|
131
|
-
|
|
132
|
-
// 豆包标准返回:{ code, message, data: "<base64 audio>", ... }
|
|
133
|
-
// code === 3000 表示成功
|
|
134
|
-
if (json.code !== undefined && json.code !== 3000) {
|
|
135
|
-
throw new Error(`API 返回错误 code=${json.code} msg=${json.message || JSON.stringify(json)}`);
|
|
136
|
-
}
|
|
137
|
-
if (!json.data) {
|
|
138
|
-
throw new Error(`API 响应无 data 字段:${JSON.stringify(json).slice(0, 500)}`);
|
|
139
|
-
}
|
|
140
|
-
return Buffer.from(json.data, 'base64');
|
|
147
|
+
return parseTtsResponse(await res.json());
|
|
141
148
|
}
|
|
142
149
|
|
|
143
150
|
async function main() {
|
|
@@ -178,7 +185,14 @@ async function main() {
|
|
|
178
185
|
console.log(JSON.stringify(result));
|
|
179
186
|
}
|
|
180
187
|
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
188
|
+
// Só executa quando chamado como script; importar o módulo (testes) não lê .env nem chama a API.
|
|
189
|
+
const isMain = process.argv[1] && fs.realpathSync(process.argv[1]) === fileURLToPath(import.meta.url);
|
|
190
|
+
if (isMain) {
|
|
191
|
+
loadEnv();
|
|
192
|
+
main().catch((err) => {
|
|
193
|
+
console.error(`TTS 失败:${err.message}`);
|
|
194
|
+
process.exit(1);
|
|
195
|
+
});
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
export { parseArgs, loadEnv, buildTtsBody, parseTtsResponse };
|
|
@@ -18,7 +18,7 @@ All text delivered is Brazilian Portuguese with "você", and no em dash in anyth
|
|
|
18
18
|
|
|
19
19
|
1. **Read the profile.** `scripts/capture-profile.sh <@> <out_dir>` (out_dir under `_wizz-output/`) saves `profile.png` and `profile.json` (NAME, bio and link as text, follower and post counts). **Open the image.** Logged out, Instagram may hide highlights, the category label and the pin marks: ask for a screenshot of those parts instead of guessing them.
|
|
20
20
|
2. **Pull what the Method already knows**, before judging:
|
|
21
|
-
- Positioning, audience and tone from the project's Cérebro (`/cerebro ver`).
|
|
21
|
+
- Positioning, audience and tone from the project's Cérebro (`/wizz-cerebro ver`).
|
|
22
22
|
- Highlights already made in the project (for example a `posts/highlights/` folder).
|
|
23
23
|
- The offer from `wizz-offer-forge`, when one exists: the link and one pin depend on it.
|
|
24
24
|
- Real performance: with Buffer connected, `get_aggregated_post_metrics` and the post list give the best posts by saves, shares and reach. Without it, ask which posts did best; never pick pins by guess.
|
|
@@ -87,7 +87,7 @@ Before the first file of a new project, and on the first use of the method in an
|
|
|
87
87
|
|
|
88
88
|
1. `node _wizz/hooks/wizz-arrumar.js layout` proposes it from what already exists (types: `codigo`, `scripts`, `dados`, `docs`, `midia`, `arquivo`; a type mapped to `.` lives at the root, e.g. a Next.js app at the root).
|
|
89
89
|
2. Show the proposal to the owner in **one line** and record it with `node _wizz/hooks/wizz-arrumar.js layout --gravar [tipo=pasta ...]`. It creates each new folder with a short README.
|
|
90
|
-
3. An existing project with loose files at the root: `wizz-arrumar.js planejar` writes a `.tsv` manifest; review it and run `wizz-arrumar.js aplicar <manifesto> --testes "<test command>" --refs <auto-memory dir>`. It moves, rewrites references in code, docs and memories, runs the tests before and after, and writes `desfazer.sh`.
|
|
90
|
+
3. An existing project with loose files at the root: `wizz-arrumar.js planejar` writes a `.tsv` manifest; review it and run `wizz-arrumar.js aplicar <manifesto> --testes "<test command>" --refs <auto-memory dir>`. It moves, rewrites references in code, docs and memories, runs the tests before and after, and writes an undo: `wizz-arrumar.js desfazer <run folder>` on any OS, or the `desfazer.sh` (`desfazer.cmd` on Windows) shortcut. `--testes` accepts only known test runners (npm/pnpm/yarn/bun test, npx vitest|jest, pytest, go/cargo/make test); any other command needs `--testes-livre`.
|
|
91
91
|
|
|
92
92
|
From then on the `wizz-artifact-guard.js` hook points out any file born loose at the root and the command that moves it. Full duty in the wizz module's `_shared/organizacao.md`.
|
|
93
93
|
|
|
@@ -8,8 +8,8 @@ description: >
|
|
|
8
8
|
ready to launch?", "pre-launch audit", "broad release checklist", "what's left
|
|
9
9
|
before going to production", considering the whole project (not just the site). Output: a diagnosis
|
|
10
10
|
prioritized by severity (red blocks launch, orange high, yellow medium, green ok), never
|
|
11
|
-
blind fixing. Different from security-audit-pentest (hunts vulnerabilities with proof of exploitation)
|
|
12
|
-
and site-launch-kit (executes the 15 rounds for ONE site): this DIAGNOSES the whole project and points to
|
|
11
|
+
blind fixing. Different from wizz-security-audit-pentest (hunts vulnerabilities with proof of exploitation)
|
|
12
|
+
and wizz-site-launch-kit (executes the 15 rounds for ONE site): this DIAGNOSES the whole project and points to
|
|
13
13
|
the right fix owner per finding. Persists the result in a dated section of project-context.md.
|
|
14
14
|
---
|
|
15
15
|
|
|
@@ -17,7 +17,7 @@ description: >
|
|
|
17
17
|
|
|
18
18
|
Seven checking areas, each a closed pass: single scope, standardized output, its own cutoff rule. At the end, a merge step consolidates everything into a prioritized diagnosis and writes the summary to the project's `project-context.md`.
|
|
19
19
|
|
|
20
|
-
This is not a build skill (that's `wizz-premium-landing-ui-researcher` / `wizz-taste-skill` / `wizz-agent-dev`), not the vulnerability-hunting methodology (that's `security-audit-pentest`), and it doesn't execute the 15 corrective rounds for a site (that's `site-launch-kit`): this is a broad, prioritized diagnosis to decide whether it's ready to launch.
|
|
20
|
+
This is not a build skill (that's `wizz-premium-landing-ui-researcher` / `wizz-taste-skill` / `wizz-agent-dev`), not the vulnerability-hunting methodology (that's `wizz-security-audit-pentest`), and it doesn't execute the 15 corrective rounds for a site (that's `wizz-site-launch-kit`): this is a broad, prioritized diagnosis to decide whether it's ready to launch.
|
|
21
21
|
|
|
22
22
|
## Stage gate (read BEFORE running)
|
|
23
23
|
|
|
@@ -25,7 +25,7 @@ Read the project's stage: `grep -m1 '^stage:' {project-root}/**/project-context.
|
|
|
25
25
|
|
|
26
26
|
- **`mvp` or `production`:** run the full audit. This is exactly what the skill exists for.
|
|
27
27
|
- **`prototype` or no `project-context.md` file:** stop before running. Reply that the project is still too early for a launch audit (little or nothing built yet to audit) and point to the right path for this stage: `wizz-inicio-de-projeto`, `wizz-forge-idea`, or `wizz-decision-maker` to define the product first. Only proceed if the user explicitly insists, and in that case warn that the findings will come back full of PENDING ITEMS due to lack of built surface.
|
|
28
|
-
- **`maintenance`:** normally not the use case (product already launched, running). Only makes sense if the request is about a NEW batch starting from scratch (a big feature, a new product within the same repo): confirm this before running; otherwise, point to `security-audit-pentest` (periodic pentest) or the `wizz-router`'s "360° Audit" mode (broad audit of a codebase already in production, not about a launch event).
|
|
28
|
+
- **`maintenance`:** normally not the use case (product already launched, running). Only makes sense if the request is about a NEW batch starting from scratch (a big feature, a new product within the same repo): confirm this before running; otherwise, point to `wizz-security-audit-pentest` (periodic pentest) or the `wizz-router`'s "360° Audit" mode (broad audit of a codebase already in production, not about a launch event).
|
|
29
29
|
|
|
30
30
|
## Common contract (applies to all 7 areas)
|
|
31
31
|
|
|
@@ -81,8 +81,8 @@ After the 7:
|
|
|
81
81
|
|
|
82
82
|
## Relationship with other skills
|
|
83
83
|
|
|
84
|
-
- **`security-audit-pentest`**: security deep dive. Area 02 here is a light sweep (exposed surface); findings that need proof of exploitation ("how it's exploited") go to `security-audit-pentest`, they aren't redone here.
|
|
85
|
-
- **`site-launch-kit`**: when the surface of the finding is a SITE (CTA, social proof, Open Graph, local schema, robots/sitemap, site LGPD, measurement), the fix owner is `site-launch-kit`. This skill doesn't repeat the 15 rounds: it only points to which round resolves the finding.
|
|
84
|
+
- **`wizz-security-audit-pentest`**: security deep dive. Area 02 here is a light sweep (exposed surface); findings that need proof of exploitation ("how it's exploited") go to `wizz-security-audit-pentest`, they aren't redone here.
|
|
85
|
+
- **`wizz-site-launch-kit`**: when the surface of the finding is a SITE (CTA, social proof, Open Graph, local schema, robots/sitemap, site LGPD, measurement), the fix owner is `wizz-site-launch-kit`. This skill doesn't repeat the 15 rounds: it only points to which round resolves the finding.
|
|
86
86
|
- **`wizz-seo-audit`**: broad ranking/traffic/Core Web Vitals diagnosis. Area 03 here is only basic indexability (can the site be found), not a full SEO audit.
|
|
87
87
|
- **`wizz-router`'s "360° Audit" mode**: a broad audit of a project already in production, by technical area (code, database, design, growth...), without the "we're about to launch" framing or the stage gate. Use wizz-launch-readiness for the launch event; use 360° mode for a mature project's general health.
|
|
88
88
|
|
|
@@ -90,5 +90,5 @@ After the 7:
|
|
|
90
90
|
|
|
91
91
|
- Doesn't fix anything on its own; it points to the fix owner.
|
|
92
92
|
- Doesn't decide GO/NO-GO on behalf of the project owner; delivers the prioritized reading.
|
|
93
|
-
- Doesn't replace `security-audit-pentest` for deep security or `site-launch-kit` for executing the 15 site rounds.
|
|
93
|
+
- Doesn't replace `wizz-security-audit-pentest` for deep security or `wizz-site-launch-kit` for executing the 15 site rounds.
|
|
94
94
|
- Doesn't run on a project with no built surface (discovery/ideation stage).
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Area 02 · Security
|
|
2
2
|
|
|
3
|
-
A sweep of the exposed SURFACE before launch, not a hunt for vulnerabilities with proof of exploitation. A finding that requires a concrete payload to prove (mass assignment, IDOR, injection) is NOT dug into here: log the suspicion as 🟠 and point to `security-audit-pentest` as the owner of the deep dive.
|
|
3
|
+
A sweep of the exposed SURFACE before launch, not a hunt for vulnerabilities with proof of exploitation. A finding that requires a concrete payload to prove (mass assignment, IDOR, injection) is NOT dug into here: log the suspicion as 🟠 and point to `wizz-security-audit-pentest` as the owner of the deep dive.
|
|
4
4
|
|
|
5
5
|
## Objective checks
|
|
6
6
|
|
|
@@ -11,11 +11,11 @@ A sweep of the exposed SURFACE before launch, not a hunt for vulnerabilities wit
|
|
|
11
11
|
5. **CORS too open.** `Access-Control-Allow-Origin: *` on an API that accepts credentials/tokens is 🔴; without credentials is 🟡.
|
|
12
12
|
6. **Rate limiting missing on a sensitive route.** Login, signup, password recovery, or an endpoint that costs money (AI, SMS, email) with no limit at all is 🟠; point to `wizz-web-security` as the fixer.
|
|
13
13
|
7. **Dependency with a known critical CVE on the production path.** Reinforces finding #7 from area 01 if it applies specifically to an auth/crypto lib: escalate to 🔴.
|
|
14
|
-
8. **Unproven indication of mass assignment, IDOR, or injection.** An update field that accepts the client's entire object with no allowlist, or a query built by string concatenation: log as 🟠 "suspicion, needs proof of exploitation" and point to `security-audit-pentest`.
|
|
14
|
+
8. **Unproven indication of mass assignment, IDOR, or injection.** An update field that accepts the client's entire object with no allowlist, or a query built by string concatenation: log as 🟠 "suspicion, needs proof of exploitation" and point to `wizz-security-audit-pentest`.
|
|
15
15
|
|
|
16
16
|
## Cutoff rule
|
|
17
17
|
|
|
18
|
-
This area NEVER delivers "how to exploit it" with a real payload: that is exclusively `security-audit-pentest`'s scope. If during the sweep you'd already have the payload ready, still don't include it here: log the suspicion and the reference, to avoid duplicating the two skills' output format.
|
|
18
|
+
This area NEVER delivers "how to exploit it" with a real payload: that is exclusively `wizz-security-audit-pentest`'s scope. If during the sweep you'd already have the payload ready, still don't include it here: log the suspicion and the reference, to avoid duplicating the two skills' output format.
|
|
19
19
|
|
|
20
20
|
## Output format
|
|
21
21
|
|
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
# Area 03 · SEO / Discoverability
|
|
2
2
|
|
|
3
|
-
Checks whether the product CAN be found on launch day. This is not a ranking, traffic, or Core Web Vitals diagnosis (that's `wizz-seo-audit`), and when the surface is a SITE, it doesn't repeat the execution rounds (that's `site-launch-kit`, rounds 08 to 13): here it only confirms whether basic indexability exists.
|
|
3
|
+
Checks whether the product CAN be found on launch day. This is not a ranking, traffic, or Core Web Vitals diagnosis (that's `wizz-seo-audit`), and when the surface is a SITE, it doesn't repeat the execution rounds (that's `wizz-site-launch-kit`, rounds 08 to 13): here it only confirms whether basic indexability exists.
|
|
4
4
|
|
|
5
5
|
If the project has no indexable public web surface (e.g., mobile-only app, internal tool), respond `ITEM DOES NOT APPLY` with a 1-line justification and stop.
|
|
6
6
|
|
|
7
7
|
## Objective checks
|
|
8
8
|
|
|
9
|
-
1. **`robots.txt` present and not blocking everything.** Missing is 🟠; present but blocking `Disallow: /` in production by mistake is 🔴. Point to `site-launch-kit` (round 13) as the fixer.
|
|
9
|
+
1. **`robots.txt` present and not blocking everything.** Missing is 🟠; present but blocking `Disallow: /` in production by mistake is 🔴. Point to `wizz-site-launch-kit` (round 13) as the fixer.
|
|
10
10
|
2. **Sitemap present and referenced in `robots.txt`.** Missing is 🟠.
|
|
11
|
-
3. **Unique title and meta description on the main public pages.** A default/repeated title (e.g., the same title on every page) is 🟠. Point to `site-launch-kit` (round 08).
|
|
12
|
-
4. **Open Graph configured.** Without `og:title`/`og:image`/`og:description`, the share preview (WhatsApp, social) comes out broken. It's 🟡, but escalates to 🟠 if the launch's main acquisition channel is social/WhatsApp. Point to `site-launch-kit` (round 09).
|
|
13
|
-
5. **Basic structured business data.** Absence isn't a standalone blocker, but if the business depends on appearing in Google local/rich snippets, it's 🟡. Point to `site-launch-kit` (round 12) or `wizz-schema-markup`.
|
|
11
|
+
3. **Unique title and meta description on the main public pages.** A default/repeated title (e.g., the same title on every page) is 🟠. Point to `wizz-site-launch-kit` (round 08).
|
|
12
|
+
4. **Open Graph configured.** Without `og:title`/`og:image`/`og:description`, the share preview (WhatsApp, social) comes out broken. It's 🟡, but escalates to 🟠 if the launch's main acquisition channel is social/WhatsApp. Point to `wizz-site-launch-kit` (round 09).
|
|
13
|
+
5. **Basic structured business data.** Absence isn't a standalone blocker, but if the business depends on appearing in Google local/rich snippets, it's 🟡. Point to `wizz-site-launch-kit` (round 12) or `wizz-schema-markup`.
|
|
14
14
|
6. **Canonical and non-duplicated indexing.** Multiple URLs serving the same content without `rel=canonical` is 🟡.
|
|
15
15
|
7. **Domain/DNS resolving to the right production environment.** A domain configured but pointing to the staging/preview environment is 🔴 (also an infra finding, see area 07; log only the discoverability part here: whether the search engine has already indexed the wrong domain).
|
|
16
16
|
|
|
@@ -6,7 +6,7 @@ Checks whether the team will be able to KNOW if the launch worked. A launch with
|
|
|
6
6
|
|
|
7
7
|
1. **Analytics tool installed and firing.** No GA4/pixel/equivalent tool loading on the public pages at all is 🔴 if the launch depends on measuring acquisition; 🟠 otherwise.
|
|
8
8
|
2. **Main conversion event configured.** The event that represents the launch's goal (signup, purchase, lead, download) not firing or not existing is 🔴.
|
|
9
|
-
3. **Thank-you/confirmation page event.** A post-conversion page with no "confirmed conversion" event (distinct from just "visited the page") is 🟠. Overlaps with `site-launch-kit` round 15 when the surface is a site.
|
|
9
|
+
3. **Thank-you/confirmation page event.** A post-conversion page with no "confirmed conversion" event (distinct from just "visited the page") is 🟠. Overlaps with `wizz-site-launch-kit` round 15 when the surface is a site.
|
|
10
10
|
4. **Trackable traffic source/UTM.** Launch campaigns without standardized UTM is 🟡: it measures what happened, but not where it came from.
|
|
11
11
|
5. **Production error monitoring (Sentry or equivalent).** A project that already uses an error tool but it's not active in the production environment is 🟠. A project that never adopted one at all is 🟡 (not a recommendation to adopt Sentry now, just logging a gap: the adoption decision belongs to the team).
|
|
12
12
|
6. **Downtime/uptime alert.** No alert configured for when the product goes down on launch day (when traffic is most sensitive) is 🟠.
|
|
@@ -1,20 +1,20 @@
|
|
|
1
1
|
# Area 05 · Content / Copy / Social Proof
|
|
2
2
|
|
|
3
|
-
Checks whether what is written and shown is REAL and ready — not whether the copy is good (that's `wizz-copywriting`/`wizz-copy-editing`). Central rule, inherited from `site-launch-kit`: no invented business data passes as compliant. Whatever is missing becomes a PENDING ITEM, never a guess filled in by estimation.
|
|
3
|
+
Checks whether what is written and shown is REAL and ready — not whether the copy is good (that's `wizz-copywriting`/`wizz-copy-editing`). Central rule, inherited from `wizz-site-launch-kit`: no invented business data passes as compliant. Whatever is missing becomes a PENDING ITEM, never a guess filled in by estimation.
|
|
4
4
|
|
|
5
5
|
## Objective checks
|
|
6
6
|
|
|
7
7
|
1. **Placeholder text in production.** `Lorem ipsum`, `TODO`, `[insert here]`, `{{LIKE THIS}}`, or any visible marker on a page/screen that's going live is 🔴.
|
|
8
|
-
2. **Real social proof.** A testimonial, rating, or client logo without a verifiable source (a generic name like "Satisfied customer", a rating with no origin, a company logo that isn't actually a client) is 🔴: fake social proof is a reputational and sometimes legal risk. Point to `site-launch-kit` (round 04) when the surface is a site.
|
|
8
|
+
2. **Real social proof.** A testimonial, rating, or client logo without a verifiable source (a generic name like "Satisfied customer", a rating with no origin, a company logo that isn't actually a client) is 🔴: fake social proof is a reputational and sometimes legal risk. Point to `wizz-site-launch-kit` (round 04) when the surface is a site.
|
|
9
9
|
3. **Current price, timeline, contact info.** A price/plan/phone/email/hours that diverges from what the business actually does is 🔴. Don't validate this "by estimate": if you have no way to confirm the real data, mark it PENDING and ask — never accept what's already written as correct by default.
|
|
10
|
-
4. **Real image vs. generic stock.** A generic stock photo in a context that should be authentic (team, product, location) is 🟡, escalating to 🟠 if the sector depends on visual trust (health, in-person service, financial). Point to `site-launch-kit` (round 06).
|
|
10
|
+
4. **Real image vs. generic stock.** A generic stock photo in a context that should be authentic (team, product, location) is 🟡, escalating to 🟠 if the sector depends on visual trust (health, in-person service, financial). Point to `wizz-site-launch-kit` (round 06).
|
|
11
11
|
5. **Product/brand name consistency.** The product name spelled differently across pages (e.g., "MeJu" vs. "Me Ju" vs. "meju") is 🟡.
|
|
12
|
-
6. **Main CTA and message present and clear.** No main CTA above the fold on the landing page is 🔴 when the launch's goal depends on direct conversion. Point to `site-launch-kit` (round 01).
|
|
13
|
-
7. **FAQ or objection-handling content ready for expected volume.** No FAQ when the product has a known recurring objection is 🟡. Point to `site-launch-kit` (round 05) or `wizz-copywriting`.
|
|
12
|
+
6. **Main CTA and message present and clear.** No main CTA above the fold on the landing page is 🔴 when the launch's goal depends on direct conversion. Point to `wizz-site-launch-kit` (round 01).
|
|
13
|
+
7. **FAQ or objection-handling content ready for expected volume.** No FAQ when the product has a known recurring objection is 🟡. Point to `wizz-site-launch-kit` (round 05) or `wizz-copywriting`.
|
|
14
14
|
|
|
15
15
|
## Cutoff rule
|
|
16
16
|
|
|
17
|
-
Never fill in missing business data "to unblock the diagnosis". If it can't be confirmed (price, testimonial, address, timeline), the item becomes PENDING with "who to get it from / how to get it", same as `site-launch-kit`. Marking 🟢 without checking the real content is worse than marking PENDING.
|
|
17
|
+
Never fill in missing business data "to unblock the diagnosis". If it can't be confirmed (price, testimonial, address, timeline), the item becomes PENDING with "who to get it from / how to get it", same as `wizz-site-launch-kit`. Marking 🟢 without checking the real content is worse than marking PENDING.
|
|
18
18
|
|
|
19
19
|
## Output format
|
|
20
20
|
|
|
@@ -4,7 +4,7 @@ Checks basic legal exposure before launch. This isn't a legal opinion (that requ
|
|
|
4
4
|
|
|
5
5
|
## Objective checks
|
|
6
6
|
|
|
7
|
-
1. **Privacy policy exists and is accessible.** Total absence, in a product that collects personal data (signup, form, analytics cookie), is 🔴. Point to `site-launch-kit` (round 14) when the surface is a site.
|
|
7
|
+
1. **Privacy policy exists and is accessible.** Total absence, in a product that collects personal data (signup, form, analytics cookie), is 🔴. Point to `wizz-site-launch-kit` (round 14) when the surface is a site.
|
|
8
8
|
2. **Privacy policy matches what the product actually does.** A generic copied document that doesn't reflect the real app (e.g., mentions data that isn't collected, or omits data that is) is 🔴: an incorrect policy is worse than none, because it creates a false legal commitment. Read the content, don't just confirm the file exists.
|
|
9
9
|
3. **Terms of use present when there's a transaction or user account.** Absence is 🟠.
|
|
10
10
|
4. **Cookie/tracking consent implemented when there's a non-essential cookie.** Analytics/pixel firing with no cookie notice at all is 🟠.
|
|
@@ -7,7 +7,7 @@ Takes the 7 tables from the areas (01 to 07) and merges them into a single diagn
|
|
|
7
7
|
1. **Paste the 7 tables** (or whichever ran, if any was marked `ITEM DOES NOT APPLY`).
|
|
8
8
|
2. **Dedup by cross-origin.** The same problem can show up in two areas (e.g., a domain pointing to the wrong environment appears in area 03 and area 07). Keep a single row, citing both source areas.
|
|
9
9
|
3. **Sort by severity first** (🔴 at the top, 🟢 at the bottom), and within the same severity, by estimated fix effort (lowest effort first): resolve first whatever is closest to go-live.
|
|
10
|
-
4. **Group by fix owner.** Several 🔴 findings going to the same owner (e.g., 3 findings for `site-launch-kit`) form a single block in the delivery, to become a single dispatch.
|
|
10
|
+
4. **Group by fix owner.** Several 🔴 findings going to the same owner (e.g., 3 findings for `wizz-site-launch-kit`) form a single block in the delivery, to become a single dispatch.
|
|
11
11
|
5. **Count pending items separately.** MANUAL VERIFICATION PENDING is not a severity: it's "can't be known yet". List it separately, with what's needed to turn it into a real verdict.
|
|
12
12
|
|
|
13
13
|
## Final table
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: wizz-offer-forge
|
|
3
|
-
description: Forges irresistible direct-response and info-product offers by integrating a unique mechanism, offer thesis, value stacking, reverse guarantee, price anchoring, and a creative matrix for paid traffic. Use when the user wants to create a new offer from scratch, restructure an existing offer that isn't converting, stack high-perception bonuses, define an aggressive guarantee, or translate audience research (Piva/VoC) into a sales machine. Do NOT use for raw audience research (use pesquisa-de-publico-do-piva) or final page copywriting (use wizz-copywriting).
|
|
3
|
+
description: Forges irresistible direct-response and info-product offers by integrating a unique mechanism, offer thesis, value stacking, reverse guarantee, price anchoring, and a creative matrix for paid traffic. Use when the user wants to create a new offer from scratch, restructure an existing offer that isn't converting, stack high-perception bonuses, define an aggressive guarantee, or translate audience research (Piva/VoC) into a sales machine. Do NOT use for raw audience research (use wizz-pesquisa-de-publico-do-piva) or final page copywriting (use wizz-copywriting).
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# Wizz Offer Forge
|
|
@@ -31,10 +31,10 @@ A master artifact `OFFER-SPEC.md` containing:
|
|
|
31
31
|
|
|
32
32
|
**Before asking anything, read what already exists.** A good offer is born from the result of the previous one, not from a blank page.
|
|
33
33
|
|
|
34
|
-
If the `cerebro` skill is installed, run `/cerebro ver` for the project and grep by theme in `_decisions/`. Look specifically for: a previous offer to the same audience, a price already tested, a guarantee already used, and any logged decision that forbids a certain path. Bring back what you found as input and state in your reply where it came from. Without the skill installed, skip this block and proceed with the questions below.
|
|
34
|
+
If the `wizz-cerebro` skill is installed, run `/wizz-cerebro ver` for the project and grep by theme in `_decisions/`. Look specifically for: a previous offer to the same audience, a price already tested, a guarantee already used, and any logged decision that forbids a certain path. Bring back what you found as input and state in your reply where it came from. Without the skill installed, skip this block and proceed with the questions below.
|
|
35
35
|
|
|
36
36
|
Then, consult existing context or ask the user:
|
|
37
|
-
1. **Prior Audience Research:** Is there a report from the `pesquisa-de-publico-do-piva` skill or VoC notes? If so, import it as primary input. If not, define the Avatar, Latent Pain, and initial Awareness Level.
|
|
37
|
+
1. **Prior Audience Research:** Is there a report from the `wizz-pesquisa-de-publico-do-piva` skill or VoC notes? If so, import it as primary input. If not, define the Avatar, Latent Pain, and initial Awareness Level.
|
|
38
38
|
2. **Business Model:** Low-ticket (R$ 10 to R$ 97), Mid front-end (R$ 197 to R$ 497), or High-ticket / Mentorship (R$ 1,000 to R$ 10,000+)?
|
|
39
39
|
3. **Delivery Vehicle:** Recorded course, community, templates/tools, live mentorship, SaaS, or hybrid?
|
|
40
40
|
|
package/src/skills-lib/{pesquisa-de-publico-do-piva → wizz-pesquisa-de-publico-do-piva}/README.md
RENAMED
|
@@ -42,7 +42,7 @@ Unzip the `pesquisa-de-publico-do-piva/` folder into `~/.claude/skills/` (to use
|
|
|
42
42
|
Open a conversation, attach your offer document (`.docx`, `.pdf`, `.md` or `.txt`) and write:
|
|
43
43
|
|
|
44
44
|
```
|
|
45
|
-
/pesquisa-de-publico-do-piva
|
|
45
|
+
/wizz-pesquisa-de-publico-do-piva
|
|
46
46
|
```
|
|
47
47
|
|
|
48
48
|
Or, without the slash, anything in that spirit:
|
package/src/skills-lib/{pesquisa-de-publico-do-piva → wizz-pesquisa-de-publico-do-piva}/SKILL.md
RENAMED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
---
|
|
2
|
-
name: pesquisa-de-publico-do-piva
|
|
2
|
+
name: wizz-pesquisa-de-publico-do-piva
|
|
3
3
|
description: Generates a complete audience research arsenal for an infoproduct offer and paid traffic, from an offer document (.docx/.md/.txt/.pdf). Produces six chained reports — VoC, Schwartz Psychographic Profile, Levels of Awareness, Trend Report, Angle Matrix and Lexicon — compiled into a tab-navigable HTML dashboard. Use when the user sends an offer and asks for audience research, VoC, voice of customer, angle matrix, audience lexicon, persona pain points, or a copy arsenal for direct traffic. Do NOT use for technical research on libraries/code (use context7), broad B2B market research (use deep-research), or visual UI research (use wizz-premium-landing-ui-researcher). Methodology by @soupiva.
|
|
4
4
|
---
|
|
5
5
|
|
|
@@ -20,7 +20,7 @@ You are the **Director / entry point** — not the orchestrator (that's `wizz-ma
|
|
|
20
20
|
|
|
21
21
|
**Installation scope note:** this is the only skill in the catalog where **global** installation (`~/.claude/skills/wizz-router`) is the operationally correct default, not an exception to the "prefer local" rule (`skills-registry.yaml`, Installation Doctrine, rule 1) — its reason for existing is to route even outside a Wizz project. It stays in sync with the global `wizz-router-enforce.js` hook via `npm run sync:global`.
|
|
22
22
|
|
|
23
|
-
**Token economy:** the `rtk-rewrite.sh` hook already handles RTK automatically (don't run `rtk --version` on every routing). Before reading raw files, prefer `/cerebro ver` or a specific `grep`.
|
|
23
|
+
**Token economy:** the `rtk-rewrite.sh` hook already handles RTK automatically (don't run `rtk --version` on every routing). Before reading raw files, prefer `/wizz-cerebro ver` or a specific `grep`.
|
|
24
24
|
|
|
25
25
|
## Triage and delegation (the Director's core job)
|
|
26
26
|
|
|
@@ -72,7 +72,7 @@ This gate does NOT fire for an open-scope request. "My site is bad, sort it out"
|
|
|
72
72
|
|
|
73
73
|
**The counterpart, and this is what is left for the maestro:** a request **of open scope, which the request itself does not delimit** — "how do I improve the signup conversion rate", "the sales page gets plenty of visits and almost nobody buys", "my sales page converts badly, improve it". There the scope has to be discovered before anything is delivered, and discovering scope is the Manager's work. The deciding difference is not the size of the request, it is whether **the request already states what the delivery is**.
|
|
74
74
|
|
|
75
|
-
**And the counterpart has one exception: a single entry already delimits the scope.** If the whole outcome being asked for fits the `when:` of ONE catalogue entry, and what leaves at the end is that entry's own deliverable — a plan, a recommendation, an audit — then the scope is not open, the catalogue delimited it, and the request goes to that entry's area. "A plan to reduce churn" is `wizz-churn-prevention`; "I want ChatGPT and Perplexity to cite us" is `wizz-ai-seo`; "what to check before going live" is `site-launch-kit`. It stops being the exception the moment delivering the outcome means changing what other areas own: "improve the signup conversion rate" ends up in copy, UI and code, so it comes back to the maestro through the area clause. Ask which single entry would deliver it whole — if it takes two, the scope really is open. (Owner's decision, 2026-09-18.)
|
|
75
|
+
**And the counterpart has one exception: a single entry already delimits the scope.** If the whole outcome being asked for fits the `when:` of ONE catalogue entry, and what leaves at the end is that entry's own deliverable — a plan, a recommendation, an audit — then the scope is not open, the catalogue delimited it, and the request goes to that entry's area. "A plan to reduce churn" is `wizz-churn-prevention`; "I want ChatGPT and Perplexity to cite us" is `wizz-ai-seo`; "what to check before going live" is `wizz-site-launch-kit`. It stops being the exception the moment delivering the outcome means changing what other areas own: "improve the signup conversion rate" ends up in copy, UI and code, so it comes back to the maestro through the area clause. Ask which single entry would deliver it whole — if it takes two, the scope really is open. (Owner's decision, 2026-09-18.)
|
|
76
76
|
|
|
77
77
|
**Changing the product's code is `dev`, even when the subject is visual.** "Adjust the secondary button's colour", "fix the mobile spacing": the delivery is a commit, so it is the dev area — `designer` decides what the look should be, it does not ship the change. Ask which artifact leaves at the end: a file in the repo → dev; a decision, a spec or a piece of art → the area that owns it. **Exception: new or rebuilt screens.** When the request asks to BUILD screens in code (a new app, page, dashboard or panel, or a whole screen rebuilt in the product), the visual decision has not been made yet, so `designer` comes first and the sequence is design → dev (2 areas → maestro): the designer runs its research gate before any screen is coded. A tweak to an existing screen (a price, a label, a spacing) stays dev, and redesigning a section with no build asked for (a hero, a card) stays designer.
|
|
78
78
|
|
|
@@ -105,4 +105,4 @@ When detecting "auditoria completa / revisa tudo / 360 / análise geral", follow
|
|
|
105
105
|
|
|
106
106
|
## Memory Duty (at the end)
|
|
107
107
|
|
|
108
|
-
After non-obvious bugs, architecture decisions, gotchas, or user corrections: record them in the project's `CLAUDE.md` ("Learnings" section) and in Cerebro (`/cerebro decisao` or `/cerebro salvar`). Remind the user if relevant.
|
|
108
|
+
After non-obvious bugs, architecture decisions, gotchas, or user corrections: record them in the project's `CLAUDE.md` ("Learnings" section) and in Cerebro (`/wizz-cerebro decisao` or `/wizz-cerebro salvar`). Remind the user if relevant.
|