@tienne/gestalt 0.102.0 → 0.104.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 (179) hide show
  1. package/README.ko.md +2 -1
  2. package/README.md +2 -1
  3. package/dist/package.json +1 -1
  4. package/dist/plugin/role-agents/video-summarizer/AGENT.md +208 -108
  5. package/dist/plugin/skills/_shared/proactive-routing.md +2 -1
  6. package/dist/plugin/skills/research/references/design.md +1 -1
  7. package/dist/plugin/skills/video-digest/SKILL.md +430 -0
  8. package/dist/plugin/skills/video-digest/templates/background.md +15 -0
  9. package/dist/plugin/skills/video-digest/templates/blog.md +16 -0
  10. package/dist/plugin/skills/video-digest/templates/comments.md +19 -0
  11. package/dist/plugin/skills/video-digest/templates/counterpoints.md +15 -0
  12. package/dist/plugin/skills/video-digest/templates/flashcards.md +15 -0
  13. package/dist/plugin/skills/video-digest/templates/interview.md +15 -0
  14. package/dist/plugin/skills/video-digest/templates/meeting.md +15 -0
  15. package/dist/plugin/skills/video-digest/templates/mindmap.md +16 -0
  16. package/dist/plugin/skills/video-digest/templates/quiz.md +16 -0
  17. package/dist/plugin/skills/video-digest/templates/quotes.md +16 -0
  18. package/dist/plugin/skills/video-digest/templates/resources.md +14 -0
  19. package/dist/plugin/skills/video-digest/templates/timestamps.md +14 -0
  20. package/dist/plugin/skills/video-digest/templates/visual.md +22 -0
  21. package/dist/src/cli/commands/digest.d.ts +60 -0
  22. package/dist/src/cli/commands/digest.d.ts.map +1 -0
  23. package/dist/src/cli/commands/digest.js +401 -0
  24. package/dist/src/cli/commands/digest.js.map +1 -0
  25. package/dist/src/cli/index.d.ts.map +1 -1
  26. package/dist/src/cli/index.js +81 -0
  27. package/dist/src/cli/index.js.map +1 -1
  28. package/dist/src/digest/blocks.d.ts +5224 -0
  29. package/dist/src/digest/blocks.d.ts.map +1 -0
  30. package/dist/src/digest/blocks.js +156 -0
  31. package/dist/src/digest/blocks.js.map +1 -0
  32. package/dist/src/digest/captions.d.ts +37 -0
  33. package/dist/src/digest/captions.d.ts.map +1 -0
  34. package/dist/src/digest/captions.js +138 -0
  35. package/dist/src/digest/captions.js.map +1 -0
  36. package/dist/src/digest/comments.d.ts +113 -0
  37. package/dist/src/digest/comments.d.ts.map +1 -0
  38. package/dist/src/digest/comments.js +153 -0
  39. package/dist/src/digest/comments.js.map +1 -0
  40. package/dist/src/digest/diagram-schema.d.ts +765 -0
  41. package/dist/src/digest/diagram-schema.d.ts.map +1 -0
  42. package/dist/src/digest/diagram-schema.js +72 -0
  43. package/dist/src/digest/diagram-schema.js.map +1 -0
  44. package/dist/src/digest/format.d.ts +9 -0
  45. package/dist/src/digest/format.d.ts.map +1 -0
  46. package/dist/src/digest/format.js +26 -0
  47. package/dist/src/digest/format.js.map +1 -0
  48. package/dist/src/digest/frames.d.ts +46 -0
  49. package/dist/src/digest/frames.d.ts.map +1 -0
  50. package/dist/src/digest/frames.js +206 -0
  51. package/dist/src/digest/frames.js.map +1 -0
  52. package/dist/src/digest/index.d.ts +26 -0
  53. package/dist/src/digest/index.d.ts.map +1 -0
  54. package/dist/src/digest/index.js +26 -0
  55. package/dist/src/digest/index.js.map +1 -0
  56. package/dist/src/digest/ingest.d.ts +65 -0
  57. package/dist/src/digest/ingest.d.ts.map +1 -0
  58. package/dist/src/digest/ingest.js +303 -0
  59. package/dist/src/digest/ingest.js.map +1 -0
  60. package/dist/src/digest/lint-extension.d.ts +71 -0
  61. package/dist/src/digest/lint-extension.d.ts.map +1 -0
  62. package/dist/src/digest/lint-extension.js +512 -0
  63. package/dist/src/digest/lint-extension.js.map +1 -0
  64. package/dist/src/digest/lint.d.ts +50 -0
  65. package/dist/src/digest/lint.d.ts.map +1 -0
  66. package/dist/src/digest/lint.js +560 -0
  67. package/dist/src/digest/lint.js.map +1 -0
  68. package/dist/src/digest/merge.d.ts +40 -0
  69. package/dist/src/digest/merge.d.ts.map +1 -0
  70. package/dist/src/digest/merge.js +107 -0
  71. package/dist/src/digest/merge.js.map +1 -0
  72. package/dist/src/digest/ocr.d.ts +100 -0
  73. package/dist/src/digest/ocr.d.ts.map +1 -0
  74. package/dist/src/digest/ocr.js +179 -0
  75. package/dist/src/digest/ocr.js.map +1 -0
  76. package/dist/src/digest/prose.d.ts +47 -0
  77. package/dist/src/digest/prose.d.ts.map +1 -0
  78. package/dist/src/digest/prose.js +171 -0
  79. package/dist/src/digest/prose.js.map +1 -0
  80. package/dist/src/digest/render-blocks.d.ts +38 -0
  81. package/dist/src/digest/render-blocks.d.ts.map +1 -0
  82. package/dist/src/digest/render-blocks.js +378 -0
  83. package/dist/src/digest/render-blocks.js.map +1 -0
  84. package/dist/src/digest/render-html.d.ts +22 -0
  85. package/dist/src/digest/render-html.d.ts.map +1 -0
  86. package/dist/src/digest/render-html.js +505 -0
  87. package/dist/src/digest/render-html.js.map +1 -0
  88. package/dist/src/digest/render-md.d.ts +18 -0
  89. package/dist/src/digest/render-md.d.ts.map +1 -0
  90. package/dist/src/digest/render-md.js +126 -0
  91. package/dist/src/digest/render-md.js.map +1 -0
  92. package/dist/src/digest/render.d.ts +47 -0
  93. package/dist/src/digest/render.d.ts.map +1 -0
  94. package/dist/src/digest/render.js +126 -0
  95. package/dist/src/digest/render.js.map +1 -0
  96. package/dist/src/digest/reports.d.ts +26 -0
  97. package/dist/src/digest/reports.d.ts.map +1 -0
  98. package/dist/src/digest/reports.js +70 -0
  99. package/dist/src/digest/reports.js.map +1 -0
  100. package/dist/src/digest/scenes.d.ts +92 -0
  101. package/dist/src/digest/scenes.d.ts.map +1 -0
  102. package/dist/src/digest/scenes.js +182 -0
  103. package/dist/src/digest/scenes.js.map +1 -0
  104. package/dist/src/digest/schema-base.d.ts +31 -0
  105. package/dist/src/digest/schema-base.d.ts.map +1 -0
  106. package/dist/src/digest/schema-base.js +19 -0
  107. package/dist/src/digest/schema-base.js.map +1 -0
  108. package/dist/src/digest/schema.d.ts +12886 -0
  109. package/dist/src/digest/schema.d.ts.map +1 -0
  110. package/dist/src/digest/schema.js +215 -0
  111. package/dist/src/digest/schema.js.map +1 -0
  112. package/dist/src/digest/server.d.ts +36 -0
  113. package/dist/src/digest/server.d.ts.map +1 -0
  114. package/dist/src/digest/server.js +278 -0
  115. package/dist/src/digest/server.js.map +1 -0
  116. package/dist/src/digest/slice.d.ts +20 -0
  117. package/dist/src/digest/slice.d.ts.map +1 -0
  118. package/dist/src/digest/slice.js +48 -0
  119. package/dist/src/digest/slice.js.map +1 -0
  120. package/dist/src/digest/store.d.ts +67 -0
  121. package/dist/src/digest/store.d.ts.map +1 -0
  122. package/dist/src/digest/store.js +152 -0
  123. package/dist/src/digest/store.js.map +1 -0
  124. package/dist/src/digest/svg.d.ts +74 -0
  125. package/dist/src/digest/svg.d.ts.map +1 -0
  126. package/dist/src/digest/svg.js +415 -0
  127. package/dist/src/digest/svg.js.map +1 -0
  128. package/dist/src/digest/templates.d.ts +38 -0
  129. package/dist/src/digest/templates.d.ts.map +1 -0
  130. package/dist/src/digest/templates.js +125 -0
  131. package/dist/src/digest/templates.js.map +1 -0
  132. package/dist/src/digest/translate.d.ts +46 -0
  133. package/dist/src/digest/translate.d.ts.map +1 -0
  134. package/dist/src/digest/translate.js +50 -0
  135. package/dist/src/digest/translate.js.map +1 -0
  136. package/dist/src/digest/viewer-js.d.ts +4 -0
  137. package/dist/src/digest/viewer-js.d.ts.map +1 -0
  138. package/dist/src/digest/viewer-js.js +735 -0
  139. package/dist/src/digest/viewer-js.js.map +1 -0
  140. package/dist/src/digest/viewer-logic.d.ts +46 -0
  141. package/dist/src/digest/viewer-logic.d.ts.map +1 -0
  142. package/dist/src/digest/viewer-logic.js +89 -0
  143. package/dist/src/digest/viewer-logic.js.map +1 -0
  144. package/dist/src/digest/ytdlp.d.ts +34 -0
  145. package/dist/src/digest/ytdlp.d.ts.map +1 -0
  146. package/dist/src/digest/ytdlp.js +64 -0
  147. package/dist/src/digest/ytdlp.js.map +1 -0
  148. package/dist/src/mcp/schemas.d.ts +48 -0
  149. package/dist/src/mcp/schemas.d.ts.map +1 -1
  150. package/dist/src/mcp/schemas.js +25 -0
  151. package/dist/src/mcp/schemas.js.map +1 -1
  152. package/dist/src/mcp/server.d.ts.map +1 -1
  153. package/dist/src/mcp/server.js +7 -1
  154. package/dist/src/mcp/server.js.map +1 -1
  155. package/dist/src/mcp/tools/digest-passthrough.d.ts +3 -0
  156. package/dist/src/mcp/tools/digest-passthrough.d.ts.map +1 -0
  157. package/dist/src/mcp/tools/digest-passthrough.js +151 -0
  158. package/dist/src/mcp/tools/digest-passthrough.js.map +1 -0
  159. package/package.json +1 -1
  160. package/plugin/.codex-plugin/plugin.json +1 -1
  161. package/plugin/.mcp.json +1 -1
  162. package/plugin/mcp.json +1 -1
  163. package/plugin/role-agents/video-summarizer/AGENT.md +208 -108
  164. package/plugin/skills/_shared/proactive-routing.md +2 -1
  165. package/plugin/skills/research/references/design.md +1 -1
  166. package/plugin/skills/video-digest/SKILL.md +430 -0
  167. package/plugin/skills/video-digest/templates/background.md +15 -0
  168. package/plugin/skills/video-digest/templates/blog.md +16 -0
  169. package/plugin/skills/video-digest/templates/comments.md +19 -0
  170. package/plugin/skills/video-digest/templates/counterpoints.md +15 -0
  171. package/plugin/skills/video-digest/templates/flashcards.md +15 -0
  172. package/plugin/skills/video-digest/templates/interview.md +15 -0
  173. package/plugin/skills/video-digest/templates/meeting.md +15 -0
  174. package/plugin/skills/video-digest/templates/mindmap.md +16 -0
  175. package/plugin/skills/video-digest/templates/quiz.md +16 -0
  176. package/plugin/skills/video-digest/templates/quotes.md +16 -0
  177. package/plugin/skills/video-digest/templates/resources.md +14 -0
  178. package/plugin/skills/video-digest/templates/timestamps.md +14 -0
  179. package/plugin/skills/video-digest/templates/visual.md +22 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"blocks.d.ts","sourceRoot":"","sources":["../../../src/digest/blocks.ts"],"names":[],"mappings":"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;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAK1B,CAAC;AAEH,MAAM,MAAM,YAAY,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,kBAAkB,CAAC,CAAC;AAC9D,MAAM,MAAM,SAAS,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,eAAe,CAAC,CAAC;AACxD,MAAM,MAAM,SAAS,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,eAAe,CAAC,CAAC;AACxD,MAAM,MAAM,UAAU,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,gBAAgB,CAAC,CAAC;AAC1D,MAAM,MAAM,SAAS,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,eAAe,CAAC,CAAC;AACxD,MAAM,MAAM,YAAY,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,kBAAkB,CAAC,CAAC;AAC9D,MAAM,MAAM,WAAW,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,iBAAiB,CAAC,CAAC;AAC5D,MAAM,MAAM,aAAa,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,mBAAmB,CAAC,CAAC;AAChE,MAAM,MAAM,KAAK,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,WAAW,CAAC,CAAC;AAChD,MAAM,MAAM,SAAS,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,eAAe,CAAC,CAAC;AAExD;;;GAGG;AACH,eAAO,MAAM,YAAY,GAAI,KAAK,IAAI,CAAC,SAAS,EAAE,UAAU,GAAG,MAAM,CAAC,KAAG,MAC1C,CAAC"}
