@actalk/inkos-core 1.6.3 → 1.7.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 (163) hide show
  1. package/dist/agent/agent-session.d.ts.map +1 -1
  2. package/dist/agent/agent-session.js +21 -11
  3. package/dist/agent/agent-session.js.map +1 -1
  4. package/dist/agent/agent-system-prompt.d.ts.map +1 -1
  5. package/dist/agent/agent-system-prompt.js +14 -8
  6. package/dist/agent/agent-system-prompt.js.map +1 -1
  7. package/dist/agent/agent-tools.d.ts +34 -2
  8. package/dist/agent/agent-tools.d.ts.map +1 -1
  9. package/dist/agent/agent-tools.js +236 -54
  10. package/dist/agent/agent-tools.js.map +1 -1
  11. package/dist/agent/chapter-import-source.d.ts +15 -0
  12. package/dist/agent/chapter-import-source.d.ts.map +1 -0
  13. package/dist/agent/chapter-import-source.js +41 -0
  14. package/dist/agent/chapter-import-source.js.map +1 -0
  15. package/dist/agent/film-authoring-tools.d.ts +5 -3
  16. package/dist/agent/film-authoring-tools.d.ts.map +1 -1
  17. package/dist/agent/film-authoring-tools.js +34 -19
  18. package/dist/agent/film-authoring-tools.js.map +1 -1
  19. package/dist/agent/index.d.ts +1 -1
  20. package/dist/agent/index.d.ts.map +1 -1
  21. package/dist/agent/index.js +1 -1
  22. package/dist/agent/index.js.map +1 -1
  23. package/dist/agents/base.d.ts +1 -0
  24. package/dist/agents/base.d.ts.map +1 -1
  25. package/dist/agents/base.js +2 -0
  26. package/dist/agents/base.js.map +1 -1
  27. package/dist/agents/script-storyboard.d.ts +3 -0
  28. package/dist/agents/script-storyboard.d.ts.map +1 -1
  29. package/dist/agents/script-storyboard.js +221 -14
  30. package/dist/agents/script-storyboard.js.map +1 -1
  31. package/dist/agents/short-fiction.d.ts +13 -2
  32. package/dist/agents/short-fiction.d.ts.map +1 -1
  33. package/dist/agents/short-fiction.js +77 -43
  34. package/dist/agents/short-fiction.js.map +1 -1
  35. package/dist/index.d.ts +8 -5
  36. package/dist/index.d.ts.map +1 -1
  37. package/dist/index.js +10 -8
  38. package/dist/index.js.map +1 -1
  39. package/dist/interaction/action-envelope.d.ts +53 -1
  40. package/dist/interaction/action-envelope.d.ts.map +1 -1
  41. package/dist/interaction/action-envelope.js +9 -0
  42. package/dist/interaction/action-envelope.js.map +1 -1
  43. package/dist/interaction/intents.d.ts +2 -2
  44. package/dist/interaction/project-control.d.ts +1 -1
  45. package/dist/interactive-film/generate.d.ts +1 -0
  46. package/dist/interactive-film/generate.d.ts.map +1 -1
  47. package/dist/interactive-film/generate.js +15 -5
  48. package/dist/interactive-film/generate.js.map +1 -1
  49. package/dist/llm/provider.d.ts +1 -0
  50. package/dist/llm/provider.d.ts.map +1 -1
  51. package/dist/llm/provider.js +64 -18
  52. package/dist/llm/provider.js.map +1 -1
  53. package/dist/llm/providers/endpoints/openrouter.d.ts.map +1 -1
  54. package/dist/llm/providers/endpoints/openrouter.js +3 -2
  55. package/dist/llm/providers/endpoints/openrouter.js.map +1 -1
  56. package/dist/llm/think-tag-stripper.d.ts +15 -0
  57. package/dist/llm/think-tag-stripper.d.ts.map +1 -0
  58. package/dist/llm/think-tag-stripper.js +60 -0
  59. package/dist/llm/think-tag-stripper.js.map +1 -0
  60. package/dist/materials/ingest.d.ts.map +1 -1
  61. package/dist/materials/ingest.js +4 -3
  62. package/dist/materials/ingest.js.map +1 -1
  63. package/dist/materials/retrieve.d.ts.map +1 -1
  64. package/dist/materials/retrieve.js +3 -1
  65. package/dist/materials/retrieve.js.map +1 -1
  66. package/dist/models/book.d.ts +28 -0
  67. package/dist/models/book.d.ts.map +1 -1
  68. package/dist/models/book.js +22 -0
  69. package/dist/models/book.js.map +1 -1
  70. package/dist/models/project.d.ts +40 -0
  71. package/dist/models/project.d.ts.map +1 -1
  72. package/dist/models/project.js +5 -0
  73. package/dist/models/project.js.map +1 -1
  74. package/dist/notify/dispatcher.d.ts.map +1 -1
  75. package/dist/notify/dispatcher.js +8 -5
  76. package/dist/notify/dispatcher.js.map +1 -1
  77. package/dist/notify/feishu.d.ts +2 -1
  78. package/dist/notify/feishu.d.ts.map +1 -1
  79. package/dist/notify/feishu.js +12 -6
  80. package/dist/notify/feishu.js.map +1 -1
  81. package/dist/notify/format.d.ts +12 -0
  82. package/dist/notify/format.d.ts.map +1 -0
  83. package/dist/notify/format.js +11 -0
  84. package/dist/notify/format.js.map +1 -0
  85. package/dist/notify/telegram.d.ts +2 -1
  86. package/dist/notify/telegram.d.ts.map +1 -1
  87. package/dist/notify/telegram.js +3 -2
  88. package/dist/notify/telegram.js.map +1 -1
  89. package/dist/notify/wechat-work.d.ts +2 -1
  90. package/dist/notify/wechat-work.d.ts.map +1 -1
  91. package/dist/notify/wechat-work.js +5 -5
  92. package/dist/notify/wechat-work.js.map +1 -1
  93. package/dist/pipeline/runner.d.ts +13 -1
  94. package/dist/pipeline/runner.d.ts.map +1 -1
  95. package/dist/pipeline/runner.js +41 -7
  96. package/dist/pipeline/runner.js.map +1 -1
  97. package/dist/pipeline/script-storyboard-runner.d.ts +3 -0
  98. package/dist/pipeline/script-storyboard-runner.d.ts.map +1 -1
  99. package/dist/pipeline/script-storyboard-runner.js +86 -43
  100. package/dist/pipeline/script-storyboard-runner.js.map +1 -1
  101. package/dist/pipeline/short-fiction-runner.d.ts +3 -1
  102. package/dist/pipeline/short-fiction-runner.d.ts.map +1 -1
  103. package/dist/pipeline/short-fiction-runner.js +80 -33
  104. package/dist/pipeline/short-fiction-runner.js.map +1 -1
  105. package/dist/play/play-runner.d.ts +8 -0
  106. package/dist/play/play-runner.d.ts.map +1 -1
  107. package/dist/play/play-runner.js +14 -0
  108. package/dist/play/play-runner.js.map +1 -1
  109. package/dist/prompts/short-fiction.d.ts +14 -13
  110. package/dist/prompts/short-fiction.d.ts.map +1 -1
  111. package/dist/prompts/short-fiction.js +253 -14
  112. package/dist/prompts/short-fiction.js.map +1 -1
  113. package/dist/state/manager.d.ts +16 -2
  114. package/dist/state/manager.d.ts.map +1 -1
  115. package/dist/state/manager.js +218 -31
  116. package/dist/state/manager.js.map +1 -1
  117. package/dist/translation/epub.d.ts +10 -0
  118. package/dist/translation/epub.d.ts.map +1 -0
  119. package/dist/translation/epub.js +86 -0
  120. package/dist/translation/epub.js.map +1 -0
  121. package/dist/translation/export.d.ts +6 -0
  122. package/dist/translation/export.d.ts.map +1 -0
  123. package/dist/translation/export.js +68 -0
  124. package/dist/translation/export.js.map +1 -0
  125. package/dist/translation/index.d.ts +9 -0
  126. package/dist/translation/index.d.ts.map +1 -0
  127. package/dist/translation/index.js +9 -0
  128. package/dist/translation/index.js.map +1 -0
  129. package/dist/translation/llm-model.d.ts +8 -0
  130. package/dist/translation/llm-model.d.ts.map +1 -0
  131. package/dist/translation/llm-model.js +134 -0
  132. package/dist/translation/llm-model.js.map +1 -0
  133. package/dist/translation/project.d.ts +3 -0
  134. package/dist/translation/project.d.ts.map +1 -0
  135. package/dist/translation/project.js +76 -0
  136. package/dist/translation/project.js.map +1 -0
  137. package/dist/translation/run-store.d.ts +11 -0
  138. package/dist/translation/run-store.d.ts.map +1 -0
  139. package/dist/translation/run-store.js +53 -0
  140. package/dist/translation/run-store.js.map +1 -0
  141. package/dist/translation/runner.d.ts +6 -0
  142. package/dist/translation/runner.d.ts.map +1 -0
  143. package/dist/translation/runner.js +88 -0
  144. package/dist/translation/runner.js.map +1 -0
  145. package/dist/translation/source.d.ts +12 -0
  146. package/dist/translation/source.d.ts.map +1 -0
  147. package/dist/translation/source.js +66 -0
  148. package/dist/translation/source.js.map +1 -0
  149. package/dist/translation/text.d.ts +10 -0
  150. package/dist/translation/text.d.ts.map +1 -0
  151. package/dist/translation/text.js +77 -0
  152. package/dist/translation/text.js.map +1 -0
  153. package/dist/translation/types.d.ts +96 -0
  154. package/dist/translation/types.d.ts.map +1 -0
  155. package/dist/translation/types.js +2 -0
  156. package/dist/translation/types.js.map +1 -0
  157. package/dist/utils/effective-llm-config.js +19 -1
  158. package/dist/utils/effective-llm-config.js.map +1 -1
  159. package/dist/utils/posix-path.d.ts +2 -0
  160. package/dist/utils/posix-path.d.ts.map +1 -0
  161. package/dist/utils/posix-path.js +7 -0
  162. package/dist/utils/posix-path.js.map +1 -0
  163. package/package.json +4 -3
