@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.
- package/README.ko.md +2 -1
- package/README.md +2 -1
- package/dist/package.json +1 -1
- package/dist/plugin/role-agents/video-summarizer/AGENT.md +208 -108
- package/dist/plugin/skills/_shared/proactive-routing.md +2 -1
- package/dist/plugin/skills/research/references/design.md +1 -1
- package/dist/plugin/skills/video-digest/SKILL.md +430 -0
- package/dist/plugin/skills/video-digest/templates/background.md +15 -0
- package/dist/plugin/skills/video-digest/templates/blog.md +16 -0
- package/dist/plugin/skills/video-digest/templates/comments.md +19 -0
- package/dist/plugin/skills/video-digest/templates/counterpoints.md +15 -0
- package/dist/plugin/skills/video-digest/templates/flashcards.md +15 -0
- package/dist/plugin/skills/video-digest/templates/interview.md +15 -0
- package/dist/plugin/skills/video-digest/templates/meeting.md +15 -0
- package/dist/plugin/skills/video-digest/templates/mindmap.md +16 -0
- package/dist/plugin/skills/video-digest/templates/quiz.md +16 -0
- package/dist/plugin/skills/video-digest/templates/quotes.md +16 -0
- package/dist/plugin/skills/video-digest/templates/resources.md +14 -0
- package/dist/plugin/skills/video-digest/templates/timestamps.md +14 -0
- package/dist/plugin/skills/video-digest/templates/visual.md +22 -0
- package/dist/src/cli/commands/digest.d.ts +60 -0
- package/dist/src/cli/commands/digest.d.ts.map +1 -0
- package/dist/src/cli/commands/digest.js +401 -0
- package/dist/src/cli/commands/digest.js.map +1 -0
- package/dist/src/cli/index.d.ts.map +1 -1
- package/dist/src/cli/index.js +81 -0
- package/dist/src/cli/index.js.map +1 -1
- package/dist/src/digest/blocks.d.ts +5224 -0
- package/dist/src/digest/blocks.d.ts.map +1 -0
- package/dist/src/digest/blocks.js +156 -0
- package/dist/src/digest/blocks.js.map +1 -0
- package/dist/src/digest/captions.d.ts +37 -0
- package/dist/src/digest/captions.d.ts.map +1 -0
- package/dist/src/digest/captions.js +138 -0
- package/dist/src/digest/captions.js.map +1 -0
- package/dist/src/digest/comments.d.ts +113 -0
- package/dist/src/digest/comments.d.ts.map +1 -0
- package/dist/src/digest/comments.js +153 -0
- package/dist/src/digest/comments.js.map +1 -0
- package/dist/src/digest/diagram-schema.d.ts +765 -0
- package/dist/src/digest/diagram-schema.d.ts.map +1 -0
- package/dist/src/digest/diagram-schema.js +72 -0
- package/dist/src/digest/diagram-schema.js.map +1 -0
- package/dist/src/digest/format.d.ts +9 -0
- package/dist/src/digest/format.d.ts.map +1 -0
- package/dist/src/digest/format.js +26 -0
- package/dist/src/digest/format.js.map +1 -0
- package/dist/src/digest/frames.d.ts +46 -0
- package/dist/src/digest/frames.d.ts.map +1 -0
- package/dist/src/digest/frames.js +206 -0
- package/dist/src/digest/frames.js.map +1 -0
- package/dist/src/digest/index.d.ts +26 -0
- package/dist/src/digest/index.d.ts.map +1 -0
- package/dist/src/digest/index.js +26 -0
- package/dist/src/digest/index.js.map +1 -0
- package/dist/src/digest/ingest.d.ts +65 -0
- package/dist/src/digest/ingest.d.ts.map +1 -0
- package/dist/src/digest/ingest.js +303 -0
- package/dist/src/digest/ingest.js.map +1 -0
- package/dist/src/digest/lint-extension.d.ts +71 -0
- package/dist/src/digest/lint-extension.d.ts.map +1 -0
- package/dist/src/digest/lint-extension.js +512 -0
- package/dist/src/digest/lint-extension.js.map +1 -0
- package/dist/src/digest/lint.d.ts +50 -0
- package/dist/src/digest/lint.d.ts.map +1 -0
- package/dist/src/digest/lint.js +560 -0
- package/dist/src/digest/lint.js.map +1 -0
- package/dist/src/digest/merge.d.ts +40 -0
- package/dist/src/digest/merge.d.ts.map +1 -0
- package/dist/src/digest/merge.js +107 -0
- package/dist/src/digest/merge.js.map +1 -0
- package/dist/src/digest/ocr.d.ts +100 -0
- package/dist/src/digest/ocr.d.ts.map +1 -0
- package/dist/src/digest/ocr.js +179 -0
- package/dist/src/digest/ocr.js.map +1 -0
- package/dist/src/digest/prose.d.ts +47 -0
- package/dist/src/digest/prose.d.ts.map +1 -0
- package/dist/src/digest/prose.js +171 -0
- package/dist/src/digest/prose.js.map +1 -0
- package/dist/src/digest/render-blocks.d.ts +38 -0
- package/dist/src/digest/render-blocks.d.ts.map +1 -0
- package/dist/src/digest/render-blocks.js +378 -0
- package/dist/src/digest/render-blocks.js.map +1 -0
- package/dist/src/digest/render-html.d.ts +22 -0
- package/dist/src/digest/render-html.d.ts.map +1 -0
- package/dist/src/digest/render-html.js +505 -0
- package/dist/src/digest/render-html.js.map +1 -0
- package/dist/src/digest/render-md.d.ts +18 -0
- package/dist/src/digest/render-md.d.ts.map +1 -0
- package/dist/src/digest/render-md.js +126 -0
- package/dist/src/digest/render-md.js.map +1 -0
- package/dist/src/digest/render.d.ts +47 -0
- package/dist/src/digest/render.d.ts.map +1 -0
- package/dist/src/digest/render.js +126 -0
- package/dist/src/digest/render.js.map +1 -0
- package/dist/src/digest/reports.d.ts +26 -0
- package/dist/src/digest/reports.d.ts.map +1 -0
- package/dist/src/digest/reports.js +70 -0
- package/dist/src/digest/reports.js.map +1 -0
- package/dist/src/digest/scenes.d.ts +92 -0
- package/dist/src/digest/scenes.d.ts.map +1 -0
- package/dist/src/digest/scenes.js +182 -0
- package/dist/src/digest/scenes.js.map +1 -0
- package/dist/src/digest/schema-base.d.ts +31 -0
- package/dist/src/digest/schema-base.d.ts.map +1 -0
- package/dist/src/digest/schema-base.js +19 -0
- package/dist/src/digest/schema-base.js.map +1 -0
- package/dist/src/digest/schema.d.ts +12886 -0
- package/dist/src/digest/schema.d.ts.map +1 -0
- package/dist/src/digest/schema.js +215 -0
- package/dist/src/digest/schema.js.map +1 -0
- package/dist/src/digest/server.d.ts +36 -0
- package/dist/src/digest/server.d.ts.map +1 -0
- package/dist/src/digest/server.js +278 -0
- package/dist/src/digest/server.js.map +1 -0
- package/dist/src/digest/slice.d.ts +20 -0
- package/dist/src/digest/slice.d.ts.map +1 -0
- package/dist/src/digest/slice.js +48 -0
- package/dist/src/digest/slice.js.map +1 -0
- package/dist/src/digest/store.d.ts +67 -0
- package/dist/src/digest/store.d.ts.map +1 -0
- package/dist/src/digest/store.js +152 -0
- package/dist/src/digest/store.js.map +1 -0
- package/dist/src/digest/svg.d.ts +74 -0
- package/dist/src/digest/svg.d.ts.map +1 -0
- package/dist/src/digest/svg.js +415 -0
- package/dist/src/digest/svg.js.map +1 -0
- package/dist/src/digest/templates.d.ts +38 -0
- package/dist/src/digest/templates.d.ts.map +1 -0
- package/dist/src/digest/templates.js +125 -0
- package/dist/src/digest/templates.js.map +1 -0
- package/dist/src/digest/translate.d.ts +46 -0
- package/dist/src/digest/translate.d.ts.map +1 -0
- package/dist/src/digest/translate.js +50 -0
- package/dist/src/digest/translate.js.map +1 -0
- package/dist/src/digest/viewer-js.d.ts +4 -0
- package/dist/src/digest/viewer-js.d.ts.map +1 -0
- package/dist/src/digest/viewer-js.js +735 -0
- package/dist/src/digest/viewer-js.js.map +1 -0
- package/dist/src/digest/viewer-logic.d.ts +46 -0
- package/dist/src/digest/viewer-logic.d.ts.map +1 -0
- package/dist/src/digest/viewer-logic.js +89 -0
- package/dist/src/digest/viewer-logic.js.map +1 -0
- package/dist/src/digest/ytdlp.d.ts +34 -0
- package/dist/src/digest/ytdlp.d.ts.map +1 -0
- package/dist/src/digest/ytdlp.js +64 -0
- package/dist/src/digest/ytdlp.js.map +1 -0
- package/dist/src/mcp/schemas.d.ts +48 -0
- package/dist/src/mcp/schemas.d.ts.map +1 -1
- package/dist/src/mcp/schemas.js +25 -0
- package/dist/src/mcp/schemas.js.map +1 -1
- package/dist/src/mcp/server.d.ts.map +1 -1
- package/dist/src/mcp/server.js +7 -1
- package/dist/src/mcp/server.js.map +1 -1
- package/dist/src/mcp/tools/digest-passthrough.d.ts +3 -0
- package/dist/src/mcp/tools/digest-passthrough.d.ts.map +1 -0
- package/dist/src/mcp/tools/digest-passthrough.js +151 -0
- package/dist/src/mcp/tools/digest-passthrough.js.map +1 -0
- package/package.json +1 -1
- package/plugin/.codex-plugin/plugin.json +1 -1
- package/plugin/.mcp.json +1 -1
- package/plugin/mcp.json +1 -1
- package/plugin/role-agents/video-summarizer/AGENT.md +208 -108
- package/plugin/skills/_shared/proactive-routing.md +2 -1
- package/plugin/skills/research/references/design.md +1 -1
- package/plugin/skills/video-digest/SKILL.md +430 -0
- package/plugin/skills/video-digest/templates/background.md +15 -0
- package/plugin/skills/video-digest/templates/blog.md +16 -0
- package/plugin/skills/video-digest/templates/comments.md +19 -0
- package/plugin/skills/video-digest/templates/counterpoints.md +15 -0
- package/plugin/skills/video-digest/templates/flashcards.md +15 -0
- package/plugin/skills/video-digest/templates/interview.md +15 -0
- package/plugin/skills/video-digest/templates/meeting.md +15 -0
- package/plugin/skills/video-digest/templates/mindmap.md +16 -0
- package/plugin/skills/video-digest/templates/quiz.md +16 -0
- package/plugin/skills/video-digest/templates/quotes.md +16 -0
- package/plugin/skills/video-digest/templates/resources.md +14 -0
- package/plugin/skills/video-digest/templates/timestamps.md +14 -0
- package/plugin/skills/video-digest/templates/visual.md +22 -0
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { rangeSpan } from './reports.js';
|
|
2
|
+
/** `90`, `1:30`, `1:02:03`을 초로 바꾼다. 꼴이 틀리면 null이다 */
|
|
3
|
+
export function parseTimeArg(value) {
|
|
4
|
+
const v = value.trim();
|
|
5
|
+
if (/^\d+(\.\d+)?$/.test(v))
|
|
6
|
+
return Number(v);
|
|
7
|
+
const m = /^(?:(\d+):)?(\d{1,2}):(\d{2})$/.exec(v);
|
|
8
|
+
if (!m)
|
|
9
|
+
return null;
|
|
10
|
+
const [h, mm, ss] = [Number(m[1] ?? 0), Number(m[2]), Number(m[3])];
|
|
11
|
+
if (ss >= 60 || (m[1] !== undefined && mm >= 60))
|
|
12
|
+
return null;
|
|
13
|
+
return h * 3600 + mm * 60 + ss;
|
|
14
|
+
}
|
|
15
|
+
/** `1:30-5:00` 꼴 구간을 [시작, 끝) 초로 바꾼다 */
|
|
16
|
+
export function parseRangeArg(value) {
|
|
17
|
+
const parts = value.split('-');
|
|
18
|
+
const from = parts.length === 2 ? parseTimeArg(parts[0]) : null;
|
|
19
|
+
const to = parts.length === 2 ? parseTimeArg(parts[1]) : null;
|
|
20
|
+
if (from === null || to === null) {
|
|
21
|
+
throw new Error(`구간은 시작-끝 꼴이어야 해요(예: 1:30-5:00, 90-300): ${value}`);
|
|
22
|
+
}
|
|
23
|
+
if (!Number.isInteger(from) || !Number.isInteger(to)) {
|
|
24
|
+
throw new Error(`구간은 초 단위 정수여야 해요: ${value}`);
|
|
25
|
+
}
|
|
26
|
+
if (from >= to)
|
|
27
|
+
throw new Error(`구간 시작이 끝보다 앞이어야 해요: ${value}`);
|
|
28
|
+
return [from, to];
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* 구간 리포트가 읽을 문장만 잘라 낸다. 출처는 원래 스크립트의 문장 번호를 가리켜야 해서
|
|
32
|
+
* i를 다시 매기지 않는다. 그래서 transcript.json 꼴이 아니라 따로 저장한다
|
|
33
|
+
*/
|
|
34
|
+
export function sliceTranscript(transcript, range) {
|
|
35
|
+
const span = rangeSpan(range, transcript.segments);
|
|
36
|
+
if (!span) {
|
|
37
|
+
throw new Error(`구간 ${range[0]}~${range[1]}초에 든 문장이 없어요. 영상 길이는 ${transcript.meta.durationSec}초예요`);
|
|
38
|
+
}
|
|
39
|
+
return {
|
|
40
|
+
slug: transcript.slug,
|
|
41
|
+
range: [range[0], range[1]],
|
|
42
|
+
from: span.from,
|
|
43
|
+
to: span.to,
|
|
44
|
+
segments: transcript.segments.slice(span.from, span.to + 1),
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
export const sliceFileName = (range) => `transcript.slice-${Math.floor(range[0])}-${Math.floor(range[1])}.json`;
|
|
48
|
+
//# sourceMappingURL=slice.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"slice.js","sourceRoot":"","sources":["../../../src/digest/slice.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { type Digest, type Transcript } from './schema.js';
|
|
2
|
+
import { SLUG_PATTERN } from './schema-base.js';
|
|
3
|
+
export { SLUG_PATTERN };
|
|
4
|
+
export type RawRead = {
|
|
5
|
+
kind: 'missing';
|
|
6
|
+
} | {
|
|
7
|
+
kind: 'invalid-json';
|
|
8
|
+
message: string;
|
|
9
|
+
} | {
|
|
10
|
+
kind: 'ok';
|
|
11
|
+
value: unknown;
|
|
12
|
+
};
|
|
13
|
+
export type TranscriptRead = {
|
|
14
|
+
ok: true;
|
|
15
|
+
transcript: Transcript;
|
|
16
|
+
} | {
|
|
17
|
+
ok: false;
|
|
18
|
+
code: 'TRANSCRIPT_NOT_FOUND' | 'TRANSCRIPT_INVALID';
|
|
19
|
+
message: string;
|
|
20
|
+
};
|
|
21
|
+
export declare function readRaw(path: string): RawRead;
|
|
22
|
+
/** 저장소 바로 아래에서 slug 폴더가 아닌 자리. 사용자 템플릿이 여기 산다 */
|
|
23
|
+
export declare const TEMPLATES_DIR_NAME = "templates";
|
|
24
|
+
export declare function isValidSlug(slug: string): boolean;
|
|
25
|
+
/**
|
|
26
|
+
* 제목을 ascii 소문자와 하이픈으로 줄이고 videoId를 끝에 붙인다.
|
|
27
|
+
* 한국어 제목은 남는 글자가 없어서 videoId만 남는다. 같은 제목의 다른 영상이 섞이지 않게 id는 항상 붙인다.
|
|
28
|
+
*/
|
|
29
|
+
export declare function slugFromMeta(videoIdOrName: string, title: string): string;
|
|
30
|
+
/**
|
|
31
|
+
* 영상 요약 저장소: `<repoRoot>/.gestalt/digest/<slug>/`.
|
|
32
|
+
* `.gestalt/`는 gitignore 대상이라 프레임과 영상 캐시가 커밋에 딸려가지 않는다.
|
|
33
|
+
*/
|
|
34
|
+
export declare class DigestStore {
|
|
35
|
+
readonly root: string;
|
|
36
|
+
constructor(repoRoot: string);
|
|
37
|
+
templatesDir(): string;
|
|
38
|
+
/** slug는 경로 조각이라 패턴을 통과한 것만 받는다 */
|
|
39
|
+
dir(slug: string): string;
|
|
40
|
+
transcriptPath(slug: string): string;
|
|
41
|
+
digestPath(slug: string): string;
|
|
42
|
+
htmlPath(slug: string): string;
|
|
43
|
+
mdPath(slug: string): string;
|
|
44
|
+
framesDir(slug: string): string;
|
|
45
|
+
/** comments 명령이 받아 두는 댓글. 댓글 분석 템플릿이 읽는다 */
|
|
46
|
+
commentsPath(slug: string): string;
|
|
47
|
+
/** frames 명령이 받아 두는 저화질 영상. 다시 뽑을 때 또 받지 않으려고 둔다 */
|
|
48
|
+
videoCacheDir(slug: string): string;
|
|
49
|
+
/**
|
|
50
|
+
* 깨진 파일도 옮기지 않는다. validate나 render 같은 읽기 명령이 파일을 치우면
|
|
51
|
+
* 사용자는 왜 사라졌는지 모른다. ingest를 다시 돌리면 어차피 덮어쓴다
|
|
52
|
+
*/
|
|
53
|
+
readTranscript(slug: string): TranscriptRead;
|
|
54
|
+
/**
|
|
55
|
+
* 요약은 세션이 손으로 쓰는 파일이라 깨져도 옮기지 않는다.
|
|
56
|
+
* 옮겨 버리면 validate 오류를 보고 고치려던 원본이 사라진다.
|
|
57
|
+
*/
|
|
58
|
+
readDigestFile(slug: string): RawRead;
|
|
59
|
+
/** 없거나 형식이 틀리면 null. 이유가 필요하면 readDigestFile과 parseDigest를 쓴다 */
|
|
60
|
+
loadDigest(slug: string): Digest | null;
|
|
61
|
+
saveTranscript(transcript: Transcript): string;
|
|
62
|
+
saveDigest(digest: Digest): string;
|
|
63
|
+
saveHtml(slug: string, html: string): string;
|
|
64
|
+
saveMd(slug: string, md: string): string;
|
|
65
|
+
private writeText;
|
|
66
|
+
}
|
|
67
|
+
//# sourceMappingURL=store.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"store.d.ts","sourceRoot":"","sources":["../../../src/digest/store.ts"],"names":[],"mappings":"AAGA,OAAO,EAAgC,KAAK,MAAM,EAAE,KAAK,UAAU,EAAE,MAAM,aAAa,CAAC;AACzF,OAAO,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAEhD,OAAO,EAAE,YAAY,EAAE,CAAC;AAIxB,MAAM,MAAM,OAAO,GACf;IAAE,IAAI,EAAE,SAAS,CAAA;CAAE,GACnB;IAAE,IAAI,EAAE,cAAc,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,GACzC;IAAE,IAAI,EAAE,IAAI,CAAC;IAAC,KAAK,EAAE,OAAO,CAAA;CAAE,CAAC;AAEnC,MAAM,MAAM,cAAc,GACtB;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,UAAU,EAAE,UAAU,CAAA;CAAE,GACpC;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,IAAI,EAAE,sBAAsB,GAAG,oBAAoB,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAAC;AAExF,wBAAgB,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAO7C;AAED,iDAAiD;AACjD,eAAO,MAAM,kBAAkB,cAAc,CAAC;AAE9C,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAEjD;AAED;;;GAGG;AACH,wBAAgB,YAAY,CAAC,aAAa,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAczE;AAED;;;GAGG;AACH,qBAAa,WAAW;IACtB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;gBAEV,QAAQ,EAAE,MAAM;IAK5B,YAAY,IAAI,MAAM;IAItB,mCAAmC;IACnC,GAAG,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM;IAKzB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM;IAIpC,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM;IAIhC,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM;IAI9B,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM;IAI5B,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM;IAI/B,4CAA4C;IAC5C,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM;IAIlC,oDAAoD;IACpD,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM;IAInC;;;OAGG;IACH,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,cAAc;IA4B5C;;;OAGG;IACH,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO;IAIrC,iEAAiE;IACjE,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI;IAOvC,cAAc,CAAC,UAAU,EAAE,UAAU,GAAG,MAAM;IAM9C,UAAU,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM;IAMlC,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM;IAI5C,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,MAAM;IAIxC,OAAO,CAAC,SAAS;CAKlB"}
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';
|
|
2
|
+
import { join, resolve } from 'node:path';
|
|
3
|
+
import { writeJsonAtomic } from '../core/json-file.js';
|
|
4
|
+
import { parseDigest, parseTranscript } from './schema.js';
|
|
5
|
+
import { SLUG_PATTERN } from './schema-base.js';
|
|
6
|
+
export { SLUG_PATTERN };
|
|
7
|
+
const SLUG_MAX = 64;
|
|
8
|
+
export function readRaw(path) {
|
|
9
|
+
if (!existsSync(path))
|
|
10
|
+
return { kind: 'missing' };
|
|
11
|
+
try {
|
|
12
|
+
return { kind: 'ok', value: JSON.parse(readFileSync(path, 'utf-8')) };
|
|
13
|
+
}
|
|
14
|
+
catch (e) {
|
|
15
|
+
return { kind: 'invalid-json', message: e instanceof Error ? e.message : String(e) };
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
/** 저장소 바로 아래에서 slug 폴더가 아닌 자리. 사용자 템플릿이 여기 산다 */
|
|
19
|
+
export const TEMPLATES_DIR_NAME = 'templates';
|
|
20
|
+
export function isValidSlug(slug) {
|
|
21
|
+
return SLUG_PATTERN.test(slug) && slug !== TEMPLATES_DIR_NAME;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* 제목을 ascii 소문자와 하이픈으로 줄이고 videoId를 끝에 붙인다.
|
|
25
|
+
* 한국어 제목은 남는 글자가 없어서 videoId만 남는다. 같은 제목의 다른 영상이 섞이지 않게 id는 항상 붙인다.
|
|
26
|
+
*/
|
|
27
|
+
export function slugFromMeta(videoIdOrName, title) {
|
|
28
|
+
const tail = videoIdOrName
|
|
29
|
+
.toLowerCase()
|
|
30
|
+
.replace(/[^a-z0-9]+/g, '-')
|
|
31
|
+
.replace(/^-+|-+$/g, '');
|
|
32
|
+
const head = title
|
|
33
|
+
.toLowerCase()
|
|
34
|
+
.normalize('NFKD')
|
|
35
|
+
.replace(/[^a-z0-9]+/g, '-')
|
|
36
|
+
.replace(/^-+|-+$/g, '');
|
|
37
|
+
const room = SLUG_MAX - tail.length - 1;
|
|
38
|
+
const trimmed = room > 0 ? head.slice(0, room).replace(/-+$/, '') : '';
|
|
39
|
+
const slug = trimmed ? `${trimmed}-${tail}` : tail;
|
|
40
|
+
return slug || 'video';
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* 영상 요약 저장소: `<repoRoot>/.gestalt/digest/<slug>/`.
|
|
44
|
+
* `.gestalt/`는 gitignore 대상이라 프레임과 영상 캐시가 커밋에 딸려가지 않는다.
|
|
45
|
+
*/
|
|
46
|
+
export class DigestStore {
|
|
47
|
+
root;
|
|
48
|
+
constructor(repoRoot) {
|
|
49
|
+
// 외부 명령은 임시 cwd에서 돌아서 상대 경로를 넘기면 프레임 같은 산출물이 그 폴더에 쓰였다가 함께 지워진다
|
|
50
|
+
this.root = join(resolve(repoRoot), '.gestalt', 'digest');
|
|
51
|
+
}
|
|
52
|
+
templatesDir() {
|
|
53
|
+
return join(this.root, TEMPLATES_DIR_NAME);
|
|
54
|
+
}
|
|
55
|
+
/** slug는 경로 조각이라 패턴을 통과한 것만 받는다 */
|
|
56
|
+
dir(slug) {
|
|
57
|
+
if (!isValidSlug(slug))
|
|
58
|
+
throw new Error(`slug가 올바르지 않다: ${slug}`);
|
|
59
|
+
return join(this.root, slug);
|
|
60
|
+
}
|
|
61
|
+
transcriptPath(slug) {
|
|
62
|
+
return join(this.dir(slug), 'transcript.json');
|
|
63
|
+
}
|
|
64
|
+
digestPath(slug) {
|
|
65
|
+
return join(this.dir(slug), 'digest.json');
|
|
66
|
+
}
|
|
67
|
+
htmlPath(slug) {
|
|
68
|
+
return join(this.dir(slug), 'digest.html');
|
|
69
|
+
}
|
|
70
|
+
mdPath(slug) {
|
|
71
|
+
return join(this.dir(slug), 'digest.md');
|
|
72
|
+
}
|
|
73
|
+
framesDir(slug) {
|
|
74
|
+
return join(this.dir(slug), 'frames');
|
|
75
|
+
}
|
|
76
|
+
/** comments 명령이 받아 두는 댓글. 댓글 분석 템플릿이 읽는다 */
|
|
77
|
+
commentsPath(slug) {
|
|
78
|
+
return join(this.dir(slug), 'comments.json');
|
|
79
|
+
}
|
|
80
|
+
/** frames 명령이 받아 두는 저화질 영상. 다시 뽑을 때 또 받지 않으려고 둔다 */
|
|
81
|
+
videoCacheDir(slug) {
|
|
82
|
+
return join(this.dir(slug), 'cache');
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* 깨진 파일도 옮기지 않는다. validate나 render 같은 읽기 명령이 파일을 치우면
|
|
86
|
+
* 사용자는 왜 사라졌는지 모른다. ingest를 다시 돌리면 어차피 덮어쓴다
|
|
87
|
+
*/
|
|
88
|
+
readTranscript(slug) {
|
|
89
|
+
const raw = readRaw(this.transcriptPath(slug));
|
|
90
|
+
const rerun = `gestalt digest ingest를 다시 돌려 주세요: ${slug}`;
|
|
91
|
+
if (raw.kind === 'missing') {
|
|
92
|
+
return {
|
|
93
|
+
ok: false,
|
|
94
|
+
code: 'TRANSCRIPT_NOT_FOUND',
|
|
95
|
+
message: `transcript.json이 없어요. 먼저 gestalt digest ingest를 돌려 주세요: ${slug}`,
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
if (raw.kind === 'invalid-json') {
|
|
99
|
+
return {
|
|
100
|
+
ok: false,
|
|
101
|
+
code: 'TRANSCRIPT_INVALID',
|
|
102
|
+
message: `transcript.json을 JSON으로 못 읽었어요(${raw.message}). ${rerun}`,
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
const parsed = parseTranscript(raw.value);
|
|
106
|
+
if (!parsed.ok) {
|
|
107
|
+
return {
|
|
108
|
+
ok: false,
|
|
109
|
+
code: 'TRANSCRIPT_INVALID',
|
|
110
|
+
message: `transcript.json 형식이 틀렸어요(${parsed.error.issues.slice(0, 3).join('; ')}). ${rerun}`,
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
return { ok: true, transcript: parsed.value };
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* 요약은 세션이 손으로 쓰는 파일이라 깨져도 옮기지 않는다.
|
|
117
|
+
* 옮겨 버리면 validate 오류를 보고 고치려던 원본이 사라진다.
|
|
118
|
+
*/
|
|
119
|
+
readDigestFile(slug) {
|
|
120
|
+
return readRaw(this.digestPath(slug));
|
|
121
|
+
}
|
|
122
|
+
/** 없거나 형식이 틀리면 null. 이유가 필요하면 readDigestFile과 parseDigest를 쓴다 */
|
|
123
|
+
loadDigest(slug) {
|
|
124
|
+
const raw = this.readDigestFile(slug);
|
|
125
|
+
if (raw.kind !== 'ok')
|
|
126
|
+
return null;
|
|
127
|
+
const parsed = parseDigest(raw.value);
|
|
128
|
+
return parsed.ok ? parsed.value : null;
|
|
129
|
+
}
|
|
130
|
+
saveTranscript(transcript) {
|
|
131
|
+
const path = this.transcriptPath(transcript.slug);
|
|
132
|
+
writeJsonAtomic(path, transcript);
|
|
133
|
+
return path;
|
|
134
|
+
}
|
|
135
|
+
saveDigest(digest) {
|
|
136
|
+
const path = this.digestPath(digest.slug);
|
|
137
|
+
writeJsonAtomic(path, digest);
|
|
138
|
+
return path;
|
|
139
|
+
}
|
|
140
|
+
saveHtml(slug, html) {
|
|
141
|
+
return this.writeText(this.htmlPath(slug), slug, html);
|
|
142
|
+
}
|
|
143
|
+
saveMd(slug, md) {
|
|
144
|
+
return this.writeText(this.mdPath(slug), slug, md);
|
|
145
|
+
}
|
|
146
|
+
writeText(path, slug, content) {
|
|
147
|
+
mkdirSync(this.dir(slug), { recursive: true });
|
|
148
|
+
writeFileSync(path, content, 'utf-8');
|
|
149
|
+
return path;
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
//# sourceMappingURL=store.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"store.js","sourceRoot":"","sources":["../../../src/digest/store.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import type { Cite } from './schema.js';
|
|
2
|
+
/**
|
|
3
|
+
* 확장 리포트와 대섹션 도식의 SVG를 그린다. 요약 층은 구조만 넘기고 좌표와 마크업은 여기서 정한다.
|
|
4
|
+
* 모델이 쓴 SVG를 그대로 실으면 스크립트나 외부 링크가 섞여 들어올 수 있어서 원문은 받지 않는다.
|
|
5
|
+
* 색은 CSS 변수를 쓰는 클래스로만 칠해 다크 모드를 따라간다
|
|
6
|
+
*/
|
|
7
|
+
export interface TreeNode {
|
|
8
|
+
label: string;
|
|
9
|
+
cite?: Cite;
|
|
10
|
+
children?: TreeNode[];
|
|
11
|
+
}
|
|
12
|
+
export interface SvgOptions {
|
|
13
|
+
/** cite.key 문장의 시작 시각. 있으면 노드에 data-sec을 달아 누르면 영상이 그 자리로 간다 */
|
|
14
|
+
sec?: (c: Cite) => number;
|
|
15
|
+
}
|
|
16
|
+
export declare const escapeXml: (s: string) => string;
|
|
17
|
+
export declare function textWidth(text: string, fontSize?: number): number;
|
|
18
|
+
/** maxPx 안에 들어오게 자른다. 잘랐으면 끝에 말줄임표를 붙인다 */
|
|
19
|
+
export declare function fitLabel(text: string, maxPx?: number, fontSize?: number): {
|
|
20
|
+
text: string;
|
|
21
|
+
cut: boolean;
|
|
22
|
+
};
|
|
23
|
+
/**
|
|
24
|
+
* 왼쪽에서 오른쪽으로 펼친 트리. 잎마다 한 줄을 주고 부모는 첫 자식과 마지막 자식의 가운데에 둔다
|
|
25
|
+
*/
|
|
26
|
+
export declare function treeSvg(root: TreeNode, opts?: SvgOptions, ariaLabel?: string): string;
|
|
27
|
+
export interface DiagramNode {
|
|
28
|
+
label: string;
|
|
29
|
+
cite?: Cite;
|
|
30
|
+
}
|
|
31
|
+
/** 단계 흐름. 넷까지는 가로로, 그보다 많으면 세로로 잇는다 */
|
|
32
|
+
export declare function flowSvg(steps: DiagramNode[], opts?: SvgOptions, ariaLabel?: string): string;
|
|
33
|
+
/**
|
|
34
|
+
* 순환. 상자를 타원 위에 12시부터 시계 방향으로 놓고 이웃끼리 타원 호로 잇는다.
|
|
35
|
+
* 상자 폭이 제각각이라 반지름은 공식으로 못 정하고 겹치지 않으면서 사이 호가 보일 때까지 키운다
|
|
36
|
+
*/
|
|
37
|
+
export declare function cycleSvg(steps: DiagramNode[], opts?: SvgOptions, ariaLabel?: string): string;
|
|
38
|
+
export interface CompareColumn {
|
|
39
|
+
title: string;
|
|
40
|
+
items: DiagramNode[];
|
|
41
|
+
}
|
|
42
|
+
/** 비교. 열마다 머리 상자 아래로 항목을 쌓는다 */
|
|
43
|
+
export declare function compareSvg(columns: CompareColumn[], opts?: SvgOptions, ariaLabel?: string): string;
|
|
44
|
+
export interface TimelineEvent extends DiagramNode {
|
|
45
|
+
when: string;
|
|
46
|
+
}
|
|
47
|
+
/** 시점 글자는 WHEN_MAX(px) 폭까지 그리고 넘으면 말줄임으로 자른다. 줄 위 글자가 이웃 칸으로 넘어가면 어느 점의 시점인지 안 읽힌다 */
|
|
48
|
+
export declare const WHEN_MAX = 120;
|
|
49
|
+
/**
|
|
50
|
+
* 타임라인. 넷까지는 가로 줄 위에 시점, 아래에 상자를 두고 그보다 많으면 세로 줄 오른쪽에 시점과 상자를 둔다.
|
|
51
|
+
* 줄 끝 화살촉이 시간 방향이다
|
|
52
|
+
*/
|
|
53
|
+
export declare function timelineSvg(events: TimelineEvent[], opts?: SvgOptions, ariaLabel?: string): string;
|
|
54
|
+
export interface MatrixAxis {
|
|
55
|
+
low: string;
|
|
56
|
+
high: string;
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* 2×2 매트릭스. cells는 왼쪽 위, 오른쪽 위, 왼쪽 아래, 오른쪽 아래 순서다.
|
|
60
|
+
* 세로축은 아래에서 위로, 가로축은 왼쪽에서 오른쪽으로 커진다
|
|
61
|
+
*/
|
|
62
|
+
export declare function matrixSvg(x: MatrixAxis, y: MatrixAxis, cells: DiagramNode[][], opts?: SvgOptions, ariaLabel?: string): string;
|
|
63
|
+
/**
|
|
64
|
+
* 원인과 결과. 왼쪽 원인들이 가운데 현상으로 모이고 오른쪽 결과로 퍼진다.
|
|
65
|
+
* 아무 노드나 잇는 그래프는 받지 않는다. 자동 배치가 어렵고 선이 엉켜서다
|
|
66
|
+
*/
|
|
67
|
+
export declare function causalSvg(inputs: DiagramNode[], center: DiagramNode, outputs: DiagramNode[], opts?: SvgOptions, ariaLabel?: string): string;
|
|
68
|
+
export interface BeforeAfterSide {
|
|
69
|
+
title?: string;
|
|
70
|
+
items: DiagramNode[];
|
|
71
|
+
}
|
|
72
|
+
/** 전후 비교. compare와 달리 두 칸 사이에 화살표를 그려 무엇이 바뀌었는지를 보인다 */
|
|
73
|
+
export declare function beforeAfterSvg(before: BeforeAfterSide, after: BeforeAfterSide, opts?: SvgOptions, ariaLabel?: string): string;
|
|
74
|
+
//# sourceMappingURL=svg.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"svg.d.ts","sourceRoot":"","sources":["../../../src/digest/svg.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,aAAa,CAAC;AAExC;;;;GAIG;AAEH,MAAM,WAAW,QAAQ;IACvB,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,IAAI,CAAC;IACZ,QAAQ,CAAC,EAAE,QAAQ,EAAE,CAAC;CACvB;AAED,MAAM,WAAW,UAAU;IACzB,gEAAgE;IAChE,GAAG,CAAC,EAAE,CAAC,CAAC,EAAE,IAAI,KAAK,MAAM,CAAC;CAC3B;AAYD,eAAO,MAAM,SAAS,GAAI,GAAG,MAAM,KAAG,MAMX,CAAC;AAW5B,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,SAAO,GAAG,MAAM,CAI/D;AAED,2CAA2C;AAC3C,wBAAgB,QAAQ,CACtB,IAAI,EAAE,MAAM,EACZ,KAAK,SAAY,EACjB,QAAQ,SAAO,GACd;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,OAAO,CAAA;CAAE,CAYhC;AAYD;;GAEG;AACH,wBAAgB,OAAO,CAAC,IAAI,EAAE,QAAQ,EAAE,IAAI,GAAE,UAAe,EAAE,SAAS,CAAC,EAAE,MAAM,GAAG,MAAM,CAkDzF;AAED,MAAM,WAAW,WAAW;IAC1B,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,IAAI,CAAC;CACb;AA2DD,uCAAuC;AACvC,wBAAgB,OAAO,CAAC,KAAK,EAAE,WAAW,EAAE,EAAE,IAAI,GAAE,UAAe,EAAE,SAAS,SAAQ,GAAG,MAAM,CA8B9F;AAeD;;;GAGG;AACH,wBAAgB,QAAQ,CACtB,KAAK,EAAE,WAAW,EAAE,EACpB,IAAI,GAAE,UAAe,EACrB,SAAS,SAAQ,GAChB,MAAM,CAuER;AAED,MAAM,WAAW,aAAa;IAC5B,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,WAAW,EAAE,CAAC;CACtB;AAED,gCAAgC;AAChC,wBAAgB,UAAU,CACxB,OAAO,EAAE,aAAa,EAAE,EACxB,IAAI,GAAE,UAAe,EACrB,SAAS,SAAQ,GAChB,MAAM,CAiBR;AA0BD,MAAM,WAAW,aAAc,SAAQ,WAAW;IAChD,IAAI,EAAE,MAAM,CAAC;CACd;AAED,sFAAsF;AACtF,eAAO,MAAM,QAAQ,MAAM,CAAC;AAE5B;;;GAGG;AACH,wBAAgB,WAAW,CACzB,MAAM,EAAE,aAAa,EAAE,EACvB,IAAI,GAAE,UAAe,EACrB,SAAS,SAAS,GACjB,MAAM,CA6CR;AAED,MAAM,WAAW,UAAU;IACzB,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,CAAC;CACd;AAED;;;GAGG;AACH,wBAAgB,SAAS,CACvB,CAAC,EAAE,UAAU,EACb,CAAC,EAAE,UAAU,EACb,KAAK,EAAE,WAAW,EAAE,EAAE,EACtB,IAAI,GAAE,UAAe,EACrB,SAAS,SAAS,GACjB,MAAM,CAiCR;AAED;;;GAGG;AACH,wBAAgB,SAAS,CACvB,MAAM,EAAE,WAAW,EAAE,EACrB,MAAM,EAAE,WAAW,EACnB,OAAO,EAAE,WAAW,EAAE,EACtB,IAAI,GAAE,UAAe,EACrB,SAAS,SAAQ,GAChB,MAAM,CA2BR;AAED,MAAM,WAAW,eAAe;IAC9B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,WAAW,EAAE,CAAC;CACtB;AAED,wDAAwD;AACxD,wBAAgB,cAAc,CAC5B,MAAM,EAAE,eAAe,EACvB,KAAK,EAAE,eAAe,EACtB,IAAI,GAAE,UAAe,EACrB,SAAS,SAAU,GAClB,MAAM,CAwBR"}
|