@@ -0,0 +1,156 @@
1
+ import { z } from 'zod';
2
+ import { citeSchema, LANG_TAG_PATTERN, textSchema } from './schema-base.js';
3
+ import { diagramSchema, mindmapNodeSchema } from './diagram-schema.js';
4
+ export { mindmapNodeSchema } from './diagram-schema.js';
5
+ /**
6
+ * 확장 리포트(회의록, 퀴즈 같은 템플릿 결과)를 이루는 블록.
7
+ * 템플릿은 이 중에서 쓸 블록을 고르고 렌더러가 타입마다 정해진 꼴로 그린다.
8
+ * 요약 에이전트는 HTML이나 SVG를 쓰지 않고 이 구조만 채운다
9
+ */
10
+ export const TEMPLATE_ID_PATTERN = /^[a-z0-9][a-z0-9-]{0,39}$/;
11
+ export const templateIdSchema = z
12
+ .string()
13
+ .regex(TEMPLATE_ID_PATTERN, '템플릿 id는 영문 소문자, 숫자, -만 쓴다');
14
+ // 3단 이상은 lint가 경로와 함께 잡는다. Bullet과 같은 이유다
15
+ export const listItemSchema = z.lazy(() => z.object({
16
+ text: textSchema,
17
+ cite: citeSchema.optional(),
18
+ children: z.array(listItemSchema).optional(),
19
+ }));
20
+ export const headingBlockSchema = z.object({
21
+ type: z.literal('heading'),
22
+ text: textSchema,
23
+ });
24
+ export const textBlockSchema = z.object({
25
+ type: z.literal('text'),
26
+ text: textSchema,
27
+ cite: citeSchema.optional(),
28
+ });
29
+ export const listBlockSchema = z.object({
30
+ type: z.literal('list'),
31
+ title: textSchema.optional(),
32
+ items: z.array(listItemSchema).min(1),
33
+ });
34
+ /** 대사를 그대로 옮긴 인용. 영상 언어와 리포트 언어가 다르면 번역은 translation에 따로 둔다 */
35
+ export const quoteBlockSchema = z.object({
36
+ type: z.literal('quote'),
37
+ text: textSchema,
38
+ translation: textSchema.optional(),
39
+ speaker: textSchema.optional(),
40
+ note: textSchema.optional(),
41
+ cite: citeSchema,
42
+ });
43
+ /** 영상 목차. 시각은 cite.key 문장의 시작 시각을 쓴다 */
44
+ export const timestampsBlockSchema = z.object({
45
+ type: z.literal('timestamps'),
46
+ items: z
47
+ .array(z.object({ title: textSchema, summary: textSchema.optional(), cite: citeSchema }))
48
+ .min(1)
49
+ .max(60),
50
+ });
51
+ export const actionsBlockSchema = z.object({
52
+ type: z.literal('actions'),
53
+ items: z
54
+ .array(z.object({
55
+ task: textSchema,
56
+ owner: textSchema.optional(),
57
+ due: textSchema.optional(),
58
+ cite: citeSchema.optional(),
59
+ }))
60
+ .min(1)
61
+ .max(50),
62
+ });
63
+ export const qaBlockSchema = z.object({
64
+ type: z.literal('qa'),
65
+ items: z
66
+ .array(z.object({ question: textSchema, answer: textSchema, cite: citeSchema.optional() }))
67
+ .min(1)
68
+ .max(40),
69
+ });
70
+ /** 앞면을 누르면 뒷면이 열린다. HTML은 details라 스크립트 없이 뒤집힌다 */
71
+ export const flashcardsBlockSchema = z.object({
72
+ type: z.literal('flashcards'),
73
+ cards: z
74
+ .array(z.object({ front: textSchema, back: textSchema, cite: citeSchema.optional() }))
75
+ .min(1)
76
+ .max(60),
77
+ });
78
+ /** answer는 choices의 0부터 센 자리다. 범위 밖이면 lint가 오류로 막는다 */
79
+ export const quizBlockSchema = z.object({
80
+ type: z.literal('quiz'),
81
+ questions: z
82
+ .array(z.object({
83
+ question: textSchema,
84
+ choices: z.array(textSchema).min(2).max(6),
85
+ answer: z.number().int().min(0),
86
+ explanation: textSchema,
87
+ cite: citeSchema.optional(),
88
+ }))
89
+ .min(1)
90
+ .max(30),
91
+ });
92
+ /** SVG 원문은 받지 않는다. 트리 구조만 받고 그림은 렌더러가 그린다 */
93
+ export const mindmapBlockSchema = z.object({
94
+ type: z.literal('mindmap'),
95
+ root: mindmapNodeSchema,
96
+ });
97
+ /**
98
+ * 개념 하나를 그림과 설명으로 짝지은 카드. diagram은 대섹션 도식과 같은 구조라 그림도 같은 코드가 그린다.
99
+ * 설명이 영상 어디서 나왔는지 따라가야 해서 cite는 빼지 않는다
100
+ */
101
+ export const figureBlockSchema = z.object({
102
+ type: z.literal('figure'),
103
+ title: textSchema,
104
+ diagram: diagramSchema,
105
+ explanation: textSchema,
106
+ cite: citeSchema,
107
+ });
108
+ export const COMMENT_TONES = ['positive', 'negative', 'neutral', 'question'];
109
+ /** yt-dlp가 주는 댓글 id. 영숫자와 -, _, .만 온다 */
110
+ export const commentIdSchema = z.string().regex(/^[A-Za-z0-9_.-]{1,120}$/);
111
+ /** 댓글을 성격별로 묶은 분석. examples.text는 댓글 원문이고 lint가 comments.json과 대조한다 */
112
+ export const commentsBlockSchema = z.object({
113
+ type: z.literal('comments'),
114
+ total: z.number().int().min(0),
115
+ overview: textSchema,
116
+ groups: z
117
+ .array(z.object({
118
+ title: textSchema,
119
+ tone: z.enum(COMMENT_TONES),
120
+ count: z.number().int().min(0),
121
+ summary: textSchema,
122
+ examples: z
123
+ .array(z.object({ id: commentIdSchema, text: textSchema }))
124
+ .max(3)
125
+ .default([]),
126
+ }))
127
+ .min(1)
128
+ .max(12),
129
+ });
130
+ export const blockSchema = z.discriminatedUnion('type', [
131
+ headingBlockSchema,
132
+ textBlockSchema,
133
+ listBlockSchema,
134
+ quoteBlockSchema,
135
+ timestampsBlockSchema,
136
+ actionsBlockSchema,
137
+ qaBlockSchema,
138
+ flashcardsBlockSchema,
139
+ quizBlockSchema,
140
+ mindmapBlockSchema,
141
+ figureBlockSchema,
142
+ commentsBlockSchema,
143
+ ]);
144
+ export const BLOCK_TYPES = blockSchema.options.map((o) => o.shape.type.value);
145
+ export const extensionSchema = z.object({
146
+ template: templateIdSchema,
147
+ title: textSchema,
148
+ lang: z.string().regex(LANG_TAG_PATTERN, '언어 태그(ko, en, pt-BR) 꼴이어야 한다').default('ko'),
149
+ blocks: z.array(blockSchema).min(1),
150
+ });
151
+ /**
152
+ * 같은 템플릿이라도 언어가 다르면 다른 확장이다. 탭 id와 merge 키로 쓴다.
153
+ * 템플릿 id와 언어 태그 둘 다 -를 쓰므로 둘 다 안 쓰는 .으로 잇는다
154
+ */
155
+ export const extensionKey = (ext) => `${ext.template}.${ext.lang}`;
156
+ //# sourceMappingURL=blocks.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"blocks.js","sourceRoot":"","sources":["../../../src/digest/blocks.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,37 @@
1
+ export interface Cue {
2
+ startSec: number;
3
+ text: string;
4
+ }
5
+ /** 자막에서 뽑은 단어 하나와 그 단어가 화면에 나온 시각 */
6
+ export interface TimedWord {
7
+ sec: number;
8
+ text: string;
9
+ /** 유튜브 자동 자막의 `>>`(화자 바뀜) 뒤 첫 단어. 앞 문장과 합치지 않는다 */
10
+ breakBefore?: boolean;
11
+ }
12
+ export interface MergeOptions {
13
+ /** 문장 부호가 없을 때 이만큼 쉬면 끊는다 */
14
+ pauseSec?: number;
15
+ /** 쉼으로 끊을 때 최소 글자 수. 짧은 맞장구가 문장 하나가 되지 않게 */
16
+ minChars?: number;
17
+ /** 부호도 쉼도 없이 이어지면 이 길이에서 끊는다 */
18
+ maxChars?: number;
19
+ }
20
+ export declare function toSeconds(stamp: string): number;
21
+ /** VTT와 SRT를 읽어 시작 시각과 글만 남긴다 */
22
+ export declare function parseCues(text: string): Cue[];
23
+ /**
24
+ * 큐를 단어로 쪼갠다. 유튜브 자동 자막의 `<00:00:01.200>` 태그가 있으면 단어마다 그 시각을 쓰고
25
+ * 없으면 큐 시작 시각을 쓴다. 문장이 큐 중간에서 시작해도 시작 시각이 틀어지지 않게 하려는 것이다.
26
+ */
27
+ export declare function parseTimedWords(text: string): TimedWord[];
28
+ /**
29
+ * 단어를 문장으로 합친다. 끝 부호에서 끊고 부호가 없으면 쉼 간격과 길이로 끊는다.
30
+ * 문장 시작 시각은 첫 단어의 시각이다.
31
+ */
32
+ export declare function mergeSentences(words: TimedWord[], options?: MergeOptions): Cue[];
33
+ /** 단어 시각이 없는 조각(whisper 구간 같은)을 조각 시작 시각의 단어로 편다 */
34
+ export declare function cuesToWords(cues: Cue[]): TimedWord[];
35
+ /** 자막 파일 하나를 문장 단위 큐로 만든다 */
36
+ export declare function captionsToSentences(text: string, options?: MergeOptions): Cue[];
37
+ //# sourceMappingURL=captions.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"captions.d.ts","sourceRoot":"","sources":["../../../src/digest/captions.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,GAAG;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;CACd;AAED,qCAAqC;AACrC,MAAM,WAAW,SAAS;IACxB,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,CAAC;IACb,mDAAmD;IACnD,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB;AAED,MAAM,WAAW,YAAY;IAC3B,6BAA6B;IAC7B,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,6CAA6C;IAC7C,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,gCAAgC;IAChC,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAOD,wBAAgB,SAAS,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAI/C;AAkDD,iCAAiC;AACjC,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,GAAG,EAAE,CAK7C;AAED;;;GAGG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,SAAS,EAAE,CA8BzD;AAED;;;GAGG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,SAAS,EAAE,EAAE,OAAO,GAAE,YAAiB,GAAG,GAAG,EAAE,CA2BpF;AAED,oDAAoD;AACpD,wBAAgB,WAAW,CAAC,IAAI,EAAE,GAAG,EAAE,GAAG,SAAS,EAAE,CAOpD;AAED,6BAA6B;AAC7B,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,YAAY,GAAG,GAAG,EAAE,CAE/E"}
@@ -0,0 +1,138 @@
1
+ const DEFAULT_MERGE = { pauseSec: 1.2, minChars: 40, maxChars: 220 };
2
+ const SENTENCE_END = /[.?!。?!…]["'”’)\]]*$/;
3
+ const TIME_TAG = /<(\d{1,2}:\d{2}:\d{2}[.,]\d{1,3}|\d{1,2}:\d{2}[.,]\d{1,3})>/g;
4
+ export function toSeconds(stamp) {
5
+ const parts = stamp.replace(',', '.').split(':').map(Number);
6
+ while (parts.length < 3)
7
+ parts.unshift(0);
8
+ return parts[0] * 3600 + parts[1] * 60 + parts[2];
9
+ }
10
+ const ENTITIES = {
11
+ '&amp;': '&',
12
+ '&lt;': '<',
13
+ '&gt;': '>',
14
+ '&quot;': '"',
15
+ '&#39;': "'",
16
+ '&nbsp;': ' ',
17
+ };
18
+ const decodeEntities = (s) => s.replace(/&(?:amp|lt|gt|quot|#39|nbsp);/g, (e) => ENTITIES[e]);
19
+ /** `[music]`, `[Applause]` 같은 소리 표기. 문장에 섞이면 요약 근거로 쓸 수 없다 */
20
+ const SOUND_TAG = /^\[[^\]]*\]$/;
21
+ const cleanLine = (l) => l
22
+ .replace(/<[^>]+>/g, '')
23
+ .replace(/\s+/g, ' ')
24
+ .trim();
25
+ /**
26
+ * 유튜브 자동 자막은 앞 줄이 다음 큐에 되풀이돼서, 직전 큐에 이미 나온 줄은 뺀다.
27
+ * plugin/skills/research/scripts/slide-extract.mjs의 parseCues와 같은 규칙이다. 플러그인 스크립트는 src를 import하지 않아 두 벌을 두고 테스트로 결과를 맞춘다.
28
+ */
29
+ function readBlocks(text) {
30
+ const out = [];
31
+ let prevLines = new Set();
32
+ for (const block of text.replace(/\r/g, '').split(/\n{2,}/)) {
33
+ const lines = block.split('\n');
34
+ const at = lines.findIndex((l) => l.includes('-->'));
35
+ if (at < 0)
36
+ continue;
37
+ const m = lines[at].match(/([\d:.,]+)\s*-->/);
38
+ if (!m)
39
+ continue;
40
+ const raw = lines.slice(at + 1).filter((l) => cleanLine(l));
41
+ const body = raw.map(cleanLine);
42
+ const freshRaw = raw.filter((_, k) => !prevLines.has(body[k]));
43
+ prevLines = new Set(body);
44
+ if (freshRaw.length === 0)
45
+ continue;
46
+ out.push({ startSec: toSeconds(m[1]), freshRaw });
47
+ }
48
+ return out;
49
+ }
50
+ /** VTT와 SRT를 읽어 시작 시각과 글만 남긴다 */
51
+ export function parseCues(text) {
52
+ return readBlocks(text).map((b) => ({
53
+ startSec: b.startSec,
54
+ text: b.freshRaw.map(cleanLine).join(' '),
55
+ }));
56
+ }
57
+ /**
58
+ * 큐를 단어로 쪼갠다. 유튜브 자동 자막의 `<00:00:01.200>` 태그가 있으면 단어마다 그 시각을 쓰고
59
+ * 없으면 큐 시작 시각을 쓴다. 문장이 큐 중간에서 시작해도 시작 시각이 틀어지지 않게 하려는 것이다.
60
+ */
61
+ export function parseTimedWords(text) {
62
+ const words = [];
63
+ let pendingBreak = false;
64
+ for (const block of readBlocks(text)) {
65
+ for (const line of block.freshRaw) {
66
+ let sec = block.startSec;
67
+ let last = 0;
68
+ const pieces = [];
69
+ for (const m of line.matchAll(TIME_TAG)) {
70
+ pieces.push({ sec, text: line.slice(last, m.index) });
71
+ sec = toSeconds(m[1]);
72
+ last = m.index + m[0].length;
73
+ }
74
+ pieces.push({ sec, text: line.slice(last) });
75
+ for (const p of pieces) {
76
+ for (const w of decodeEntities(cleanLine(p.text)).split(' ')) {
77
+ if (!w || SOUND_TAG.test(w))
78
+ continue;
79
+ if (w === '>>') {
80
+ pendingBreak = true;
81
+ continue;
82
+ }
83
+ words.push(pendingBreak ? { sec: p.sec, text: w, breakBefore: true } : { sec: p.sec, text: w });
84
+ pendingBreak = false;
85
+ }
86
+ }
87
+ }
88
+ }
89
+ return words;
90
+ }
91
+ /**
92
+ * 단어를 문장으로 합친다. 끝 부호에서 끊고 부호가 없으면 쉼 간격과 길이로 끊는다.
93
+ * 문장 시작 시각은 첫 단어의 시각이다.
94
+ */
95
+ export function mergeSentences(words, options = {}) {
96
+ const opt = { ...DEFAULT_MERGE, ...options };
97
+ const out = [];
98
+ let buf = [];
99
+ let len = 0;
100
+ const flush = () => {
101
+ if (buf.length === 0)
102
+ return;
103
+ out.push({ startSec: buf[0].sec, text: buf.map((w) => w.text).join(' ') });
104
+ buf = [];
105
+ len = 0;
106
+ };
107
+ for (let k = 0; k < words.length; k++) {
108
+ const w = words[k];
109
+ if (w.breakBefore)
110
+ flush();
111
+ buf.push(w);
112
+ len += w.text.length + (buf.length > 1 ? 1 : 0);
113
+ const next = words[k + 1];
114
+ if (!next)
115
+ break;
116
+ const gap = next.sec - w.sec;
117
+ if (SENTENCE_END.test(w.text))
118
+ flush();
119
+ else if (gap >= opt.pauseSec && len >= opt.minChars)
120
+ flush();
121
+ else if (len >= opt.maxChars)
122
+ flush();
123
+ }
124
+ flush();
125
+ return out;
126
+ }
127
+ /** 단어 시각이 없는 조각(whisper 구간 같은)을 조각 시작 시각의 단어로 편다 */
128
+ export function cuesToWords(cues) {
129
+ return cues.flatMap((c) => c.text
130
+ .split(/\s+/)
131
+ .filter(Boolean)
132
+ .map((text) => ({ sec: c.startSec, text })));
133
+ }
134
+ /** 자막 파일 하나를 문장 단위 큐로 만든다 */
135
+ export function captionsToSentences(text, options) {
136
+ return mergeSentences(parseTimedWords(text), options);
137
+ }
138
+ //# sourceMappingURL=captions.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"captions.js","sourceRoot":"","sources":["../../../src/digest/captions.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,113 @@
1
+ import { z } from 'zod';
2
+ import { DigestStore } from './store.js';
3
+ import { type RunCommand } from './ytdlp.js';
4
+ /**
5
+ * 유튜브 댓글을 받아 comments.json으로 둔다. 댓글 분석 템플릿이 이 파일을 읽는다.
6
+ * 작성자 이름과 채널 id, 프로필 사진은 저장하지 않는다. 분석에 안 쓰는 개인정보를 레포에 남기지 않으려는 것이다
7
+ */
8
+ export declare const COMMENTS_DEFAULT_MAX = 200;
9
+ export declare const COMMENTS_MAX = 1000;
10
+ export declare const storedCommentSchema: z.ZodObject<{
11
+ id: z.ZodString;
12
+ text: z.ZodString;
13
+ likes: z.ZodNumber;
14
+ pinned: z.ZodOptional<z.ZodBoolean>;
15
+ byUploader: z.ZodOptional<z.ZodBoolean>;
16
+ }, "strip", z.ZodTypeAny, {
17
+ text: string;
18
+ id: string;
19
+ likes: number;
20
+ pinned?: boolean | undefined;
21
+ byUploader?: boolean | undefined;
22
+ }, {
23
+ text: string;
24
+ id: string;
25
+ likes: number;
26
+ pinned?: boolean | undefined;
27
+ byUploader?: boolean | undefined;
28
+ }>;
29
+ export declare const commentsFileSchema: z.ZodObject<{
30
+ schemaVersion: z.ZodLiteral<"1.0.0">;
31
+ videoId: z.ZodString;
32
+ fetchedAt: z.ZodString;
33
+ /** 영상 정보에 적힌 전체 댓글 수. 받은 개수가 아니다 */
34
+ commentCount: z.ZodNullable<z.ZodNumber>;
35
+ comments: z.ZodArray<z.ZodObject<{
36
+ id: z.ZodString;
37
+ text: z.ZodString;
38
+ likes: z.ZodNumber;
39
+ pinned: z.ZodOptional<z.ZodBoolean>;
40
+ byUploader: z.ZodOptional<z.ZodBoolean>;
41
+ }, "strip", z.ZodTypeAny, {
42
+ text: string;
43
+ id: string;
44
+ likes: number;
45
+ pinned?: boolean | undefined;
46
+ byUploader?: boolean | undefined;
47
+ }, {
48
+ text: string;
49
+ id: string;
50
+ likes: number;
51
+ pinned?: boolean | undefined;
52
+ byUploader?: boolean | undefined;
53
+ }>, "many">;
54
+ }, "strip", z.ZodTypeAny, {
55
+ comments: {
56
+ text: string;
57
+ id: string;
58
+ likes: number;
59
+ pinned?: boolean | undefined;
60
+ byUploader?: boolean | undefined;
61
+ }[];
62
+ schemaVersion: "1.0.0";
63
+ videoId: string;
64
+ fetchedAt: string;
65
+ commentCount: number | null;
66
+ }, {
67
+ comments: {
68
+ text: string;
69
+ id: string;
70
+ likes: number;
71
+ pinned?: boolean | undefined;
72
+ byUploader?: boolean | undefined;
73
+ }[];
74
+ schemaVersion: "1.0.0";
75
+ videoId: string;
76
+ fetchedAt: string;
77
+ commentCount: number | null;
78
+ }>;
79
+ export type StoredComment = z.infer<typeof storedCommentSchema>;
80
+ export type CommentsFile = z.infer<typeof commentsFileSchema>;
81
+ /**
82
+ * yt-dlp -J 결과에서 최상위 댓글만 골라 좋아요 순으로 max개를 남긴다.
83
+ * 답글은 원 댓글 맥락 없이 읽으면 성격을 잘못 묶기 쉬워서 뺀다
84
+ */
85
+ export declare function parseYtComments(raw: unknown, max: number): {
86
+ comments: StoredComment[];
87
+ commentCount: number | null;
88
+ };
89
+ export type CommentsRead = {
90
+ kind: 'missing';
91
+ } | {
92
+ kind: 'invalid';
93
+ message: string;
94
+ } | {
95
+ kind: 'ok';
96
+ value: CommentsFile;
97
+ };
98
+ export declare function readComments(store: DigestStore, slug: string): CommentsRead;
99
+ /** lint가 받는 꼴. 파일이 없거나 깨졌으면 null이다 */
100
+ export declare function commentsMap(store: DigestStore, slug: string): Map<string, string> | null;
101
+ export interface FetchCommentsOptions {
102
+ repoRoot: string;
103
+ max?: number;
104
+ run?: RunCommand;
105
+ }
106
+ export interface FetchCommentsResult {
107
+ slug: string;
108
+ path: string;
109
+ fetched: number;
110
+ commentCount: number | null;
111
+ }
112
+ export declare function fetchComments(slug: string, opts: FetchCommentsOptions): Promise<FetchCommentsResult>;
113
+ //# sourceMappingURL=comments.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"comments.d.ts","sourceRoot":"","sources":["../../../src/digest/comments.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAIxB,OAAO,EAAE,WAAW,EAAW,MAAM,YAAY,CAAC;AAClD,OAAO,EAAqB,KAAK,UAAU,EAAE,MAAM,YAAY,CAAC;AAEhE;;;GAGG;AAEH,eAAO,MAAM,oBAAoB,MAAM,CAAC;AACxC,eAAO,MAAM,YAAY,OAAO,CAAC;AAIjC,eAAO,MAAM,mBAAmB;;;;;;;;;;;;;;;;;;EAM9B,CAAC;AAEH,eAAO,MAAM,kBAAkB;;;;IAI7B,oCAAoC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAGpC,CAAC;AAEH,MAAM,MAAM,aAAa,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,mBAAmB,CAAC,CAAC;AAChE,MAAM,MAAM,YAAY,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,kBAAkB,CAAC,CAAC;AAW9D;;;GAGG;AACH,wBAAgB,eAAe,CAC7B,GAAG,EAAE,OAAO,EACZ,GAAG,EAAE,MAAM,GACV;IAAE,QAAQ,EAAE,aAAa,EAAE,CAAC;IAAC,YAAY,EAAE,MAAM,GAAG,IAAI,CAAA;CAAE,CAkC5D;AAED,MAAM,MAAM,YAAY,GACpB;IAAE,IAAI,EAAE,SAAS,CAAA;CAAE,GACnB;IAAE,IAAI,EAAE,SAAS,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,GACpC;IAAE,IAAI,EAAE,IAAI,CAAC;IAAC,KAAK,EAAE,YAAY,CAAA;CAAE,CAAC;AAExC,wBAAgB,YAAY,CAAC,KAAK,EAAE,WAAW,EAAE,IAAI,EAAE,MAAM,GAAG,YAAY,CAY3E;AAED,sCAAsC;AACtC,wBAAgB,WAAW,CAAC,KAAK,EAAE,WAAW,EAAE,IAAI,EAAE,MAAM,GAAG,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,IAAI,CAGxF;AAED,MAAM,WAAW,oBAAoB;IACnC,QAAQ,EAAE,MAAM,CAAC;IACjB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,GAAG,CAAC,EAAE,UAAU,CAAC;CAClB;AAED,MAAM,WAAW,mBAAmB;IAClC,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;CAC7B;AAED,wBAAsB,aAAa,CACjC,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,oBAAoB,GACzB,OAAO,CAAC,mBAAmB,CAAC,CAiD9B"}
@@ -0,0 +1,153 @@
1
+ import { mkdtempSync, rmSync } from 'node:fs';
2
+ import { tmpdir } from 'node:os';
3
+ import { join } from 'node:path';
4
+ import { z } from 'zod';
5
+ import { writeJsonAtomic } from '../core/json-file.js';
6
+ import { commentIdSchema } from './blocks.js';
7
+ import { youtubeWatchUrl } from './schema.js';
8
+ import { DigestStore, readRaw } from './store.js';
9
+ import { runCommand, ytdlp } from './ytdlp.js';
10
+ /**
11
+ * 유튜브 댓글을 받아 comments.json으로 둔다. 댓글 분석 템플릿이 이 파일을 읽는다.
12
+ * 작성자 이름과 채널 id, 프로필 사진은 저장하지 않는다. 분석에 안 쓰는 개인정보를 레포에 남기지 않으려는 것이다
13
+ */
14
+ export const COMMENTS_DEFAULT_MAX = 200;
15
+ export const COMMENTS_MAX = 1000;
16
+ /** 댓글 하나가 이보다 길면 자른다. 분석에는 앞부분이면 충분하다 */
17
+ const COMMENT_TEXT_MAX = 2000;
18
+ export const storedCommentSchema = z.object({
19
+ id: commentIdSchema,
20
+ text: z.string().min(1).max(COMMENT_TEXT_MAX),
21
+ likes: z.number().int().min(0),
22
+ pinned: z.boolean().optional(),
23
+ byUploader: z.boolean().optional(),
24
+ });
25
+ export const commentsFileSchema = z.object({
26
+ schemaVersion: z.literal('1.0.0'),
27
+ videoId: z.string(),
28
+ fetchedAt: z.string(),
29
+ /** 영상 정보에 적힌 전체 댓글 수. 받은 개수가 아니다 */
30
+ commentCount: z.number().int().min(0).nullable(),
31
+ comments: z.array(storedCommentSchema),
32
+ });
33
+ const rawCommentSchema = z.object({
34
+ id: z.unknown(),
35
+ text: z.unknown(),
36
+ parent: z.unknown().optional(),
37
+ like_count: z.unknown().optional(),
38
+ is_pinned: z.unknown().optional(),
39
+ author_is_uploader: z.unknown().optional(),
40
+ });
41
+ /**
42
+ * yt-dlp -J 결과에서 최상위 댓글만 골라 좋아요 순으로 max개를 남긴다.
43
+ * 답글은 원 댓글 맥락 없이 읽으면 성격을 잘못 묶기 쉬워서 뺀다
44
+ */
45
+ export function parseYtComments(raw, max) {
46
+ const obj = (raw ?? {});
47
+ const list = Array.isArray(obj.comments) ? obj.comments : [];
48
+ const out = [];
49
+ const seen = new Set();
50
+ for (const item of list) {
51
+ const r = rawCommentSchema.safeParse(item);
52
+ if (!r.success)
53
+ continue;
54
+ const c = r.data;
55
+ if (c.parent !== undefined && c.parent !== 'root')
56
+ continue;
57
+ if (typeof c.id !== 'string' || !commentIdSchema.safeParse(c.id).success)
58
+ continue;
59
+ if (seen.has(c.id))
60
+ continue;
61
+ const text = typeof c.text === 'string' ? c.text.trim().slice(0, COMMENT_TEXT_MAX) : '';
62
+ if (!text)
63
+ continue;
64
+ seen.add(c.id);
65
+ const likes = typeof c.like_count === 'number' && Number.isFinite(c.like_count)
66
+ ? Math.max(0, Math.floor(c.like_count))
67
+ : 0;
68
+ out.push({
69
+ id: c.id,
70
+ text,
71
+ likes,
72
+ ...(c.is_pinned === true ? { pinned: true } : {}),
73
+ ...(c.author_is_uploader === true ? { byUploader: true } : {}),
74
+ });
75
+ }
76
+ // sort는 안정 정렬이라 좋아요가 같으면 yt-dlp가 준 순서(인기순)를 지킨다
77
+ out.sort((a, b) => b.likes - a.likes);
78
+ const count = typeof obj.comment_count === 'number' && Number.isInteger(obj.comment_count)
79
+ ? Math.max(0, obj.comment_count)
80
+ : null;
81
+ return { comments: out.slice(0, max), commentCount: count };
82
+ }
83
+ export function readComments(store, slug) {
84
+ const raw = readRaw(store.commentsPath(slug));
85
+ if (raw.kind === 'missing')
86
+ return raw;
87
+ if (raw.kind === 'invalid-json')
88
+ return { kind: 'invalid', message: raw.message };
89
+ const parsed = commentsFileSchema.safeParse(raw.value);
90
+ if (!parsed.success) {
91
+ const issues = parsed.error.issues
92
+ .slice(0, 3)
93
+ .map((i) => `${i.path.join('.') || '(root)'}: ${i.message}`);
94
+ return { kind: 'invalid', message: issues.join('; ') };
95
+ }
96
+ return { kind: 'ok', value: parsed.data };
97
+ }
98
+ /** lint가 받는 꼴. 파일이 없거나 깨졌으면 null이다 */
99
+ export function commentsMap(store, slug) {
100
+ const r = readComments(store, slug);
101
+ return r.kind === 'ok' ? new Map(r.value.comments.map((c) => [c.id, c.text])) : null;
102
+ }
103
+ export async function fetchComments(slug, opts) {
104
+ const max = opts.max ?? COMMENTS_DEFAULT_MAX;
105
+ if (!Number.isInteger(max) || max < 1 || max > COMMENTS_MAX) {
106
+ throw new Error(`--max는 1~${COMMENTS_MAX} 사이 정수여야 해요: ${max}`);
107
+ }
108
+ const store = new DigestStore(opts.repoRoot);
109
+ const t = store.readTranscript(slug);
110
+ if (!t.ok)
111
+ throw new Error(t.message);
112
+ const { meta } = t.transcript;
113
+ if (meta.source !== 'youtube' || !meta.videoId) {
114
+ throw new Error('댓글은 유튜브 영상만 받을 수 있어요.');
115
+ }
116
+ // 답글은 받지 않는다(max_comments의 세 번째와 네 번째 값이 0). 정렬은 인기순이다
117
+ const args = [
118
+ ...['--skip-download', '--get-comments', '-J'],
119
+ ...['--extractor-args', `youtube:max_comments=${max},${max},0,0;comment_sort=top`],
120
+ youtubeWatchUrl(meta.videoId),
121
+ ];
122
+ // 레포 안을 cwd로 쓰면 그 레포의 yt-dlp.conf를 읽는다. frames와 같은 이유로 임시 폴더에서 돈다
123
+ const cwd = mkdtempSync(join(tmpdir(), 'gestalt-digest-run-'));
124
+ try {
125
+ const { stdout } = await ytdlp(opts.run ?? runCommand, args, args, {
126
+ cwd,
127
+ // 댓글은 20개씩 끊어 받아서 개수에 비례해 오래 걸린다
128
+ timeoutMs: (120 + max * 0.5) * 1000,
129
+ });
130
+ let raw;
131
+ try {
132
+ raw = JSON.parse(stdout);
133
+ }
134
+ catch (e) {
135
+ throw new Error(`yt-dlp 출력을 JSON으로 못 읽었어요: ${e instanceof Error ? e.message : String(e)}`, { cause: e });
136
+ }
137
+ const { comments, commentCount } = parseYtComments(raw, max);
138
+ const file = {
139
+ schemaVersion: '1.0.0',
140
+ videoId: meta.videoId,
141
+ fetchedAt: new Date().toISOString(),
142
+ commentCount,
143
+ comments,
144
+ };
145
+ const path = store.commentsPath(slug);
146
+ writeJsonAtomic(path, file);
147
+ return { slug, path, fetched: comments.length, commentCount };
148
+ }
149
+ finally {
150
+ rmSync(cwd, { recursive: true, force: true });
151
+ }
152
+ }
153
+ //# sourceMappingURL=comments.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"comments.js","sourceRoot":"","sources":["../../../src/digest/comments.ts"],"names":[],"mappings":"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"}