@geolonia/yuuhitsu 0.1.16 → 0.2.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.
@@ -1,9 +1,15 @@
1
- import type { AIProvider, ChatRequest, ChatResponse, StreamChunk } from "./interface.js";
1
+ import type { AIProvider, ChatRequest, ChatResponse, StreamChunk, StructuredTranslateRequest, StructuredTranslateResponse } from "./interface.js";
2
2
  export declare class ClaudeProvider implements AIProvider {
3
3
  private client;
4
4
  private model;
5
5
  constructor(model: string);
6
6
  chat(request: ChatRequest): Promise<ChatResponse>;
7
7
  chatStream(request: ChatRequest): AsyncIterable<StreamChunk>;
8
+ /**
9
+ * Translate segments using Anthropic tool_use (structured output).
10
+ * Forces Claude to return a JSON object matching the translation schema —
11
+ * no prose wrapping, no schema deviations.
12
+ */
13
+ translateStructured(request: StructuredTranslateRequest): Promise<StructuredTranslateResponse>;
8
14
  }
9
15
  //# sourceMappingURL=claude.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"claude.d.ts","sourceRoot":"","sources":["../../src/provider/claude.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACV,UAAU,EACV,WAAW,EACX,YAAY,EACZ,WAAW,EACZ,MAAM,gBAAgB,CAAC;AAExB,qBAAa,cAAe,YAAW,UAAU;IAC/C,OAAO,CAAC,MAAM,CAAY;IAC1B,OAAO,CAAC,KAAK,CAAS;gBAEV,KAAK,EAAE,MAAM;IAYnB,IAAI,CAAC,OAAO,EAAE,WAAW,GAAG,OAAO,CAAC,YAAY,CAAC;IAiChD,UAAU,CAAC,OAAO,EAAE,WAAW,GAAG,aAAa,CAAC,WAAW,CAAC;CA6BpE"}
