@dzhechkov/keysarium 1.4.0 → 1.5.1

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.
Files changed (80) hide show
  1. package/README.md +52 -5
  2. package/README.ru.md +541 -0
  3. package/bin/cli.js +0 -0
  4. package/package.json +11 -9
  5. package/templates/.claude/commands/analyst-manual.md +38 -0
  6. package/templates/.claude/commands/casarium.md +55 -4
  7. package/templates/.claude/commands/feature-adr.md +8 -0
  8. package/templates/.claude/rules/trust-tiers.md +5 -0
  9. package/templates/.claude/shards/feature-adr.shard.md +64 -10
  10. package/templates/.claude/shards/phase-ai-factory.shard.md +109 -0
  11. package/templates/.claude/skills/ai-factory-mapper/README.md +90 -0
  12. package/templates/.claude/skills/ai-factory-mapper/SKILL.md +309 -0
  13. package/templates/.claude/skills/ai-factory-mapper/assets/report-template.md +123 -0
  14. package/templates/.claude/skills/ai-factory-mapper/references/catalog.md +230 -0
  15. package/templates/.claude/skills/ai-factory-mapper/references/coverage-formula.md +219 -0
  16. package/templates/.claude/skills/ai-factory-mapper/references/decomposition-checklist.md +183 -0
  17. package/templates/.claude/skills/ai-factory-mapper/references/pattern-library.md +312 -0
  18. package/templates/.claude/skills/ai-factory-mapper/scripts/build_docx_report.js +423 -0
  19. package/templates/.claude/skills/analyst-manual-full/SKILL.md +286 -0
  20. package/templates/.claude/skills/edu-site-generator/SKILL.md +254 -0
  21. package/templates/.claude/skills/edu-site-generator/examples/sample-course-structure.md +116 -0
  22. package/templates/.claude/skills/edu-site-generator/modules/00-content-analysis.md +84 -0
  23. package/templates/.claude/skills/edu-site-generator/modules/01-course-structure.md +75 -0
  24. package/templates/.claude/skills/edu-site-generator/modules/02-data-generation.md +186 -0
  25. package/templates/.claude/skills/edu-site-generator/modules/03-scaffold.md +249 -0
  26. package/templates/.claude/skills/edu-site-generator/modules/04-components.md +130 -0
  27. package/templates/.claude/skills/edu-site-generator/modules/05-gamification.md +163 -0
  28. package/templates/.claude/skills/edu-site-generator/modules/06-deploy.md +88 -0
  29. package/templates/.claude/skills/edu-site-generator/modules/07-verification.md +97 -0
  30. package/templates/.claude/skills/edu-site-generator/references/component-templates.md +436 -0
  31. package/templates/.claude/skills/edu-site-generator/references/data-schemas.md +164 -0
  32. package/templates/.claude/skills/edu-site-generator/references/exercise-catalog.md +110 -0
  33. package/templates/.claude/skills/edu-site-generator/references/tech-stack.md +69 -0
  34. package/templates/.claude/skills/feature-adr/SKILL.md +245 -59
  35. package/templates/.claude/skills/feature-adr/modules/03-adr.md +43 -0
  36. package/templates/.claude/skills/feature-adr/modules/03.5-ideation-swarm.md +180 -0
  37. package/templates/.claude/skills/feature-adr/modules/06-implementation-plan.md +56 -7
  38. package/templates/.claude/skills/feature-adr/modules/08-qe.md +87 -23
  39. package/templates/.claude/skills/feature-adr/modules/09-fleet-qe.md +305 -0
  40. package/templates/.claude/skills/feature-adr/references/agentic-qe/README.md +143 -0
  41. package/templates/.claude/skills/feature-adr/references/agentic-qe/brutal-honesty-review.md +240 -0
  42. package/templates/.claude/skills/feature-adr/references/agentic-qe/chaos-engineering-resilience.md +163 -0
  43. package/templates/.claude/skills/feature-adr/references/agentic-qe/code-goal-planner.md +446 -0
  44. package/templates/.claude/skills/feature-adr/references/agentic-qe/enterprise-integration-testing.md +111 -0
  45. package/templates/.claude/skills/feature-adr/references/agentic-qe/mutation-testing.md +236 -0
  46. package/templates/.claude/skills/feature-adr/references/agentic-qe/performance-testing.md +315 -0
  47. package/templates/.claude/skills/feature-adr/references/agentic-qe/qcsd-ideation-swarm.md +126 -0
  48. package/templates/.claude/skills/feature-adr/references/agentic-qe/qcsd-production-swarm.md +108 -0
  49. package/templates/.claude/skills/feature-adr/references/agentic-qe/qe-coverage-analysis.md +193 -0
  50. package/templates/.claude/skills/feature-adr/references/agentic-qe/qe-requirements-validation.md +254 -0
  51. package/templates/.claude/skills/feature-adr/references/agentic-qe/regression-testing.md +233 -0
  52. package/templates/.claude/skills/feature-adr/references/agentic-qe/risk-based-testing.md +212 -0
  53. package/templates/.claude/skills/feature-adr/references/agentic-qe/security-testing.md +311 -0
  54. package/templates/.claude/skills/feature-adr/references/agentic-qe/shift-left-testing.md +231 -0
  55. package/templates/.claude/skills/feature-adr/references/agentic-qe/tdd-london-chicago.md +249 -0
  56. package/templates/.claude/skills/transcript-site-generator/SKILL.md +287 -0
  57. package/templates/.claude/skills/transcript-site-generator/examples/sample-text-only-site.md +123 -0
  58. package/templates/.claude/skills/transcript-site-generator/examples/sample-transcript-site.md +134 -0
  59. package/templates/.claude/skills/transcript-site-generator/modules/00-input-analysis.md +132 -0
  60. package/templates/.claude/skills/transcript-site-generator/modules/01-content-parsing.md +117 -0
  61. package/templates/.claude/skills/transcript-site-generator/modules/02-site-generation.md +293 -0
  62. package/templates/.claude/skills/transcript-site-generator/modules/03-interactivity.md +406 -0
  63. package/templates/.claude/skills/transcript-site-generator/modules/04-deploy.md +130 -0
  64. package/templates/.claude/skills/transcript-site-generator/modules/05-verification.md +155 -0
  65. package/templates/.claude/skills/transcript-site-generator/references/component-catalog.md +86 -0
  66. package/templates/.claude/skills/transcript-site-generator/references/data-schemas.md +123 -0
  67. package/templates/.claude/skills/transcript-site-generator/references/tech-stack.md +132 -0
  68. package/templates/CLAUDE.md +9 -2
  69. package/templates/docs/edu-site-generator/01-deployment-guide.md +911 -0
  70. package/templates/docs/edu-site-generator/02-admin-guide.md +901 -0
  71. package/templates/docs/edu-site-generator/03-user-guide.md +1008 -0
  72. package/templates/docs/edu-site-generator/04-infrastructure-requirements.md +489 -0
  73. package/templates/docs/edu-site-generator/05-architecture.md +902 -0
  74. package/templates/docs/edu-site-generator/06-user-flows.md +759 -0
  75. package/templates/docs/transcript-site-generator/01-deployment-guide.md +1042 -0
  76. package/templates/docs/transcript-site-generator/02-admin-guide.md +918 -0
  77. package/templates/docs/transcript-site-generator/03-user-guide.md +925 -0
  78. package/templates/docs/transcript-site-generator/04-infrastructure-requirements.md +482 -0
  79. package/templates/docs/transcript-site-generator/05-architecture.md +1068 -0
  80. package/templates/docs/transcript-site-generator/06-user-flows.md +855 -0