@@ -0,0 +1,134 @@
1
+ import { chatCompletion } from "../llm/provider.js";
2
+ export function createLLMTranslationModel(input) {
3
+ return {
4
+ async translateSegments(request) {
5
+ const response = await chatCompletion(input.client, input.model, [
6
+ {
7
+ role: "system",
8
+ content: [
9
+ "You are InkOS Translation Agent.",
10
+ "Translate faithfully between the requested languages.",
11
+ "Preserve paragraph order, scene meaning, names, tone, and terminology.",
12
+ "Do not summarize. Do not add commentary outside JSON.",
13
+ "Return JSON only: {\"segments\":[{\"index\":1,\"target\":\"...\",\"notes\":\"optional\"}],\"glossary\":[{\"source\":\"...\",\"target\":\"...\",\"note\":\"optional\"}]}",
14
+ ].join("\n"),
15
+ },
16
+ {
17
+ role: "user",
18
+ content: JSON.stringify({
19
+ sourceLanguage: request.sourceLanguage,
20
+ targetLanguage: request.targetLanguage,
21
+ chapterTitle: request.chapterTitle,
22
+ glossary: request.glossary,
23
+ segments: request.segments.map((segment) => ({
24
+ index: segment.index,
25
+ source: segment.source,
26
+ })),
27
+ }, null, 2),
28
+ },
29
+ ], { temperature: 0.2, maxTokens: input.maxTokens ?? 8192 });
30
+ const parsed = parseJsonObject(response.content);
31
+ return {
32
+ segments: parseTranslatedSegments(parsed.segments, request.segments),
33
+ glossary: parseGlossary(parsed.glossary),
34
+ };
35
+ },
36
+ async reviewChapter(request) {
37
+ const response = await chatCompletion(input.client, input.model, [
38
+ {
39
+ role: "system",
40
+ content: [
41
+ "You are InkOS Translation Review Agent.",
42
+ "Check fidelity, omissions, terminology, pronouns, names, and target-language readability.",
43
+ "Return JSON only: {\"passed\":true,\"summary\":\"...\",\"issues\":[\"...\"]}.",
44
+ ].join("\n"),
45
+ },
46
+ {
47
+ role: "user",
48
+ content: JSON.stringify({
49
+ sourceLanguage: request.sourceLanguage,
50
+ targetLanguage: request.targetLanguage,
51
+ chapterTitle: request.chapterTitle,
52
+ glossary: request.glossary,
53
+ segments: request.segments.map((segment) => ({
54
+ index: segment.index,
55
+ source: segment.source,
56
+ target: segment.target ?? "",
57
+ })),
58
+ }, null, 2),
59
+ },
60
+ ], { temperature: 0.1, maxTokens: 4096 });
61
+ const parsed = parseJsonObject(response.content);
62
+ return {
63
+ passed: parsed.passed === true,
64
+ summary: typeof parsed.summary === "string" ? parsed.summary : "Translation review completed.",
65
+ issues: Array.isArray(parsed.issues) ? parsed.issues.filter((issue) => typeof issue === "string") : [],
66
+ };
67
+ },
68
+ };
69
+ }
70
+ function parseTranslatedSegments(value, sourceSegments) {
71
+ if (!Array.isArray(value)) {
72
+ throw new Error("Translation model did not return a segments array.");
73
+ }
74
+ const sourceIndex = new Set(sourceSegments.map((segment) => segment.index));
75
+ const parsed = value.flatMap((item) => {
76
+ if (!item || typeof item !== "object")
77
+ return [];
78
+ const record = item;
79
+ const index = Number(record.index);
80
+ const target = typeof record.target === "string" ? record.target.trim() : "";
81
+ if (!Number.isInteger(index) || !sourceIndex.has(index) || !target)
82
+ return [];
83
+ return [{
84
+ index,
85
+ target,
86
+ ...(typeof record.notes === "string" && record.notes.trim() ? { notes: record.notes.trim() } : {}),
87
+ }];
88
+ });
89
+ if (parsed.length === 0)
90
+ throw new Error("Translation model returned no usable translated segments.");
91
+ return parsed;
92
+ }
93
+ function parseGlossary(value) {
94
+ if (!Array.isArray(value))
95
+ return [];
96
+ return value.flatMap((item) => {
97
+ if (!item || typeof item !== "object")
98
+ return [];
99
+ const record = item;
100
+ const source = typeof record.source === "string" ? record.source.trim() : "";
101
+ const target = typeof record.target === "string" ? record.target.trim() : "";
102
+ if (!source || !target)
103
+ return [];
104
+ return [{
105
+ source,
106
+ target,
107
+ ...(typeof record.note === "string" && record.note.trim() ? { note: record.note.trim() } : {}),
108
+ }];
109
+ });
110
+ }
111
+ function parseJsonObject(raw) {
112
+ const trimmed = stripFence(raw.trim());
113
+ try {
114
+ const parsed = JSON.parse(trimmed);
115
+ if (parsed && typeof parsed === "object" && !Array.isArray(parsed))
116
+ return parsed;
117
+ }
118
+ catch {
119
+ // Try extracting the first object below.
120
+ }
121
+ const start = trimmed.indexOf("{");
122
+ const end = trimmed.lastIndexOf("}");
123
+ if (start >= 0 && end > start) {
124
+ const parsed = JSON.parse(trimmed.slice(start, end + 1));
125
+ if (parsed && typeof parsed === "object" && !Array.isArray(parsed))
126
+ return parsed;
127
+ }
128
+ throw new Error("Translation model did not return a JSON object.");
129
+ }
130
+ function stripFence(raw) {
131
+ const match = /^```(?:json)?\s*([\s\S]*?)\s*```$/i.exec(raw);
132
+ return match ? match[1].trim() : raw;
133
+ }
134
+ //# sourceMappingURL=llm-model.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"llm-model.js","sourceRoot":"","sources":["../../src/translation/llm-model.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import type { CreateTranslationProjectInput, TranslationProjectCreateResult } from "./types.js";
2
+ export declare function createTranslationProjectFromFile(projectRoot: string, input: CreateTranslationProjectInput): Promise<TranslationProjectCreateResult>;
3
+ //# sourceMappingURL=project.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"project.d.ts","sourceRoot":"","sources":["../../src/translation/project.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EACV,6BAA6B,EAG7B,8BAA8B,EAE/B,MAAM,YAAY,CAAC;AAEpB,wBAAsB,gCAAgC,CACpD,WAAW,EAAE,MAAM,EACnB,KAAK,EAAE,6BAA6B,GACnC,OAAO,CAAC,8BAA8B,CAAC,CAgEzC"}
@@ -0,0 +1,76 @@
1
+ import { mkdir, writeFile } from "node:fs/promises";
2
+ import { join, relative } from "node:path";
3
+ import { toPosixPath } from "../utils/posix-path.js";
4
+ import { extractTranslationSource } from "./source.js";
5
+ import { segmentTranslationText } from "./text.js";
6
+ export async function createTranslationProjectFromFile(projectRoot, input) {
7
+ const source = await extractTranslationSource(projectRoot, input);
8
+ const now = new Date().toISOString();
9
+ const id = `${now.replace(/[:.]/g, "-")}-${slug(source.title)}`;
10
+ const projectDirAbs = join(projectRoot, "translations", id);
11
+ const sourceDirAbs = join(projectDirAbs, "source");
12
+ const translatedDirAbs = join(projectDirAbs, "translated");
13
+ await mkdir(sourceDirAbs, { recursive: true });
14
+ await mkdir(translatedDirAbs, { recursive: true });
15
+ const chapters = [];
16
+ for (const [index, chapter] of source.chapters.entries()) {
17
+ const number = index + 1;
18
+ const sourceChapterAbs = join(sourceDirAbs, `chapter-${number.toString().padStart(4, "0")}.json`);
19
+ const translatedChapterAbs = join(translatedDirAbs, `chapter-${number.toString().padStart(4, "0")}.json`);
20
+ const segments = segmentTranslationText(chapter.content, input.segmentMaxChars).map((segment, segmentIndex) => ({
21
+ index: segmentIndex + 1,
22
+ source: segment,
23
+ }));
24
+ const chapterFile = {
25
+ number,
26
+ title: chapter.title,
27
+ sourceLanguage: input.sourceLanguage,
28
+ targetLanguage: input.targetLanguage,
29
+ segments,
30
+ };
31
+ await writeFile(sourceChapterAbs, JSON.stringify(chapterFile, null, 2), "utf-8");
32
+ await writeFile(translatedChapterAbs, JSON.stringify({ ...chapterFile, segments: [] }, null, 2), "utf-8");
33
+ chapters.push({
34
+ number,
35
+ title: chapter.title,
36
+ sourcePath: toPosixPath(relative(projectRoot, sourceChapterAbs)),
37
+ translatedPath: toPosixPath(relative(projectRoot, translatedChapterAbs)),
38
+ segmentCount: segments.length,
39
+ charCount: chapter.content.length,
40
+ status: "pending",
41
+ });
42
+ }
43
+ const manifest = {
44
+ id,
45
+ title: input.title?.trim() || source.title,
46
+ sourceLanguage: input.sourceLanguage,
47
+ targetLanguage: input.targetLanguage,
48
+ createdAt: now,
49
+ updatedAt: now,
50
+ source: {
51
+ kind: source.kind,
52
+ path: source.sourcePath,
53
+ charCount: source.charCount,
54
+ ...(source.totalPages !== undefined ? { totalPages: source.totalPages } : {}),
55
+ },
56
+ chapters,
57
+ };
58
+ const manifestPathAbs = join(projectDirAbs, "manifest.json");
59
+ await writeFile(manifestPathAbs, JSON.stringify(manifest, null, 2), "utf-8");
60
+ await writeFile(join(projectDirAbs, "glossary.json"), JSON.stringify({ terms: [] }, null, 2), "utf-8");
61
+ await writeFile(join(projectDirAbs, "review-report.md"), "# Translation Review\n\nPending.\n", "utf-8");
62
+ return {
63
+ projectDir: toPosixPath(relative(projectRoot, projectDirAbs)),
64
+ manifestPath: toPosixPath(relative(projectRoot, manifestPathAbs)),
65
+ manifest,
66
+ };
67
+ }
68
+ function slug(value) {
69
+ return value
70
+ .trim()
71
+ .toLowerCase()
72
+ .replace(/[^\p{L}\p{N}]+/gu, "-")
73
+ .replace(/^-+|-+$/g, "")
74
+ .slice(0, 80) || "translation";
75
+ }
76
+ //# sourceMappingURL=project.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"project.js","sourceRoot":"","sources":["../../src/translation/project.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,11 @@
1
+ import type { TranslationChapterFile, TranslationGlossaryTerm, TranslationProjectManifest } from "./types.js";
2
+ export declare function translationProjectDir(projectRoot: string, projectId: string): string;
3
+ export declare function translationManifestPath(projectRoot: string, projectId: string): string;
4
+ export declare function loadTranslationManifest(projectRoot: string, projectId: string): Promise<TranslationProjectManifest>;
5
+ export declare function saveTranslationManifest(projectRoot: string, manifest: TranslationProjectManifest): Promise<void>;
6
+ export declare function loadTranslationChapter(projectRoot: string, chapterPath: string): Promise<TranslationChapterFile>;
7
+ export declare function saveTranslationChapter(projectRoot: string, chapterPath: string, chapter: TranslationChapterFile): Promise<void>;
8
+ export declare function loadTranslationGlossary(projectRoot: string, projectId: string): Promise<ReadonlyArray<TranslationGlossaryTerm>>;
9
+ export declare function saveTranslationGlossary(projectRoot: string, projectId: string, terms: ReadonlyArray<TranslationGlossaryTerm>): Promise<void>;
10
+ export declare function mergeGlossaryTerms(terms: ReadonlyArray<TranslationGlossaryTerm>): ReadonlyArray<TranslationGlossaryTerm>;
11
+ //# sourceMappingURL=run-store.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"run-store.d.ts","sourceRoot":"","sources":["../../src/translation/run-store.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EACV,sBAAsB,EACtB,uBAAuB,EACvB,0BAA0B,EAC3B,MAAM,YAAY,CAAC;AAEpB,wBAAgB,qBAAqB,CAAC,WAAW,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,CAEpF;AAED,wBAAgB,uBAAuB,CAAC,WAAW,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,CAEtF;AAED,wBAAsB,uBAAuB,CAC3C,WAAW,EAAE,MAAM,EACnB,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,0BAA0B,CAAC,CAErC;AAED,wBAAsB,uBAAuB,CAC3C,WAAW,EAAE,MAAM,EACnB,QAAQ,EAAE,0BAA0B,GACnC,OAAO,CAAC,IAAI,CAAC,CAEf;AAED,wBAAsB,sBAAsB,CAC1C,WAAW,EAAE,MAAM,EACnB,WAAW,EAAE,MAAM,GAClB,OAAO,CAAC,sBAAsB,CAAC,CAEjC;AAED,wBAAsB,sBAAsB,CAC1C,WAAW,EAAE,MAAM,EACnB,WAAW,EAAE,MAAM,EACnB,OAAO,EAAE,sBAAsB,GAC9B,OAAO,CAAC,IAAI,CAAC,CAEf;AAED,wBAAsB,uBAAuB,CAC3C,WAAW,EAAE,MAAM,EACnB,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,aAAa,CAAC,uBAAuB,CAAC,CAAC,CASjD;AAED,wBAAsB,uBAAuB,CAC3C,WAAW,EAAE,MAAM,EACnB,SAAS,EAAE,MAAM,EACjB,KAAK,EAAE,aAAa,CAAC,uBAAuB,CAAC,GAC5C,OAAO,CAAC,IAAI,CAAC,CAMf;AAED,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,aAAa,CAAC,uBAAuB,CAAC,GAAG,aAAa,CAAC,uBAAuB,CAAC,CAYxH"}
@@ -0,0 +1,53 @@
1
+ import { readFile, writeFile } from "node:fs/promises";
2
+ import { join } from "node:path";
3
+ export function translationProjectDir(projectRoot, projectId) {
4
+ return join(projectRoot, "translations", projectId);
5
+ }
6
+ export function translationManifestPath(projectRoot, projectId) {
7
+ return join(translationProjectDir(projectRoot, projectId), "manifest.json");
8
+ }
9
+ export async function loadTranslationManifest(projectRoot, projectId) {
10
+ return JSON.parse(await readFile(translationManifestPath(projectRoot, projectId), "utf-8"));
11
+ }
12
+ export async function saveTranslationManifest(projectRoot, manifest) {
13
+ await writeFile(translationManifestPath(projectRoot, manifest.id), JSON.stringify(manifest, null, 2), "utf-8");
14
+ }
15
+ export async function loadTranslationChapter(projectRoot, chapterPath) {
16
+ return JSON.parse(await readFile(join(projectRoot, chapterPath), "utf-8"));
17
+ }
18
+ export async function saveTranslationChapter(projectRoot, chapterPath, chapter) {
19
+ await writeFile(join(projectRoot, chapterPath), JSON.stringify(chapter, null, 2), "utf-8");
20
+ }
21
+ export async function loadTranslationGlossary(projectRoot, projectId) {
22
+ try {
23
+ const raw = JSON.parse(await readFile(join(translationProjectDir(projectRoot, projectId), "glossary.json"), "utf-8"));
24
+ return Array.isArray(raw.terms) ? raw.terms.filter(isGlossaryTerm) : [];
25
+ }
26
+ catch {
27
+ return [];
28
+ }
29
+ }
30
+ export async function saveTranslationGlossary(projectRoot, projectId, terms) {
31
+ await writeFile(join(translationProjectDir(projectRoot, projectId), "glossary.json"), JSON.stringify({ terms: mergeGlossaryTerms(terms) }, null, 2), "utf-8");
32
+ }
33
+ export function mergeGlossaryTerms(terms) {
34
+ const map = new Map();
35
+ for (const term of terms) {
36
+ const key = term.source.trim().toLowerCase();
37
+ if (!key)
38
+ continue;
39
+ map.set(key, {
40
+ source: term.source.trim(),
41
+ target: term.target.trim(),
42
+ ...(term.note?.trim() ? { note: term.note.trim() } : {}),
43
+ });
44
+ }
45
+ return [...map.values()];
46
+ }
47
+ function isGlossaryTerm(value) {
48
+ if (!value || typeof value !== "object")
49
+ return false;
50
+ const record = value;
51
+ return typeof record.source === "string" && typeof record.target === "string";
52
+ }
53
+ //# sourceMappingURL=run-store.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"run-store.js","sourceRoot":"","sources":["../../src/translation/run-store.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,6 @@
1
+ import type { RunTranslationProjectResult, TranslationModelPort } from "./types.js";
2
+ export declare function runTranslationProject(projectRoot: string, projectId: string, options: {
3
+ readonly model: TranslationModelPort;
4
+ readonly batchSize?: number;
5
+ }): Promise<RunTranslationProjectResult>;
6
+ //# sourceMappingURL=runner.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"runner.d.ts","sourceRoot":"","sources":["../../src/translation/runner.ts"],"names":[],"mappings":"AAYA,OAAO,KAAK,EACV,2BAA2B,EAE3B,oBAAoB,EAGrB,MAAM,YAAY,CAAC;AAEpB,wBAAsB,qBAAqB,CACzC,WAAW,EAAE,MAAM,EACnB,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE;IACP,QAAQ,CAAC,KAAK,EAAE,oBAAoB,CAAC;IACrC,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;CAC7B,GACA,OAAO,CAAC,2BAA2B,CAAC,CA4EtC"}
@@ -0,0 +1,88 @@
1
+ import { writeFile } from "node:fs/promises";
2
+ import { join } from "node:path";
3
+ import { loadTranslationChapter, loadTranslationGlossary, loadTranslationManifest, mergeGlossaryTerms, saveTranslationChapter, saveTranslationGlossary, saveTranslationManifest, translationProjectDir, } from "./run-store.js";
4
+ export async function runTranslationProject(projectRoot, projectId, options) {
5
+ let manifest = await loadTranslationManifest(projectRoot, projectId);
6
+ let glossary = [...await loadTranslationGlossary(projectRoot, projectId)];
7
+ const reportLines = [`# Translation Review`, ""];
8
+ let translatedSegments = 0;
9
+ let reviewedChapters = 0;
10
+ const batchSize = Math.max(1, Math.min(options.batchSize ?? 8, 32));
11
+ for (const chapterInfo of manifest.chapters) {
12
+ const source = await loadTranslationChapter(projectRoot, chapterInfo.sourcePath);
13
+ const translated = await loadTranslationChapter(projectRoot, chapterInfo.translatedPath).catch(() => ({
14
+ ...source,
15
+ segments: [],
16
+ }));
17
+ const translatedByIndex = new Map(translated.segments.map((segment) => [segment.index, segment]));
18
+ const pending = source.segments.filter((segment) => !translatedByIndex.get(segment.index)?.target?.trim());
19
+ for (let offset = 0; offset < pending.length; offset += batchSize) {
20
+ const batch = pending.slice(offset, offset + batchSize);
21
+ const result = await options.model.translateSegments({
22
+ sourceLanguage: manifest.sourceLanguage,
23
+ targetLanguage: manifest.targetLanguage,
24
+ chapterTitle: source.title,
25
+ segments: batch,
26
+ glossary,
27
+ });
28
+ for (const item of result.segments) {
29
+ const original = source.segments.find((segment) => segment.index === item.index);
30
+ if (!original)
31
+ continue;
32
+ translatedByIndex.set(item.index, {
33
+ ...original,
34
+ target: item.target,
35
+ ...(item.notes?.trim() ? { notes: item.notes.trim() } : {}),
36
+ });
37
+ translatedSegments++;
38
+ }
39
+ if (result.glossary?.length) {
40
+ glossary = [...mergeGlossaryTerms([...glossary, ...result.glossary])];
41
+ }
42
+ await saveTranslationGlossary(projectRoot, projectId, glossary);
43
+ await saveTranslationChapter(projectRoot, chapterInfo.translatedPath, {
44
+ ...source,
45
+ segments: orderedTranslatedSegments(source.segments, translatedByIndex),
46
+ });
47
+ }
48
+ const completedChapter = await loadTranslationChapter(projectRoot, chapterInfo.translatedPath);
49
+ let status = "translated";
50
+ if (options.model.reviewChapter && completedChapter.segments.some((segment) => segment.target?.trim())) {
51
+ const review = await options.model.reviewChapter({
52
+ sourceLanguage: manifest.sourceLanguage,
53
+ targetLanguage: manifest.targetLanguage,
54
+ chapterTitle: source.title,
55
+ segments: completedChapter.segments,
56
+ glossary,
57
+ });
58
+ reviewedChapters++;
59
+ status = review.passed ? "reviewed" : "translated";
60
+ reportLines.push(`## ${source.title}`, "", `- passed: ${review.passed ? "yes" : "no"}`, `- summary: ${review.summary}`, "");
61
+ for (const issue of review.issues) {
62
+ reportLines.push(`- issue: ${issue}`);
63
+ }
64
+ reportLines.push("");
65
+ }
66
+ manifest = updateChapterStatus(manifest, chapterInfo.number, status);
67
+ await saveTranslationManifest(projectRoot, manifest);
68
+ }
69
+ const reportPathAbs = join(translationProjectDir(projectRoot, projectId), "review-report.md");
70
+ await writeFile(reportPathAbs, reportLines.join("\n").trimEnd() + "\n", "utf-8");
71
+ return {
72
+ projectId,
73
+ translatedSegments,
74
+ reviewedChapters,
75
+ reportPath: `translations/${projectId}/review-report.md`,
76
+ };
77
+ }
78
+ function orderedTranslatedSegments(sourceSegments, translatedByIndex) {
79
+ return sourceSegments.map((segment) => translatedByIndex.get(segment.index) ?? segment);
80
+ }
81
+ function updateChapterStatus(manifest, chapterNumber, status) {
82
+ return {
83
+ ...manifest,
84
+ updatedAt: new Date().toISOString(),
85
+ chapters: manifest.chapters.map((chapter) => chapter.number === chapterNumber ? { ...chapter, status } : chapter),
86
+ };
87
+ }
88
+ //# sourceMappingURL=runner.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"runner.js","sourceRoot":"","sources":["../../src/translation/runner.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,12 @@
1
+ import { type TranslationTextChapter } from "./text.js";
2
+ import type { CreateTranslationProjectInput, TranslationSourceKind } from "./types.js";
3
+ export interface ExtractedTranslationSource {
4
+ readonly title: string;
5
+ readonly kind: TranslationSourceKind;
6
+ readonly sourcePath: string;
7
+ readonly charCount: number;
8
+ readonly totalPages?: number;
9
+ readonly chapters: ReadonlyArray<TranslationTextChapter>;
10
+ }
11
+ export declare function extractTranslationSource(projectRoot: string, input: CreateTranslationProjectInput): Promise<ExtractedTranslationSource>;
12
+ //# sourceMappingURL=source.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"source.d.ts","sourceRoot":"","sources":["../../src/translation/source.ts"],"names":[],"mappings":"AAMA,OAAO,EAAsD,KAAK,sBAAsB,EAAE,MAAM,WAAW,CAAC;AAC5G,OAAO,KAAK,EAAE,6BAA6B,EAAE,qBAAqB,EAAE,MAAM,YAAY,CAAC;AAEvF,MAAM,WAAW,0BAA0B;IACzC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,IAAI,EAAE,qBAAqB,CAAC;IACrC,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,QAAQ,EAAE,aAAa,CAAC,sBAAsB,CAAC,CAAC;CAC1D;AAID,wBAAsB,wBAAwB,CAC5C,WAAW,EAAE,MAAM,EACnB,KAAK,EAAE,6BAA6B,GACnC,OAAO,CAAC,0BAA0B,CAAC,CAoDrC"}
@@ -0,0 +1,66 @@
1
+ import { readFile } from "node:fs/promises";
2
+ import { basename, extname, relative } from "node:path";
3
+ import { extractText, getDocumentProxy } from "unpdf";
4
+ import { safeChildPath } from "../utils/path-safety.js";
5
+ import { toPosixPath } from "../utils/posix-path.js";
6
+ import { extractEpub } from "./epub.js";
7
+ import { normalizeTranslationText, splitTranslationChapters } from "./text.js";
8
+ const MAX_INPUT_BYTES = 80 * 1024 * 1024;
9
+ export async function extractTranslationSource(projectRoot, input) {
10
+ const safePath = safeChildPath(projectRoot, input.filePath);
11
+ const buffer = await readFile(safePath);
12
+ if (buffer.byteLength > MAX_INPUT_BYTES) {
13
+ throw new Error(`Translation input is too large (${buffer.byteLength} bytes).`);
14
+ }
15
+ const sourcePath = toPosixPath(relative(projectRoot, safePath));
16
+ const filename = basename(safePath);
17
+ const ext = extname(filename).toLowerCase();
18
+ if (ext === ".pdf") {
19
+ const pdf = await getDocumentProxy(new Uint8Array(buffer));
20
+ const extracted = await extractText(pdf, { mergePages: true });
21
+ const text = normalizeTranslationText(extracted.text);
22
+ if (!text)
23
+ throw new Error("PDF text extraction returned no text. Scanned PDFs require OCR and are not supported yet.");
24
+ return {
25
+ title: input.title?.trim() || titleFromFilename(filename),
26
+ kind: "pdf",
27
+ sourcePath,
28
+ charCount: text.length,
29
+ totalPages: extracted.totalPages,
30
+ chapters: splitTranslationChapters(text),
31
+ };
32
+ }
33
+ if (ext === ".epub") {
34
+ const epub = await extractEpub(buffer);
35
+ const chapters = epub.chapters.map((chapter) => ({
36
+ title: chapter.title,
37
+ content: chapter.content,
38
+ }));
39
+ return {
40
+ title: input.title?.trim() || epub.title || titleFromFilename(filename),
41
+ kind: "epub",
42
+ sourcePath,
43
+ charCount: chapters.reduce((sum, chapter) => sum + chapter.content.length, 0),
44
+ chapters,
45
+ };
46
+ }
47
+ if (isTextExt(ext)) {
48
+ const text = normalizeTranslationText(buffer.toString("utf-8"));
49
+ return {
50
+ title: input.title?.trim() || titleFromFilename(filename),
51
+ kind: ext === ".md" || ext === ".markdown" ? "markdown" : "text",
52
+ sourcePath,
53
+ charCount: text.length,
54
+ chapters: splitTranslationChapters(text),
55
+ };
56
+ }
57
+ throw new Error(`Unsupported translation input type: ${ext || filename}`);
58
+ }
59
+ function isTextExt(ext) {
60
+ return [".txt", ".md", ".markdown"].includes(ext);
61
+ }
62
+ function titleFromFilename(filename) {
63
+ const ext = extname(filename);
64
+ return ext ? filename.slice(0, -ext.length) : filename;
65
+ }
66
+ //# sourceMappingURL=source.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"source.js","sourceRoot":"","sources":["../../src/translation/source.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,10 @@
1
+ export interface TranslationTextChapter {
2
+ readonly title: string;
3
+ readonly content: string;
4
+ }
5
+ export declare function normalizeTranslationText(value: string): string;
6
+ export declare function splitTranslationChapters(text: string): ReadonlyArray<TranslationTextChapter>;
7
+ export declare function segmentTranslationText(text: string, maxChars?: number): ReadonlyArray<string>;
8
+ export declare function stripHtml(html: string): string;
9
+ export declare function decodeHtml(value: string): string;
10
+ //# sourceMappingURL=text.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"text.d.ts","sourceRoot":"","sources":["../../src/translation/text.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,sBAAsB;IACrC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;CAC1B;AAED,wBAAgB,wBAAwB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAM9D;AAED,wBAAgB,wBAAwB,CAAC,IAAI,EAAE,MAAM,GAAG,aAAa,CAAC,sBAAsB,CAAC,CAY5F;AAED,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,SAAO,GAAG,aAAa,CAAC,MAAM,CAAC,CAY3F;AA4BD,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAO9C;AAED,wBAAgB,UAAU,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAUhD"}
@@ -0,0 +1,77 @@
1
+ import { splitChapters } from "../utils/chapter-splitter.js";
2
+ export function normalizeTranslationText(value) {
3
+ return decodeHtml(value)
4
+ .replace(/\r\n/g, "\n")
5
+ .replace(/[ \t]+\n/g, "\n")
6
+ .replace(/\n{4,}/g, "\n\n\n")
7
+ .trim();
8
+ }
9
+ export function splitTranslationChapters(text) {
10
+ const normalized = normalizeTranslationText(text);
11
+ const detected = splitChapters(normalized);
12
+ if (detected.length > 0)
13
+ return detected;
14
+ const markdownSections = splitMarkdownHeadings(normalized);
15
+ if (markdownSections.length > 0)
16
+ return markdownSections;
17
+ return [{
18
+ title: "Chapter 1",
19
+ content: normalized,
20
+ }];
21
+ }
22
+ export function segmentTranslationText(text, maxChars = 1200) {
23
+ const normalized = normalizeTranslationText(text);
24
+ if (!normalized)
25
+ return [];
26
+ const paragraphs = normalized
27
+ .split(/\n{2,}/)
28
+ .map((part) => part.trim())
29
+ .filter(Boolean);
30
+ const units = paragraphs.length > 0 ? paragraphs : [normalized];
31
+ return units.flatMap((paragraph) => paragraph.length > maxChars ? splitLongParagraph(paragraph, maxChars) : [paragraph]);
32
+ }
33
+ function splitMarkdownHeadings(text) {
34
+ const lines = text.split("\n");
35
+ const headings = [];
36
+ for (let i = 0; i < lines.length; i++) {
37
+ const match = /^#{1,3}\s+(.+?)\s*$/.exec(lines[i] ?? "");
38
+ if (match)
39
+ headings.push({ title: match[1].trim(), line: i });
40
+ }
41
+ if (headings.length === 0)
42
+ return [];
43
+ return headings.map((heading, index) => {
44
+ const next = headings[index + 1]?.line ?? lines.length;
45
+ return {
46
+ title: heading.title,
47
+ content: lines.slice(heading.line + 1, next).join("\n").trim(),
48
+ };
49
+ }).filter((chapter) => chapter.content.trim().length > 0);
50
+ }
51
+ function splitLongParagraph(paragraph, maxChars) {
52
+ const chunks = [];
53
+ for (let start = 0; start < paragraph.length; start += maxChars) {
54
+ chunks.push(paragraph.slice(start, start + maxChars).trim());
55
+ }
56
+ return chunks.filter(Boolean);
57
+ }
58
+ export function stripHtml(html) {
59
+ return decodeHtml(html
60
+ .replace(/<script[\s\S]*?<\/script>/gi, " ")
61
+ .replace(/<style[\s\S]*?<\/style>/gi, " ")
62
+ .replace(/<br\s*\/?>/gi, "\n")
63
+ .replace(/<\/(?:p|div|h[1-6]|li|section|article)>/gi, "\n")
64
+ .replace(/<[^>]+>/g, " "));
65
+ }
66
+ export function decodeHtml(value) {
67
+ return value
68
+ .replace(/&nbsp;/gi, " ")
69
+ .replace(/&amp;/gi, "&")
70
+ .replace(/&lt;/gi, "<")
71
+ .replace(/&gt;/gi, ">")
72
+ .replace(/&quot;/gi, "\"")
73
+ .replace(/&#39;/gi, "'")
74
+ .replace(/&#(\d+);/g, (_, code) => String.fromCodePoint(Number(code)))
75
+ .replace(/&#x([0-9a-f]+);/gi, (_, code) => String.fromCodePoint(Number.parseInt(code, 16)));
76
+ }
77
+ //# sourceMappingURL=text.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"text.js","sourceRoot":"","sources":["../../src/translation/text.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,8BAA8B,CAAC;AAO7D,MAAM,UAAU,wBAAwB,CAAC,KAAa;IACpD,OAAO,UAAU,CAAC,KAAK,CAAC;SACrB,OAAO,CAAC,OAAO,EAAE,IAAI,CAAC;SACtB,OAAO,CAAC,WAAW,EAAE,IAAI,CAAC;SAC1B,OAAO,CAAC,SAAS,EAAE,QAAQ,CAAC;SAC5B,IAAI,EAAE,CAAC;AACZ,CAAC;AAED,MAAM,UAAU,wBAAwB,CAAC,IAAY;IACnD,MAAM,UAAU,GAAG,wBAAwB,CAAC,IAAI,CAAC,CAAC;IAClD,MAAM,QAAQ,GAAG,aAAa,CAAC,UAAU,CAAC,CAAC;IAC3C,IAAI,QAAQ,CAAC,MAAM,GAAG,CAAC;QAAE,OAAO,QAAQ,CAAC;IAEzC,MAAM,gBAAgB,GAAG,qBAAqB,CAAC,UAAU,CAAC,CAAC;IAC3D,IAAI,gBAAgB,CAAC,MAAM,GAAG,CAAC;QAAE,OAAO,gBAAgB,CAAC;IAEzD,OAAO,CAAC;YACN,KAAK,EAAE,WAAW;YAClB,OAAO,EAAE,UAAU;SACpB,CAAC,CAAC;AACL,CAAC;AAED,MAAM,UAAU,sBAAsB,CAAC,IAAY,EAAE,QAAQ,GAAG,IAAI;IAClE,MAAM,UAAU,GAAG,wBAAwB,CAAC,IAAI,CAAC,CAAC;IAClD,IAAI,CAAC,UAAU;QAAE,OAAO,EAAE,CAAC;IAE3B,MAAM,UAAU,GAAG,UAAU;SAC1B,KAAK,CAAC,QAAQ,CAAC;SACf,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC;SAC1B,MAAM,CAAC,OAAO,CAAC,CAAC;IACnB,MAAM,KAAK,GAAG,UAAU,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC;IAChE,OAAO,KAAK,CAAC,OAAO,CAAC,CAAC,SAAS,EAAE,EAAE,CACjC,SAAS,CAAC,MAAM,GAAG,QAAQ,CAAC,CAAC,CAAC,kBAAkB,CAAC,SAAS,EAAE,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CACpF,CAAC;AACJ,CAAC;AAED,SAAS,qBAAqB,CAAC,IAAY;IACzC,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IAC/B,MAAM,QAAQ,GAA2C,EAAE,CAAC;IAC5D,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACtC,MAAM,KAAK,GAAG,qBAAqB,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC;QACzD,IAAI,KAAK;YAAE,QAAQ,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,KAAK,CAAC,CAAC,CAAE,CAAC,IAAI,EAAE,EAAE,IAAI,EAAE,CAAC,EAAE,CAAC,CAAC;IACjE,CAAC;IACD,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,EAAE,CAAC;IAErC,OAAO,QAAQ,CAAC,GAAG,CAAC,CAAC,OAAO,EAAE,KAAK,EAAE,EAAE;QACrC,MAAM,IAAI,GAAG,QAAQ,CAAC,KAAK,GAAG,CAAC,CAAC,EAAE,IAAI,IAAI,KAAK,CAAC,MAAM,CAAC;QACvD,OAAO;YACL,KAAK,EAAE,OAAO,CAAC,KAAK;YACpB,OAAO,EAAE,KAAK,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,GAAG,CAAC,EAAE,IAAI,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE;SAC/D,CAAC;IACJ,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;AAC5D,CAAC;AAED,SAAS,kBAAkB,CAAC,SAAiB,EAAE,QAAgB;IAC7D,MAAM,MAAM,GAAa,EAAE,CAAC;IAC5B,KAAK,IAAI,KAAK,GAAG,CAAC,EAAE,KAAK,GAAG,SAAS,CAAC,MAAM,EAAE,KAAK,IAAI,QAAQ,EAAE,CAAC;QAChE,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,KAAK,EAAE,KAAK,GAAG,QAAQ,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC;IAC/D,CAAC;IACD,OAAO,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;AAChC,CAAC;AAED,MAAM,UAAU,SAAS,CAAC,IAAY;IACpC,OAAO,UAAU,CAAC,IAAI;SACnB,OAAO,CAAC,6BAA6B,EAAE,GAAG,CAAC;SAC3C,OAAO,CAAC,2BAA2B,EAAE,GAAG,CAAC;SACzC,OAAO,CAAC,cAAc,EAAE,IAAI,CAAC;SAC7B,OAAO,CAAC,2CAA2C,EAAE,IAAI,CAAC;SAC1D,OAAO,CAAC,UAAU,EAAE,GAAG,CAAC,CAAC,CAAC;AAC/B,CAAC;AAED,MAAM,UAAU,UAAU,CAAC,KAAa;IACtC,OAAO,KAAK;SACT,OAAO,CAAC,UAAU,EAAE,GAAG,CAAC;SACxB,OAAO,CAAC,SAAS,EAAE,GAAG,CAAC;SACvB,OAAO,CAAC,QAAQ,EAAE,GAAG,CAAC;SACtB,OAAO,CAAC,QAAQ,EAAE,GAAG,CAAC;SACtB,OAAO,CAAC,UAAU,EAAE,IAAI,CAAC;SACzB,OAAO,CAAC,SAAS,EAAE,GAAG,CAAC;SACvB,OAAO,CAAC,WAAW,EAAE,CAAC,CAAC,EAAE,IAAY,EAAE,EAAE,CAAC,MAAM,CAAC,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC;SAC7E,OAAO,CAAC,mBAAmB,EAAE,CAAC,CAAC,EAAE,IAAY,EAAE,EAAE,CAAC,MAAM,CAAC,aAAa,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC;AACxG,CAAC"}