@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.
Files changed (105) hide show
  1. package/README.md +70 -10
  2. package/bin/cli.js +0 -0
  3. package/package.json +5 -3
  4. package/src/utils.js +1 -1
  5. package/templates/.claude/commands/analyst-manual.md +38 -0
  6. package/templates/.claude/commands/brain-export.md +2 -0
  7. package/templates/.claude/commands/bto-benchmark.md +302 -0
  8. package/templates/.claude/commands/casarium.md +55 -4
  9. package/templates/.claude/commands/feature-adr.md +8 -0
  10. package/templates/.claude/commands/harvest.md +28 -46
  11. package/templates/.claude/rules/trust-tiers.md +6 -0
  12. package/templates/.claude/shards/feature-adr.shard.md +64 -10
  13. package/templates/.claude/shards/phase-ai-factory.shard.md +109 -0
  14. package/templates/.claude/skills/ai-factory-mapper/README.md +90 -0
  15. package/templates/.claude/skills/ai-factory-mapper/SKILL.md +309 -0
  16. package/templates/.claude/skills/ai-factory-mapper/assets/report-template.md +123 -0
  17. package/templates/.claude/skills/ai-factory-mapper/references/catalog.md +230 -0
  18. package/templates/.claude/skills/ai-factory-mapper/references/coverage-formula.md +219 -0
  19. package/templates/.claude/skills/ai-factory-mapper/references/decomposition-checklist.md +183 -0
  20. package/templates/.claude/skills/ai-factory-mapper/references/pattern-library.md +312 -0
  21. package/templates/.claude/skills/ai-factory-mapper/scripts/build_docx_report.js +423 -0
  22. package/templates/.claude/skills/analyst-manual-full/SKILL.md +286 -0
  23. package/templates/.claude/skills/edu-site-generator/SKILL.md +254 -0
  24. package/templates/.claude/skills/edu-site-generator/examples/sample-course-structure.md +116 -0
  25. package/templates/.claude/skills/edu-site-generator/modules/00-content-analysis.md +84 -0
  26. package/templates/.claude/skills/edu-site-generator/modules/01-course-structure.md +75 -0
  27. package/templates/.claude/skills/edu-site-generator/modules/02-data-generation.md +186 -0
  28. package/templates/.claude/skills/edu-site-generator/modules/03-scaffold.md +249 -0
  29. package/templates/.claude/skills/edu-site-generator/modules/04-components.md +130 -0
  30. package/templates/.claude/skills/edu-site-generator/modules/05-gamification.md +163 -0
  31. package/templates/.claude/skills/edu-site-generator/modules/06-deploy.md +88 -0
  32. package/templates/.claude/skills/edu-site-generator/modules/07-verification.md +97 -0
  33. package/templates/.claude/skills/edu-site-generator/references/component-templates.md +436 -0
  34. package/templates/.claude/skills/edu-site-generator/references/data-schemas.md +164 -0
  35. package/templates/.claude/skills/edu-site-generator/references/exercise-catalog.md +110 -0
  36. package/templates/.claude/skills/edu-site-generator/references/tech-stack.md +69 -0
  37. package/templates/.claude/skills/feature-adr/SKILL.md +245 -59
  38. package/templates/.claude/skills/feature-adr/modules/03-adr.md +43 -0
  39. package/templates/.claude/skills/feature-adr/modules/03.5-ideation-swarm.md +180 -0
  40. package/templates/.claude/skills/feature-adr/modules/06-implementation-plan.md +56 -7
  41. package/templates/.claude/skills/feature-adr/modules/08-qe.md +87 -23
  42. package/templates/.claude/skills/feature-adr/modules/09-fleet-qe.md +305 -0
  43. package/templates/.claude/skills/feature-adr/references/agentic-qe/README.md +143 -0
  44. package/templates/.claude/skills/feature-adr/references/agentic-qe/brutal-honesty-review.md +240 -0
  45. package/templates/.claude/skills/feature-adr/references/agentic-qe/chaos-engineering-resilience.md +163 -0
  46. package/templates/.claude/skills/feature-adr/references/agentic-qe/code-goal-planner.md +446 -0
  47. package/templates/.claude/skills/feature-adr/references/agentic-qe/enterprise-integration-testing.md +111 -0
  48. package/templates/.claude/skills/feature-adr/references/agentic-qe/mutation-testing.md +236 -0
  49. package/templates/.claude/skills/feature-adr/references/agentic-qe/performance-testing.md +315 -0
  50. package/templates/.claude/skills/feature-adr/references/agentic-qe/qcsd-ideation-swarm.md +126 -0
  51. package/templates/.claude/skills/feature-adr/references/agentic-qe/qcsd-production-swarm.md +108 -0
  52. package/templates/.claude/skills/feature-adr/references/agentic-qe/qe-coverage-analysis.md +193 -0
  53. package/templates/.claude/skills/feature-adr/references/agentic-qe/qe-requirements-validation.md +254 -0
  54. package/templates/.claude/skills/feature-adr/references/agentic-qe/regression-testing.md +233 -0
  55. package/templates/.claude/skills/feature-adr/references/agentic-qe/risk-based-testing.md +212 -0
  56. package/templates/.claude/skills/feature-adr/references/agentic-qe/security-testing.md +311 -0
  57. package/templates/.claude/skills/feature-adr/references/agentic-qe/shift-left-testing.md +231 -0
  58. package/templates/.claude/skills/feature-adr/references/agentic-qe/tdd-london-chicago.md +249 -0
  59. package/templates/.claude/skills/knowledge-extractor/SKILL.md +254 -0
  60. package/templates/.claude/skills/knowledge-extractor/modules/01-extract.md +188 -0
  61. package/templates/.claude/skills/knowledge-extractor/modules/02-classify.md +99 -0
  62. package/templates/.claude/skills/knowledge-extractor/modules/03-gate.md +150 -0
  63. package/templates/.claude/skills/knowledge-extractor/modules/04-integrate.md +159 -0
  64. package/templates/.claude/skills/knowledge-extractor/references/artifact-categories.md +100 -0
  65. package/templates/.claude/skills/knowledge-extractor/references/maturity-model.md +94 -0
  66. package/templates/.claude/skills/knowledge-extractor/references/quality-gates.md +98 -0
  67. package/templates/.claude/skills/knowledge-extractor/templates/artifact-card.md +63 -0
  68. package/templates/.claude/skills/knowledge-extractor/templates/harvest-report.md +102 -0
  69. package/templates/.claude/skills/transcript-site-generator/SKILL.md +287 -0
  70. package/templates/.claude/skills/transcript-site-generator/examples/sample-text-only-site.md +123 -0
  71. package/templates/.claude/skills/transcript-site-generator/examples/sample-transcript-site.md +134 -0
  72. package/templates/.claude/skills/transcript-site-generator/modules/00-input-analysis.md +132 -0
  73. package/templates/.claude/skills/transcript-site-generator/modules/01-content-parsing.md +117 -0
  74. package/templates/.claude/skills/transcript-site-generator/modules/02-site-generation.md +293 -0
  75. package/templates/.claude/skills/transcript-site-generator/modules/03-interactivity.md +406 -0
  76. package/templates/.claude/skills/transcript-site-generator/modules/04-deploy.md +130 -0
  77. package/templates/.claude/skills/transcript-site-generator/modules/05-verification.md +155 -0
  78. package/templates/.claude/skills/transcript-site-generator/references/component-catalog.md +86 -0
  79. package/templates/.claude/skills/transcript-site-generator/references/data-schemas.md +123 -0
  80. package/templates/.claude/skills/transcript-site-generator/references/tech-stack.md +132 -0
  81. package/templates/CLAUDE.md +30 -9
  82. package/templates/docs/continuous-learning-guide.md +622 -0
  83. package/templates/docs/edu-site-generator/01-deployment-guide.md +911 -0
  84. package/templates/docs/edu-site-generator/02-admin-guide.md +901 -0
  85. package/templates/docs/edu-site-generator/03-user-guide.md +1008 -0
  86. package/templates/docs/edu-site-generator/04-infrastructure-requirements.md +489 -0
  87. package/templates/docs/edu-site-generator/05-architecture.md +902 -0
  88. package/templates/docs/edu-site-generator/06-user-flows.md +759 -0
  89. package/templates/docs/improvement-directions.md +8 -4
  90. package/templates/docs/keysarium-core/02-functionality.md +3 -1
  91. package/templates/docs/skills-bto/01-deployment-guide.md +1 -1
  92. package/templates/docs/skills-bto/02-admin-guide.md +4 -1
  93. package/templates/docs/skills-bto/03-user-guide.md +4 -3
  94. package/templates/docs/skills-bto/04-infrastructure-requirements.md +2 -1
  95. package/templates/docs/skills-bto/05-architecture.md +11 -11
  96. package/templates/docs/skills-bto/06-user-flows.md +2 -1
  97. package/templates/docs/transcript-site-generator/01-deployment-guide.md +1042 -0
  98. package/templates/docs/transcript-site-generator/02-admin-guide.md +918 -0
  99. package/templates/docs/transcript-site-generator/03-user-guide.md +925 -0
  100. package/templates/docs/transcript-site-generator/04-infrastructure-requirements.md +482 -0
  101. package/templates/docs/transcript-site-generator/05-architecture.md +1068 -0
  102. package/templates/docs/transcript-site-generator/06-user-flows.md +855 -0
  103. package/templates/lib/dream-engine.md +1 -1
  104. package/templates/lib/memory-protocol.md +6 -2
  105. 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 &middot; 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, `&amp;` 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} &middot;
121
+ <i class="far fa-file-alt"></i> {WORD_COUNT} {words_label} &middot;
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} &middot; {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} &middot; {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
+ ```