dsh-desktop-kit 2.2.1 → 2.7.3
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/CHANGELOG.md +86 -0
- package/README.md +114 -27
- package/client.js +3270 -32
- package/docs/AGENT-HARNESS.md +144 -0
- package/docs/ARCHITECTURE.md +38 -7
- package/docs/COMPATIBILITY.md +4 -2
- package/docs/DEVELOPMENT.md +56 -0
- package/docs/INSTALL.md +20 -11
- package/docs/LAPTOP-INSTALL.md +96 -0
- package/docs/ROADMAP-3.0.md +353 -0
- package/docs/ROADMAP.md +1 -1
- package/docs/SUBAGENTS.md +25 -0
- package/docs/TEST-0.2.2.md +5 -5
- package/docs/TEST-2.3.0.md +49 -0
- package/docs/TEST-2.7.2.md +46 -0
- package/docs/TEST-2.7.3.md +20 -0
- package/docs/TOKENS.md +2 -2
- package/docs/TROUBLESHOOTING.md +27 -0
- package/docs/UI-QA.md +28 -0
- package/docs/images/peak-toast-peak.png +0 -0
- package/docs/images/peak-toast-soon.png +0 -0
- package/docs/preview/peak-toast.html +155 -0
- package/index.js +18 -1
- package/package.json +26 -6
- package/plugins/dsh-agent-extensions/README.md +107 -0
- package/plugins/dsh-agent-extensions/client.js +157 -0
- package/plugins/dsh-agent-extensions/index.js +174 -0
- package/plugins/dsh-agent-extensions/lib/agents.js +76 -0
- package/plugins/dsh-agent-extensions/lib/api.js +53 -0
- package/plugins/dsh-agent-extensions/lib/checkpoints.js +103 -0
- package/plugins/dsh-agent-extensions/lib/commands.js +255 -0
- package/plugins/dsh-agent-extensions/lib/hooks.js +182 -0
- package/plugins/dsh-agent-extensions/lib/policy.js +84 -0
- package/plugins/dsh-agent-extensions/lib/project.js +144 -0
- package/plugins/dsh-agent-extensions/lib/scaffold.js +151 -0
- package/plugins/dsh-agent-extensions/package.json +20 -0
- package/plugins/dsh-agent-extensions/screenshots/agents-1440.png +0 -0
- package/plugins/dsh-agent-extensions/screenshots/agents-390.png +0 -0
- package/plugins/dsh-browser-qa/README.md +221 -0
- package/plugins/dsh-browser-qa/cordis.patch.yml +4 -0
- package/plugins/dsh-browser-qa/index.js +165 -0
- package/plugins/dsh-browser-qa/lib/cdp.js +224 -0
- package/plugins/dsh-browser-qa/lib/chrome.js +466 -0
- package/plugins/dsh-browser-qa/lib/pages.js +552 -0
- package/plugins/dsh-browser-qa/lib/qa.js +827 -0
- package/plugins/dsh-browser-qa/lib/ui-gate.js +256 -0
- package/plugins/dsh-browser-qa/package.json +31 -0
- package/plugins/dsh-checkpoints/README.md +22 -0
- package/plugins/dsh-checkpoints/cordis.patch.yml +3 -0
- package/plugins/dsh-checkpoints/index.js +80 -0
- package/plugins/dsh-checkpoints/lib/checkpoints.js +111 -0
- package/plugins/dsh-checkpoints/package.json +25 -0
- package/plugins/dsh-github-review/README.md +131 -0
- package/plugins/dsh-github-review/cordis.patch.yml +3 -0
- package/plugins/dsh-github-review/index.js +536 -0
- package/plugins/dsh-github-review/lib/gh.js +494 -0
- package/plugins/dsh-github-review/lib/normalize.js +662 -0
- package/plugins/dsh-github-review/package.json +28 -0
- package/plugins/dsh-guardrails/README.md +264 -0
- package/plugins/dsh-guardrails/cordis.patch.yml +5 -0
- package/plugins/dsh-guardrails/index.js +389 -0
- package/plugins/dsh-guardrails/lib/hooks.js +262 -0
- package/plugins/dsh-guardrails/lib/modes.js +77 -0
- package/plugins/dsh-guardrails/lib/policy.js +592 -0
- package/plugins/dsh-guardrails/lib/scan.js +451 -0
- package/plugins/dsh-guardrails/lib/secrets.js +274 -0
- package/plugins/dsh-guardrails/package.json +26 -0
- package/plugins/dsh-mcp-manager/README.md +78 -0
- package/plugins/dsh-mcp-manager/client.js +373 -0
- package/plugins/dsh-mcp-manager/index.js +159 -0
- package/plugins/dsh-mcp-manager/lib/api.js +250 -0
- package/plugins/dsh-mcp-manager/lib/client.js +219 -0
- package/plugins/dsh-mcp-manager/lib/config.js +217 -0
- package/plugins/dsh-mcp-manager/lib/manager.js +146 -0
- package/plugins/dsh-mcp-manager/package.json +18 -0
- package/plugins/dsh-mcp-manager/screenshots/modal-390.png +0 -0
- package/plugins/dsh-mcp-manager/screenshots/settings-1440.png +0 -0
- package/plugins/dsh-mcp-manager/screenshots/settings-390.png +0 -0
- package/plugins/dsh-memory-bridge/README.md +161 -0
- package/plugins/dsh-memory-bridge/client.js +2264 -0
- package/plugins/dsh-memory-bridge/cordis.patch.yml +5 -0
- package/plugins/dsh-memory-bridge/docs/images/conflicts.png +0 -0
- package/plugins/dsh-memory-bridge/docs/images/hero.png +0 -0
- package/plugins/dsh-memory-bridge/docs/images/settings-dark.png +0 -0
- package/plugins/dsh-memory-bridge/docs/images/settings-light.png +0 -0
- package/plugins/dsh-memory-bridge/docs/images/settings-mobile.png +0 -0
- package/plugins/dsh-memory-bridge/docs/images/setup.png +0 -0
- package/plugins/dsh-memory-bridge/icon.svg +13 -0
- package/plugins/dsh-memory-bridge/index.js +378 -0
- package/plugins/dsh-memory-bridge/lib/bridge.js +636 -0
- package/plugins/dsh-memory-bridge/lib/github.js +473 -0
- package/plugins/dsh-memory-bridge/lib/merge.js +205 -0
- package/plugins/dsh-memory-bridge/lib/portable.js +314 -0
- package/plugins/dsh-memory-bridge/lib/state.js +565 -0
- package/plugins/dsh-memory-bridge/lib/sync.js +984 -0
- package/plugins/dsh-memory-bridge/locale/en.json +6 -0
- package/plugins/dsh-memory-bridge/locale/ru.json +6 -0
- package/plugins/dsh-memory-bridge/package.json +67 -0
- package/plugins/dsh-peak-guard/README.md +16 -3
- package/plugins/dsh-peak-guard/client.js +223 -8
- package/plugins/dsh-peak-guard/package.json +1 -1
- package/plugins/dsh-plan-mode/README.md +24 -0
- package/plugins/dsh-plan-mode/cordis.patch.yml +3 -0
- package/plugins/dsh-plan-mode/index.js +103 -0
- package/plugins/dsh-plan-mode/lib/plan.js +89 -0
- package/plugins/dsh-plan-mode/package.json +18 -0
- package/plugins/dsh-profile-transfer/client.js +277 -17
- package/plugins/dsh-profile-transfer/index.js +10 -0
- package/plugins/dsh-profile-transfer/package.json +3 -1
- package/plugins/dsh-profile-transfer/transfer.js +101 -2
- package/plugins/dsh-project-memory/index.js +92 -2
- package/plugins/dsh-project-memory/package.json +1 -1
- package/plugins/dsh-repo-map/README.md +26 -0
- package/plugins/dsh-repo-map/cordis.patch.yml +3 -0
- package/plugins/dsh-repo-map/index.js +99 -0
- package/plugins/dsh-repo-map/lib/repo-map.js +170 -0
- package/plugins/dsh-repo-map/package.json +25 -0
- package/plugins/dsh-skill-autopilot/index.js +135 -11
- package/skills/delivery-gate/SKILL.md +31 -0
- package/skills/git-and-ci/SKILL.md +5 -1
- package/skills/manifest.json +31 -6
- package/skills/requirements-and-planning/SKILL.md +3 -0
- package/skills/research-first/SKILL.md +35 -0
- package/skills/research-first/references/query-patterns.md +20 -0
- package/skills/subagent-playbook/SKILL.md +36 -0
- package/skills/subagent-playbook/references/prompts.md +39 -0
- package/skills/ui-craft/SKILL.md +43 -0
- package/skills/visual-qa/SKILL.md +29 -0
- package/skills/visual-qa/references/commands.md +32 -0
- package/skills-baseline.json +219 -0
|
@@ -21,8 +21,17 @@ import path from "node:path";
|
|
|
21
21
|
export const inject = ["systemPrompt"];
|
|
22
22
|
|
|
23
23
|
const STATE_FILE = "dsh-autopilot.json";
|
|
24
|
-
const MAX_HINT_TOKENS =
|
|
24
|
+
const MAX_HINT_TOKENS = 300;
|
|
25
25
|
const SKILL_CACHE_MS = 60_000;
|
|
26
|
+
const AUTO_LOAD_MAX_BYTES = 4200;
|
|
27
|
+
const AUTO_LOAD_MAX_SKILLS = 2;
|
|
28
|
+
const PROJECT_RULES_MAX_BYTES = 2500;
|
|
29
|
+
const QUALITY_CONTRACT = [
|
|
30
|
+
"<quality-contract>",
|
|
31
|
+
"Работай как топовый агент: 1) факты, версии, цены и практики — только после web_search/web_fetch; 2) дай 2+ независимых источника, дату и ссылки; 3) для рекомендаций предложи 2–3 конкретных референса/варианта и объясни выбор; 4) UI: до правок — wow-design/ui-craft, после — browser_qa audit 390/768/1440, исправь overflow, console errors и markup (alt, labels, duplicate id, heading order), приложи скриншоты; 5) код — repo_map/checkpoint/план/тесты; 6) не заявляй «готово» без проверки; если проверить нельзя — скажи честно.",
|
|
32
|
+
"</quality-contract>",
|
|
33
|
+
].join("\n");
|
|
34
|
+
let skillMetaCache = { at: 0, map: new Map() };
|
|
26
35
|
|
|
27
36
|
/* ------------------------------------------------------------------ */
|
|
28
37
|
/* intent rules */
|
|
@@ -38,8 +47,32 @@ const RULES = [
|
|
|
38
47
|
id: "ui",
|
|
39
48
|
label: "UI/дизайн",
|
|
40
49
|
any: ["вёрстк", "верстк", "дизайн", "интерфейс", " ui ", "ux", "лендинг", "страниц", "компонент", "адаптив", "css", "tailwind", "макет", "красив", "темн", "светл", "кнопк", "форм"],
|
|
41
|
-
skills: ["wow-design", "ui-design-system"],
|
|
42
|
-
follow: { any: ["критик", "аудит", "оцен", "улучш", "передела"], skills: ["design-critique"] },
|
|
50
|
+
skills: ["wow-design", "ui-design-system", "ui-craft"],
|
|
51
|
+
follow: { any: ["критик", "аудит", "оцен", "улучш", "передела", "скриншот", "отступ", "мобил", "планшет", "overflow", "горизонт"], skills: ["design-critique", "visual-qa"] },
|
|
52
|
+
},
|
|
53
|
+
{
|
|
54
|
+
id: "quality",
|
|
55
|
+
label: "Качество UI",
|
|
56
|
+
any: ["отступ", "адаптив", "горизонт", "overflow", "скриншот", "мобил", "планшет", "поехал", "съехал", "вёрстк", "верстк"],
|
|
57
|
+
skills: ["ui-craft", "visual-qa"],
|
|
58
|
+
},
|
|
59
|
+
{
|
|
60
|
+
id: "markup",
|
|
61
|
+
label: "Разметка и доступность",
|
|
62
|
+
any: ["разметк", "html", "валид", "alt", "aria", "a11y", "доступн", "семант", "label", "заголовк"],
|
|
63
|
+
skills: ["ui-craft", "visual-qa"],
|
|
64
|
+
},
|
|
65
|
+
{
|
|
66
|
+
id: "subagents",
|
|
67
|
+
label: "Субагенты",
|
|
68
|
+
any: ["субагент", "subagent", "команда агентов", "параллельн", "ревьюер", "независимый аудит"],
|
|
69
|
+
skills: ["subagent-playbook"],
|
|
70
|
+
},
|
|
71
|
+
{
|
|
72
|
+
id: "orchestrate",
|
|
73
|
+
label: "Оркестрация",
|
|
74
|
+
any: ["весь проект", "все плагины", "комплексн", "рефакторинг", "архитектур", "оркестр", "workflow", "несколько задач", "параллельн", "релиз всего", "сложн"],
|
|
75
|
+
skills: ["subagent-playbook", "requirements-and-planning", "delivery-gate"],
|
|
43
76
|
},
|
|
44
77
|
{
|
|
45
78
|
id: "seo",
|
|
@@ -57,14 +90,15 @@ const RULES = [
|
|
|
57
90
|
{
|
|
58
91
|
id: "research",
|
|
59
92
|
label: "Актуальные факты",
|
|
60
|
-
any: ["актуал", "новост", "цена", "курс", "верси", "закон", "документац", "сравни", "найди в интернете", "последн", "сегодня", "2026", "рынок"],
|
|
61
|
-
skills: ["web-research"],
|
|
93
|
+
any: ["актуал", "новост", "цена", "курс", "верси", "закон", "документац", "сравни", "найди в интернете", "последн", "сегодня", "2026", "рынок", "лучшие практики", "best practice"],
|
|
94
|
+
skills: ["web-research", "research-first"],
|
|
62
95
|
},
|
|
63
96
|
{
|
|
64
97
|
id: "plan",
|
|
65
98
|
label: "Планирование",
|
|
66
99
|
any: ["план", "тз", "требован", "декомпоз", "оцен", "архитектур", "вариант", "исследован", "предложи", "концепц"],
|
|
67
100
|
skills: ["requirements-and-planning", "dev-workflow"],
|
|
101
|
+
follow: { any: ["субагент", "параллельн", "ревьюер"], skills: ["subagent-playbook"] },
|
|
68
102
|
},
|
|
69
103
|
{
|
|
70
104
|
id: "debug",
|
|
@@ -207,6 +241,90 @@ function loadSkillCosts() {
|
|
|
207
241
|
return map;
|
|
208
242
|
}
|
|
209
243
|
|
|
244
|
+
/**
|
|
245
|
+
* Read SKILL.md metadata + body lazily. `autoLoad: true` in frontmatter lets the
|
|
246
|
+
* autopilot inject the core instructions instead of only naming the skill.
|
|
247
|
+
*/
|
|
248
|
+
function loadSkillMeta(name) {
|
|
249
|
+
const now = Date.now();
|
|
250
|
+
if (now - skillMetaCache.at > SKILL_CACHE_MS) skillMetaCache = { at: now, map: new Map() };
|
|
251
|
+
if (skillMetaCache.map.has(name)) return skillMetaCache.map.get(name);
|
|
252
|
+
const file = path.join(dshHome(), "skills", name, "SKILL.md");
|
|
253
|
+
let meta = null;
|
|
254
|
+
try {
|
|
255
|
+
const text = fs.readFileSync(file, "utf8");
|
|
256
|
+
const match = text.match(/^---\r?\n([\s\S]*?)\r?\n---\r?\n?/u);
|
|
257
|
+
const front = match ? match[1] : "";
|
|
258
|
+
const autoLoad = /^autoLoad:\s*true\s*$/mu.test(front);
|
|
259
|
+
const body = (match ? text.slice(match[0].length) : text).trim();
|
|
260
|
+
meta = { autoLoad, body, bytes: Buffer.byteLength(body, "utf8") };
|
|
261
|
+
} catch {
|
|
262
|
+
meta = null;
|
|
263
|
+
}
|
|
264
|
+
skillMetaCache.map.set(name, meta);
|
|
265
|
+
return meta;
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
function loadAutoSkills(names) {
|
|
269
|
+
const blocks = [];
|
|
270
|
+
let used = 0;
|
|
271
|
+
for (const name of names) {
|
|
272
|
+
if (blocks.length >= AUTO_LOAD_MAX_SKILLS) break;
|
|
273
|
+
if (used >= AUTO_LOAD_MAX_BYTES) break;
|
|
274
|
+
const meta = loadSkillMeta(name);
|
|
275
|
+
if (!meta || !meta.autoLoad || meta.body.length === 0) continue;
|
|
276
|
+
const remaining = AUTO_LOAD_MAX_BYTES - used;
|
|
277
|
+
let body = meta.body;
|
|
278
|
+
if (Buffer.byteLength(body, "utf8") > remaining) {
|
|
279
|
+
body = body.slice(0, Math.max(0, remaining - 200)).trimEnd() + "\n…";
|
|
280
|
+
}
|
|
281
|
+
if (body.length === 0) continue;
|
|
282
|
+
blocks.push(`<auto-skill name="${name}">\n${body}\n</auto-skill>`);
|
|
283
|
+
used += Buffer.byteLength(body, "utf8");
|
|
284
|
+
}
|
|
285
|
+
return blocks;
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
/**
|
|
289
|
+
* Project rules: <cwd>/.dsh/rules/*.md. Rules with `always: true` or without
|
|
290
|
+
* `paths` are injected on every prompt; path-scoped rules are left for a
|
|
291
|
+
* future file-aware loader to avoid leaking irrelevant instructions.
|
|
292
|
+
*/
|
|
293
|
+
function loadProjectRules(session) {
|
|
294
|
+
const cwd = typeof session?.header?.cwd === "string" ? session.header.cwd : "";
|
|
295
|
+
if (cwd.length === 0) return "";
|
|
296
|
+
const directory = path.join(cwd, ".dsh", "rules");
|
|
297
|
+
let entries = [];
|
|
298
|
+
try {
|
|
299
|
+
entries = fs.readdirSync(directory, { withFileTypes: true }).filter((entry) => entry.isFile() && entry.name.endsWith(".md"));
|
|
300
|
+
} catch {
|
|
301
|
+
return "";
|
|
302
|
+
}
|
|
303
|
+
const blocks = [];
|
|
304
|
+
let used = 0;
|
|
305
|
+
for (const entry of entries.sort((left, right) => left.name.localeCompare(right.name))) {
|
|
306
|
+
try {
|
|
307
|
+
const text = fs.readFileSync(path.join(directory, entry.name), "utf8");
|
|
308
|
+
const front = text.match(/^---\r?\n([\s\S]*?)\r?\n---\r?\n?/u);
|
|
309
|
+
const metadata = front ? front[1] : "";
|
|
310
|
+
const hasPaths = /^paths\s*:/mu.test(metadata);
|
|
311
|
+
const always = /^always:\s*true\s*$/mu.test(metadata);
|
|
312
|
+
if (hasPaths && !always) continue;
|
|
313
|
+
const body = (front ? text.slice(front[0].length) : text).trim();
|
|
314
|
+
if (body.length === 0) continue;
|
|
315
|
+
const remaining = PROJECT_RULES_MAX_BYTES - used;
|
|
316
|
+
if (remaining <= 0) break;
|
|
317
|
+
const clipped = body.length > remaining ? `${body.slice(0, Math.max(0, remaining - 120)).trimEnd()}\n…` : body;
|
|
318
|
+
blocks.push(`### ${entry.name}\n${clipped}`);
|
|
319
|
+
used += Buffer.byteLength(clipped, "utf8");
|
|
320
|
+
} catch {
|
|
321
|
+
/* unreadable rule */
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
if (blocks.length === 0) return "";
|
|
325
|
+
return `<project-rules>\n${blocks.join("\n\n")}\n</project-rules>`;
|
|
326
|
+
}
|
|
327
|
+
|
|
210
328
|
/** The latest durable user message of a session, read from the surface tail. */
|
|
211
329
|
const lastMessageCache = new Map();
|
|
212
330
|
function latestUserMessage(session) {
|
|
@@ -287,16 +405,18 @@ export function routeMessage(rawText, available = loadSkillCosts(), maxSkills =
|
|
|
287
405
|
/* Prefer skills from the most specific (later, rarer) rules? Keep rule order:
|
|
288
406
|
* it is ordered from the most common task families to the narrow ones. */
|
|
289
407
|
const ordered = [];
|
|
408
|
+
const allNames = [];
|
|
290
409
|
const seen = new Set();
|
|
291
410
|
for (const hit of hits) {
|
|
292
411
|
for (const name of hit.names) {
|
|
293
412
|
if (seen.has(name) || !available.has(name)) continue;
|
|
294
413
|
seen.add(name);
|
|
414
|
+
allNames.push(name);
|
|
295
415
|
ordered.push({ name, tokens: available.get(name) });
|
|
296
416
|
}
|
|
297
417
|
}
|
|
298
418
|
const skills = ordered.sort((left, right) => (right.tokens || 0) - (left.tokens || 0)).slice(0, maxSkills);
|
|
299
|
-
return { intents: hits.map((hit) => hit.label), skills };
|
|
419
|
+
return { intents: hits.map((hit) => hit.label), skills, allSkills: allNames };
|
|
300
420
|
}
|
|
301
421
|
|
|
302
422
|
function renderHint(route) {
|
|
@@ -427,9 +547,12 @@ export function apply(ctx) {
|
|
|
427
547
|
const message = latestUserMessage(session);
|
|
428
548
|
if (!message) return "";
|
|
429
549
|
const route = routeMessage(message.text, loadSkillCosts(), readState().maxSkills);
|
|
430
|
-
|
|
431
|
-
const
|
|
432
|
-
|
|
550
|
+
const hint = route.skills.length > 0 ? renderHint(route) : "";
|
|
551
|
+
const autoSkills = loadAutoSkills(route.allSkills ?? []);
|
|
552
|
+
const autoBlock = autoSkills.length > 0 ? `<auto-skills>\n${autoSkills.join("\n")}\n</auto-skills>` : "";
|
|
553
|
+
const rules = loadProjectRules(session);
|
|
554
|
+
const value = [QUALITY_CONTRACT, rules, autoBlock, hint].filter((part) => part.length > 0).join("\n");
|
|
555
|
+
if (route.skills.length === 0) return value;
|
|
433
556
|
const now = Date.now();
|
|
434
557
|
lastHintAt = now;
|
|
435
558
|
lastMatches.set(String(session.id), {
|
|
@@ -437,13 +560,13 @@ export function apply(ctx) {
|
|
|
437
560
|
at: new Date(now).toISOString(),
|
|
438
561
|
intents: route.intents,
|
|
439
562
|
skills: route.skills,
|
|
440
|
-
chars:
|
|
563
|
+
chars: value.length,
|
|
441
564
|
});
|
|
442
565
|
if (lastMatches.size > 40) {
|
|
443
566
|
const oldest = [...lastMatches.entries()].sort((a, b) => a[1].at.localeCompare(b[1].at))[0];
|
|
444
567
|
if (oldest) lastMatches.delete(oldest[0]);
|
|
445
568
|
}
|
|
446
|
-
return
|
|
569
|
+
return value;
|
|
447
570
|
} catch (error) {
|
|
448
571
|
logger?.warn?.(`[skill-autopilot] route failed: ${String(error)}`);
|
|
449
572
|
return "";
|
|
@@ -459,3 +582,4 @@ export function apply(ctx) {
|
|
|
459
582
|
};
|
|
460
583
|
}, "skill-autopilot: lifecycle");
|
|
461
584
|
}
|
|
585
|
+
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: delivery-gate
|
|
3
|
+
description: "Финальный гейт перед сдачей: критерии, тесты, скриншоты, безопасность, источники, отсутствие дублей. Не отдавать результат без проверки."
|
|
4
|
+
whenToUse: "Перед финальным ответом, релизом, публикацией, PR или после крупной правки."
|
|
5
|
+
user-invocable: true
|
|
6
|
+
autoLoad: true
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# Delivery Gate — сдавать только проверенное
|
|
10
|
+
|
|
11
|
+
> ≈350 токенов. Короткий чек-лист; детали — `code-review-checklist`, `testing-strategy`, `visual-qa`.
|
|
12
|
+
|
|
13
|
+
## 1. Чек-лист
|
|
14
|
+
- [ ] Требование и критерий «готово» сформулированы до кода.
|
|
15
|
+
- [ ] `plan` согласован для крупной задачи; код не начат до approve.
|
|
16
|
+
- [ ] Тесты/проверки прошли; нет скрытых падений и «пока не проверял».
|
|
17
|
+
- [ ] UI: `browser_qa action=audit` на 1440/768/390, light/dark, нет overflow и обрезаний.
|
|
18
|
+
- [ ] `guardrails action=check` перед коммитом: секреты, `.env`, защищённые пути, `git diff --check`.
|
|
19
|
+
- [ ] Безопасность: нет секретов, публичных данных, опасных дефолтов.
|
|
20
|
+
- [ ] Нет дублей: один сценарий = одно место/один источник правды.
|
|
21
|
+
- [ ] Внешние факты — со ссылками и датами.
|
|
22
|
+
- [ ] Отчёт: что сделано, как проверено, риски, что дальше.
|
|
23
|
+
|
|
24
|
+
## 2. Красные флаги
|
|
25
|
+
- «Должно работать» без запуска; скриншот без просмотра; источник без ссылки.
|
|
26
|
+
- Два экрана делают одно и то же; новый компонент копирует старый вместо переиспользования.
|
|
27
|
+
- Фикс без регрессионного теста/проверки, миграция без бэкапа, публикация без checksum.
|
|
28
|
+
|
|
29
|
+
## 3. Формат отчёта
|
|
30
|
+
Короткий итог → проверки (команды/скриншоты) → коммиты/артефакты → ограничения → следующий шаг.
|
|
31
|
+
|
|
@@ -8,6 +8,7 @@ user-invocable: true
|
|
|
8
8
|
# Git и CI (универсально)
|
|
9
9
|
|
|
10
10
|
## 0. Когда применять
|
|
11
|
+
- В DSH для PR используй `github_review` (status/pr/checks/comments/diff); comment — только с confirm.
|
|
11
12
|
- Создаёшь репозиторий, `.gitignore`, первый коммит.
|
|
12
13
|
- Коммитишь, ветвишься, мержишь, ставишь тег.
|
|
13
14
|
- Настраиваешь/чинишь CI или pre-commit.
|
|
@@ -18,7 +19,8 @@ user-invocable: true
|
|
|
18
19
|
**Репозиторий**
|
|
19
20
|
- `.gitignore` до первого коммита: зависимости, сборки, `.env*`, runtime, IDE, дампы; lock-файлы — в git.
|
|
20
21
|
- Перед коммитом: `git status --short`, `git diff --check`, `git diff --stat`; в индекс — только осознанные файлы.
|
|
21
|
-
- Не коммитить: `vendor/`,
|
|
22
|
+
- Не коммитить: `vendor/`,
|
|
23
|
+
ode_modules/`, `public/build`, `storage/`-рантайм, дампы, PII.
|
|
22
24
|
|
|
23
25
|
**Ветки и коммиты**
|
|
24
26
|
- `main` — стабильная и защищённая; работа — в `feature/<кратко>` / `fix/<кратко>`.
|
|
@@ -58,3 +60,5 @@ CI гоняет те же команды, что локально; `main` — т
|
|
|
58
60
|
- [ ] Линтер, статанализ, тесты зелёные; для UI — E2E.
|
|
59
61
|
- [ ] Тег на проверенном коммите; CI на `main` зелёный.
|
|
60
62
|
- [ ] Секрет ротирован, история очищена.
|
|
63
|
+
|
|
64
|
+
|
package/skills/manifest.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"schema": 1,
|
|
3
|
-
"kitVersion": "2.2
|
|
4
|
-
"generatedAt": "2026-11-
|
|
3
|
+
"kitVersion": "2.7.2",
|
|
4
|
+
"generatedAt": "2026-11-10T05:35:22.614Z",
|
|
5
5
|
"skills": {
|
|
6
6
|
"code-review-checklist": {
|
|
7
7
|
"hash": "e665bf72cfbfb77948a3cd6df6ebced38777f9aff543d7b9c80b2ced8cccc662",
|
|
@@ -28,6 +28,11 @@
|
|
|
28
28
|
"files": 1,
|
|
29
29
|
"bytes": 4443
|
|
30
30
|
},
|
|
31
|
+
"delivery-gate": {
|
|
32
|
+
"hash": "7b76909a8d5ce099d03813533a1f935aef62d8fe11e63080961c38fd9835e47f",
|
|
33
|
+
"files": 1,
|
|
34
|
+
"bytes": 2409
|
|
35
|
+
},
|
|
31
36
|
"design-critique": {
|
|
32
37
|
"hash": "bbc6ca34b0b76798d581dcd78e83a59040dfac028b5e10d8e7a9be28225410b8",
|
|
33
38
|
"files": 6,
|
|
@@ -39,9 +44,9 @@
|
|
|
39
44
|
"bytes": 17194
|
|
40
45
|
},
|
|
41
46
|
"git-and-ci": {
|
|
42
|
-
"hash": "
|
|
47
|
+
"hash": "a2dc59c5920190bbc715a4a523f3a1592e1914e6d06385ec07341fb76897a6b6",
|
|
43
48
|
"files": 1,
|
|
44
|
-
"bytes":
|
|
49
|
+
"bytes": 4318
|
|
45
50
|
},
|
|
46
51
|
"pg-upgrade-verify": {
|
|
47
52
|
"hash": "d734178c5dad317fc55842215bbeeba85230cdd8e7b0ea46d74eed92910b8dea",
|
|
@@ -64,9 +69,14 @@
|
|
|
64
69
|
"bytes": 4409
|
|
65
70
|
},
|
|
66
71
|
"requirements-and-planning": {
|
|
67
|
-
"hash": "
|
|
72
|
+
"hash": "16f3235a9dcdcd1858112806854ef03d76f77588b56434bbacab803bd204f005",
|
|
68
73
|
"files": 4,
|
|
69
|
-
"bytes":
|
|
74
|
+
"bytes": 13078
|
|
75
|
+
},
|
|
76
|
+
"research-first": {
|
|
77
|
+
"hash": "3a18814f9817a6843962c1c5bdd7c5c0bc535cf864a5039d5e3ac359990579a4",
|
|
78
|
+
"files": 2,
|
|
79
|
+
"bytes": 4273
|
|
70
80
|
},
|
|
71
81
|
"security-review": {
|
|
72
82
|
"hash": "8665b2c469de8e83aca670021d5c335fa8c9b93b8dc6bb866759e6062b1abde4",
|
|
@@ -108,16 +118,31 @@
|
|
|
108
118
|
"files": 3,
|
|
109
119
|
"bytes": 13888
|
|
110
120
|
},
|
|
121
|
+
"subagent-playbook": {
|
|
122
|
+
"hash": "72d10995462d43891e7ec2d028caa0ccbca7932875410d4a0d6cfa75c5fe2df9",
|
|
123
|
+
"files": 2,
|
|
124
|
+
"bytes": 5375
|
|
125
|
+
},
|
|
111
126
|
"testing-strategy": {
|
|
112
127
|
"hash": "773fdf1e389e59841b7766862f8890a11fba4a2fce42a2022b9c4bfaae8f6ecc",
|
|
113
128
|
"files": 1,
|
|
114
129
|
"bytes": 4279
|
|
115
130
|
},
|
|
131
|
+
"ui-craft": {
|
|
132
|
+
"hash": "0fbca80ca2ca434828b3238ecd901fce54b5dc306456cb81a4ed52f7a95921c5",
|
|
133
|
+
"files": 1,
|
|
134
|
+
"bytes": 3387
|
|
135
|
+
},
|
|
116
136
|
"ui-design-system": {
|
|
117
137
|
"hash": "19244221171995b758dbad02f2e3602859308370b50cc37d93c6f2a6d44cd6f1",
|
|
118
138
|
"files": 4,
|
|
119
139
|
"bytes": 19454
|
|
120
140
|
},
|
|
141
|
+
"visual-qa": {
|
|
142
|
+
"hash": "97ff6c9c02bbab4bb38c8591a39792f4f51c45bfe278dd7ea839d6cad27c7cf9",
|
|
143
|
+
"files": 2,
|
|
144
|
+
"bytes": 4118
|
|
145
|
+
},
|
|
121
146
|
"web-research": {
|
|
122
147
|
"hash": "9bf4d8ba6d2a0fc39c241cdd9f5fe54835af28872473aa617941589c526387c8",
|
|
123
148
|
"files": 3,
|
|
@@ -9,6 +9,7 @@ user-invocable: true
|
|
|
9
9
|
> ≈1 600 токенов. Это ядро; детали — по ссылкам и только когда реально нужны.
|
|
10
10
|
|
|
11
11
|
## 0. Когда применять
|
|
12
|
+
- В DSH крупную задачу веди через `plan` (`.dsh/PLAN.md`): draft → approve → код.
|
|
12
13
|
- Новая задача: фича, страница, релиз, миграция — до первой правки.
|
|
13
14
|
- Запрос расплывчат: «сделай красиво», «ускорь», «почини», «улучши как-то».
|
|
14
15
|
- Нужны ТЗ, оценка, сравнение вариантов, критерии «готово»; результат — выводы и план, а не осмотр.
|
|
@@ -47,3 +48,5 @@ user-invocable: true
|
|
|
47
48
|
- [ ] План с проверками и откатом выполнен; scope не расширен молча, «потом» вынесено.
|
|
48
49
|
- [ ] Подобраны скиллы (`skills-router`), пройдены их гейты: тесты/скриншоты/SEO/бэкап.
|
|
49
50
|
- [ ] Отчёт «сделано / как проверено / риски / дальше»; память и версия обновлены.
|
|
51
|
+
|
|
52
|
+
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: research-first
|
|
3
|
+
description: "Перед задачей проверить интернет, собрать факты и лучшие практики, сравнить 2–3 варианта и только потом делать. Ссылки, даты, источник — обязательны."
|
|
4
|
+
whenToUse: "Почти любая задача, где есть версии, API, цены, законы, конкуренты, дизайн-референсы, «как правильно», «лучшие практики», новые технологии или риск устаревших знаний."
|
|
5
|
+
user-invocable: true
|
|
6
|
+
autoLoad: true
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# Research-first — сначала факты и варианты, потом код
|
|
10
|
+
|
|
11
|
+
> ≈600 токенов. Ядро; глубина — по `references/`.
|
|
12
|
+
|
|
13
|
+
## 1. Когда поиск обязателен (по умолчанию — почти всегда)
|
|
14
|
+
- Версии, API, библиотеки, плагины, цены, тарифы, законы, даты, релизы.
|
|
15
|
+
- «Лучшие практики», архитектура, дизайн, UX, безопасность, релиз.
|
|
16
|
+
- Есть риск, что знания модели устарели или это спорный факт.
|
|
17
|
+
- Не ищи только если задача чисто локальная и проверяемая кодом/файлом.
|
|
18
|
+
|
|
19
|
+
## 2. Протокол (до реализации)
|
|
20
|
+
1. **2–4 запроса**: русский + английский, официальные термины, `site:` для docs.
|
|
21
|
+
2. **2–3 независимых источника**, приоритет: официальная документация → первоисточник/paper → крупный инженерный блог. Маркетинг — только как мнение.
|
|
22
|
+
3. **Открой ключевые страницы** (`web_fetch`), не ограничивайся сниппетами.
|
|
23
|
+
4. Зафиксируй: дата поиска, версия/дата источника, расхождения.
|
|
24
|
+
5. Сделай **матрицу вариантов**: 2–3 подхода, плюсы, минусы, риски, стоимость, рекомендация. Для мелкой задачи — 3 строки, не эссе.
|
|
25
|
+
6. Только после этого — план и код. Ссылки — в ответе и в отчёте.
|
|
26
|
+
|
|
27
|
+
## 3. Проверка качества
|
|
28
|
+
- Нет ссылки — нет утверждения о внешнем факте.
|
|
29
|
+
- Не выдавай пересказ за первоисточник; платный/закрытый источник помечай.
|
|
30
|
+
- Не используй данные старше ~12 месяцев без пометки (кроме исторических).
|
|
31
|
+
- Если поиск не дал ответа — скажи прямо и предложи, что уточнить.
|
|
32
|
+
|
|
33
|
+
## 4. Выход
|
|
34
|
+
Короткий вывод (1–3 предложения) → факты с датами → матрица вариантов → рекомендация → источники.
|
|
35
|
+
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# Query patterns
|
|
2
|
+
|
|
3
|
+
## Свежесть
|
|
4
|
+
- Версии/API: `site:docs.<project> <api> <year>`, `release notes <project>`
|
|
5
|
+
- Цены/тарифы: `<vendor> pricing <year>`, официальная страница
|
|
6
|
+
- Законы: `site:gov.ru <тема>`, официальный документ
|
|
7
|
+
- Дизайн: `site:dribbble.com <pattern>`, `site:mobbin.com <pattern>`, `site:linear.app changelog`
|
|
8
|
+
|
|
9
|
+
## Источники
|
|
10
|
+
1. Официальная документация / спецификация / changelog.
|
|
11
|
+
2. Первоисточник (paper, RFC, закон, датасет).
|
|
12
|
+
3. Инженерный блог/конференция с деталями реализации.
|
|
13
|
+
4. Маркетинг/обзор — только как мнение, не как факт.
|
|
14
|
+
|
|
15
|
+
## Матрица вариантов
|
|
16
|
+
| Вариант | Плюсы | Минусы | Риск | Стоимость | Рекомендация |
|
|
17
|
+
|---|---|---|---|---|---|
|
|
18
|
+
|
|
19
|
+
## Пометки
|
|
20
|
+
Актуально на: YYYY-MM-DD. Источник: URL (дата публикации). Если данные устарели — скажи явно.
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: subagent-playbook
|
|
3
|
+
description: "Когда и как привлекать субагентов: research-scout, ui-critic, responsive-qa, release-auditor, code-reviewer. Готовые промпты и разделение ролей."
|
|
4
|
+
whenToUse: "Сложная задача, много файлов, нужен независимый аудит/ресёрч/визуальная критика/релизная проверка, или параллельная работа без общего контекста."
|
|
5
|
+
user-invocable: true
|
|
6
|
+
autoLoad: true
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# Subagent Playbook — роли, которые усиливают
|
|
10
|
+
|
|
11
|
+
> ≈550 токенов. Промпты — `references/prompts.md`.
|
|
12
|
+
|
|
13
|
+
## 1. Когда spawn
|
|
14
|
+
- Задача > ~1 часа или затрагивает несколько областей (дизайн + код + релиз).
|
|
15
|
+
- Нужен свежий взгляд: критика UI, security/release аудит, независимый факт-чек.
|
|
16
|
+
- Исследование, которое не должно съедать основной контекст.
|
|
17
|
+
- Если независимых потоков ≥3 — сначала план, затем `workflow`; 1–2 роли — обычный `subagent`.
|
|
18
|
+
- Не spawn ради количества: 1–2 роли на задачу, с чётким deliverable.
|
|
19
|
+
|
|
20
|
+
## 2. Роли
|
|
21
|
+
| Роль | Что делает | Выход |
|
|
22
|
+
|---|---|---|
|
|
23
|
+
| **research-scout** | 2–4 запроса, официальные источники, даты, варианты | матрица + ссылки |
|
|
24
|
+
| **ui-critic** | скриншоты 1440/768/390, иерархия, отступы, состояния | 5–7 приоритетных правок |
|
|
25
|
+
| **responsive-qa** | overflow, переносы, тач-цели, safe-area | список багов + доказательства |
|
|
26
|
+
| **release-auditor** | тесты, версии, changelog, security, откат | go/no-go |
|
|
27
|
+
| **code-reviewer** | диффы, риски, тесты, совместимость | блокеры/ниты |
|
|
28
|
+
|
|
29
|
+
## 3. Как формулировать
|
|
30
|
+
- Дай контекст, файлы/URL, ограничения, формат результата и критерий «готово».
|
|
31
|
+
- Запрети менять чужие файлы, если роль только читает.
|
|
32
|
+
- Проси ссылки/скриншоты/логи, а не мнение без доказательств.
|
|
33
|
+
- Результаты своди в решение сам: субагент советует, Lead отвечает за итог.
|
|
34
|
+
|
|
35
|
+
## 4. Параллельность
|
|
36
|
+
Независимые роли (research + UI review) запускай одним сообщением; зависимости — через `wait_agent`/задачи. Не дублируй одну и ту же работу двумя ролями.
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
# Subagent prompt templates
|
|
2
|
+
|
|
3
|
+
## research-scout
|
|
4
|
+
```
|
|
5
|
+
Ты research-scout. Собери актуальные факты по теме: <тема>.
|
|
6
|
+
Сделай 2–4 запроса (RU/EN), приоритет официальной документации и первоисточникам.
|
|
7
|
+
Сверь ≥2 независимых источника. Для каждого факта: утверждение, источник (URL), дата,
|
|
8
|
+
расхождение/ограничение. В конце — матрица 2–3 вариантов решения (плюсы/минусы/риски) и
|
|
9
|
+
рекомендация. Не пиши код и не меняй файлы. Верни только выжимку + ссылки.
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
## ui-critic
|
|
13
|
+
```
|
|
14
|
+
Ты ui-critic. Оцени интерфейс по скриншотам <пути/URL> на 1440/768/390.
|
|
15
|
+
Критерии: иерархия, сетка 4/8, отступы, типографика, состояния, контраст, дубли,
|
|
16
|
+
горизонтальный скролл, обрезания. Дай 5–7 приоритетных правок с «до/после» и
|
|
17
|
+
ссылками на конкретные элементы. Не меняй файлы. Верни список и вердикт go/no-go.
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
## responsive-qa
|
|
21
|
+
```
|
|
22
|
+
Ты responsive-qa. Проверь <URL/HTML> на 390/768/1440: scrollWidth vs clientWidth,
|
|
23
|
+
overflow-элементы, переносы длинных путей, тач-цели, safe-area, модалки/тосты.
|
|
24
|
+
Приложи измерения и скриншоты проблем. Не меняй файлы. Верни баги по приоритету.
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
## release-auditor
|
|
28
|
+
```
|
|
29
|
+
Ты release-auditor. Проверь готовность релиза <версия/репозиторий>: тесты, CI, package,
|
|
30
|
+
security (gitleaks/audit), миграции, откат, checksums, changelog. Верни go/no-go,
|
|
31
|
+
блокеры и точные команды для исправления. Файлы не меняй.
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
## code-reviewer
|
|
35
|
+
```
|
|
36
|
+
Ты code-reviewer. Проверь диффы/файлы <список>. Ищи баги, регрессии, безопасность,
|
|
37
|
+
производительность, несовместимость API, отсутствие тестов. Дай только конкретные
|
|
38
|
+
замечания с файлом/строкой и severity. Не переписывай код без просьбы.
|
|
39
|
+
```
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: ui-craft
|
|
3
|
+
description: "Инженерная дисциплина UI: сетка и шкала отступов 4/8, типографика, состояния, адаптив 1440/768/390, отсутствие случайных сдвигов и дублей. Использовать при любой вёрстке и правке стилей."
|
|
4
|
+
whenToUse: "Вёрстка, стили, карточки, формы, адаптив, исправление «поехавших» отступов, полировка интерфейса, дизайн-апгрейд."
|
|
5
|
+
user-invocable: true
|
|
6
|
+
autoLoad: true
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# UI Craft — аккуратная геометрия и адаптив
|
|
10
|
+
|
|
11
|
+
> ≈750 токенов. Дополняет `wow-design` и `ui-design-system`, не дублирует их.
|
|
12
|
+
|
|
13
|
+
## 1. Сетка и отступы (жёстко)
|
|
14
|
+
- Одна шкала: **4 / 8 / 12 / 16 / 24 / 32 / 48**. Никаких 7, 13, 23 px «на глаз».
|
|
15
|
+
- Внешние отступы карточки = внутренние + 4/8; одинаковые интервалы по вертикали.
|
|
16
|
+
- Заголовок → описание: 4–6 px; описание → контрол: 12–16; контролы между собой: 8–12.
|
|
17
|
+
- Один контейнер = один max-width; текст не прилипает к краям (мин. 16–20 px).
|
|
18
|
+
- Не выравнивай «по центру» то, что должно быть по базовой линии; проверяй по левому краю.
|
|
19
|
+
|
|
20
|
+
## 2. Типографика
|
|
21
|
+
- 2–3 размера текста + иерархия заголовков; line-height 1.35–1.55.
|
|
22
|
+
- Числа и таймеры — `font-variant-numeric: tabular-nums`.
|
|
23
|
+
- Не более 70–75 символов в строке; длинные пути/имена — `word-break` и `min-width:0`.
|
|
24
|
+
|
|
25
|
+
## 3. Адаптив
|
|
26
|
+
- Проверяй **1440, 768, 390** и промежуточные 560/640.
|
|
27
|
+
- Вертикальный скролл допустим; **горизонтального быть не должно**.
|
|
28
|
+
- Flex/grid: `min-width:0`, `flex-wrap`, `minmax(0,1fr)`, без фиксированных ширин больше контейнера.
|
|
29
|
+
- Таблицы и пары ключ–значение на мобиле — в колонку, а не в обрез.
|
|
30
|
+
- Тач-цели ≥ 40–44 px; отступы у краёв с `env(safe-area-inset-*)`.
|
|
31
|
+
- Модалки/тосты: `max-height`, внутренний скролл, не перекрывают композер.
|
|
32
|
+
|
|
33
|
+
## 4. Состояния и дубли
|
|
34
|
+
- default / hover / focus-visible / active / disabled / loading / empty / error.
|
|
35
|
+
- Фокус видимый, не только цветом; `prefers-reduced-motion`.
|
|
36
|
+
- Одна мысль — один компонент. Если два экрана делают одно и то же, разведи роли или удали дубль.
|
|
37
|
+
|
|
38
|
+
## 5. Гейт сдачи
|
|
39
|
+
1. Снять скриншоты 1440/768/390 (light/dark, если тема есть).
|
|
40
|
+
2. Проверить `scrollWidth <= clientWidth` и отсутствие обрезанных текстов.
|
|
41
|
+
3. Свериться с референсами из `wow-design`, но не копировать вслепую.
|
|
42
|
+
4. Только после этого отдавать результат; см. `visual-qa`.
|
|
43
|
+
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: visual-qa
|
|
3
|
+
description: "Скриншот-проверка интерфейса: 1440/768/390, light/dark, поиск горизонтального скролла, обрезанных текстов и сдвигов; сравнение до/после."
|
|
4
|
+
whenToUse: "После любой правки UI, перед сдачей или релизом; при жалобах на отступы, адаптив, скролл, «поехало»."
|
|
5
|
+
user-invocable: true
|
|
6
|
+
autoLoad: true
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# Visual QA — снимки и объективная проверка
|
|
10
|
+
|
|
11
|
+
> ≈500 токенов. Команды и шаблоны — `references/commands.md`.
|
|
12
|
+
|
|
13
|
+
## 1. Что проверяем
|
|
14
|
+
- **Горизонтальный скролл:** `document.documentElement.scrollWidth <= clientWidth` на 390/768/1440.
|
|
15
|
+
- **Обрезания:** текст не выходит за карточку; кнопки не наезжают; длинные пути/числа переносятся.
|
|
16
|
+
- **Ритм:** одинаковые отступы, выравнивание по сетке, нет «прыжков» между секциями.
|
|
17
|
+
- **Контраст:** текст ≥ 4.5:1, крупный ≥ 3:1; фокус видим.
|
|
18
|
+
- **Состояния:** loading/empty/error/disabled, тёмная тема, reduced-motion.
|
|
19
|
+
|
|
20
|
+
## 2. Как снимать
|
|
21
|
+
1. В DSH сначала инструмент `browser_qa action=audit url=... widths=[390,768,1440] outDir=...` — он сам даёт PNG, overflow и console errors.
|
|
22
|
+
2. Живой DSH (если есть авторизованный URL) или preview-harness с реальным клиентским кодом.
|
|
23
|
+
3. Смотреть каждый PNG глазами; сомнительные — увеличить/переснять. Для API-страниц без авторизации используй preview.
|
|
24
|
+
4. Для overflow — доверяй `browser_qa`, а не угадыванию; при необходимости CDP-замер.
|
|
25
|
+
5. После правок — повторный снимок и сравнение «до/после».
|
|
26
|
+
|
|
27
|
+
## 3. Гейт
|
|
28
|
+
Не отдавать UI без: 3 ширин, отсутствия горизонтального скролла, проверенных текстов и фокуса. Если снять нельзя — честно сказать и запросить скриншот пользователя.
|
|
29
|
+
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
# Visual QA commands
|
|
2
|
+
|
|
3
|
+
## Скриншоты Chrome (Windows)
|
|
4
|
+
```powershell
|
|
5
|
+
$chrome = "C:\Program Files\Google\Chrome\Application\chrome.exe"
|
|
6
|
+
& $chrome --headless=new --disable-gpu --hide-scrollbars `
|
|
7
|
+
--window-size=1440,900 --virtual-time-budget=1500 `
|
|
8
|
+
--screenshot="$env:TEMP\ui-1440.png" "file:///C:/path/preview.html"
|
|
9
|
+
```
|
|
10
|
+
Повтори для 768×1024 и 390×844. Для локального файла с кириллицей скопируй HTML в `%TEMP%` с ASCII-именем.
|
|
11
|
+
|
|
12
|
+
## Overflow через DevTools/CDP
|
|
13
|
+
```js
|
|
14
|
+
({
|
|
15
|
+
scrollWidth: document.documentElement.scrollWidth,
|
|
16
|
+
clientWidth: document.documentElement.clientWidth,
|
|
17
|
+
overflow: document.documentElement.scrollWidth > document.documentElement.clientWidth,
|
|
18
|
+
});
|
|
19
|
+
```
|
|
20
|
+
Также проверь:
|
|
21
|
+
```js
|
|
22
|
+
[...document.querySelectorAll("*")].filter(el => el.scrollWidth > el.clientWidth + 1 && getComputedStyle(el).overflowX === "visible")
|
|
23
|
+
```
|
|
24
|
+
— исключи намеренные скролл-контейнеры.
|
|
25
|
+
|
|
26
|
+
## Preview-harness
|
|
27
|
+
- `dsh-memory-bridge/docs/preview/capture.mjs` — реальные клиентские компоненты, точные viewport, overflow-флаг.
|
|
28
|
+
- `dsh-desktop-kit/tools/peak-toast-preview.mjs` — пример статического превью из настоящего CSS.
|
|
29
|
+
- Всегда открывай итоговый PNG глазами; цифры не заменяют взгляд.
|
|
30
|
+
|
|
31
|
+
## Приёмка
|
|
32
|
+
1440×900, 768×1024, 390×844 · light/dark (если есть) · нет горизонтального скролла · нет обрезанных строк/кнопок · фокус видим · длинные пути переносятся.
|