1
+ {"version":3,"file":"claude.d.ts","sourceRoot":"","sources":["../../src/provider/claude.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACV,UAAU,EACV,WAAW,EACX,YAAY,EACZ,WAAW,EACX,0BAA0B,EAC1B,2BAA2B,EAC5B,MAAM,gBAAgB,CAAC;AA2BxB,qBAAa,cAAe,YAAW,UAAU;IAC/C,OAAO,CAAC,MAAM,CAAY;IAC1B,OAAO,CAAC,KAAK,CAAS;gBAEV,KAAK,EAAE,MAAM;IAYnB,IAAI,CAAC,OAAO,EAAE,WAAW,GAAG,OAAO,CAAC,YAAY,CAAC;IAiChD,UAAU,CAAC,OAAO,EAAE,WAAW,GAAG,aAAa,CAAC,WAAW,CAAC;IA8BnE;;;;OAIG;IACG,mBAAmB,CACvB,OAAO,EAAE,0BAA0B,GAClC,OAAO,CAAC,2BAA2B,CAAC;CA2CxC"}
@@ -1,9 +1,32 @@
1
1
  import Anthropic from "@anthropic-ai/sdk";
2
+ const TRANSLATION_TOOL_NAME = "record_translations";
3
+ const TRANSLATION_TOOL = {
4
+ name: TRANSLATION_TOOL_NAME,
5
+ description: "Record the translated text segments in structured JSON format",
6
+ input_schema: {
7
+ type: "object",
8
+ properties: {
9
+ translations: {
10
+ type: "array",
11
+ items: {
12
+ type: "object",
13
+ properties: {
14
+ id: { type: "integer", description: "Segment ID (must match input ID exactly)" },
15
+ text: { type: "string", description: "Translated text for this segment" },
16
+ },
17
+ required: ["id", "text"],
18
+ },
19
+ description: "Translated segments — one entry per input segment, ID must match",
20
+ },
21
+ },
22
+ required: ["translations"],
23
+ },
24
+ };
2
25
  export class ClaudeProvider {
3
26
  client;
4
27
  model;
5
28
  constructor(model) {
6
- const apiKey = process.env.ANTHROPIC_API_KEY;
29
+ const apiKey = process.env.ANTHROPIC_API_KEY?.trim();
7
30
  if (!apiKey) {
8
31
  throw new Error("ANTHROPIC_API_KEY environment variable is not set. " +
9
32
  "Get your API key at https://console.anthropic.com/settings/keys");
@@ -65,5 +88,42 @@ export class ClaudeProvider {
65
88
  }
66
89
  yield { content: "", done: true };
67
90
  }
91
+ /**
92
+ * Translate segments using Anthropic tool_use (structured output).
93
+ * Forces Claude to return a JSON object matching the translation schema —
94
+ * no prose wrapping, no schema deviations.
95
+ */
96
+ async translateStructured(request) {
97
+ const response = await this.client.messages.create({
98
+ model: request.model || this.model,
99
+ max_tokens: request.maxTokens ?? 4096,
100
+ system: request.systemPrompt,
101
+ messages: [
102
+ {
103
+ role: "user",
104
+ content: JSON.stringify({ segments: request.segments }),
105
+ },
106
+ ],
107
+ tools: [TRANSLATION_TOOL],
108
+ tool_choice: { type: "tool", name: TRANSLATION_TOOL_NAME },
109
+ });
110
+ const toolUseBlock = response.content.find((b) => b.type === "tool_use");
111
+ if (!toolUseBlock) {
112
+ throw new Error(`[yuuhitsu] ClaudeProvider.translateStructured: no tool_use block in response` +
113
+ ` (stop_reason: ${response.stop_reason})`);
114
+ }
115
+ const input = toolUseBlock.input;
116
+ if (!Array.isArray(input.translations)) {
117
+ throw new Error(`[yuuhitsu] ClaudeProvider.translateStructured: translations field is missing or not an array`);
118
+ }
119
+ return {
120
+ translations: input.translations,
121
+ usage: {
122
+ promptTokens: response.usage.input_tokens,
123
+ completionTokens: response.usage.output_tokens,
124
+ totalTokens: response.usage.input_tokens + response.usage.output_tokens,
125
+ },
126
+ };
127
+ }
68
128
  }
69
129
  //# sourceMappingURL=claude.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"claude.js","sourceRoot":"","sources":["../../src/provider/claude.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"claude.js","sourceRoot":"","sources":["../../src/provider/claude.ts"],"names":[],"mappings":"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"}
@@ -23,8 +23,35 @@ export interface StreamChunk {
23
23
  content: string;
24
24
  done: boolean;
25
25
  }
26
+ /** Request for structured output translation (tool_use path). */
27
+ export interface StructuredTranslateRequest {
28
+ segments: Array<{
29
+ id: number;
30
+ text: string;
31
+ }>;
32
+ systemPrompt: string;
33
+ model?: string;
34
+ maxTokens?: number;
35
+ }
36
+ /** Response from structured output translation. */
37
+ export interface StructuredTranslateResponse {
38
+ translations: Array<{
39
+ id: number;
40
+ text: string;
41
+ }>;
42
+ usage: {
43
+ promptTokens: number;
44
+ completionTokens: number;
45
+ totalTokens: number;
46
+ };
47
+ }
26
48
  export interface AIProvider {
27
49
  chat(request: ChatRequest): Promise<ChatResponse>;
28
50
  chatStream(request: ChatRequest): AsyncIterable<StreamChunk>;
51
+ /**
52
+ * Structured output translation via provider-native JSON schema enforcement.
53
+ * Optional: implemented by Claude. Gemini and Ollama fall back to text mode.
54
+ */
55
+ translateStructured?(request: StructuredTranslateRequest): Promise<StructuredTranslateResponse>;
29
56
  }
30
57
  //# sourceMappingURL=interface.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"interface.d.ts","sourceRoot":"","sources":["../../src/provider/interface.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,QAAQ,GAAG,MAAM,GAAG,WAAW,CAAC;IACtC,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,WAAW;IAC1B,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,WAAW,EAAE,CAAC;IACxB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB;AAED,MAAM,WAAW,YAAY;IAC3B,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE;QACL,YAAY,EAAE,MAAM,CAAC;QACrB,gBAAgB,EAAE,MAAM,CAAC;QACzB,WAAW,EAAE,MAAM,CAAC;KACrB,CAAC;IACF,YAAY,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,WAAW;IAC1B,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,OAAO,CAAC;CACf;AAED,MAAM,WAAW,UAAU;IACzB,IAAI,CAAC,OAAO,EAAE,WAAW,GAAG,OAAO,CAAC,YAAY,CAAC,CAAC;IAClD,UAAU,CAAC,OAAO,EAAE,WAAW,GAAG,aAAa,CAAC,WAAW,CAAC,CAAC;CAC9D"}
1
+ {"version":3,"file":"interface.d.ts","sourceRoot":"","sources":["../../src/provider/interface.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,QAAQ,GAAG,MAAM,GAAG,WAAW,CAAC;IACtC,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,WAAW;IAC1B,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,WAAW,EAAE,CAAC;IACxB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB;AAED,MAAM,WAAW,YAAY;IAC3B,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE;QACL,YAAY,EAAE,MAAM,CAAC;QACrB,gBAAgB,EAAE,MAAM,CAAC;QACzB,WAAW,EAAE,MAAM,CAAC;KACrB,CAAC;IACF,YAAY,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,WAAW;IAC1B,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,OAAO,CAAC;CACf;AAED,iEAAiE;AACjE,MAAM,WAAW,0BAA0B;IACzC,QAAQ,EAAE,KAAK,CAAC;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAC9C,YAAY,EAAE,MAAM,CAAC;IACrB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,mDAAmD;AACnD,MAAM,WAAW,2BAA2B;IAC1C,YAAY,EAAE,KAAK,CAAC;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAClD,KAAK,EAAE;QACL,YAAY,EAAE,MAAM,CAAC;QACrB,gBAAgB,EAAE,MAAM,CAAC;QACzB,WAAW,EAAE,MAAM,CAAC;KACrB,CAAC;CACH;AAED,MAAM,WAAW,UAAU;IACzB,IAAI,CAAC,OAAO,EAAE,WAAW,GAAG,OAAO,CAAC,YAAY,CAAC,CAAC;IAClD,UAAU,CAAC,OAAO,EAAE,WAAW,GAAG,aAAa,CAAC,WAAW,CAAC,CAAC;IAC7D;;;OAGG;IACH,mBAAmB,CAAC,CAClB,OAAO,EAAE,0BAA0B,GAClC,OAAO,CAAC,2BAA2B,CAAC,CAAC;CACzC"}
@@ -6,43 +6,10 @@ interface FrontmatterSeparation {
6
6
  body: string;
7
7
  }
8
8
  /**
9
- * Separate frontmatter from Markdown content
9
+ * Separate frontmatter from Markdown content.
10
10
  * Handles: LF, CRLF, no trailing newline after closing ---, trailing spaces, empty frontmatter
11
- * @param content - Full Markdown content
12
- * @returns Object with separated frontmatter and body
13
11
  */
14
12
  export declare function separateFrontmatter(content: string): FrontmatterSeparation;
15
- interface CodeProtection {
16
- text: string;
17
- map: Map<string, string>;
18
- }
19
- /**
20
- * Replace fenced code blocks and inline code with placeholders.
21
- * Uses a line-by-line parser instead of regex to avoid V8 stack overflow
22
- * on files with many code blocks (backreference + [\s\S]*? causes recursive backtracking).
23
- */
24
- export declare function protectCodeBlocks(content: string): CodeProtection;
25
- /**
26
- * Restore placeholders back to original code blocks/inline code.
27
- */
28
- export declare function restoreCodeBlocks(content: string, map: Map<string, string>): string;
29
- export declare const BLOCK_BOUNDARY_SENTINEL = "<!--BB-->";
30
- /**
31
- * Insert block boundary sentinels before structural Markdown elements
32
- * (list items, headings, horizontal rules, code fences, code block placeholders).
33
- * P-A4: prevents newline collapse around structural boundaries during LLM translation.
34
- * When called after protectCodeBlocks, fenced blocks appear as __CODE_BLOCK_N__ placeholders;
35
- * the function treats those placeholders as structural to protect fence-adjacent newlines.
36
- */
37
- export declare function protectBlockBoundaries(content: string): string;
38
- /**
39
- * Remove block boundary sentinels and restore newlines lost during LLM translation.
40
- * Uses a 3-pass strategy:
41
- * Pass 1: normalize LLM-deformed variants (e.g. <!-- BB -->) to exact sentinel form
42
- * Pass 2: split + restore newlines (handles both clean and collapsed sentinel cases)
43
- * Pass 3: post-restore warning for residual sentinel-like patterns (silent failure prevention)
44
- */
45
- export declare function restoreBlockBoundaries(content: string): string;
46
13
  export interface TranslateOptions {
47
14
  provider: AIProvider;
48
15
  inputPath: string;
@@ -67,8 +34,8 @@ export interface TranslateResult {
67
34
  */
68
35
  export declare function findHeadingPositions(lines: string[], level: number): number[];
69
36
  /**
70
- * Split lines at the given positions into chunks (each position starts a new chunk).
71
- * Segments exceeding maxChunkLines are further split using ### headings or safeSplitLines.
37
+ * Split lines at the given positions into chunks. Segments exceeding maxChunkLines
38
+ * are further split using ### headings or safeSplitLines.
72
39
  */
73
40
  export declare function splitAtPositions(lines: string[], positions: number[], maxChunkLines: number): string[];
74
41
  /**
@@ -77,8 +44,7 @@ export declare function splitAtPositions(lines: string[], positions: number[], m
77
44
  */
78
45
  export declare function safeSplitLines(lines: string[], maxChunkLines: number): string[];
79
46
  /**
80
- * Merge chunks smaller than MIN_CHUNK_LINES into the previous chunk,
81
- * as long as the merged result does not exceed maxLines.
47
+ * Merge chunks smaller than MIN_CHUNK_LINES into the previous chunk.
82
48
  */
83
49
  export declare function mergeSmallChunks(chunks: string[], maxLines: number): string[];
84
50
  /**
@@ -86,6 +52,33 @@ export declare function mergeSmallChunks(chunks: string[], maxLines: number): st
86
52
  * Falls back to safe line-count splitting when no headings are present.
87
53
  */
88
54
  export declare function splitIntoChunks(content: string, maxChunkLines?: number): string[];
55
+ interface CodeProtection {
56
+ text: string;
57
+ map: Map<string, string>;
58
+ }
59
+ /**
60
+ * Replace fenced code blocks and inline code with placeholders.
61
+ * Used by glossary-fix.ts to protect code blocks before text replacement.
62
+ */
63
+ export declare function protectCodeBlocks(content: string): CodeProtection;
64
+ /**
65
+ * Restore placeholders back to original code blocks/inline code.
66
+ */
67
+ export declare function restoreCodeBlocks(content: string, map: Map<string, string>): string;
68
+ /**
69
+ * Translate a Markdown file using AST-based approach.
70
+ *
71
+ * Architecture (0.2.0):
72
+ * 1. Separate frontmatter (preserved verbatim)
73
+ * 2. Split body into chunks by heading boundaries
74
+ * 3. For each chunk: parse to AST → extract text nodes → translate via LLM → write back
75
+ * 4. Serialize AST → markdown → concatenate → write output
76
+ *
77
+ * Key properties:
78
+ * - Code blocks (fenced and inline) are never sent to LLM (AST handles them deterministically)
79
+ * - Markdown structure (headings, lists, tables, HR) is preserved by AST round-trip
80
+ * - No sentinel injection or removal needed
81
+ */
89
82
  export declare function translateFile(options: TranslateOptions): Promise<TranslateResult>;
90
83
  export {};
91
84
  //# sourceMappingURL=translate.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"translate.d.ts","sourceRoot":"","sources":["../../src/tasks/translate.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,UAAU,EAAe,MAAM,0BAA0B,CAAC;AACxE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAGpD,eAAO,MAAM,uBAAuB,MAAM,CAAC;AAG3C,UAAU,qBAAqB;IAC7B,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,IAAI,EAAE,MAAM,CAAC;CACd;AAED;;;;;GAKG;AACH,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,MAAM,GAAG,qBAAqB,CAmB1E;AAED,UAAU,cAAc;IACtB,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAC1B;AAED;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,MAAM,GAAG,cAAc,CAwDjE;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,MAAM,CASnF;AAED,eAAO,MAAM,uBAAuB,cAAc,CAAC;AASnD;;;;;;GAMG;AACH,wBAAgB,sBAAsB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CA4B9D;AAED;;;;;;GAMG;AACH,wBAAgB,sBAAsB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CA0C9D;AAED,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,EAAE,UAAU,CAAC;IACrB,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,MAAM,CAAC;IACnB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,cAAc,CAAC,EAAE,cAAc,CAAC;IAChC,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAED,MAAM,WAAW,eAAe;IAC9B,UAAU,EAAE,MAAM,CAAC;IACnB,KAAK,EAAE;QACL,YAAY,EAAE,MAAM,CAAC;QACrB,gBAAgB,EAAE,MAAM,CAAC;QACzB,WAAW,EAAE,MAAM,CAAC;KACrB,CAAC;IACF,MAAM,EAAE,MAAM,CAAC;CAChB;AAkHD;;;GAGG;AACH,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE,CAa7E;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,CAC9B,KAAK,EAAE,MAAM,EAAE,EACf,SAAS,EAAE,MAAM,EAAE,EACnB,aAAa,EAAE,MAAM,GACpB,MAAM,EAAE,CA2BV;AAED;;;GAGG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE,aAAa,EAAE,MAAM,GAAG,MAAM,EAAE,CA6B/E;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,MAAM,EAAE,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,EAAE,CAiB7E;AAED;;;GAGG;AACH,wBAAgB,eAAe,CAC7B,OAAO,EAAE,MAAM,EACf,aAAa,SAA0B,GACtC,MAAM,EAAE,CAcV;AAED,wBAAsB,aAAa,CACjC,OAAO,EAAE,gBAAgB,GACxB,OAAO,CAAC,eAAe,CAAC,CAwE1B"}
1
+ {"version":3,"file":"translate.d.ts","sourceRoot":"","sources":["../../src/tasks/translate.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,UAAU,EAAe,MAAM,0BAA0B,CAAC;AACxE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAGpD,eAAO,MAAM,uBAAuB,MAAM,CAAC;AAM3C,UAAU,qBAAqB;IAC7B,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,IAAI,EAAE,MAAM,CAAC;CACd;AAED;;;GAGG;AACH,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,MAAM,GAAG,qBAAqB,CAa1E;AAED,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,EAAE,UAAU,CAAC;IACrB,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,MAAM,CAAC;IACnB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,cAAc,CAAC,EAAE,cAAc,CAAC;IAChC,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAED,MAAM,WAAW,eAAe;IAC9B,UAAU,EAAE,MAAM,CAAC;IACnB,KAAK,EAAE;QACL,YAAY,EAAE,MAAM,CAAC;QACrB,gBAAgB,EAAE,MAAM,CAAC;QACzB,WAAW,EAAE,MAAM,CAAC;KACrB,CAAC;IACF,MAAM,EAAE,MAAM,CAAC;CAChB;AAID;;;GAGG;AACH,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE,CAa7E;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,CAC9B,KAAK,EAAE,MAAM,EAAE,EACf,SAAS,EAAE,MAAM,EAAE,EACnB,aAAa,EAAE,MAAM,GACpB,MAAM,EAAE,CAyBV;AAED;;;GAGG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE,aAAa,EAAE,MAAM,GAAG,MAAM,EAAE,CAyB/E;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,MAAM,EAAE,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,EAAE,CAiB7E;AAED;;;GAGG;AACH,wBAAgB,eAAe,CAC7B,OAAO,EAAE,MAAM,EACf,aAAa,SAA0B,GACtC,MAAM,EAAE,CAcV;AAMD,UAAU,cAAc;IACtB,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAC1B;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,MAAM,GAAG,cAAc,CA8CjE;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,MAAM,CAYnF;AAkRD;;;;;;;;;;;;;GAaG;AACH,wBAAsB,aAAa,CACjC,OAAO,EAAE,gBAAgB,GACxB,OAAO,CAAC,eAAe,CAAC,CA+E1B"}
@@ -1,21 +1,19 @@
1
1
  import { readFileSync, writeFileSync, mkdirSync } from "fs";
2
2
  import { dirname, basename, extname, join } from "path";
3
+ import { remark } from "remark";
4
+ import remarkGfm from "remark-gfm";
5
+ import { visit } from "unist-util-visit";
3
6
  import { buildGlossaryPrompt } from "./glossary.js";
4
7
  export const DEFAULT_MAX_CHUNK_LINES = 300;
5
8
  const MIN_CHUNK_LINES = 50;
9
+ // P-A1: minimum ratio of output characters to input characters (truncation check)
10
+ const MIN_OUTPUT_RATIO = 0.3;
6
11
  /**
7
- * Separate frontmatter from Markdown content
12
+ * Separate frontmatter from Markdown content.
8
13
  * Handles: LF, CRLF, no trailing newline after closing ---, trailing spaces, empty frontmatter
9
- * @param content - Full Markdown content
10
- * @returns Object with separated frontmatter and body
11
14
  */
12
15
  export function separateFrontmatter(content) {
13
- // Normalize CRLF to LF for regex matching
14
16
  const normalized = content.replace(/\r\n/g, "\n");
15
- // Match frontmatter (two alternations to keep closing --- on its own line):
16
- // Case 1: non-empty body: ^---\n ... \n---[ \t]*(\n|$)
17
- // Case 2: empty body: ^---\n---[ \t]*(\n|$)
18
- // Using alternation avoids the \n? ambiguity that allows --- to match mid-line.
19
17
  const frontmatterRegex = /^---\n([\s\S]*?)\n---[ \t]*(\n|$)|^---\n---[ \t]*(\n|$)/;
20
18
  const match = normalized.match(frontmatterRegex);
21
19
  if (match) {
@@ -26,253 +24,7 @@ export function separateFrontmatter(content) {
26
24
  }
27
25
  return { frontmatter: null, body: normalized };
28
26
  }
29
- /**
30
- * Replace fenced code blocks and inline code with placeholders.
31
- * Uses a line-by-line parser instead of regex to avoid V8 stack overflow
32
- * on files with many code blocks (backreference + [\s\S]*? causes recursive backtracking).
33
- */
34
- export function protectCodeBlocks(content) {
35
- const map = new Map();
36
- let blockIndex = 0;
37
- let inlineIndex = 0;
38
- // Step 1: Replace fenced code blocks using line-by-line parsing
39
- const lines = content.split("\n");
40
- const resultLines = [];
41
- let fenceOpen = null; // the backtick sequence that opened the current block
42
- let blockLines = [];
43
- for (const line of lines) {
44
- const fenceMatch = line.match(/^(`{3,})/);
45
- if (fenceOpen === null) {
46
- // Not inside a code block
47
- if (fenceMatch) {
48
- // Opening fence found
49
- fenceOpen = fenceMatch[1];
50
- blockLines = [line];
51
- }
52
- else {
53
- resultLines.push(line);
54
- }
55
- }
56
- else {
57
- // Inside a code block — look for closing fence with same or more backticks
58
- blockLines.push(line);
59
- if (fenceMatch && fenceMatch[1].length >= fenceOpen.length && line.trim() === fenceMatch[1]) {
60
- // Closing fence found — store as single-line placeholder (no padding).
61
- // Padding was previously used to preserve line count, but it caused chunk
62
- // boundaries to fall inside the placeholder's whitespace region, leading to
63
- // non-deterministic LLM output when the code block exceeded --max-chunk-lines.
64
- const original = blockLines.join("\n") + "\n";
65
- const placeholder = `__CODE_BLOCK_${blockIndex++}__`;
66
- map.set(placeholder, original);
67
- resultLines.push(placeholder);
68
- fenceOpen = null;
69
- blockLines = [];
70
- }
71
- }
72
- }
73
- // If we ended inside an unclosed fence, emit lines as-is
74
- if (fenceOpen !== null) {
75
- resultLines.push(...blockLines);
76
- }
77
- let result = resultLines.join("\n");
78
- // Step 2: Replace inline code (single backtick, not within code blocks)
79
- result = result.replace(/`([^`\n]+)`/g, (match) => {
80
- const placeholder = `__INLINE_CODE_${inlineIndex++}__`;
81
- map.set(placeholder, match);
82
- return placeholder;
83
- });
84
- return { text: result, map };
85
- }
86
- /**
87
- * Restore placeholders back to original code blocks/inline code.
88
- */
89
- export function restoreCodeBlocks(content, map) {
90
- let result = content;
91
- // Restore fenced code blocks (may have trailing newline added by protect)
92
- for (const [placeholder, original] of map.entries()) {
93
- // The placeholder may appear with or without trailing newline
94
- result = result.split(placeholder + "\n").join(original);
95
- result = result.split(placeholder).join(original);
96
- }
97
- return result;
98
- }
99
- export const BLOCK_BOUNDARY_SENTINEL = "<!--BB-->";
100
- // Temporary escape for pre-existing <!--BB--> literals in user content.
101
- // Uses a character sequence unlikely to appear in markdown documents.
102
- const ESCAPED_SENTINEL = "\x01BB\x01";
103
- // Fallback regex: catches LLM-deformed variants (e.g. <!-- BB -->, <!--BB__-->, <!--BBx-->)
104
- const SENTINEL_FALLBACK = /<!--\s*BB[a-zA-Z0-9_-]*\s*-->/g;
105
- // Broad check: detects severely-deformed residuals not caught by SENTINEL_FALLBACK
106
- const SENTINEL_RESIDUAL_CHECK = /<!--[\s\S]*?BB[\s\S]*?-->/g;
107
- /**
108
- * Insert block boundary sentinels before structural Markdown elements
109
- * (list items, headings, horizontal rules, code fences, code block placeholders).
110
- * P-A4: prevents newline collapse around structural boundaries during LLM translation.
111
- * When called after protectCodeBlocks, fenced blocks appear as __CODE_BLOCK_N__ placeholders;
112
- * the function treats those placeholders as structural to protect fence-adjacent newlines.
113
- */
114
- export function protectBlockBoundaries(content) {
115
- // Escape all sentinel-like patterns (exact + variants) to prevent control-marker confusion.
116
- // SENTINEL_FALLBACK covers <!--BB-->, <!-- BB -->, <!--BBx-->, <!--BB-x-->, etc.
117
- // On restore, these all round-trip back to <!--BB--> (minor cosmetic vs. content deletion).
118
- const escaped = content.replace(SENTINEL_FALLBACK, ESCAPED_SENTINEL);
119
- const lines = escaped.split("\n");
120
- const result = [];
121
- for (const line of lines) {
122
- const isStructural = /^\s*[-*+]\s/.test(line) || // unordered list
123
- /^\s*\d+\.\s/.test(line) || // ordered list
124
- /^ {0,3}#{1,6}\s/.test(line) || // heading (CommonMark: 0-3 leading spaces)
125
- /^ {0,3}-{3,}\s*$/.test(line) || // hr (dash, 0-3 leading spaces)
126
- /^ {0,3}\*{3,}\s*$/.test(line) || // hr (asterisk, 0-3 leading spaces)
127
- /^ {0,3}_{3,}\s*$/.test(line) || // hr (underscore, 0-3 leading spaces)
128
- /^\s*`{3,}/.test(line) || // fenced code (backtick)
129
- /^\s*~{3,}/.test(line) || // fenced code (tilde)
130
- /^__CODE_BLOCK_\d+__$/.test(line.trim()); // code block placeholder (after protectCodeBlocks)
131
- if (isStructural) {
132
- result.push(BLOCK_BOUNDARY_SENTINEL);
133
- }
134
- result.push(line);
135
- }
136
- return result.join("\n");
137
- }
138
- /**
139
- * Remove block boundary sentinels and restore newlines lost during LLM translation.
140
- * Uses a 3-pass strategy:
141
- * Pass 1: normalize LLM-deformed variants (e.g. <!-- BB -->) to exact sentinel form
142
- * Pass 2: split + restore newlines (handles both clean and collapsed sentinel cases)
143
- * Pass 3: post-restore warning for residual sentinel-like patterns (silent failure prevention)
144
- */
145
- export function restoreBlockBoundaries(content) {
146
- // Pass 1: normalize variant sentinels introduced by LLM deformation (cmd_389 Root Cause A/B)
147
- const normalized = content.replace(SENTINEL_FALLBACK, BLOCK_BOUNDARY_SENTINEL);
148
- // Pass 2: split + restore newlines
149
- if (!normalized.includes(BLOCK_BOUNDARY_SENTINEL)) {
150
- // Still unescape any escaped sentinels from original content
151
- return normalized.includes(ESCAPED_SENTINEL)
152
- ? normalized.split(ESCAPED_SENTINEL).join(BLOCK_BOUNDARY_SENTINEL)
153
- : normalized;
154
- }
155
- const parts = normalized.split(BLOCK_BOUNDARY_SENTINEL);
156
- let restored = parts[0];
157
- for (let i = 1; i < parts.length; i++) {
158
- // Strip a leading newline from next part (present when LLM preserved sentinel on its own line)
159
- const stripped = parts[i].replace(/^\n/, "");
160
- if (restored.length === 0) {
161
- // Sentinel was at the very start of content — no preceding text to separate from
162
- restored = stripped;
163
- }
164
- else {
165
- // Ensure restored ends with exactly one newline before appending next part
166
- restored = restored.replace(/\n?$/, "\n") + stripped;
167
- }
168
- }
169
- // Pass 3: post-restore warning for patterns not caught by SENTINEL_FALLBACK
170
- // Check before unescaping to avoid false positives from user-content <!--BB-->
171
- const residuals = restored.match(SENTINEL_RESIDUAL_CHECK);
172
- if (residuals && residuals.length > 0) {
173
- console.warn(`[yuuhitsu] restoreBlockBoundaries: ${residuals.length} residual sentinel-like pattern(s) detected after restore:`, residuals.slice(0, 5));
174
- }
175
- // Unescape any pre-existing <!--BB--> that were escaped before protection
176
- if (restored.includes(ESCAPED_SENTINEL)) {
177
- restored = restored.split(ESCAPED_SENTINEL).join(BLOCK_BOUNDARY_SENTINEL);
178
- }
179
- return restored;
180
- }
181
- const DEFAULT_TEMPLATE = `You are a professional translator. Translate the following Markdown document to {{targetLanguage}}.
182
-
183
- Rules:
184
- - Preserve all Markdown formatting (headings, links, code blocks, tables, lists)
185
- - Do not translate code blocks, URLs, or file paths
186
- - Do not translate frontmatter keys (only translate values where appropriate)
187
- - Maintain the same document structure
188
- - Produce natural, fluent text in the target language
189
- - Every opening \`\`\` you write MUST be followed by a language identifier on the same line (e.g., \`\`\`json, \`\`\`bash, \`\`\`typescript)
190
- - If the language is unknown, use \`\`\`text — never emit a bare opening \`\`\`
191
-
192
- CRITICAL - Link and URL preservation:
193
- - NEVER modify any URLs or link paths. Keep all href/src values exactly as-is.
194
- - NEVER change internal link paths (e.g., /ja/..., /en/..., ./relative-path). Preserve them verbatim.
195
- - NEVER convert external URLs to different language versions.
196
- - If the source has [text](/ja/changelog), the output must keep the same path, only translate the link text if needed.
197
- - Example: [紹介](/ja/intro) → translate "紹介" but keep "/ja/intro" unchanged
198
- - Example: [MDN](https://developer.mozilla.org/ja/) → keep the /ja/ in URL, translate "MDN" if needed
199
-
200
- Additional rules for Japanese translation:
201
- - Use full-width punctuation: 。、?! (not .,?!)
202
- - Add half-width spaces around English words and numbers (e.g., "Vela とは", "NGSIv2 は", "3 つの")
203
- - Use natural Japanese terms for technical words where appropriate (e.g., "registration" → "登録", "subscription" → "サブスクリプション")
204
- - Keep product names, proper nouns, and abbreviations unchanged (e.g., Vela, FIWARE, NGSIv2, NGSI-LD, MCP)
205
-
206
- Example — code fence with language identifier:
207
- Bad: \`\`\` echo hello \`\`\`
208
- Good: \`\`\`bash echo hello \`\`\``;
209
- function buildPrompt(content, targetLang, hasPlaceholders, hasSentinels, templateContent, glossaryConfig) {
210
- const template = templateContent || DEFAULT_TEMPLATE;
211
- let systemPrompt = template
212
- .replace(/\{\{targetLanguage\}\}/g, targetLang)
213
- .replace(/\{\{content\}\}/g, "");
214
- if (glossaryConfig) {
215
- const glossarySection = buildGlossaryPrompt(glossaryConfig, targetLang);
216
- if (glossarySection) {
217
- systemPrompt += glossarySection;
218
- }
219
- }
220
- if (hasSentinels) {
221
- systemPrompt +=
222
- "\n\n## Block boundary markers (P-A4 v2)\n\n" +
223
- "Lines containing the marker `<!--BB-->` are **block boundary markers** inserted\n" +
224
- "by the translation pipeline to preserve newlines around structural elements.\n\n" +
225
- "Rules for `<!--BB-->` markers (HTML comment form):\n" +
226
- "- Output every `<!--BB-->` marker **verbatim and unchanged** in your translation.\n" +
227
- "- Each marker must remain on its own line, in the same position relative to\n" +
228
- " surrounding content.\n" +
229
- "- Do not translate, remove, paraphrase, modify, normalize whitespace inside, or\n" +
230
- " rename these markers.\n" +
231
- "- Do not add new `<!--BB-->` markers; only preserve existing ones.\n\n" +
232
- "Good example (correct preservation):\n" +
233
- " Input:\n" +
234
- " <!--BB-->\n" +
235
- " - List item one\n" +
236
- " <!--BB-->\n" +
237
- " - List item two\n" +
238
- " <!--BB-->\n" +
239
- " ## Section heading\n" +
240
- " Output:\n" +
241
- " <!--BB-->\n" +
242
- " - リスト項目その一\n" +
243
- " <!--BB-->\n" +
244
- " - リスト項目その二\n" +
245
- " <!--BB-->\n" +
246
- " ## セクション見出し\n\n" +
247
- "Bad examples (DO NOT do these):\n" +
248
- " - <!--BB--> ❌ → <!--BB__--> (added suffix — FORBIDDEN)\n" +
249
- " - <!--BB--> ❌ → <!-- BB --> (added internal whitespace — FORBIDDEN)\n" +
250
- " - <!--BB--> ❌ → <!--bb--> (case change — FORBIDDEN)\n" +
251
- " - <!--BB--> ❌ → (omitted) (deleted — FORBIDDEN)\n" +
252
- " - <!--BB--> ❌ → <!--BB-x--> (added suffix — FORBIDDEN)\n\n" +
253
- "Preserve the marker exactly: 9 characters, opening `<!--`, content `BB`,\n" +
254
- "closing `-->`, no whitespace, no case changes, no suffixes.";
255
- }
256
- if (hasPlaceholders) {
257
- systemPrompt +=
258
- "\n\nIMPORTANT - Placeholder preservation:\n" +
259
- "- Tokens matching __CODE_BLOCK_N__ or __INLINE_CODE_N__ are placeholders for code blocks/inline code.\n" +
260
- "- Output them VERBATIM and UNCHANGED. Do NOT translate, modify, or remove them.\n" +
261
- "- Example: if input has __CODE_BLOCK_0__, output must contain __CODE_BLOCK_0__ exactly.";
262
- }
263
- return [
264
- { role: "system", content: systemPrompt },
265
- { role: "user", content },
266
- ];
267
- }
268
- function resolveOutputPath(inputPath, targetLang, outputPath) {
269
- if (outputPath)
270
- return outputPath;
271
- const dir = dirname(inputPath);
272
- const ext = extname(inputPath);
273
- const base = basename(inputPath, ext);
274
- return join(dir, `${base}.${targetLang}${ext}`);
275
- }
27
+ // ─── Chunking utilities (kept for splitIntoChunks export) ───────────────────
276
28
  /**
277
29
  * Find positions (line indices) of Markdown headings at the given level,
278
30
  * excluding lines inside fenced code blocks or table rows.
@@ -283,7 +35,7 @@ export function findHeadingPositions(lines, level) {
283
35
  const prefix = "#".repeat(level) + " ";
284
36
  for (let i = 0; i < lines.length; i++) {
285
37
  const line = lines[i];
286
- if (/^`{3,}/.test(line))
38
+ if (/^(`{3,}|~{3,})/.test(line))
287
39
  inCodeBlock = !inCodeBlock;
288
40
  if (inCodeBlock)
289
41
  continue;
@@ -295,8 +47,8 @@ export function findHeadingPositions(lines, level) {
295
47
  return positions;
296
48
  }
297
49
  /**
298
- * Split lines at the given positions into chunks (each position starts a new chunk).
299
- * Segments exceeding maxChunkLines are further split using ### headings or safeSplitLines.
50
+ * Split lines at the given positions into chunks. Segments exceeding maxChunkLines
51
+ * are further split using ### headings or safeSplitLines.
300
52
  */
301
53
  export function splitAtPositions(lines, positions, maxChunkLines) {
302
54
  const result = [];
@@ -311,8 +63,6 @@ export function splitAtPositions(lines, positions, maxChunkLines) {
311
63
  continue;
312
64
  if (segmentLines.length > maxChunkLines) {
313
65
  const subPositions = findHeadingPositions(segmentLines, 3);
314
- // Filter out position 0: splitting at the start doesn't reduce segment size
315
- // and causes infinite recursion when the only heading is at position 0.
316
66
  const effectivePositions = subPositions.filter((p) => p > 0);
317
67
  if (effectivePositions.length > 0) {
318
68
  result.push(...splitAtPositions(segmentLines, effectivePositions, maxChunkLines));
@@ -337,12 +87,8 @@ export function safeSplitLines(lines, maxChunkLines) {
337
87
  let inCodeBlock = false;
338
88
  for (let i = 0; i < lines.length; i++) {
339
89
  const line = lines[i];
340
- const isFence = /^`{3,}/.test(line);
90
+ const isFence = /^(`{3,}|~{3,})/.test(line);
341
91
  const isTableLine = line.startsWith("|");
342
- // Check split eligibility BEFORE toggling fence state:
343
- // - never split inside a code block
344
- // - never split ON a fence line (would separate opening/closing ``` from their block)
345
- // - never split ON a table row
346
92
  const canSplitHere = !inCodeBlock && !isFence && !isTableLine;
347
93
  if (isFence)
348
94
  inCodeBlock = !inCodeBlock;
@@ -357,8 +103,7 @@ export function safeSplitLines(lines, maxChunkLines) {
357
103
  return chunks.filter((c) => c.trim().length > 0);
358
104
  }
359
105
  /**
360
- * Merge chunks smaller than MIN_CHUNK_LINES into the previous chunk,
361
- * as long as the merged result does not exceed maxLines.
106
+ * Merge chunks smaller than MIN_CHUNK_LINES into the previous chunk.
362
107
  */
363
108
  export function mergeSmallChunks(chunks, maxLines) {
364
109
  if (chunks.length <= 1)
@@ -394,9 +139,290 @@ export function splitIntoChunks(content, maxChunkLines = DEFAULT_MAX_CHUNK_LINES
394
139
  }
395
140
  return safeSplitLines(lines, maxChunkLines);
396
141
  }
142
+ /**
143
+ * Replace fenced code blocks and inline code with placeholders.
144
+ * Used by glossary-fix.ts to protect code blocks before text replacement.
145
+ */
146
+ export function protectCodeBlocks(content) {
147
+ const map = new Map();
148
+ let blockIndex = 0;
149
+ let inlineIndex = 0;
150
+ const lines = content.split("\n");
151
+ const resultLines = [];
152
+ let fenceOpen = null;
153
+ let blockLines = [];
154
+ for (const line of lines) {
155
+ const fenceMatch = line.match(/^(`{3,})/);
156
+ if (fenceOpen === null) {
157
+ if (fenceMatch) {
158
+ fenceOpen = fenceMatch[1];
159
+ blockLines = [line];
160
+ }
161
+ else {
162
+ resultLines.push(line);
163
+ }
164
+ }
165
+ else {
166
+ blockLines.push(line);
167
+ if (fenceMatch && fenceMatch[1].length >= fenceOpen.length && line.trim() === fenceMatch[1]) {
168
+ const original = blockLines.join("\n") + "\n";
169
+ const placeholder = `__CODE_BLOCK_${blockIndex++}__`;
170
+ map.set(placeholder, original);
171
+ resultLines.push(placeholder);
172
+ fenceOpen = null;
173
+ blockLines = [];
174
+ }
175
+ }
176
+ }
177
+ if (fenceOpen !== null) {
178
+ resultLines.push(...blockLines);
179
+ }
180
+ let result = resultLines.join("\n");
181
+ result = result.replace(/`([^`\n]+)`/g, (match) => {
182
+ const placeholder = `__INLINE_CODE_${inlineIndex++}__`;
183
+ map.set(placeholder, match);
184
+ return placeholder;
185
+ });
186
+ return { text: result, map };
187
+ }
188
+ /**
189
+ * Restore placeholders back to original code blocks/inline code.
190
+ */
191
+ export function restoreCodeBlocks(content, map) {
192
+ let result = content;
193
+ for (const [placeholder, original] of map.entries()) {
194
+ if (original.endsWith("\n")) {
195
+ result = result.split(placeholder + "\n").join(original);
196
+ result = result.split(placeholder).join(original);
197
+ }
198
+ else {
199
+ result = result.split(placeholder + "\n").join(original + "\n");
200
+ result = result.split(placeholder).join(original);
201
+ }
202
+ }
203
+ return result;
204
+ }
205
+ /**
206
+ * Extract all translatable text nodes from an mdast AST.
207
+ * remark AST guarantees text nodes cannot be inside code/inlineCode nodes,
208
+ * so we only skip empty/whitespace-only nodes.
209
+ */
210
+ function extractTextNodes(ast) {
211
+ const nodes = [];
212
+ visit(ast, "text", (node) => {
213
+ if (!node.value.trim())
214
+ return;
215
+ nodes.push({ node, id: nodes.length });
216
+ });
217
+ return nodes;
218
+ }
219
+ /**
220
+ * Build system prompt for text-mode batch translation (Gemini / Ollama fallback).
221
+ * Includes JSON format instructions since we're relying on the LLM to output JSON.
222
+ */
223
+ function buildBatchSystemPrompt(targetLang, templateContent, glossaryConfig) {
224
+ const basePrompt = templateContent
225
+ ? templateContent.replace(/\{\{targetLanguage\}\}/g, targetLang)
226
+ : `You are a professional translator. Translate text segments to ${targetLang}.
227
+
228
+ Rules:
229
+ - Translate only the text content; do not add or remove punctuation structure
230
+ - Preserve proper nouns, code identifiers, URLs, and file paths unchanged
231
+ - Produce natural, fluent text in the target language
232
+ - For Japanese: use full-width punctuation (。、?!), add half-width spaces around English words/numbers
233
+ - Keep product names, abbreviations, and technical terms unchanged (e.g., NGSI-LD, MCP, GeoJSON)`;
234
+ let prompt = basePrompt;
235
+ if (glossaryConfig) {
236
+ const glossarySection = buildGlossaryPrompt(glossaryConfig, targetLang);
237
+ if (glossarySection)
238
+ prompt += glossarySection;
239
+ }
240
+ prompt += `
241
+
242
+ ## Translation format
243
+
244
+ You will receive a JSON object with a "segments" array.
245
+ Each segment has an "id" (integer) and "text" (string to translate).
246
+
247
+ Return ONLY a valid JSON object with a "translations" array.
248
+ Each translation must have the same "id" and the translated "text".
249
+ Do not include any explanation, markdown, or text outside the JSON object.
250
+
251
+ Example input:
252
+ {"segments": [{"id": 0, "text": "Hello world"}, {"id": 1, "text": "This is a test."}]}
253
+
254
+ Example output:
255
+ {"translations": [{"id": 0, "text": "こんにちは世界"}, {"id": 1, "text": "これはテストです。"}]}`;
256
+ return prompt;
257
+ }
258
+ /**
259
+ * Build system prompt for structured output translation (Claude tool_use path).
260
+ * No JSON format instructions needed — the tool schema enforces the response shape.
261
+ */
262
+ function buildStructuredSystemPrompt(targetLang, templateContent, glossaryConfig) {
263
+ const basePrompt = templateContent
264
+ ? templateContent.replace(/\{\{targetLanguage\}\}/g, targetLang)
265
+ : `You are a professional translator. Translate each text segment to ${targetLang}.
266
+
267
+ Rules:
268
+ - Translate only the text content; do not alter structure or punctuation outside the text
269
+ - Preserve proper nouns, code identifiers, URLs, and file paths unchanged
270
+ - Produce natural, fluent text in the target language
271
+ - For Japanese: use full-width punctuation (。、?!), add half-width spaces around English words/numbers
272
+ - Keep product names, abbreviations, and technical terms unchanged (e.g., NGSI-LD, MCP, GeoJSON)
273
+ - Each segment is independent; translate it on its own`;
274
+ let prompt = basePrompt;
275
+ if (glossaryConfig) {
276
+ const glossarySection = buildGlossaryPrompt(glossaryConfig, targetLang);
277
+ if (glossarySection)
278
+ prompt += glossarySection;
279
+ }
280
+ return prompt;
281
+ }
282
+ /**
283
+ * Parse translation JSON response from LLM (text mode fallback).
284
+ * Handles both clean JSON and JSON embedded in prose (extracts first {...} block).
285
+ */
286
+ function parseTranslationResponse(raw) {
287
+ const trimmed = raw.trim();
288
+ try {
289
+ return JSON.parse(trimmed);
290
+ }
291
+ catch {
292
+ // Extract first JSON object if LLM added prose around it
293
+ const jsonMatch = trimmed.match(/\{[\s\S]*\}/);
294
+ if (jsonMatch) {
295
+ return JSON.parse(jsonMatch[0]);
296
+ }
297
+ throw new Error(`Failed to parse translation response: ${trimmed.slice(0, 200)}`);
298
+ }
299
+ }
300
+ function assertValidTranslations(value) {
301
+ if (!Array.isArray(value) ||
302
+ value.some((item) => {
303
+ if (typeof item !== "object" || item === null)
304
+ return true;
305
+ const candidate = item;
306
+ return typeof candidate.id !== "number" || typeof candidate.text !== "string";
307
+ })) {
308
+ throw new Error("[yuuhitsu] translateBatch: invalid translation payload — expected Array<{id: number, text: string}>");
309
+ }
310
+ }
311
+ /**
312
+ * Translate a batch of text segments using the provider.
313
+ *
314
+ * - If the provider implements `translateStructured` (Claude): uses tool_use to
315
+ * enforce the JSON schema at the API level, guaranteeing 1:1 ID mapping.
316
+ * - Otherwise: falls back to text-mode JSON prompt (Gemini / Ollama).
317
+ *
318
+ * In both paths the 1:1 ID mapping is validated and an error is thrown on mismatch.
319
+ */
320
+ async function translateBatch(provider, nodes, targetLang, templateContent, glossaryConfig) {
321
+ if (nodes.length === 0) {
322
+ return { usage: { promptTokens: 0, completionTokens: 0, totalTokens: 0 } };
323
+ }
324
+ const segments = nodes.map(({ node, id }) => ({ id, text: node.value }));
325
+ // P-A1: track total input character count for truncation detection
326
+ const totalInputChars = segments.reduce((sum, s) => sum + s.text.length, 0);
327
+ let translations;
328
+ let usage;
329
+ if (provider.translateStructured) {
330
+ // Structured output path: provider (Claude) enforces JSON schema via tool_use
331
+ const systemPrompt = buildStructuredSystemPrompt(targetLang, templateContent, glossaryConfig);
332
+ const result = await provider.translateStructured({ segments, systemPrompt });
333
+ assertValidTranslations(result.translations);
334
+ translations = result.translations;
335
+ usage = result.usage;
336
+ // P-A1: warn on truncation (compare translated chars to input chars)
337
+ const totalOutputChars = translations.reduce((sum, t) => sum + t.text.length, 0);
338
+ if (totalInputChars > 0 && totalOutputChars < totalInputChars * MIN_OUTPUT_RATIO) {
339
+ console.warn(`[yuuhitsu] translateBatch: output may be truncated ` +
340
+ `(input chars: ${totalInputChars}, output chars: ${totalOutputChars})`);
341
+ }
342
+ }
343
+ else {
344
+ // Text mode fallback: Gemini / Ollama
345
+ const systemPrompt = buildBatchSystemPrompt(targetLang, templateContent, glossaryConfig);
346
+ const messages = [
347
+ { role: "system", content: systemPrompt },
348
+ { role: "user", content: JSON.stringify({ segments }) },
349
+ ];
350
+ const response = await provider.chat({ model: "", messages });
351
+ const parsed = parseTranslationResponse(response.content);
352
+ assertValidTranslations(parsed.translations);
353
+ // P-A1: warn on truncation (compare translated text chars, not raw JSON string length)
354
+ const totalOutputChars = parsed.translations.reduce((sum, t) => sum + t.text.length, 0);
355
+ if (totalInputChars > 0 && totalOutputChars < totalInputChars * MIN_OUTPUT_RATIO) {
356
+ console.warn(`[yuuhitsu] translateBatch: output may be truncated ` +
357
+ `(input chars: ${totalInputChars}, output chars: ${totalOutputChars})`);
358
+ }
359
+ translations = parsed.translations;
360
+ usage = response.usage;
361
+ }
362
+ // Validate strict 1:1 ID mapping (both paths):
363
+ // - no duplicate output IDs (Map silently overwrites; we must detect before)
364
+ // - no unexpected IDs (IDs not present in the input set)
365
+ // - no missing IDs (input ID absent from output)
366
+ const inputIds = new Set(nodes.map(({ id }) => id));
367
+ const seenOutputIds = new Set();
368
+ const duplicateIds = [];
369
+ const unexpectedIds = [];
370
+ for (const t of translations) {
371
+ if (seenOutputIds.has(t.id)) {
372
+ duplicateIds.push(t.id);
373
+ }
374
+ else {
375
+ seenOutputIds.add(t.id);
376
+ }
377
+ if (!inputIds.has(t.id)) {
378
+ unexpectedIds.push(t.id);
379
+ }
380
+ }
381
+ if (duplicateIds.length > 0) {
382
+ throw new Error(`[yuuhitsu] translateBatch: duplicate IDs in response (IDs: ${duplicateIds.join(", ")})`);
383
+ }
384
+ if (unexpectedIds.length > 0) {
385
+ throw new Error(`[yuuhitsu] translateBatch: unexpected IDs in response (IDs: ${unexpectedIds.join(", ")})`);
386
+ }
387
+ const translationMap = new Map(translations.map((t) => [t.id, t.text]));
388
+ const missingIds = nodes.filter(({ id }) => !translationMap.has(id)).map(({ id }) => id);
389
+ if (missingIds.length > 0) {
390
+ throw new Error(`[yuuhitsu] translateBatch: partial translation — ${missingIds.length} node(s) missing` +
391
+ ` from response (IDs: ${missingIds.join(", ")})`);
392
+ }
393
+ // Apply translations back to AST nodes
394
+ for (const { node, id } of nodes) {
395
+ const translated = translationMap.get(id);
396
+ if (translated !== undefined && translated.trim()) {
397
+ node.value = translated;
398
+ }
399
+ }
400
+ return { usage };
401
+ }
402
+ function resolveOutputPath(inputPath, targetLang, outputPath) {
403
+ if (outputPath)
404
+ return outputPath;
405
+ const dir = dirname(inputPath);
406
+ const ext = extname(inputPath);
407
+ const base = basename(inputPath, ext);
408
+ return join(dir, `${base}.${targetLang}${ext}`);
409
+ }
410
+ /**
411
+ * Translate a Markdown file using AST-based approach.
412
+ *
413
+ * Architecture (0.2.0):
414
+ * 1. Separate frontmatter (preserved verbatim)
415
+ * 2. Split body into chunks by heading boundaries
416
+ * 3. For each chunk: parse to AST → extract text nodes → translate via LLM → write back
417
+ * 4. Serialize AST → markdown → concatenate → write output
418
+ *
419
+ * Key properties:
420
+ * - Code blocks (fenced and inline) are never sent to LLM (AST handles them deterministically)
421
+ * - Markdown structure (headings, lists, tables, HR) is preserved by AST round-trip
422
+ * - No sentinel injection or removal needed
423
+ */
397
424
  export async function translateFile(options) {
398
- const { provider, inputPath, targetLang, templateContent, glossaryConfig, maxChunkLines } = options;
399
- // Read input file
425
+ const { provider, inputPath, targetLang, templateContent, glossaryConfig, maxChunkLines, } = options;
400
426
  let content;
401
427
  try {
402
428
  content = readFileSync(inputPath, "utf-8");
@@ -407,46 +433,41 @@ export async function translateFile(options) {
407
433
  }
408
434
  throw err;
409
435
  }
410
- // Check for empty file
411
436
  if (content.trim().length === 0) {
412
437
  throw new Error(`Input file is empty: ${inputPath}`);
413
438
  }
414
439
  const resolvedOutput = resolveOutputPath(inputPath, targetLang, options.outputPath);
415
- // Ensure output directory exists
416
440
  mkdirSync(dirname(resolvedOutput), { recursive: true });
417
- // Separate frontmatter from body
418
441
  const { frontmatter, body } = separateFrontmatter(content);
419
- // Protect code blocks: replace with placeholders before sending to LLM
420
- const { text: protectedBody, map: codeMap } = protectCodeBlocks(body);
421
- const hasPlaceholders = codeMap.size > 0;
422
- // Protect block boundaries: insert %%BB%% sentinels before structural elements (P-A4)
423
- const bodyWithSentinels = protectBlockBoundaries(protectedBody);
424
- const hasSentinels = bodyWithSentinels.includes(BLOCK_BOUNDARY_SENTINEL);
425
- // Split body into chunks if needed (frontmatter is never sent to LLM)
426
- const chunks = splitIntoChunks(bodyWithSentinels, maxChunkLines);
427
- const translatedParts = [];
442
+ // Split body into text chunks (heading-based, same as before)
443
+ const chunks = splitIntoChunks(body, maxChunkLines ?? DEFAULT_MAX_CHUNK_LINES);
444
+ const translatedChunks = [];
428
445
  let totalUsage = { promptTokens: 0, completionTokens: 0, totalTokens: 0 };
429
446
  for (const chunk of chunks) {
430
- const messages = buildPrompt(chunk, targetLang, hasPlaceholders, hasSentinels, templateContent, glossaryConfig);
431
- const response = await provider.chat({
432
- model: "",
433
- messages,
434
- });
435
- translatedParts.push(response.content);
436
- totalUsage.promptTokens += response.usage.promptTokens;
437
- totalUsage.completionTokens += response.usage.completionTokens;
438
- totalUsage.totalTokens += response.usage.totalTokens;
447
+ // Parse chunk to AST (code blocks, inline code become typed nodes → never reach LLM)
448
+ const processor = remark().use(remarkGfm);
449
+ const ast = processor.parse(chunk);
450
+ // Extract translatable text nodes
451
+ const textNodes = extractTextNodes(ast);
452
+ if (textNodes.length > 0) {
453
+ const { usage } = await translateBatch(provider, textNodes, targetLang, templateContent, glossaryConfig);
454
+ totalUsage.promptTokens += usage.promptTokens;
455
+ totalUsage.completionTokens += usage.completionTokens;
456
+ totalUsage.totalTokens += usage.totalTokens;
457
+ }
458
+ // Serialize AST back to markdown
459
+ const translatedChunk = processor.stringify(ast);
460
+ translatedChunks.push(translatedChunk);
439
461
  }
440
- // Restore block boundaries (sentinels newlines) then restore code block placeholders.
441
- // join("\n") ensures chunk boundaries always have a separator even if LLM drops trailing newlines.
442
- const translatedBodyWithSentinels = translatedParts.join("\n");
443
- const translatedBodyWithPlaceholders = restoreBlockBoundaries(translatedBodyWithSentinels);
444
- const translatedBody = restoreCodeBlocks(translatedBodyWithPlaceholders, codeMap);
445
- // Recombine frontmatter with translated body
462
+ // Join chunks: normalize each chunk to exactly one trailing newline
463
+ // (preserves trailing spaces for Markdown hard line breaks), then join
464
+ // with a single "\n" so chunk boundaries produce exactly one blank line.
465
+ const translatedBody = translatedChunks
466
+ .map((c) => c.replace(/\n+$/, "\n"))
467
+ .join("\n");
446
468
  const translatedContent = frontmatter
447
469
  ? frontmatter + translatedBody
448
470
  : translatedBody;
449
- // Write output
450
471
  writeFileSync(resolvedOutput, translatedContent, "utf-8");
451
472
  return {
452
473
  outputPath: resolvedOutput,
@@ -1 +1 @@
1
- {"version":3,"file":"translate.js","sourceRoot":"","sources":["../../src/tasks/translate.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"translate.js","sourceRoot":"","sources":["../../src/tasks/translate.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@geolonia/yuuhitsu",
3
- "version": "0.1.16",
3
+ "version": "0.2.0",
4
4
  "description": "右筆 (Yuuhitsu) - AI-powered document operations CLI. Translate, generate, and sync documents using Claude, Gemini, or Ollama.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -12,7 +12,7 @@
12
12
  "dev": "tsx src/cli/index.ts",
13
13
  "test": "vitest run",
14
14
  "test:watch": "vitest",
15
- "test:integration": "vitest run tests/integration/translate-block-boundaries.real-llm.test.ts",
15
+ "test:integration": "vitest run --config vitest.integration.config.ts",
16
16
  "lint": "tsc --noEmit"
17
17
  },
18
18
  "keywords": [
@@ -36,6 +36,9 @@
36
36
  "dotenv": "^16.4.0",
37
37
  "fast-glob": "^3.3.3",
38
38
  "openai": "^4.77.0",
39
+ "remark": "^15.0.1",
40
+ "remark-gfm": "^4.0.1",
41
+ "unist-util-visit": "^5.1.0",
39
42
  "yaml": "^2.7.0"
40
43
  },
41
44
  "devDependencies": {
@@ -43,5 +46,9 @@
43
46
  "tsx": "^4.19.0",
44
47
  "typescript": "^5.7.0",
45
48
  "vitest": "^3.0.0"
49
+ },
50
+ "publishConfig": {
51
+ "access": "public",
52
+ "registry": "https://registry.npmjs.org/"
46
53
  }
47
54
  }