@dzhechkov/keysarium 1.3.0 → 1.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +70 -10
- package/bin/cli.js +0 -0
- package/package.json +5 -3
- package/src/utils.js +1 -1
- package/templates/.claude/commands/analyst-manual.md +38 -0
- package/templates/.claude/commands/brain-export.md +2 -0
- package/templates/.claude/commands/bto-benchmark.md +302 -0
- package/templates/.claude/commands/casarium.md +55 -4
- package/templates/.claude/commands/feature-adr.md +8 -0
- package/templates/.claude/commands/harvest.md +28 -46
- package/templates/.claude/rules/trust-tiers.md +6 -0
- package/templates/.claude/shards/feature-adr.shard.md +64 -10
- package/templates/.claude/shards/phase-ai-factory.shard.md +109 -0
- package/templates/.claude/skills/ai-factory-mapper/README.md +90 -0
- package/templates/.claude/skills/ai-factory-mapper/SKILL.md +309 -0
- package/templates/.claude/skills/ai-factory-mapper/assets/report-template.md +123 -0
- package/templates/.claude/skills/ai-factory-mapper/references/catalog.md +230 -0
- package/templates/.claude/skills/ai-factory-mapper/references/coverage-formula.md +219 -0
- package/templates/.claude/skills/ai-factory-mapper/references/decomposition-checklist.md +183 -0
- package/templates/.claude/skills/ai-factory-mapper/references/pattern-library.md +312 -0
- package/templates/.claude/skills/ai-factory-mapper/scripts/build_docx_report.js +423 -0
- package/templates/.claude/skills/analyst-manual-full/SKILL.md +286 -0
- package/templates/.claude/skills/edu-site-generator/SKILL.md +254 -0
- package/templates/.claude/skills/edu-site-generator/examples/sample-course-structure.md +116 -0
- package/templates/.claude/skills/edu-site-generator/modules/00-content-analysis.md +84 -0
- package/templates/.claude/skills/edu-site-generator/modules/01-course-structure.md +75 -0
- package/templates/.claude/skills/edu-site-generator/modules/02-data-generation.md +186 -0
- package/templates/.claude/skills/edu-site-generator/modules/03-scaffold.md +249 -0
- package/templates/.claude/skills/edu-site-generator/modules/04-components.md +130 -0
- package/templates/.claude/skills/edu-site-generator/modules/05-gamification.md +163 -0
- package/templates/.claude/skills/edu-site-generator/modules/06-deploy.md +88 -0
- package/templates/.claude/skills/edu-site-generator/modules/07-verification.md +97 -0
- package/templates/.claude/skills/edu-site-generator/references/component-templates.md +436 -0
- package/templates/.claude/skills/edu-site-generator/references/data-schemas.md +164 -0
- package/templates/.claude/skills/edu-site-generator/references/exercise-catalog.md +110 -0
- package/templates/.claude/skills/edu-site-generator/references/tech-stack.md +69 -0
- package/templates/.claude/skills/feature-adr/SKILL.md +245 -59
- package/templates/.claude/skills/feature-adr/modules/03-adr.md +43 -0
- package/templates/.claude/skills/feature-adr/modules/03.5-ideation-swarm.md +180 -0
- package/templates/.claude/skills/feature-adr/modules/06-implementation-plan.md +56 -7
- package/templates/.claude/skills/feature-adr/modules/08-qe.md +87 -23
- package/templates/.claude/skills/feature-adr/modules/09-fleet-qe.md +305 -0
- package/templates/.claude/skills/feature-adr/references/agentic-qe/README.md +143 -0
- package/templates/.claude/skills/feature-adr/references/agentic-qe/brutal-honesty-review.md +240 -0
- package/templates/.claude/skills/feature-adr/references/agentic-qe/chaos-engineering-resilience.md +163 -0
- package/templates/.claude/skills/feature-adr/references/agentic-qe/code-goal-planner.md +446 -0
- package/templates/.claude/skills/feature-adr/references/agentic-qe/enterprise-integration-testing.md +111 -0
- package/templates/.claude/skills/feature-adr/references/agentic-qe/mutation-testing.md +236 -0
- package/templates/.claude/skills/feature-adr/references/agentic-qe/performance-testing.md +315 -0
- package/templates/.claude/skills/feature-adr/references/agentic-qe/qcsd-ideation-swarm.md +126 -0
- package/templates/.claude/skills/feature-adr/references/agentic-qe/qcsd-production-swarm.md +108 -0
- package/templates/.claude/skills/feature-adr/references/agentic-qe/qe-coverage-analysis.md +193 -0
- package/templates/.claude/skills/feature-adr/references/agentic-qe/qe-requirements-validation.md +254 -0
- package/templates/.claude/skills/feature-adr/references/agentic-qe/regression-testing.md +233 -0
- package/templates/.claude/skills/feature-adr/references/agentic-qe/risk-based-testing.md +212 -0
- package/templates/.claude/skills/feature-adr/references/agentic-qe/security-testing.md +311 -0
- package/templates/.claude/skills/feature-adr/references/agentic-qe/shift-left-testing.md +231 -0
- package/templates/.claude/skills/feature-adr/references/agentic-qe/tdd-london-chicago.md +249 -0
- package/templates/.claude/skills/knowledge-extractor/SKILL.md +254 -0
- package/templates/.claude/skills/knowledge-extractor/modules/01-extract.md +188 -0
- package/templates/.claude/skills/knowledge-extractor/modules/02-classify.md +99 -0
- package/templates/.claude/skills/knowledge-extractor/modules/03-gate.md +150 -0
- package/templates/.claude/skills/knowledge-extractor/modules/04-integrate.md +159 -0
- package/templates/.claude/skills/knowledge-extractor/references/artifact-categories.md +100 -0
- package/templates/.claude/skills/knowledge-extractor/references/maturity-model.md +94 -0
- package/templates/.claude/skills/knowledge-extractor/references/quality-gates.md +98 -0
- package/templates/.claude/skills/knowledge-extractor/templates/artifact-card.md +63 -0
- package/templates/.claude/skills/knowledge-extractor/templates/harvest-report.md +102 -0
- package/templates/.claude/skills/transcript-site-generator/SKILL.md +287 -0
- package/templates/.claude/skills/transcript-site-generator/examples/sample-text-only-site.md +123 -0
- package/templates/.claude/skills/transcript-site-generator/examples/sample-transcript-site.md +134 -0
- package/templates/.claude/skills/transcript-site-generator/modules/00-input-analysis.md +132 -0
- package/templates/.claude/skills/transcript-site-generator/modules/01-content-parsing.md +117 -0
- package/templates/.claude/skills/transcript-site-generator/modules/02-site-generation.md +293 -0
- package/templates/.claude/skills/transcript-site-generator/modules/03-interactivity.md +406 -0
- package/templates/.claude/skills/transcript-site-generator/modules/04-deploy.md +130 -0
- package/templates/.claude/skills/transcript-site-generator/modules/05-verification.md +155 -0
- package/templates/.claude/skills/transcript-site-generator/references/component-catalog.md +86 -0
- package/templates/.claude/skills/transcript-site-generator/references/data-schemas.md +123 -0
- package/templates/.claude/skills/transcript-site-generator/references/tech-stack.md +132 -0
- package/templates/CLAUDE.md +30 -9
- package/templates/docs/continuous-learning-guide.md +622 -0
- package/templates/docs/edu-site-generator/01-deployment-guide.md +911 -0
- package/templates/docs/edu-site-generator/02-admin-guide.md +901 -0
- package/templates/docs/edu-site-generator/03-user-guide.md +1008 -0
- package/templates/docs/edu-site-generator/04-infrastructure-requirements.md +489 -0
- package/templates/docs/edu-site-generator/05-architecture.md +902 -0
- package/templates/docs/edu-site-generator/06-user-flows.md +759 -0
- package/templates/docs/improvement-directions.md +8 -4
- package/templates/docs/keysarium-core/02-functionality.md +3 -1
- package/templates/docs/skills-bto/01-deployment-guide.md +1 -1
- package/templates/docs/skills-bto/02-admin-guide.md +4 -1
- package/templates/docs/skills-bto/03-user-guide.md +4 -3
- package/templates/docs/skills-bto/04-infrastructure-requirements.md +2 -1
- package/templates/docs/skills-bto/05-architecture.md +11 -11
- package/templates/docs/skills-bto/06-user-flows.md +2 -1
- package/templates/docs/transcript-site-generator/01-deployment-guide.md +1042 -0
- package/templates/docs/transcript-site-generator/02-admin-guide.md +918 -0
- package/templates/docs/transcript-site-generator/03-user-guide.md +925 -0
- package/templates/docs/transcript-site-generator/04-infrastructure-requirements.md +482 -0
- package/templates/docs/transcript-site-generator/05-architecture.md +1068 -0
- package/templates/docs/transcript-site-generator/06-user-flows.md +855 -0
- package/templates/lib/dream-engine.md +1 -1
- package/templates/lib/memory-protocol.md +6 -2
- package/templates/lib/reward-tracker.md +6 -3
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
# Example: Podcast Transcript Site
|
|
2
|
+
|
|
3
|
+
## Input
|
|
4
|
+
|
|
5
|
+
```
|
|
6
|
+
YouTube URL: https://www.youtube.com/watch?v=julbw1JuAz0
|
|
7
|
+
Title: "Building Claude Code with Boris Cherny"
|
|
8
|
+
Language: Russian
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Parsed Sections (Step 1 Output)
|
|
12
|
+
|
|
13
|
+
```
|
|
14
|
+
Section 1: "Введение" (00:00:00) - 342 words
|
|
15
|
+
Section 2: "Ранняя карьера: от Pokemon до программирования" (00:02:15) - 890 words
|
|
16
|
+
Section 3: "Опыт в Meta: Instagram, Facebook, WhatsApp" (00:08:30) - 1240 words
|
|
17
|
+
Section 4: "Приход в Anthropic и первый pull request" (00:15:45) - 780 words
|
|
18
|
+
Section 5: "Рождение Claude Code" (00:22:10) - 1450 words
|
|
19
|
+
Section 6: "Рабочие паттерны: 20-30 PR в день" (00:32:00) - 950 words
|
|
20
|
+
Section 7: "Code Review с AI" (00:38:20) - 670 words
|
|
21
|
+
Section 8: "Архитектура и безопасность" (00:43:15) - 1100 words
|
|
22
|
+
Section 9: "Культура Anthropic" (00:50:30) - 820 words
|
|
23
|
+
Section 10: "Claude как коллега" (00:56:45) - 560 words
|
|
24
|
+
Section 11: "Agent Teams и будущее" (01:02:10) - 740 words
|
|
25
|
+
Section 12: "Метафора печатного станка" (01:08:30) - 1320 words
|
|
26
|
+
Section 13: "Навыки инженера будущего" (01:15:00) - 680 words
|
|
27
|
+
|
|
28
|
+
Total: 11,542 words, ~58 min read, 2 speakers
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
## Generated File Structure
|
|
32
|
+
|
|
33
|
+
```
|
|
34
|
+
project-root/
|
|
35
|
+
├── docs/
|
|
36
|
+
│ ├── index.html (87 KB)
|
|
37
|
+
│ └── static/
|
|
38
|
+
│ ├── app.js (11 KB)
|
|
39
|
+
│ └── style.css (0.4 KB)
|
|
40
|
+
├── .github/
|
|
41
|
+
│ └── workflows/
|
|
42
|
+
│ └── deploy.yml
|
|
43
|
+
└── README.md
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
## index.html Highlights
|
|
47
|
+
|
|
48
|
+
### SEO Head
|
|
49
|
+
|
|
50
|
+
```html
|
|
51
|
+
<title>Building Claude Code with Boris Cherny — Транскрипт</title>
|
|
52
|
+
<meta name="description" content="Полный русский транскрипт подкаста Pragmatic Engineer с Борисом Черным, создателем Claude Code в Anthropic." />
|
|
53
|
+
<meta property="og:type" content="video.other" />
|
|
54
|
+
<meta property="og:image" content="https://img.youtube.com/vi/julbw1JuAz0/maxresdefault.jpg" />
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
### JSON-LD
|
|
58
|
+
|
|
59
|
+
```json
|
|
60
|
+
[
|
|
61
|
+
{
|
|
62
|
+
"@type": "Article",
|
|
63
|
+
"headline": "Building Claude Code with Boris Cherny — Транскрипт",
|
|
64
|
+
"wordCount": 11542
|
|
65
|
+
},
|
|
66
|
+
{
|
|
67
|
+
"@type": "VideoObject",
|
|
68
|
+
"name": "Building Claude Code with Boris Cherny",
|
|
69
|
+
"embedUrl": "https://www.youtube.com/embed/julbw1JuAz0"
|
|
70
|
+
}
|
|
71
|
+
]
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
### Sample Section HTML
|
|
75
|
+
|
|
76
|
+
```html
|
|
77
|
+
<section id="section-birth-of-claude-code" class="mb-12 scroll-mt-20">
|
|
78
|
+
<div class="flex items-start justify-between mb-4">
|
|
79
|
+
<h2 class="text-2xl font-bold text-gray-900 dark:text-white">
|
|
80
|
+
<a href="#section-birth-of-claude-code" role="button" data-seek="1330"
|
|
81
|
+
class="timestamp-link text-primary-500 hover:text-primary-600 text-sm font-mono mr-2">22:10</a>
|
|
82
|
+
5. Рождение Claude Code
|
|
83
|
+
</h2>
|
|
84
|
+
<button data-copy="section-birth-of-claude-code"
|
|
85
|
+
class="copy-btn flex-shrink-0 p-2 rounded-lg hover:bg-gray-100 dark:hover:bg-gray-800
|
|
86
|
+
text-gray-400 hover:text-gray-600 dark:hover:text-gray-300 no-print"
|
|
87
|
+
aria-label="Скопировать">
|
|
88
|
+
<i class="far fa-copy"></i>
|
|
89
|
+
</button>
|
|
90
|
+
</div>
|
|
91
|
+
<div class="mb-3 flex items-center gap-2">
|
|
92
|
+
<span class="inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium
|
|
93
|
+
bg-primary-100 text-primary-800 dark:bg-primary-900 dark:text-primary-200">
|
|
94
|
+
Boris Cherny · Guest
|
|
95
|
+
</span>
|
|
96
|
+
</div>
|
|
97
|
+
<div class="prose prose-lg dark:prose-invert max-w-none">
|
|
98
|
+
<p>Когда я пришел в Anthropic, мой первый pull request был написан от руки...</p>
|
|
99
|
+
<p>И тогда я подумал: а что если Claude сможет сам писать код?...</p>
|
|
100
|
+
</div>
|
|
101
|
+
</section>
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
### YouTube Embed
|
|
105
|
+
|
|
106
|
+
```html
|
|
107
|
+
<div class="mb-8 rounded-xl overflow-hidden shadow-lg aspect-video max-w-3xl mx-auto">
|
|
108
|
+
<iframe id="yt-player"
|
|
109
|
+
src="https://www.youtube.com/embed/julbw1JuAz0?enablejsapi=1&origin=https://user.github.io"
|
|
110
|
+
class="w-full h-full" frameborder="0"
|
|
111
|
+
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture"
|
|
112
|
+
allowfullscreen>
|
|
113
|
+
</iframe>
|
|
114
|
+
</div>
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
## Stats Displayed in Header
|
|
118
|
+
|
|
119
|
+
```
|
|
120
|
+
⏱ 58 мин чтения · 📄 11 542 слов · 13 разделов
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
## Verification Results
|
|
124
|
+
|
|
125
|
+
```
|
|
126
|
+
File checks: 5/5 passed
|
|
127
|
+
HTML structure: 13/13 passed
|
|
128
|
+
Content: 6/6 passed
|
|
129
|
+
Interactivity: 10/10 passed
|
|
130
|
+
Responsive: 6/6 passed
|
|
131
|
+
Dark mode: 6/6 passed
|
|
132
|
+
SEO: 7/7 passed
|
|
133
|
+
Print: 4/4 passed
|
|
134
|
+
```
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
# Step 0: Input Analysis
|
|
2
|
+
|
|
3
|
+
## Purpose
|
|
4
|
+
|
|
5
|
+
Detect the input type, extract raw transcript text, and gather metadata for downstream steps.
|
|
6
|
+
|
|
7
|
+
## Protocol
|
|
8
|
+
|
|
9
|
+
### 1. Classify Input
|
|
10
|
+
|
|
11
|
+
Scan the user's input for:
|
|
12
|
+
|
|
13
|
+
| Pattern | Input Type | Action |
|
|
14
|
+
|---------|-----------|--------|
|
|
15
|
+
| `youtube.com/watch?v=` or `youtu.be/` | YouTube URL | Extract via yt-dlp |
|
|
16
|
+
| File path ending in `.txt`, `.md`, `.vtt`, `.srt` | Local file | Read file |
|
|
17
|
+
| Multi-line text block (>100 chars) | Pasted text | Use directly |
|
|
18
|
+
| URL + text block | Combined | URL for embed, text as transcript |
|
|
19
|
+
|
|
20
|
+
If the input is ambiguous, ask:
|
|
21
|
+
```
|
|
22
|
+
Detected both a URL and text. Which should I use?
|
|
23
|
+
1. URL for video embed + text as transcript content
|
|
24
|
+
2. URL only (extract transcript from video)
|
|
25
|
+
3. Text only (ignore URL)
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
### 2. YouTube Extraction (if applicable)
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
# Check yt-dlp availability
|
|
32
|
+
which yt-dlp || pip install yt-dlp
|
|
33
|
+
|
|
34
|
+
# Extract video metadata
|
|
35
|
+
yt-dlp --print title --print channel --print duration --skip-download "<URL>"
|
|
36
|
+
|
|
37
|
+
# Extract subtitles (prefer manual, fallback to auto-generated)
|
|
38
|
+
yt-dlp --write-sub --sub-lang ru,en --skip-download --sub-format vtt -o "/tmp/transcript" "<URL>" 2>/dev/null \
|
|
39
|
+
|| yt-dlp --write-auto-sub --sub-lang ru,en --skip-download --sub-format vtt -o "/tmp/transcript" "<URL>"
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
#### VTT Parsing
|
|
43
|
+
|
|
44
|
+
Parse the `.vtt` file:
|
|
45
|
+
1. Skip the `WEBVTT` header and any style blocks
|
|
46
|
+
2. Extract timestamp + text pairs
|
|
47
|
+
3. Remove duplicate lines (VTT shows overlapping segments)
|
|
48
|
+
4. Merge consecutive segments from the same speaker
|
|
49
|
+
5. Clean up formatting: remove `<c>` tags, `&` entities, alignment cues
|
|
50
|
+
|
|
51
|
+
Output format:
|
|
52
|
+
```javascript
|
|
53
|
+
[
|
|
54
|
+
{ timestamp: "00:00:00", text: "First paragraph of merged text..." },
|
|
55
|
+
{ timestamp: "00:02:15", text: "Second paragraph..." },
|
|
56
|
+
// ...
|
|
57
|
+
]
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
### 3. Language Detection
|
|
61
|
+
|
|
62
|
+
Analyze the first 500 characters of the transcript to determine the primary UI language:
|
|
63
|
+
|
|
64
|
+
1. Count Unicode script ranges in the text:
|
|
65
|
+
- Cyrillic: U+0400-U+04FF (Russian, Ukrainian, Bulgarian, Serbian, etc.)
|
|
66
|
+
- Latin: U+0041-U+024F
|
|
67
|
+
- CJK: U+4E00-U+9FFF, U+3040-U+309F, U+30A0-U+30FF
|
|
68
|
+
- Arabic: U+0600-U+06FF
|
|
69
|
+
2. Pick the dominant script (highest character count).
|
|
70
|
+
3. Map to UI language:
|
|
71
|
+
- Cyrillic-dominant -> `ru` (Russian UI strings)
|
|
72
|
+
- Latin-dominant -> `en` (English UI strings)
|
|
73
|
+
- Other scripts -> `en` (fallback; UI strings in English)
|
|
74
|
+
|
|
75
|
+
This determines UI strings only (button labels, search placeholder, stats labels).
|
|
76
|
+
The transcript content itself is rendered as-is regardless of language.
|
|
77
|
+
|
|
78
|
+
> **Limitation:** UI strings are currently available in Russian and English only. For other
|
|
79
|
+
> Cyrillic-script languages (Ukrainian, Bulgarian), Russian UI strings are used as the closest
|
|
80
|
+
> available option. Adding more UI languages requires extending the strings table in Step 2.
|
|
81
|
+
|
|
82
|
+
### 4. Metadata Collection
|
|
83
|
+
|
|
84
|
+
Build metadata object:
|
|
85
|
+
|
|
86
|
+
```javascript
|
|
87
|
+
{
|
|
88
|
+
title: "", // From YouTube title, or ask user
|
|
89
|
+
description: "", // First 160 chars of transcript (for SEO)
|
|
90
|
+
author: "", // From YouTube channel, or ask user
|
|
91
|
+
language: "ru|en",
|
|
92
|
+
sourceUrl: "", // YouTube URL if provided
|
|
93
|
+
videoId: "", // Extracted from YouTube URL
|
|
94
|
+
duration: "", // Video duration if YouTube
|
|
95
|
+
publishDate: "", // Video publish date if YouTube
|
|
96
|
+
wordCount: 0, // Computed after text extraction
|
|
97
|
+
estimatedReadTime: 0 // wordCount / 200 (avg reading speed)
|
|
98
|
+
}
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
### 5. Output
|
|
102
|
+
|
|
103
|
+
Pass to Step 1:
|
|
104
|
+
- `rawText`: Full transcript text (cleaned)
|
|
105
|
+
- `timestamps`: Array of `{ timestamp, text }` pairs (or empty if no timestamps)
|
|
106
|
+
- `metadata`: Metadata object
|
|
107
|
+
- `hasVideo`: Boolean (true if YouTube URL provided)
|
|
108
|
+
- `videoId`: YouTube video ID (or null)
|
|
109
|
+
|
|
110
|
+
## Edge Cases
|
|
111
|
+
|
|
112
|
+
| Case | Handling |
|
|
113
|
+
|------|----------|
|
|
114
|
+
| yt-dlp not installed | Prompt user to install or paste text manually |
|
|
115
|
+
| No subtitles available | Inform user, ask for manual transcript |
|
|
116
|
+
| VTT in unexpected format | Fallback to line-by-line parsing |
|
|
117
|
+
| Very short transcript (<500 words) | Warn: site may have minimal content |
|
|
118
|
+
| Very long transcript (>50K words) | Proceed normally; long content benefits most from navigation |
|
|
119
|
+
| Multiple subtitle languages | Prefer user's detected language, then `ru`, then `en` |
|
|
120
|
+
|
|
121
|
+
## Checkpoint
|
|
122
|
+
|
|
123
|
+
```
|
|
124
|
+
Step 0/5: Input Analysis Complete
|
|
125
|
+
Input type: [text | YouTube | combined]
|
|
126
|
+
Language: [ru | en]
|
|
127
|
+
Word count: [N] (~[M] min read)
|
|
128
|
+
Sections hint: ~[K] sections expected
|
|
129
|
+
Video: [yes (videoId) | no]
|
|
130
|
+
|
|
131
|
+
"ok" to continue | "[feedback]" to adjust
|
|
132
|
+
```
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
# Step 1: Content Parsing
|
|
2
|
+
|
|
3
|
+
## Purpose
|
|
4
|
+
|
|
5
|
+
Split raw transcript text into logical sections with titles, timestamps, and word counts.
|
|
6
|
+
|
|
7
|
+
## Protocol
|
|
8
|
+
|
|
9
|
+
### 1. Section Detection Strategy
|
|
10
|
+
|
|
11
|
+
Try these strategies in order until one yields 3+ sections:
|
|
12
|
+
|
|
13
|
+
#### Strategy A: Explicit Markers
|
|
14
|
+
Look for existing structure in the text:
|
|
15
|
+
- Markdown headings (`## Title`, `### Title`)
|
|
16
|
+
- Numbered headers (`1. Topic`, `2. Topic`)
|
|
17
|
+
- Bold markers (`**Topic:**`)
|
|
18
|
+
- Speaker labels (`Speaker Name:`, `Host:`, `Guest:`)
|
|
19
|
+
- Explicit section breaks (`---`, `===`, blank lines > 3)
|
|
20
|
+
|
|
21
|
+
#### Strategy B: Topic Shift Detection
|
|
22
|
+
If no explicit markers found:
|
|
23
|
+
- Analyze paragraphs for semantic topic shifts
|
|
24
|
+
- Group related paragraphs into sections
|
|
25
|
+
- Target 5-15 sections for optimal navigation
|
|
26
|
+
- Each section should be 200-2000 words
|
|
27
|
+
|
|
28
|
+
#### Strategy C: Time-Based Splitting (for YouTube with timestamps)
|
|
29
|
+
If timestamps are available:
|
|
30
|
+
- Group content into ~5-minute segments
|
|
31
|
+
- Adjust boundaries to natural pause points
|
|
32
|
+
- Use topic keywords from each segment for titles
|
|
33
|
+
|
|
34
|
+
### 2. Title Generation
|
|
35
|
+
|
|
36
|
+
For each section, generate a concise title (3-8 words):
|
|
37
|
+
- Extract the main topic or key phrase
|
|
38
|
+
- Use sentence case
|
|
39
|
+
- Avoid generic titles ("Part 1", "Continued")
|
|
40
|
+
- If speakers are identified, optionally include: "Speaker Name: Topic"
|
|
41
|
+
|
|
42
|
+
### 3. Timestamp Association
|
|
43
|
+
|
|
44
|
+
For each section:
|
|
45
|
+
- Assign the timestamp of its first paragraph
|
|
46
|
+
- Format: `HH:MM:SS` or `MM:SS` (depending on duration)
|
|
47
|
+
- If no timestamps available, set to `null`
|
|
48
|
+
|
|
49
|
+
### 4. Section Schema
|
|
50
|
+
|
|
51
|
+
```javascript
|
|
52
|
+
{
|
|
53
|
+
id: "section-slug", // kebab-case from title
|
|
54
|
+
order: 1, // 1-based sequential
|
|
55
|
+
title: "Section Title",
|
|
56
|
+
shortTitle: "Short", // 2-3 words for mobile TOC
|
|
57
|
+
timestamp: "00:05:30", // or null
|
|
58
|
+
timestampSeconds: 330, // for YouTube seek, or null
|
|
59
|
+
content: "Full text...", // Markdown-safe text
|
|
60
|
+
wordCount: 450,
|
|
61
|
+
speakerName: "Boris", // or null if not identified
|
|
62
|
+
speakerRole: "Guest" // "Host" | "Guest" | null
|
|
63
|
+
}
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
### 5. Speaker Detection
|
|
67
|
+
|
|
68
|
+
If the transcript has multiple speakers:
|
|
69
|
+
- Detect speaker labels (Name:, [Name], SPEAKER_NAME:)
|
|
70
|
+
- Assign speaker metadata to each section
|
|
71
|
+
- Generate speaker list for metadata:
|
|
72
|
+
```javascript
|
|
73
|
+
speakers: [
|
|
74
|
+
{ name: "Boris Cherny", role: "Guest" },
|
|
75
|
+
{ name: "Gergely Orosz", role: "Host" }
|
|
76
|
+
]
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
### 6. Content Cleaning
|
|
80
|
+
|
|
81
|
+
For each section's content:
|
|
82
|
+
- Normalize whitespace (collapse multiple spaces/newlines)
|
|
83
|
+
- Fix broken sentences from VTT merging
|
|
84
|
+
- Preserve paragraph breaks (double newline)
|
|
85
|
+
- Escape HTML special characters (`<`, `>`, `&`, `"`)
|
|
86
|
+
- Convert `**bold**` to retain emphasis
|
|
87
|
+
- Remove timecode artifacts if they appear inline
|
|
88
|
+
|
|
89
|
+
## Output
|
|
90
|
+
|
|
91
|
+
Pass to Step 2:
|
|
92
|
+
- `sections`: Array of section objects (schema above)
|
|
93
|
+
- `speakers`: Array of speaker objects (or empty)
|
|
94
|
+
- `totalWordCount`: Sum of all section word counts
|
|
95
|
+
- `estimatedReadTime`: totalWordCount / 200, rounded up
|
|
96
|
+
|
|
97
|
+
## Edge Cases
|
|
98
|
+
|
|
99
|
+
| Case | Handling |
|
|
100
|
+
|------|----------|
|
|
101
|
+
| Only 1-2 sections detected | Warn user, suggest splitting by time or paragraphs |
|
|
102
|
+
| Section > 3000 words | Auto-split at paragraph boundaries |
|
|
103
|
+
| No clear topic shifts | Split every ~500 words with generated titles |
|
|
104
|
+
| Mixed languages in transcript | Keep as-is, note in metadata |
|
|
105
|
+
| Code blocks in transcript | Preserve with ``` markers |
|
|
106
|
+
|
|
107
|
+
## Checkpoint
|
|
108
|
+
|
|
109
|
+
```
|
|
110
|
+
Step 1/5: Content Parsing Complete
|
|
111
|
+
Sections: [N] sections created
|
|
112
|
+
Speakers: [names or "single speaker"]
|
|
113
|
+
Timestamps: [available | not available]
|
|
114
|
+
Avg section length: [N] words
|
|
115
|
+
|
|
116
|
+
"ok" to continue | "[feedback]" to adjust
|
|
117
|
+
```
|
|
@@ -0,0 +1,293 @@
|
|
|
1
|
+
# Step 2: Site Generation
|
|
2
|
+
|
|
3
|
+
## Purpose
|
|
4
|
+
|
|
5
|
+
Generate the complete `docs/index.html` — a self-contained static page with all transcript content, Tailwind CSS via CDN, SEO meta, and responsive layout.
|
|
6
|
+
|
|
7
|
+
## Protocol
|
|
8
|
+
|
|
9
|
+
### 1. Create docs/ Directory
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
mkdir -p docs/static
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
### 2. Generate index.html
|
|
16
|
+
|
|
17
|
+
The HTML file follows this structure:
|
|
18
|
+
|
|
19
|
+
```html
|
|
20
|
+
<!DOCTYPE html>
|
|
21
|
+
<html lang="{language}" class="scroll-smooth">
|
|
22
|
+
<head>
|
|
23
|
+
<meta charset="UTF-8" />
|
|
24
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
25
|
+
<title>{TITLE}</title>
|
|
26
|
+
<meta name="description" content="{DESCRIPTION_160_CHARS}" />
|
|
27
|
+
<meta name="author" content="{AUTHOR}" />
|
|
28
|
+
|
|
29
|
+
<!-- Open Graph -->
|
|
30
|
+
<meta property="og:title" content="{TITLE}" />
|
|
31
|
+
<meta property="og:description" content="{DESCRIPTION}" />
|
|
32
|
+
<meta property="og:type" content="{article|video.other}" />
|
|
33
|
+
<meta property="og:url" content="https://{username}.github.io/{repo}/" />
|
|
34
|
+
<!-- If YouTube: -->
|
|
35
|
+
<meta property="og:image" content="https://img.youtube.com/vi/{VIDEO_ID}/maxresdefault.jpg" />
|
|
36
|
+
<meta property="og:video" content="https://www.youtube.com/embed/{VIDEO_ID}" />
|
|
37
|
+
|
|
38
|
+
<!-- Twitter Card -->
|
|
39
|
+
<meta name="twitter:card" content="summary_large_image" />
|
|
40
|
+
<meta name="twitter:title" content="{TITLE}" />
|
|
41
|
+
<meta name="twitter:description" content="{DESCRIPTION}" />
|
|
42
|
+
|
|
43
|
+
<!-- JSON-LD Structured Data -->
|
|
44
|
+
<script type="application/ld+json">
|
|
45
|
+
{
|
|
46
|
+
"@context": "https://schema.org",
|
|
47
|
+
"@type": "Article",
|
|
48
|
+
"headline": "{TITLE}",
|
|
49
|
+
"author": { "@type": "Person", "name": "{AUTHOR}" },
|
|
50
|
+
"datePublished": "{DATE}",
|
|
51
|
+
"description": "{DESCRIPTION}",
|
|
52
|
+
"wordCount": {WORD_COUNT}
|
|
53
|
+
}
|
|
54
|
+
</script>
|
|
55
|
+
|
|
56
|
+
<!-- If YouTube, add VideoObject: -->
|
|
57
|
+
<script type="application/ld+json">
|
|
58
|
+
{
|
|
59
|
+
"@context": "https://schema.org",
|
|
60
|
+
"@type": "VideoObject",
|
|
61
|
+
"name": "{TITLE}",
|
|
62
|
+
"description": "{DESCRIPTION}",
|
|
63
|
+
"thumbnailUrl": "https://img.youtube.com/vi/{VIDEO_ID}/maxresdefault.jpg",
|
|
64
|
+
"uploadDate": "{PUBLISH_DATE}",
|
|
65
|
+
"contentUrl": "{YOUTUBE_URL}",
|
|
66
|
+
"embedUrl": "https://www.youtube.com/embed/{VIDEO_ID}"
|
|
67
|
+
}
|
|
68
|
+
</script>
|
|
69
|
+
|
|
70
|
+
<!-- Tailwind CSS via CDN -->
|
|
71
|
+
<script src="https://cdn.tailwindcss.com"></script>
|
|
72
|
+
<script>
|
|
73
|
+
tailwind.config = {
|
|
74
|
+
darkMode: 'class',
|
|
75
|
+
theme: {
|
|
76
|
+
extend: {
|
|
77
|
+
colors: {
|
|
78
|
+
primary: { 50: '#eef2ff', 100: '#e0e7ff', 200: '#c7d2fe', 300: '#a5b4fc',
|
|
79
|
+
400: '#818cf8', 500: '#6366f1', 600: '#4f46e5', 700: '#4338ca',
|
|
80
|
+
800: '#3730a3', 900: '#312e81', 950: '#1e1b4b' }
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
</script>
|
|
86
|
+
|
|
87
|
+
<!-- Font Awesome for icons (with SRI hash) -->
|
|
88
|
+
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.1/css/all.min.css"
|
|
89
|
+
integrity="sha512-DTOQO9RWCH3ppGqcWaEA1BIZOC6xxalwEsw9c2QQeAIftl+Vegovlnee1c9QX4TctnWMn13TZye+giMm8e2LwA=="
|
|
90
|
+
crossorigin="anonymous" referrerpolicy="no-referrer" />
|
|
91
|
+
|
|
92
|
+
<link rel="stylesheet" href="static/style.css" />
|
|
93
|
+
</head>
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
### 3. Body Structure
|
|
97
|
+
|
|
98
|
+
```html
|
|
99
|
+
<body class="bg-white dark:bg-gray-900 text-gray-900 dark:text-gray-100 transition-colors duration-300">
|
|
100
|
+
|
|
101
|
+
<!-- Reading Progress Bar -->
|
|
102
|
+
<div id="progress-bar" class="fixed top-0 left-0 h-1 bg-primary-500 z-50 transition-all duration-150" style="width: 0%"></div>
|
|
103
|
+
|
|
104
|
+
<!-- Skip Navigation Link -->
|
|
105
|
+
<a href="#main-content" class="sr-only focus:not-sr-only focus:absolute focus:top-2 focus:left-2 focus:z-50 focus:px-4 focus:py-2 focus:bg-primary-500 focus:text-white focus:rounded-lg">
|
|
106
|
+
Skip to content
|
|
107
|
+
</a>
|
|
108
|
+
|
|
109
|
+
<!-- Header -->
|
|
110
|
+
<header class="sticky top-0 z-40 bg-white/95 dark:bg-gray-900/95 backdrop-blur-sm border-b border-gray-200 dark:border-gray-700" role="banner">
|
|
111
|
+
<div class="max-w-7xl mx-auto px-4 py-3 flex items-center justify-between">
|
|
112
|
+
<div class="flex items-center gap-3">
|
|
113
|
+
<!-- Mobile menu button -->
|
|
114
|
+
<button id="menu-toggle" class="lg:hidden p-2 rounded-lg hover:bg-gray-100 dark:hover:bg-gray-800">
|
|
115
|
+
<i class="fas fa-bars text-lg"></i>
|
|
116
|
+
</button>
|
|
117
|
+
<div>
|
|
118
|
+
<h1 class="text-lg font-bold text-primary-700 dark:text-primary-400 line-clamp-1">{TITLE}</h1>
|
|
119
|
+
<p class="text-xs text-gray-500 dark:text-gray-400">
|
|
120
|
+
<i class="far fa-clock"></i> {READ_TIME} {min_label} ·
|
|
121
|
+
<i class="far fa-file-alt"></i> {WORD_COUNT} {words_label} ·
|
|
122
|
+
{SECTION_COUNT} {sections_label}
|
|
123
|
+
</p>
|
|
124
|
+
</div>
|
|
125
|
+
</div>
|
|
126
|
+
<div class="flex items-center gap-2">
|
|
127
|
+
<button id="search-btn" class="p-2 rounded-lg hover:bg-gray-100 dark:hover:bg-gray-800" title="Ctrl+K">
|
|
128
|
+
<i class="fas fa-search"></i>
|
|
129
|
+
</button>
|
|
130
|
+
<button id="theme-toggle" class="p-2 rounded-lg hover:bg-gray-100 dark:hover:bg-gray-800">
|
|
131
|
+
<i class="fas fa-moon" id="theme-icon"></i>
|
|
132
|
+
</button>
|
|
133
|
+
</div>
|
|
134
|
+
</div>
|
|
135
|
+
</header>
|
|
136
|
+
|
|
137
|
+
<!-- Main Layout -->
|
|
138
|
+
<div class="max-w-7xl mx-auto flex">
|
|
139
|
+
|
|
140
|
+
<!-- Sidebar TOC (desktop) / Slide-out (mobile) -->
|
|
141
|
+
<nav id="sidebar" aria-label="Table of Contents" class="fixed lg:sticky top-16 left-0 h-[calc(100vh-4rem)] w-72 bg-white dark:bg-gray-900 border-r border-gray-200 dark:border-gray-700 overflow-y-auto transform -translate-x-full lg:translate-x-0 transition-transform duration-300 z-30 no-print">
|
|
142
|
+
<div class="p-4">
|
|
143
|
+
<h2 class="text-sm font-semibold text-gray-500 dark:text-gray-400 uppercase tracking-wider mb-3">
|
|
144
|
+
{toc_label}
|
|
145
|
+
</h2>
|
|
146
|
+
<ul class="space-y-1">
|
|
147
|
+
<!-- For each section: -->
|
|
148
|
+
<li>
|
|
149
|
+
<a href="#section-{id}" class="toc-link block px-3 py-2 text-sm rounded-lg hover:bg-gray-100 dark:hover:bg-gray-800 text-gray-700 dark:text-gray-300 transition-colors" data-section="section-{id}">
|
|
150
|
+
{section_title}
|
|
151
|
+
</a>
|
|
152
|
+
</li>
|
|
153
|
+
</ul>
|
|
154
|
+
</div>
|
|
155
|
+
</nav>
|
|
156
|
+
|
|
157
|
+
<!-- Main Content -->
|
|
158
|
+
<main id="main-content" class="flex-1 min-w-0 px-4 py-8 lg:px-8" role="main">
|
|
159
|
+
|
|
160
|
+
<!-- YouTube Embed (if video URL provided) -->
|
|
161
|
+
<div class="mb-8 rounded-xl overflow-hidden shadow-lg aspect-video max-w-3xl mx-auto">
|
|
162
|
+
<iframe id="yt-player" src="https://www.youtube.com/embed/{VIDEO_ID}?enablejsapi=1&origin=https://{username}.github.io"
|
|
163
|
+
class="w-full h-full" frameborder="0"
|
|
164
|
+
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture"
|
|
165
|
+
allowfullscreen></iframe>
|
|
166
|
+
</div>
|
|
167
|
+
|
|
168
|
+
<!-- Transcript Sections -->
|
|
169
|
+
<!-- For each section: -->
|
|
170
|
+
<section id="section-{id}" class="mb-12 scroll-mt-20">
|
|
171
|
+
<div class="flex items-start justify-between mb-4">
|
|
172
|
+
<h2 class="text-2xl font-bold text-gray-900 dark:text-white">
|
|
173
|
+
<!-- If timestamp: -->
|
|
174
|
+
<a href="#{id}" role="button" data-seek="{seconds}" class="timestamp-link text-primary-500 hover:text-primary-600 text-sm font-mono mr-2">{timestamp}</a>
|
|
175
|
+
{section_title}
|
|
176
|
+
</h2>
|
|
177
|
+
<button data-copy="section-{id}" class="copy-btn flex-shrink-0 p-2 rounded-lg hover:bg-gray-100 dark:hover:bg-gray-800 text-gray-400 hover:text-gray-600 dark:hover:text-gray-300 no-print" title="{copy_label}">
|
|
178
|
+
<i class="far fa-copy"></i>
|
|
179
|
+
</button>
|
|
180
|
+
</div>
|
|
181
|
+
<!-- If speaker identified: -->
|
|
182
|
+
<div class="mb-3 flex items-center gap-2">
|
|
183
|
+
<span class="inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium bg-primary-100 text-primary-800 dark:bg-primary-900 dark:text-primary-200">
|
|
184
|
+
{speaker_name} · {speaker_role}
|
|
185
|
+
</span>
|
|
186
|
+
</div>
|
|
187
|
+
<div class="prose prose-lg dark:prose-invert max-w-none">
|
|
188
|
+
<!-- Transcript content paragraphs as <p> tags -->
|
|
189
|
+
<p>{paragraph_1}</p>
|
|
190
|
+
<p>{paragraph_2}</p>
|
|
191
|
+
</div>
|
|
192
|
+
</section>
|
|
193
|
+
|
|
194
|
+
<!-- Footer -->
|
|
195
|
+
<footer class="border-t border-gray-200 dark:border-gray-700 mt-16 pt-8 pb-12 text-center text-sm text-gray-500 dark:text-gray-400">
|
|
196
|
+
<p>{AUTHOR} · {DATE}</p>
|
|
197
|
+
<!-- If YouTube: -->
|
|
198
|
+
<p class="mt-2">
|
|
199
|
+
<a href="{YOUTUBE_URL}" target="_blank" class="text-primary-500 hover:text-primary-600">
|
|
200
|
+
<i class="fab fa-youtube"></i> {watch_video_label}
|
|
201
|
+
</a>
|
|
202
|
+
</p>
|
|
203
|
+
</footer>
|
|
204
|
+
</main>
|
|
205
|
+
</div>
|
|
206
|
+
|
|
207
|
+
<!-- Search Modal -->
|
|
208
|
+
<div id="search-modal" class="hidden fixed inset-0 z-50 bg-black/50 backdrop-blur-sm flex items-start justify-center pt-[15vh]" role="dialog" aria-modal="true" aria-label="Search">
|
|
209
|
+
<div class="bg-white dark:bg-gray-800 rounded-xl shadow-2xl w-full max-w-lg mx-4 overflow-hidden">
|
|
210
|
+
<div class="p-4 border-b border-gray-200 dark:border-gray-700">
|
|
211
|
+
<div class="flex items-center gap-3">
|
|
212
|
+
<i class="fas fa-search text-gray-400"></i>
|
|
213
|
+
<input id="search-input" type="text" placeholder="{search_placeholder}" class="flex-1 bg-transparent outline-none text-lg" autocomplete="off" />
|
|
214
|
+
<kbd class="hidden sm:inline-flex px-2 py-1 text-xs bg-gray-100 dark:bg-gray-700 rounded">{esc_label}</kbd>
|
|
215
|
+
</div>
|
|
216
|
+
</div>
|
|
217
|
+
<div id="search-results" class="max-h-[50vh] overflow-y-auto p-2">
|
|
218
|
+
<!-- Results populated by app.js -->
|
|
219
|
+
</div>
|
|
220
|
+
</div>
|
|
221
|
+
</div>
|
|
222
|
+
|
|
223
|
+
<!-- Back to Top Button -->
|
|
224
|
+
<button id="back-to-top" class="hidden fixed bottom-8 right-8 p-3 rounded-full bg-primary-500 text-white shadow-lg hover:bg-primary-600 transition-all duration-300 hover:scale-110 z-30 no-print">
|
|
225
|
+
<i class="fas fa-arrow-up"></i>
|
|
226
|
+
</button>
|
|
227
|
+
|
|
228
|
+
<script src="static/app.js"></script>
|
|
229
|
+
</body>
|
|
230
|
+
</html>
|
|
231
|
+
```
|
|
232
|
+
|
|
233
|
+
### 4. Content Rendering Rules
|
|
234
|
+
|
|
235
|
+
When rendering transcript content into HTML:
|
|
236
|
+
- Each paragraph becomes a `<p>` tag inside `.prose`
|
|
237
|
+
- `**bold**` markers → `<strong>bold</strong>`
|
|
238
|
+
- `*italic*` → `<em>italic</em>`
|
|
239
|
+
- Code backticks → `<code class="bg-gray-100 dark:bg-gray-800 px-1.5 py-0.5 rounded text-sm">code</code>`
|
|
240
|
+
- URLs → `<a href="url" target="_blank" class="text-primary-500 hover:underline">url</a>`
|
|
241
|
+
- Escape HTML entities in transcript text (`<`, `>`, `&`, `"`)
|
|
242
|
+
- Newlines within a section become paragraph breaks
|
|
243
|
+
|
|
244
|
+
### 5. Generate style.css
|
|
245
|
+
|
|
246
|
+
```css
|
|
247
|
+
/* docs/static/style.css */
|
|
248
|
+
h1 { font-family: Arial, Helvetica, sans-serif; }
|
|
249
|
+
|
|
250
|
+
@media print {
|
|
251
|
+
.no-print { display: none !important; }
|
|
252
|
+
body { font-size: 12pt; color: black !important; background: white !important; }
|
|
253
|
+
section { break-inside: avoid; page-break-inside: avoid; }
|
|
254
|
+
h2 { break-after: avoid; }
|
|
255
|
+
a[href]::after { content: " (" attr(href) ")"; font-size: 0.8em; color: gray; }
|
|
256
|
+
.prose { max-width: 100% !important; }
|
|
257
|
+
#sidebar, #progress-bar, #back-to-top, #search-modal, .copy-btn { display: none !important; }
|
|
258
|
+
}
|
|
259
|
+
```
|
|
260
|
+
|
|
261
|
+
### 6. Language-Specific UI Strings
|
|
262
|
+
|
|
263
|
+
| Key | Russian (ru) | English (en) |
|
|
264
|
+
|-----|-------------|-------------|
|
|
265
|
+
| toc_label | Содержание | Table of Contents |
|
|
266
|
+
| search_placeholder | Поиск по транскрипту... | Search transcript... |
|
|
267
|
+
| esc_label | Esc | Esc |
|
|
268
|
+
| copy_label | Скопировать | Copy |
|
|
269
|
+
| copied_label | Скопировано! | Copied! |
|
|
270
|
+
| no_results | Ничего не найдено | No results found |
|
|
271
|
+
| watch_video_label | Смотреть видео | Watch video |
|
|
272
|
+
| min_label | мин чтения | min read |
|
|
273
|
+
| words_label | слов | words |
|
|
274
|
+
| sections_label | разделов | sections |
|
|
275
|
+
| back_to_top | Наверх | Back to top |
|
|
276
|
+
|
|
277
|
+
## Output
|
|
278
|
+
|
|
279
|
+
Files created:
|
|
280
|
+
- `docs/index.html` (~50-100 KB depending on transcript length)
|
|
281
|
+
- `docs/static/style.css` (~500 B)
|
|
282
|
+
|
|
283
|
+
## Checkpoint
|
|
284
|
+
|
|
285
|
+
```
|
|
286
|
+
Step 2/5: Site Generation Complete
|
|
287
|
+
Files: docs/index.html ({N} KB), docs/static/style.css
|
|
288
|
+
Sections: {N} rendered
|
|
289
|
+
SEO: OG + Twitter + JSON-LD configured
|
|
290
|
+
YouTube: {embedded | not included}
|
|
291
|
+
|
|
292
|
+
"ok" to continue | "[feedback]" to adjust
|
|
293
|
+
```
|