@@ -0,0 +1,855 @@
1
+ # Пользовательские потоки @dzhechkov/skills-transcript-site
2
+
3
+ ## Содержание
4
+
5
+ 1. [Flow: Полный пайплайн (6 шагов)](#1-flow-полный-пайплайн-6-шагов)
6
+ 2. [Flow: YouTube URL](#2-flow-youtube-url)
7
+ 3. [Flow: Text-only](#3-flow-text-only)
8
+ 4. [Flow: Search](#4-flow-search)
9
+ 5. [Flow: Dark Mode](#5-flow-dark-mode)
10
+ 6. [Flow: TOC Scroll-Spy](#6-flow-toc-scroll-spy)
11
+ 7. [Flow: Copy Quote](#7-flow-copy-quote)
12
+ 8. [Flow: Mobile Navigation](#8-flow-mobile-navigation)
13
+ 9. [Flow: YouTube Timestamp Sync](#9-flow-youtube-timestamp-sync)
14
+ 10. [Flow: GitHub Pages Deployment](#10-flow-github-pages-deployment)
15
+ 11. [Flow: Error Handling](#11-flow-error-handling)
16
+
17
+ ---
18
+
19
+ ## 1. Flow: Полный пайплайн (6 шагов)
20
+
21
+ ### Sequence Diagram
22
+
23
+ ```mermaid
24
+ sequenceDiagram
25
+ actor U as Пользователь
26
+ participant C as Claude (/transcript-site)
27
+ participant YT as yt-dlp
28
+ participant FS as File System
29
+
30
+ U->>C: /transcript-site [source]
31
+
32
+ Note over C: === Шаг 1: INPUT ANALYSIS ===
33
+
34
+ alt YouTube URL
35
+ C->>YT: yt-dlp --dump-json [URL]
36
+ YT-->>C: Метаданные (title, duration, channel, date)
37
+ C->>YT: yt-dlp --write-auto-sub [URL]
38
+ YT-->>C: Субтитры (VTT/SRT)
39
+ else Текст или файл
40
+ C->>FS: Прочитать входные данные
41
+ FS-->>C: Сырой текст
42
+ end
43
+
44
+ C->>C: Language detection
45
+ C-->>U: Checkpoint 1/6: Input Analysis Complete
46
+
47
+ U->>C: "ok"
48
+
49
+ Note over C: === Шаг 2: CONTENT PARSING ===
50
+
51
+ C->>C: Разбиение на секции
52
+ C->>C: Определение спикеров
53
+ C->>C: Маппинг временных меток
54
+ C->>C: Извлечение ключевых цитат
55
+ C-->>U: Checkpoint 2/6: Content Parsing Complete<br/>Sections: N, Speakers: M
56
+
57
+ U->>C: "ok"
58
+
59
+ Note over C: === Шаг 3: SITE GENERATION ===
60
+
61
+ C->>C: Загрузить references/html-template.md
62
+ C->>C: Загрузить references/tailwind-config.md
63
+ C->>C: Загрузить references/seo-checklist.md
64
+ C->>C: Генерация HTML структуры
65
+ C->>C: Добавление SEO мета-тегов
66
+ C->>FS: Записать docs/index.html
67
+ C-->>U: Checkpoint 3/6: Site Generation Complete
68
+
69
+ U->>C: "ok"
70
+
71
+ Note over C: === Шаг 4: INTERACTIVITY ===
72
+
73
+ C->>C: Добавить Search (Ctrl+K)
74
+ C->>C: Добавить Dark Mode
75
+ C->>C: Добавить TOC scroll-spy
76
+ C->>C: Добавить YouTube sync (если YouTube)
77
+ C->>C: Добавить Copy quote buttons
78
+ C->>C: Добавить Back-to-top
79
+ C->>C: Добавить Progress bar
80
+ C->>C: Добавить Reading stats
81
+ C->>FS: Обновить docs/index.html
82
+ C-->>U: Checkpoint 4/6: Interactivity Complete
83
+
84
+ U->>C: "ok"
85
+
86
+ Note over C: === Шаг 5: DEPLOY ===
87
+
88
+ C->>FS: Записать docs/robots.txt
89
+ C->>FS: Записать docs/sitemap.xml
90
+ C-->>U: Checkpoint 5/6: Deploy Config Complete
91
+
92
+ U->>C: "ok"
93
+
94
+ Note over C: === Шаг 6: VERIFICATION ===
95
+
96
+ C->>FS: Прочитать docs/index.html
97
+ C->>C: HTML checks (8)
98
+ C->>C: JS checks (6)
99
+ C->>C: CSS checks (4)
100
+ C->>C: SEO checks (5)
101
+ C->>C: A11y checks (5)
102
+ C->>C: Security checks (4)
103
+ C->>C: Performance checks (3)
104
+ C-->>U: Verification: 35/35 passed
105
+
106
+ C-->>U: PIPELINE COMPLETE<br/>Output: docs/index.html
107
+ ```
108
+
109
+ ### Flowchart с точками принятия решений
110
+
111
+ ```mermaid
112
+ flowchart TD
113
+ START(["/transcript-site [source]"]) --> DETECT{"Тип<br/>источника?"}
114
+
115
+ DETECT -->|"YouTube URL"| YTDLP["yt-dlp extraction"]
116
+ DETECT -->|"Файл"| FREAD["Чтение файла"]
117
+ DETECT -->|"Текст"| TREAD["Чтение ввода"]
118
+ DETECT -->|"URL + text"| COMBINED["YouTube meta +<br/>текстовый контент"]
119
+
120
+ YTDLP --> HAS_SUBS{"Есть<br/>субтитры?"}
121
+ HAS_SUBS -->|"Да"| LANG["Language Detection"]
122
+ HAS_SUBS -->|"Нет"| MANUAL["Запросить текст<br/>у пользователя"]
123
+ MANUAL --> LANG
124
+
125
+ FREAD --> LANG
126
+ TREAD --> LANG
127
+ COMBINED --> LANG
128
+
129
+ LANG --> CP1["Checkpoint 1/6"]
130
+ CP1 --> PARSE["Content Parsing:<br/>Секции + Спикеры +<br/>Timestamps + Цитаты"]
131
+
132
+ PARSE --> CP2["Checkpoint 2/6"]
133
+ CP2 --> EMBED{"YouTube<br/>источник?"}
134
+
135
+ EMBED -->|"Да"| GEN_YT["Генерация HTML<br/>с YouTube embed"]
136
+ EMBED -->|"Нет"| GEN_TEXT["Генерация HTML<br/>без embed"]
137
+
138
+ GEN_YT --> CP3["Checkpoint 3/6"]
139
+ GEN_TEXT --> CP3
140
+
141
+ CP3 --> FEATURES["Добавление фич:<br/>Search, Dark Mode, TOC,<br/>Copy, Back-to-top,<br/>Progress, Stats"]
142
+
143
+ FEATURES --> HAS_YT{"YouTube<br/>embed?"}
144
+ HAS_YT -->|"Да"| ADD_SYNC["+ YouTube Sync<br/>(seekTo)"]
145
+ HAS_YT -->|"Нет"| CP4
146
+
147
+ ADD_SYNC --> CP4["Checkpoint 4/6"]
148
+
149
+ CP4 --> DEPLOY["Генерация:<br/>robots.txt + sitemap.xml"]
150
+ DEPLOY --> CP5["Checkpoint 5/6"]
151
+
152
+ CP5 --> VERIFY["Verification:<br/>35 checks"]
153
+ VERIFY --> PASS{"Все<br/>прошли?"}
154
+
155
+ PASS -->|"Да"| DONE(["PIPELINE COMPLETE<br/>docs/index.html"])
156
+ PASS -->|"Нет"| FIX["Отчёт ошибок +<br/>рекомендации"]
157
+ FIX --> VERIFY
158
+ ```
159
+
160
+ ---
161
+
162
+ ## 2. Flow: YouTube URL
163
+
164
+ ### Sequence Diagram
165
+
166
+ ```mermaid
167
+ sequenceDiagram
168
+ actor U as Пользователь
169
+ participant C as Claude
170
+ participant YT as yt-dlp
171
+ participant API as YouTube API
172
+
173
+ U->>C: /transcript-site https://youtube.com/watch?v=VIDEO_ID
174
+
175
+ C->>C: Определить: YouTube URL<br/>Извлечь VIDEO_ID
176
+
177
+ Note over C,YT: Извлечение метаданных
178
+
179
+ C->>YT: yt-dlp --dump-json --no-download URL
180
+ YT->>API: HTTP GET (video info)
181
+ API-->>YT: JSON metadata
182
+ YT-->>C: {title, duration, channel,<br/>upload_date, thumbnail_url}
183
+
184
+ Note over C,YT: Извлечение субтитров
185
+
186
+ C->>YT: yt-dlp --write-auto-sub --sub-lang en,ru<br/>--sub-format vtt --skip-download URL
187
+ YT->>API: HTTP GET (subtitles)
188
+ API-->>YT: VTT subtitles
189
+ YT-->>C: transcript.vtt
190
+
191
+ Note over C: Парсинг VTT
192
+
193
+ C->>C: Удалить дубли строк<br/>(YouTube auto-subs часто дублируют)
194
+ C->>C: Нормализовать timestamps<br/>(HH:MM:SS.mmm -> секунды)
195
+ C->>C: Объединить фрагменты<br/>(каждые 3-5 сек -> одно предложение)
196
+
197
+ C-->>U: Метаданные извлечены:<br/>Title: "...", Duration: MM:SS<br/>Language: en, Words: N
198
+
199
+ Note over C: Генерация HTML с embed
200
+
201
+ C->>C: Создать iframe:<br/>src=youtube.com/embed/VIDEO_ID<br/>?enablejsapi=1&origin=...
202
+
203
+ C->>C: Добавить data-seek атрибуты<br/>на все timestamp links
204
+
205
+ C->>C: Добавить YouTube API JS:<br/>- YT.Player initialization<br/>- seekTo() handler<br/>- postMessage origin check
206
+ ```
207
+
208
+ ### Обработка edge cases
209
+
210
+ ```mermaid
211
+ flowchart TD
212
+ URL["YouTube URL"] --> VALID{"URL<br/>валидный?"}
213
+ VALID -->|"Нет"| ERR_URL["Ошибка: невалидный URL<br/>Предложить проверить формат"]
214
+ VALID -->|"Да"| YTDLP_RUN["yt-dlp extraction"]
215
+
216
+ YTDLP_RUN --> YTDLP_OK{"yt-dlp<br/>установлен?"}
217
+ YTDLP_OK -->|"Нет"| ERR_YTDLP["Ошибка: yt-dlp not found<br/>Предложить: pip install yt-dlp<br/>Или вставить текст вручную"]
218
+ YTDLP_OK -->|"Да"| EXTRACT["Извлечение"]
219
+
220
+ EXTRACT --> SUBS_OK{"Субтитры<br/>найдены?"}
221
+ SUBS_OK -->|"Нет"| NO_SUBS["Субтитры не найдены.<br/>Запросить текст вручную."]
222
+ SUBS_OK -->|"Да"| QUALITY{"Качество<br/>субтитров?"}
223
+
224
+ QUALITY -->|"Авто-генерированные"| WARN["Предупреждение:<br/>авто-субтитры могут<br/>содержать ошибки"]
225
+ QUALITY -->|"Ручные"| GOOD["Ручные субтитры:<br/>высокое качество"]
226
+
227
+ NO_SUBS --> MANUAL["Пользователь вставляет<br/>текст вручную"]
228
+ WARN --> CONTINUE["Продолжить с<br/>авто-субтитрами"]
229
+ GOOD --> CONTINUE
230
+ MANUAL --> CONTINUE
231
+
232
+ CONTINUE --> PARSE["Content Parsing"]
233
+ ```
234
+
235
+ ---
236
+
237
+ ## 3. Flow: Text-only
238
+
239
+ ### Flowchart
240
+
241
+ ```mermaid
242
+ flowchart TD
243
+ START(["/transcript-site [text or file]"]) --> TYPE{"Тип<br/>ввода?"}
244
+
245
+ TYPE -->|"Путь к файлу"| READ_FILE["Прочитать файл"]
246
+ TYPE -->|"Текст в чате"| READ_TEXT["Прочитать текст из чата"]
247
+
248
+ READ_FILE --> FORMAT{"Формат<br/>файла?"}
249
+ READ_TEXT --> FORMAT
250
+
251
+ FORMAT -->|".txt"| PLAIN["Plain text"]
252
+ FORMAT -->|".srt"| SRT["SRT subtitles"]
253
+ FORMAT -->|".vtt"| VTT["VTT subtitles"]
254
+ FORMAT -->|".md"| MD["Markdown"]
255
+ FORMAT -->|"auto-detect"| AUTO["Автоопределение<br/>по содержимому"]
256
+
257
+ PLAIN --> NORMALIZE["Нормализация"]
258
+ SRT --> SRT_PARSE["Парсинг SRT:<br/>номер, timestamps, текст"]
259
+ VTT --> VTT_PARSE["Парсинг VTT:<br/>timestamps, текст, voice tags"]
260
+ MD --> MD_PARSE["Парсинг Markdown:<br/>заголовки = секции"]
261
+ AUTO --> NORMALIZE
262
+
263
+ SRT_PARSE --> NORMALIZE
264
+ VTT_PARSE --> NORMALIZE
265
+ MD_PARSE --> NORMALIZE
266
+
267
+ NORMALIZE --> LANG["Language Detection"]
268
+ LANG --> SECTIONS["Разбиение на секции"]
269
+ SECTIONS --> SPEAKERS["Определение спикеров"]
270
+ SPEAKERS --> GEN["Генерация HTML<br/>(без YouTube embed)"]
271
+
272
+ GEN --> FEATURES["Добавление фич:<br/>Search, Dark Mode, TOC,<br/>Copy, Back-to-top,<br/>Progress, Stats<br/>(БЕЗ YouTube sync)"]
273
+
274
+ FEATURES --> OUTPUT(["docs/index.html<br/>(text-only site)"])
275
+ ```
276
+
277
+ ### Отличия от YouTube flow
278
+
279
+ | Компонент | YouTube flow | Text-only flow |
280
+ |-----------|-------------|----------------|
281
+ | YouTube embed | Да (iframe) | Нет |
282
+ | Timestamp links | Кликабельные (seekTo) | Текстовые метки (нет seekTo) |
283
+ | YouTube sync JS | Да | Нет |
284
+ | postMessage handler | Да | Нет |
285
+ | og:type | video | article |
286
+ | JSON-LD | VideoObject | Article |
287
+ | Thumbnail | YouTube maxresdefault | Placeholder или пользовательское |
288
+
289
+ ---
290
+
291
+ ## 4. Flow: Search
292
+
293
+ ### Sequence Diagram
294
+
295
+ ```mermaid
296
+ sequenceDiagram
297
+ actor U as Пользователь
298
+ participant K as Keyboard
299
+ participant M as Search Modal
300
+ participant S as performSearch()
301
+ participant DOM as DOM
302
+
303
+ U->>K: Ctrl+K (или Cmd+K)
304
+ K->>M: Открыть modal<br/>(display: flex)
305
+ M->>M: Focus на input поле
306
+
307
+ U->>M: Ввод "machine learning"
308
+
309
+ Note over M,S: Debounce: 300ms
310
+
311
+ M->>M: Запустить таймер 300ms
312
+ U->>M: Ввод "s" (ещё символ)
313
+ M->>M: Сбросить таймер, начать заново
314
+
315
+ Note over M,S: 300ms прошло без новых символов
316
+
317
+ M->>S: performSearch("machine learnings")
318
+
319
+ S->>S: Проверка: length >= 2
320
+ S->>S: escapeRegex("machine learnings")
321
+ S->>S: regex = new RegExp(escaped, 'gi')
322
+
323
+ S->>DOM: Удалить все существующие <mark>
324
+ S->>DOM: Найти все .transcript-text элементы
325
+ S->>DOM: textContent.match(regex)
326
+
327
+ loop Для каждого совпадения (max 50)
328
+ S->>DOM: Обернуть в <mark class="bg-yellow-200<br/>dark:bg-yellow-800">
329
+ end
330
+
331
+ S->>M: Обновить счётчик: "Найдено: 12"
332
+ S->>DOM: scrollIntoView(первый <mark>)
333
+ S->>DOM: Добавить ring на текущий <mark>
334
+
335
+ U->>K: Enter
336
+ K->>S: navigateToNext()
337
+ S->>DOM: scrollIntoView(следующий <mark>)
338
+ S->>DOM: Переместить ring
339
+
340
+ U->>K: Shift+Enter
341
+ K->>S: navigateToPrev()
342
+ S->>DOM: scrollIntoView(предыдущий <mark>)
343
+
344
+ U->>K: Escape
345
+ K->>DOM: Удалить все <mark>
346
+ K->>M: Скрыть modal (display: none)
347
+ K->>M: Очистить input
348
+ ```
349
+
350
+ ### Flowchart обработки поиска
351
+
352
+ ```mermaid
353
+ flowchart TD
354
+ INPUT["Ввод в search input"] --> CHECK_LEN{"Длина >= 2<br/>символов?"}
355
+
356
+ CHECK_LEN -->|"Нет"| CLEAR["Удалить все <mark><br/>Сбросить счётчик"]
357
+ CHECK_LEN -->|"Да"| DEBOUNCE["Debounce 300ms"]
358
+
359
+ DEBOUNCE --> ESCAPE_REGEX["escapeRegex(query)"]
360
+ ESCAPE_REGEX --> CREATE_REGEX["new RegExp(escaped, 'gi')"]
361
+
362
+ CREATE_REGEX --> CLEAR_OLD["Удалить старые <mark>"]
363
+ CLEAR_OLD --> FIND["Найти совпадения<br/>в .transcript-text"]
364
+
365
+ FIND --> COUNT{"Количество<br/>совпадений?"}
366
+
367
+ COUNT -->|"0"| NO_RESULTS["Показать: Ничего не найдено"]
368
+ COUNT -->|"1-50"| HIGHLIGHT["Обернуть в <mark>"]
369
+ COUNT -->|"> 50"| LIMIT["Обернуть первые 50<br/>Показать: 50+ найдено"]
370
+
371
+ HIGHLIGHT --> SCROLL["scrollIntoView<br/>первого результата"]
372
+ LIMIT --> SCROLL
373
+
374
+ SCROLL --> COUNTER["Обновить счётчик:<br/>Найдено: N"]
375
+ ```
376
+
377
+ ---
378
+
379
+ ## 5. Flow: Dark Mode
380
+
381
+ ### Flowchart
382
+
383
+ ```mermaid
384
+ flowchart TD
385
+ PAGE_LOAD["Загрузка страницы"] --> CHECK_LS{"localStorage<br/>theme?"}
386
+
387
+ CHECK_LS -->|"'dark'"| SET_DARK["document.documentElement<br/>.classList.add('dark')"]
388
+ CHECK_LS -->|"'light'"| SET_LIGHT["Оставить без dark class"]
389
+ CHECK_LS -->|"не установлен"| CHECK_SYSTEM{"System prefers<br/>dark?"}
390
+
391
+ CHECK_SYSTEM -->|"Да"| SET_DARK
392
+ CHECK_SYSTEM -->|"Нет"| SET_LIGHT
393
+
394
+ SET_DARK --> SHOW_SUN["Показать иконку солнца<br/>(переключить на light)"]
395
+ SET_LIGHT --> SHOW_MOON["Показать иконку луны<br/>(переключить на dark)"]
396
+
397
+ SHOW_SUN --> READY["Страница готова"]
398
+ SHOW_MOON --> READY
399
+
400
+ READY --> CLICK["Клик на toggle button"]
401
+
402
+ CLICK --> TOGGLE["classList.toggle('dark')"]
403
+ TOGGLE --> IS_DARK{"classList<br/>contains<br/>'dark'?"}
404
+
405
+ IS_DARK -->|"Да"| STORE_DARK["localStorage.setItem<br/>('theme', 'dark')"]
406
+ IS_DARK -->|"Нет"| STORE_LIGHT["localStorage.setItem<br/>('theme', 'light')"]
407
+
408
+ STORE_DARK --> UPDATE_ICON["Показать солнце"]
409
+ STORE_LIGHT --> UPDATE_ICON_2["Показать луну"]
410
+ ```
411
+
412
+ ### Sequence Diagram
413
+
414
+ ```mermaid
415
+ sequenceDiagram
416
+ participant B as Браузер
417
+ participant LS as localStorage
418
+ participant DOM as DOM
419
+ participant CSS as Tailwind CSS
420
+
421
+ Note over B: Загрузка страницы
422
+
423
+ B->>LS: getItem('theme')
424
+ LS-->>B: 'dark' / 'light' / null
425
+
426
+ alt theme === 'dark'
427
+ B->>DOM: html.classList.add('dark')
428
+ else theme === null
429
+ B->>B: matchMedia('(prefers-color-scheme: dark)')
430
+ alt System dark mode
431
+ B->>DOM: html.classList.add('dark')
432
+ end
433
+ end
434
+
435
+ DOM->>CSS: Применить dark: утилиты<br/>bg-white -> bg-gray-900<br/>text-gray-900 -> text-gray-100
436
+
437
+ Note over B: Пользователь нажимает toggle
438
+
439
+ B->>DOM: html.classList.toggle('dark')
440
+ DOM->>CSS: Мгновенно переключить стили
441
+ B->>LS: setItem('theme', 'dark' | 'light')
442
+ ```
443
+
444
+ ---
445
+
446
+ ## 6. Flow: TOC Scroll-Spy
447
+
448
+ ### Sequence Diagram
449
+
450
+ ```mermaid
451
+ sequenceDiagram
452
+ participant IO as IntersectionObserver
453
+ participant SEC as Section Elements
454
+ participant TOC as TOC Links
455
+ participant U as Пользователь
456
+
457
+ Note over IO: Инициализация при загрузке
458
+
459
+ IO->>SEC: observer.observe(section-01)
460
+ IO->>SEC: observer.observe(section-02)
461
+ IO->>SEC: observer.observe(section-03)
462
+ IO->>SEC: ...
463
+
464
+ Note over U: Пользователь скроллит
465
+
466
+ U->>SEC: scroll -> section-02 enters viewport
467
+
468
+ SEC->>IO: IntersectionObserver callback<br/>entry.isIntersecting = true<br/>entry.target.id = "section-02"
469
+
470
+ IO->>TOC: Убрать подсветку со всех links
471
+ IO->>TOC: Найти [data-section="section-02"]
472
+ IO->>TOC: Добавить: bg-primary-100, font-bold
473
+
474
+ Note over U: Скролл продолжается
475
+
476
+ U->>SEC: scroll -> section-03 enters viewport
477
+
478
+ SEC->>IO: callback: section-03 isIntersecting
479
+
480
+ IO->>TOC: Убрать подсветку со всех
481
+ IO->>TOC: Подсветить section-03
482
+ ```
483
+
484
+ ### Flowchart
485
+
486
+ ```mermaid
487
+ flowchart TD
488
+ INIT["Инициализация<br/>IntersectionObserver"] --> CONFIG["Конфигурация:<br/>rootMargin: -20% 0px -70% 0px<br/>threshold: 0"]
489
+
490
+ CONFIG --> OBSERVE["Observe все section[id]"]
491
+ OBSERVE --> SCROLL["Пользователь скроллит"]
492
+
493
+ SCROLL --> CALLBACK["Observer callback"]
494
+ CALLBACK --> IS_INTERSECTING{"entry<br/>isIntersecting?"}
495
+
496
+ IS_INTERSECTING -->|"Нет"| IGNORE["Игнорировать"]
497
+ IS_INTERSECTING -->|"Да"| REMOVE_ALL["Убрать подсветку<br/>со всех TOC links"]
498
+
499
+ REMOVE_ALL --> FIND_LINK["Найти TOC link<br/>с data-section = entry.target.id"]
500
+
501
+ FIND_LINK --> HIGHLIGHT["Добавить классы:<br/>bg-primary-100<br/>dark:bg-primary-900<br/>font-bold"]
502
+
503
+ HIGHLIGHT --> SCROLL_TOC["Если TOC scrollable:<br/>scrollIntoView(link)"]
504
+ ```
505
+
506
+ ---
507
+
508
+ ## 7. Flow: Copy Quote
509
+
510
+ ### Sequence Diagram
511
+
512
+ ```mermaid
513
+ sequenceDiagram
514
+ actor U as Пользователь
515
+ participant BTN as Copy Button
516
+ participant CB as Clipboard API
517
+ participant FB as Feedback
518
+
519
+ U->>BTN: Клик на кнопку копирования
520
+
521
+ Note over BTN: Event delegation:<br/>e.target.closest('[data-copy]')
522
+
523
+ BTN->>BTN: text = dataset.copy
524
+ BTN->>CB: navigator.clipboard.writeText(text)
525
+
526
+ alt Clipboard API доступен
527
+ CB-->>BTN: Promise resolved
528
+ BTN->>FB: Сменить текст кнопки:<br/>"Копировать" -> "Скопировано!"
529
+ FB->>FB: setTimeout(2000ms)
530
+ FB->>BTN: Вернуть текст:<br/>"Скопировано!" -> "Копировать"
531
+ else Clipboard API недоступен (HTTP)
532
+ BTN->>BTN: Fallback: document.execCommand('copy')
533
+ Note over BTN: Создать textarea,<br/>select, execCommand, remove
534
+ BTN->>FB: Сменить текст кнопки
535
+ end
536
+ ```
537
+
538
+ ### Flowchart
539
+
540
+ ```mermaid
541
+ flowchart TD
542
+ CLICK["Клик на [data-copy]"] --> GET_TEXT["text = dataset.copy"]
543
+ GET_TEXT --> CHECK_API{"navigator.clipboard<br/>доступен?"}
544
+
545
+ CHECK_API -->|"Да"| CLIPBOARD["clipboard.writeText(text)"]
546
+ CHECK_API -->|"Нет"| FALLBACK["Fallback:<br/>textarea + execCommand"]
547
+
548
+ CLIPBOARD --> SUCCESS["Успех"]
549
+ FALLBACK --> SUCCESS
550
+
551
+ SUCCESS --> FEEDBACK["Сменить текст кнопки<br/>на 'Скопировано!'"]
552
+ FEEDBACK --> TIMEOUT["setTimeout 2000ms"]
553
+ TIMEOUT --> RESTORE["Восстановить<br/>исходный текст кнопки"]
554
+ ```
555
+
556
+ ---
557
+
558
+ ## 8. Flow: Mobile Navigation
559
+
560
+ ### Flowchart
561
+
562
+ ```mermaid
563
+ flowchart TD
564
+ LOAD["Загрузка на мобильном<br/>(viewport < 768px)"] --> HIDE_ASIDE["aside: hidden<br/>(transform: translateX(-100%))"]
565
+
566
+ HIDE_ASIDE --> SHOW_HAMBURGER["Показать кнопку<br/>hamburger в nav"]
567
+
568
+ SHOW_HAMBURGER --> CLICK_HAMBURGER["Клик на hamburger"]
569
+ CLICK_HAMBURGER --> OPEN_DRAWER["aside: transform translateX(0)<br/>+ overlay backdrop"]
570
+
571
+ OPEN_DRAWER --> USER_CHOICE{"Действие<br/>пользователя?"}
572
+
573
+ USER_CHOICE -->|"Клик на секцию<br/>в TOC"| SCROLL_SECTION["scrollIntoView(section)<br/>Закрыть drawer"]
574
+ USER_CHOICE -->|"Клик на overlay"| CLOSE_DRAWER["Закрыть drawer:<br/>translateX(-100%)<br/>Убрать overlay"]
575
+ USER_CHOICE -->|"Escape"| CLOSE_DRAWER
576
+
577
+ SCROLL_SECTION --> HIDE_ASIDE
578
+ CLOSE_DRAWER --> HIDE_ASIDE
579
+ ```
580
+
581
+ ### Sequence Diagram
582
+
583
+ ```mermaid
584
+ sequenceDiagram
585
+ actor U as Пользователь (мобильный)
586
+ participant NAV as Nav Bar
587
+ participant ASIDE as Sidebar (aside)
588
+ participant OVERLAY as Overlay
589
+ participant SECTION as Section
590
+
591
+ Note over NAV: Viewport < 768px
592
+
593
+ U->>NAV: Тап на hamburger icon
594
+
595
+ NAV->>ASIDE: classList.remove('translate-x-full')<br/>classList.add('translate-x-0')
596
+ NAV->>OVERLAY: display: block<br/>opacity: 0.5
597
+
598
+ Note over ASIDE: Sidebar выезжает слева<br/>поверх контента
599
+
600
+ U->>ASIDE: Тап на "Section 3" в TOC
601
+
602
+ ASIDE->>SECTION: scrollIntoView({ behavior: 'smooth' })
603
+ ASIDE->>ASIDE: classList.add('translate-x-full')
604
+ ASIDE->>OVERLAY: display: none
605
+
606
+ Note over NAV: Sidebar скрыт,<br/>страница проскроллена к Section 3
607
+ ```
608
+
609
+ ---
610
+
611
+ ## 9. Flow: YouTube Timestamp Sync
612
+
613
+ ### Sequence Diagram
614
+
615
+ ```mermaid
616
+ sequenceDiagram
617
+ actor U as Пользователь
618
+ participant LINK as Timestamp Link
619
+ participant JS as Event Handler
620
+ participant IFRAME as YouTube iframe
621
+ participant YT as YouTube Player API
622
+
623
+ Note over IFRAME: При загрузке страницы
624
+
625
+ JS->>IFRAME: Create iframe with enablejsapi=1
626
+ IFRAME->>YT: Load YouTube IFrame API
627
+ YT-->>JS: onYouTubeIframeAPIReady()
628
+ JS->>YT: new YT.Player('yt-player', {...})
629
+ YT-->>JS: player ready
630
+
631
+ Note over U: Клик на timestamp
632
+
633
+ U->>LINK: Клик на [2:05]
634
+
635
+ Note over LINK: HTML:<br/>a data-seek="125"
636
+
637
+ LINK->>JS: click event (delegation)
638
+ JS->>JS: e.target.closest('[data-seek]')
639
+ JS->>JS: seconds = parseInt(dataset.seek) = 125
640
+
641
+ JS->>YT: player.seekTo(125, true)
642
+ YT->>IFRAME: Перемотка на 2:05
643
+
644
+ JS->>IFRAME: scrollIntoView({ behavior: 'smooth' })<br/>(если iframe не в viewport)
645
+
646
+ Note over U: Видео начинает воспроизведение с 2:05
647
+ ```
648
+
649
+ ### Flowchart с обработкой ошибок
650
+
651
+ ```mermaid
652
+ flowchart TD
653
+ CLICK["Клик на [data-seek]"] --> PREVENT["e.preventDefault()"]
654
+ PREVENT --> PARSE["seconds = parseInt(dataset.seek)"]
655
+
656
+ PARSE --> CHECK_PLAYER{"player<br/>ready?"}
657
+
658
+ CHECK_PLAYER -->|"Да"| SEEK["player.seekTo(seconds, true)"]
659
+ CHECK_PLAYER -->|"Нет (player undefined)"| FALLBACK_1["Открыть YouTube URL<br/>с параметром t=seconds<br/>в новой вкладке"]
660
+
661
+ SEEK --> IN_VIEW{"iframe<br/>в viewport?"}
662
+
663
+ IN_VIEW -->|"Да"| DONE["Видео перемотано"]
664
+ IN_VIEW -->|"Нет"| SCROLL["scrollIntoView(iframe,<br/>{ behavior: 'smooth' })"]
665
+ SCROLL --> DONE
666
+
667
+ FALLBACK_1 --> DONE_ALT["YouTube открыт<br/>в новой вкладке"]
668
+ ```
669
+
670
+ ---
671
+
672
+ ## 10. Flow: GitHub Pages Deployment
673
+
674
+ ### Flowchart
675
+
676
+ ```mermaid
677
+ flowchart TD
678
+ GEN["Сайт сгенерирован<br/>docs/index.html"] --> GIT_INIT{"git repo<br/>инициализирован?"}
679
+
680
+ GIT_INIT -->|"Нет"| INIT["git init"]
681
+ GIT_INIT -->|"Да"| ADD
682
+
683
+ INIT --> ADD["git add docs/"]
684
+ ADD --> COMMIT["git commit -m<br/>'add transcript site'"]
685
+ COMMIT --> REMOTE{"Remote<br/>настроен?"}
686
+
687
+ REMOTE -->|"Нет"| ADD_REMOTE["git remote add origin<br/>https://github.com/USER/REPO"]
688
+ REMOTE -->|"Да"| PUSH
689
+
690
+ ADD_REMOTE --> PUSH["git push origin main"]
691
+ PUSH --> GITHUB["GitHub Repository"]
692
+ GITHUB --> SETTINGS["Settings > Pages"]
693
+
694
+ SETTINGS --> CONFIG["Source: Deploy from branch<br/>Branch: main<br/>Folder: /docs"]
695
+ CONFIG --> BUILD["GitHub Pages build<br/>(~1-2 минуты)"]
696
+ BUILD --> LIVE["Сайт доступен:<br/>https://USER.github.io/REPO/"]
697
+
698
+ LIVE --> VERIFY_LIVE["Проверить:<br/>открыть URL в браузере"]
699
+ ```
700
+
701
+ ### Sequence Diagram с GitHub Actions
702
+
703
+ ```mermaid
704
+ sequenceDiagram
705
+ actor D as Разработчик
706
+ participant GIT as git
707
+ participant GH as GitHub
708
+ participant GA as GitHub Actions
709
+ participant GP as GitHub Pages
710
+
711
+ D->>GIT: git add docs/
712
+ D->>GIT: git commit -m "add transcript site"
713
+ D->>GIT: git push origin main
714
+
715
+ GIT->>GH: Push docs/ файлы
716
+
717
+ alt GitHub Pages настроен на docs/
718
+ GH->>GP: Deploy из docs/ напрямую
719
+ GP-->>D: Сайт live через 1-2 минуты
720
+ else GitHub Actions workflow настроен
721
+ GH->>GA: Trigger workflow<br/>(on push, paths: docs/**)
722
+ GA->>GA: actions/checkout
723
+ GA->>GA: actions/upload-pages-artifact<br/>(path: docs/)
724
+ GA->>GP: actions/deploy-pages
725
+ GP-->>D: Сайт live через 2-3 минуты
726
+ end
727
+
728
+ D->>GP: Открыть https://USER.github.io/REPO/
729
+ GP-->>D: Интерактивный transcript сайт
730
+ ```
731
+
732
+ ---
733
+
734
+ ## 11. Flow: Error Handling
735
+
736
+ ### yt-dlp не найден
737
+
738
+ ```mermaid
739
+ flowchart TD
740
+ URL["YouTube URL предоставлен"] --> CHECK{"yt-dlp<br/>в PATH?"}
741
+
742
+ CHECK -->|"Да"| EXTRACT["Извлечение субтитров"]
743
+ CHECK -->|"Нет"| ERROR["WARN: yt-dlp not found"]
744
+
745
+ ERROR --> OPTIONS{"Варианты:"}
746
+
747
+ OPTIONS -->|"Установить yt-dlp"| INSTALL["pip install yt-dlp<br/>Повторить запуск"]
748
+ OPTIONS -->|"Вставить текст"| MANUAL["Пользователь вставляет<br/>текст транскрипта<br/>в чат"]
749
+
750
+ MANUAL --> CONTINUE["Продолжить как<br/>text-only flow"]
751
+ INSTALL --> EXTRACT
752
+ ```
753
+
754
+ ### Транскрипт слишком короткий
755
+
756
+ ```mermaid
757
+ flowchart TD
758
+ PARSE["Content Parsing"] --> COUNT{"Слов<br/>< 50?"}
759
+
760
+ COUNT -->|"Да"| SHORT["WARN: Транскрипт слишком короткий"]
761
+ COUNT -->|"Нет"| CONTINUE["Продолжить"]
762
+
763
+ SHORT --> OPTIONS{"Варианты:"}
764
+
765
+ OPTIONS -->|"Продолжить<br/>(small site)"| SMALL["Генерация minimal site:<br/>1 секция, без TOC"]
766
+ OPTIONS -->|"Добавить текст"| ADD["Пользователь добавляет<br/>ещё текст"]
767
+ OPTIONS -->|"Отмена"| CANCEL["Прервать пайплайн"]
768
+
769
+ ADD --> PARSE
770
+ ```
771
+
772
+ ### HTML validation failure
773
+
774
+ ```mermaid
775
+ flowchart TD
776
+ VERIFY["Шаг 6: Verification"] --> CHECK{"Все 35<br/>проверок<br/>прошли?"}
777
+
778
+ CHECK -->|"Да"| DONE["PIPELINE COMPLETE"]
779
+ CHECK -->|"Нет"| REPORT["Отчёт ошибок"]
780
+
781
+ REPORT --> SEVERITY{"Уровень<br/>ошибок?"}
782
+
783
+ SEVERITY -->|"Critical<br/>(HTML, Security)"| BLOCK["BLOCK: Исправить<br/>перед деплоем"]
784
+ SEVERITY -->|"Warning<br/>(Performance)"| WARN["WARN: Рекомендации"]
785
+ SEVERITY -->|"Info<br/>(SEO optional)"| INFO["INFO: Опционально"]
786
+
787
+ BLOCK --> AUTO_FIX{"Авто-<br/>исправление<br/>возможно?"}
788
+
789
+ AUTO_FIX -->|"Да"| FIX["Автоматическое<br/>исправление"]
790
+ AUTO_FIX -->|"Нет"| MANUAL["Требуется ручное<br/>вмешательство"]
791
+
792
+ FIX --> REVERIFY["Повторная<br/>верификация"]
793
+ REVERIFY --> CHECK
794
+
795
+ WARN --> DONE_WARN["PIPELINE COMPLETE<br/>(с предупреждениями)"]
796
+ INFO --> DONE_INFO["PIPELINE COMPLETE"]
797
+ ```
798
+
799
+ ### Общая обработка ошибок
800
+
801
+ ```mermaid
802
+ flowchart TD
803
+ ERROR["Ошибка на любом шаге"] --> TYPE{"Тип<br/>ошибки?"}
804
+
805
+ TYPE -->|"yt-dlp не найден"| YTDLP_ERR["Предложить установку<br/>или ручной ввод"]
806
+ TYPE -->|"Пустой транскрипт"| EMPTY_ERR["Запросить текст<br/>у пользователя"]
807
+ TYPE -->|"Файл не найден"| FILE_ERR["Проверить путь<br/>Показать ls директории"]
808
+ TYPE -->|"Кодировка"| ENC_ERR["Предложить конвертацию<br/>iconv -f WINDOWS-1251 -t UTF-8"]
809
+ TYPE -->|"Превышен размер"| SIZE_ERR["Предложить chunking<br/>--chunking multi"]
810
+ TYPE -->|"GitHub Pages 404"| GH_ERR["Проверить Settings > Pages<br/>Branch + Folder"]
811
+ TYPE -->|"Tailwind CDN offline"| CDN_ERR["Предложить --tailwind inline"]
812
+
813
+ YTDLP_ERR --> CONTINUE["Продолжить<br/>с fallback"]
814
+ EMPTY_ERR --> CONTINUE
815
+ FILE_ERR --> RETRY["Повторить<br/>с правильным путём"]
816
+ ENC_ERR --> RETRY
817
+ SIZE_ERR --> CONTINUE
818
+ GH_ERR --> MANUAL_FIX["Ручная настройка<br/>GitHub Pages"]
819
+ CDN_ERR --> CONTINUE
820
+ ```
821
+
822
+ ---
823
+
824
+ ## Быстрый справочник команд
825
+
826
+ | Команда | Назначение | Минимальный вход | Результат |
827
+ |---------|-----------|-----------------|-----------|
828
+ | `/transcript-site [source]` | Полный пайплайн (6 шагов) | YouTube URL, текст или путь к файлу | docs/index.html + robots.txt + sitemap.xml |
829
+ | `/transcript-site-generate [source]` | Только генерация HTML (шаги 1-4) | YouTube URL, текст или путь к файлу | docs/index.html |
830
+ | `/transcript-site-deploy [path]` | Только деплой конфиг (шаги 5-6) | Путь к существующему HTML | robots.txt + sitemap.xml + verification |
831
+
832
+ ## Частые сценарии
833
+
834
+ ```
835
+ # YouTube видео -> интерактивный сайт
836
+ /transcript-site https://youtube.com/watch?v=VIDEO_ID
837
+
838
+ # Текстовый файл -> сайт
839
+ /transcript-site /path/to/transcript.txt
840
+
841
+ # Markdown файл -> сайт
842
+ /transcript-site researches/case/08_executive_summary.md
843
+
844
+ # YouTube + исправленный текст
845
+ /transcript-site https://youtube.com/watch?v=... --text corrected.txt
846
+
847
+ # Кастомная тема + язык
848
+ /transcript-site [source] --theme emerald --lang ru
849
+
850
+ # Полностью offline-совместимый сайт
851
+ /transcript-site [source] --tailwind inline --icons inline --no-embed
852
+
853
+ # Multi-page для длинного транскрипта
854
+ /transcript-site [source] --chunking multi --output docs/long-talk/
855
+ ```