dialekt 0.1.0 → 0.1.1

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 (71) hide show
  1. package/README.md +8 -10
  2. package/TESTING.md +29 -29
  3. package/dist/cli/main.d.mts +1 -1
  4. package/dist/cli/main.mjs +549 -362
  5. package/dist/formatters-De4Q-X1d.mjs +516 -435
  6. package/dist/index.d.mts +162 -25
  7. package/dist/index.mjs +119 -34
  8. package/package.json +3 -3
  9. package/pnpm-workspace.yaml +3 -3
  10. package/src/adapter/types.test.ts +57 -57
  11. package/src/adapter/types.ts +7 -4
  12. package/src/benchmark/metrics.test.ts +141 -69
  13. package/src/benchmark/metrics.ts +6 -6
  14. package/src/benchmark/report.test.ts +38 -38
  15. package/src/benchmark/report.ts +6 -6
  16. package/src/benchmark/runner.test.ts +70 -72
  17. package/src/benchmark/runner.ts +4 -4
  18. package/src/cli/commands/add.test.ts +90 -109
  19. package/src/cli/commands/add.ts +40 -28
  20. package/src/cli/commands/benchmark.test.ts +77 -64
  21. package/src/cli/commands/benchmark.ts +64 -41
  22. package/src/cli/commands/languages.test.ts +45 -42
  23. package/src/cli/commands/languages.ts +16 -12
  24. package/src/cli/commands/missing.test.ts +143 -92
  25. package/src/cli/commands/missing.ts +24 -17
  26. package/src/cli/commands/translate.test.ts +79 -79
  27. package/src/cli/commands/translate.ts +41 -31
  28. package/src/cli/commands/unused.test.ts +62 -51
  29. package/src/cli/commands/unused.ts +18 -14
  30. package/src/cli/commands/validate.test.ts +130 -72
  31. package/src/cli/commands/validate.ts +25 -20
  32. package/src/cli/config-resolution.test.ts +169 -49
  33. package/src/cli/config-resolution.ts +5 -7
  34. package/src/cli/format.test.ts +50 -50
  35. package/src/cli/format.ts +57 -60
  36. package/src/cli/formatters.test.ts +128 -106
  37. package/src/cli/formatters.ts +72 -95
  38. package/src/cli/main.ts +13 -13
  39. package/src/config/define-config.test.ts +44 -29
  40. package/src/config/define-config.ts +1 -1
  41. package/src/config/load-config.test.ts +21 -18
  42. package/src/config/load-config.ts +5 -5
  43. package/src/config/types.test.ts +50 -44
  44. package/src/config/types.ts +2 -2
  45. package/src/index.ts +22 -26
  46. package/src/keys/flatten.test.ts +52 -52
  47. package/src/keys/flatten.ts +7 -9
  48. package/src/sdk/file-io.test.ts +47 -59
  49. package/src/sdk/file-io.ts +2 -2
  50. package/src/sdk/node-layer.test.ts +18 -18
  51. package/src/sdk/node-layer.ts +2 -2
  52. package/src/sdk/php-array-reader.test.ts +49 -40
  53. package/src/sdk/php-array-reader.ts +5 -5
  54. package/src/translation/chunking.test.ts +52 -44
  55. package/src/translation/chunking.ts +1 -1
  56. package/src/translation/missing-keys.test.ts +86 -93
  57. package/src/translation/missing-keys.ts +4 -6
  58. package/src/translation/model-registry.test.ts +41 -32
  59. package/src/translation/model-registry.ts +9 -9
  60. package/src/translation/one-shot-strategy.test.ts +105 -86
  61. package/src/translation/one-shot-strategy.ts +10 -12
  62. package/src/translation/orchestrator.test.ts +90 -101
  63. package/src/translation/orchestrator.ts +26 -26
  64. package/src/translation/prompt.test.ts +76 -76
  65. package/src/translation/prompt.ts +2 -2
  66. package/src/translation/tool-loop-strategy.test.ts +134 -107
  67. package/src/translation/tool-loop-strategy.ts +14 -18
  68. package/src/translation/types.test.ts +22 -22
  69. package/src/translation/types.ts +3 -3
  70. package/tsdown.config.ts +3 -3
  71. package/vitest.config.ts +3 -3
@@ -12,7 +12,7 @@ Rules:
12
12
  - Escape double quotes in translations with a backslash when needed.`;
13
13
  }
14
14
 
15
- import type { TranslationContext } from './types.js';
15
+ import type { TranslationContext } from "./types.js";
16
16
 
17
17
  export function buildUserPrompt(ctx: TranslationContext): string {
18
18
  const sourceJson = JSON.stringify(ctx.sourceMap, null, 2);
@@ -20,7 +20,7 @@ export function buildUserPrompt(ctx: TranslationContext): string {
20
20
 
21
21
  const keysWithValues: Record<string, string> = {};
22
22
  for (const key of ctx.keys) {
23
- keysWithValues[key] = ctx.sourceMap[key] ?? '';
23
+ keysWithValues[key] = ctx.sourceMap[key] ?? "";
24
24
  }
25
25
  const keysJson = JSON.stringify(keysWithValues, null, 2);
26
26
 
@@ -1,29 +1,29 @@
1
- import { describe, expect, it } from 'vitest';
2
- import { Effect, Either } from 'effect';
3
- import { MockLanguageModelV3 } from 'ai/test';
4
- import { createToolLoopStrategy } from './tool-loop-strategy.js';
5
- import { TranslationFailedError } from './types.js';
1
+ import { describe, expect, it } from "vitest";
2
+ import { Effect, Either } from "effect";
3
+ import { MockLanguageModelV3 } from "ai/test";
4
+ import { createToolLoopStrategy } from "./tool-loop-strategy.js";
5
+ import { TranslationFailedError } from "./types.js";
6
6
 
7
- describe('createToolLoopStrategy', () => {
8
- it('returns translated map when tool is called', async () => {
7
+ describe("createToolLoopStrategy", () => {
8
+ it("returns translated map when tool is called", async () => {
9
9
  const model = new MockLanguageModelV3({
10
10
  doGenerate: async () => ({
11
- text: '',
11
+ text: "",
12
12
  content: [
13
13
  {
14
- type: 'tool-call',
15
- toolCallId: 'call-1',
16
- toolName: 'submitTranslations',
17
- input: JSON.stringify({ hello: 'Hallo', bye: 'Tschüss' }),
14
+ type: "tool-call",
15
+ toolCallId: "call-1",
16
+ toolName: "submitTranslations",
17
+ input: JSON.stringify({ hello: "Hallo", bye: "Tschüss" }),
18
18
  },
19
19
  ],
20
- finishReason: { unified: 'tool-calls' as const, raw: 'tool_calls' },
20
+ finishReason: { unified: "tool-calls" as const, raw: "tool_calls" },
21
21
  usage: {
22
22
  inputTokens: { total: 10, noCache: 10, cacheRead: 0, cacheWrite: 0 },
23
23
  outputTokens: { total: 4, text: 0, reasoning: 0 },
24
24
  },
25
25
  response: {
26
- modelId: 'mock',
26
+ modelId: "mock",
27
27
  timestamp: new Date(),
28
28
  },
29
29
  request: { body: {} },
@@ -37,32 +37,32 @@ describe('createToolLoopStrategy', () => {
37
37
  });
38
38
 
39
39
  const ctx = {
40
- sourceLocale: 'en',
41
- targetLocale: 'de',
42
- sourceMap: { hello: 'Hello', bye: 'Bye' },
40
+ sourceLocale: "en",
41
+ targetLocale: "de",
42
+ sourceMap: { hello: "Hello", bye: "Bye" },
43
43
  targetMap: {},
44
- keys: ['hello', 'bye'],
44
+ keys: ["hello", "bye"],
45
45
  };
46
46
 
47
47
  const result = await Effect.runPromise(strategy.translateChunk(ctx));
48
- expect(result).toEqual({ hello: 'Hallo', bye: 'Tschüss' });
48
+ expect(result).toEqual({ hello: "Hallo", bye: "Tschüss" });
49
49
  });
50
50
 
51
- it('retries when tool is not called and fails after exhaustion', async () => {
51
+ it("retries when tool is not called and fails after exhaustion", async () => {
52
52
  let calls = 0;
53
53
  const model = new MockLanguageModelV3({
54
54
  doGenerate: async () => {
55
55
  calls++;
56
56
  return {
57
- text: '',
58
- content: [{ type: 'text' as const, text: 'I will translate now' }],
59
- finishReason: { unified: 'stop' as const, raw: 'stop' },
57
+ text: "",
58
+ content: [{ type: "text" as const, text: "I will translate now" }],
59
+ finishReason: { unified: "stop" as const, raw: "stop" },
60
60
  usage: {
61
61
  inputTokens: { total: 10, noCache: 10, cacheRead: 0, cacheWrite: 0 },
62
62
  outputTokens: { total: 2, text: 2, reasoning: 0 },
63
63
  },
64
64
  response: {
65
- modelId: 'mock',
65
+ modelId: "mock",
66
66
  timestamp: new Date(),
67
67
  },
68
68
  request: { body: {} },
@@ -77,35 +77,42 @@ describe('createToolLoopStrategy', () => {
77
77
  });
78
78
 
79
79
  const ctx = {
80
- sourceLocale: 'en',
81
- targetLocale: 'de',
82
- sourceMap: { hello: 'Hello', bye: 'Bye' },
80
+ sourceLocale: "en",
81
+ targetLocale: "de",
82
+ sourceMap: { hello: "Hello", bye: "Bye" },
83
83
  targetMap: {},
84
- keys: ['hello', 'bye'],
84
+ keys: ["hello", "bye"],
85
85
  };
86
86
 
87
- const exit = await Effect.runPromise(Effect.either(strategy.translateChunk(ctx))) as Either.Either<unknown, TranslationFailedError>;
87
+ const exit = (await Effect.runPromise(
88
+ Effect.either(strategy.translateChunk(ctx)),
89
+ )) as Either.Either<unknown, TranslationFailedError>;
88
90
  expect(calls).toBeGreaterThan(1);
89
- if (exit._tag === 'Left') {
90
- expect(exit.left._tag).toBe('TranslationFailedError');
91
+ if (exit._tag === "Left") {
92
+ expect(exit.left._tag).toBe("TranslationFailedError");
91
93
  } else {
92
- throw new Error('Expected Left');
94
+ throw new Error("Expected Left");
93
95
  }
94
96
  });
95
97
 
96
- it('handles empty keys', async () => {
98
+ it("handles empty keys", async () => {
97
99
  const model = new MockLanguageModelV3({
98
100
  doGenerate: async () => ({
99
- text: '',
100
- content: [{
101
- type: 'tool-call',
102
- toolCallId: 'call-1',
103
- toolName: 'submitTranslations',
104
- input: JSON.stringify({}),
105
- }],
106
- finishReason: { unified: 'tool-calls' as const, raw: 'tool_calls' },
107
- usage: { inputTokens: { total: 1, noCache: 1, cacheRead: 0, cacheWrite: 0 }, outputTokens: { total: 1, text: 0, reasoning: 0 } },
108
- response: { modelId: 'mock', timestamp: new Date() },
101
+ text: "",
102
+ content: [
103
+ {
104
+ type: "tool-call",
105
+ toolCallId: "call-1",
106
+ toolName: "submitTranslations",
107
+ input: JSON.stringify({}),
108
+ },
109
+ ],
110
+ finishReason: { unified: "tool-calls" as const, raw: "tool_calls" },
111
+ usage: {
112
+ inputTokens: { total: 1, noCache: 1, cacheRead: 0, cacheWrite: 0 },
113
+ outputTokens: { total: 1, text: 0, reasoning: 0 },
114
+ },
115
+ response: { modelId: "mock", timestamp: new Date() },
109
116
  request: { body: {} },
110
117
  warnings: [],
111
118
  }),
@@ -117,8 +124,8 @@ describe('createToolLoopStrategy', () => {
117
124
  });
118
125
 
119
126
  const ctx = {
120
- sourceLocale: 'en',
121
- targetLocale: 'de',
127
+ sourceLocale: "en",
128
+ targetLocale: "de",
122
129
  sourceMap: {},
123
130
  targetMap: {},
124
131
  keys: [],
@@ -128,22 +135,27 @@ describe('createToolLoopStrategy', () => {
128
135
  expect(result).toEqual({});
129
136
  });
130
137
 
131
- it('handles wrong tool name by retrying', async () => {
138
+ it("handles wrong tool name by retrying", async () => {
132
139
  let calls = 0;
133
140
  const model = new MockLanguageModelV3({
134
141
  doGenerate: async () => {
135
142
  calls++;
136
143
  return {
137
- text: '',
138
- content: [{
139
- type: 'tool-call',
140
- toolCallId: 'call-1',
141
- toolName: calls < 2 ? 'wrongTool' : 'submitTranslations',
142
- input: JSON.stringify({ k: 'v' }),
143
- }],
144
- finishReason: { unified: 'tool-calls' as const, raw: 'tool_calls' },
145
- usage: { inputTokens: { total: 1, noCache: 1, cacheRead: 0, cacheWrite: 0 }, outputTokens: { total: 1, text: 0, reasoning: 0 } },
146
- response: { modelId: 'mock', timestamp: new Date() },
144
+ text: "",
145
+ content: [
146
+ {
147
+ type: "tool-call",
148
+ toolCallId: "call-1",
149
+ toolName: calls < 2 ? "wrongTool" : "submitTranslations",
150
+ input: JSON.stringify({ k: "v" }),
151
+ },
152
+ ],
153
+ finishReason: { unified: "tool-calls" as const, raw: "tool_calls" },
154
+ usage: {
155
+ inputTokens: { total: 1, noCache: 1, cacheRead: 0, cacheWrite: 0 },
156
+ outputTokens: { total: 1, text: 0, reasoning: 0 },
157
+ },
158
+ response: { modelId: "mock", timestamp: new Date() },
147
159
  request: { body: {} },
148
160
  warnings: [],
149
161
  };
@@ -156,34 +168,39 @@ describe('createToolLoopStrategy', () => {
156
168
  });
157
169
 
158
170
  const ctx = {
159
- sourceLocale: 'en',
160
- targetLocale: 'de',
161
- sourceMap: { k: 'K' },
171
+ sourceLocale: "en",
172
+ targetLocale: "de",
173
+ sourceMap: { k: "K" },
162
174
  targetMap: {},
163
- keys: ['k'],
175
+ keys: ["k"],
164
176
  };
165
177
 
166
178
  const result = await Effect.runPromise(strategy.translateChunk(ctx));
167
- expect(result).toEqual({ k: 'v' });
179
+ expect(result).toEqual({ k: "v" });
168
180
  expect(calls).toBeGreaterThan(1);
169
181
  });
170
182
 
171
- it('handles malformed tool input by retrying', async () => {
183
+ it("handles malformed tool input by retrying", async () => {
172
184
  let calls = 0;
173
185
  const model = new MockLanguageModelV3({
174
186
  doGenerate: async () => {
175
187
  calls++;
176
188
  return {
177
- text: '',
178
- content: [{
179
- type: 'tool-call',
180
- toolCallId: 'call-1',
181
- toolName: 'submitTranslations',
182
- input: calls < 2 ? 'not-json' : JSON.stringify({ k: 'v' }),
183
- }],
184
- finishReason: { unified: 'tool-calls' as const, raw: 'tool_calls' },
185
- usage: { inputTokens: { total: 1, noCache: 1, cacheRead: 0, cacheWrite: 0 }, outputTokens: { total: 1, text: 0, reasoning: 0 } },
186
- response: { modelId: 'mock', timestamp: new Date() },
189
+ text: "",
190
+ content: [
191
+ {
192
+ type: "tool-call",
193
+ toolCallId: "call-1",
194
+ toolName: "submitTranslations",
195
+ input: calls < 2 ? "not-json" : JSON.stringify({ k: "v" }),
196
+ },
197
+ ],
198
+ finishReason: { unified: "tool-calls" as const, raw: "tool_calls" },
199
+ usage: {
200
+ inputTokens: { total: 1, noCache: 1, cacheRead: 0, cacheWrite: 0 },
201
+ outputTokens: { total: 1, text: 0, reasoning: 0 },
202
+ },
203
+ response: { modelId: "mock", timestamp: new Date() },
187
204
  request: { body: {} },
188
205
  warnings: [],
189
206
  };
@@ -196,26 +213,29 @@ describe('createToolLoopStrategy', () => {
196
213
  });
197
214
 
198
215
  const ctx = {
199
- sourceLocale: 'en',
200
- targetLocale: 'de',
201
- sourceMap: { k: 'K' },
216
+ sourceLocale: "en",
217
+ targetLocale: "de",
218
+ sourceMap: { k: "K" },
202
219
  targetMap: {},
203
- keys: ['k'],
220
+ keys: ["k"],
204
221
  };
205
222
 
206
223
  const result = await Effect.runPromise(strategy.translateChunk(ctx));
207
- expect(result).toEqual({ k: 'v' });
224
+ expect(result).toEqual({ k: "v" });
208
225
  expect(calls).toBeGreaterThan(1);
209
226
  });
210
227
 
211
- it('fails after all retries when tool never called', async () => {
228
+ it("fails after all retries when tool never called", async () => {
212
229
  const model = new MockLanguageModelV3({
213
230
  doGenerate: async () => ({
214
- text: '',
215
- content: [{ type: 'text', text: 'I will translate now' }],
216
- finishReason: { unified: 'stop' as const, raw: 'stop' },
217
- usage: { inputTokens: { total: 1, noCache: 1, cacheRead: 0, cacheWrite: 0 }, outputTokens: { total: 1, text: 1, reasoning: 0 } },
218
- response: { modelId: 'mock', timestamp: new Date() },
231
+ text: "",
232
+ content: [{ type: "text", text: "I will translate now" }],
233
+ finishReason: { unified: "stop" as const, raw: "stop" },
234
+ usage: {
235
+ inputTokens: { total: 1, noCache: 1, cacheRead: 0, cacheWrite: 0 },
236
+ outputTokens: { total: 1, text: 1, reasoning: 0 },
237
+ },
238
+ response: { modelId: "mock", timestamp: new Date() },
219
239
  request: { body: {} },
220
240
  warnings: [],
221
241
  }),
@@ -227,34 +247,41 @@ describe('createToolLoopStrategy', () => {
227
247
  });
228
248
 
229
249
  const ctx = {
230
- sourceLocale: 'en',
231
- targetLocale: 'de',
232
- sourceMap: { k: 'K' },
250
+ sourceLocale: "en",
251
+ targetLocale: "de",
252
+ sourceMap: { k: "K" },
233
253
  targetMap: {},
234
- keys: ['k'],
254
+ keys: ["k"],
235
255
  };
236
256
 
237
- const exit = await Effect.runPromise(Effect.either(strategy.translateChunk(ctx))) as Either.Either<unknown, TranslationFailedError>;
238
- if (exit._tag === 'Left') {
239
- expect(exit.left._tag).toBe('TranslationFailedError');
257
+ const exit = (await Effect.runPromise(
258
+ Effect.either(strategy.translateChunk(ctx)),
259
+ )) as Either.Either<unknown, TranslationFailedError>;
260
+ if (exit._tag === "Left") {
261
+ expect(exit.left._tag).toBe("TranslationFailedError");
240
262
  } else {
241
- throw new Error('Expected Left');
263
+ throw new Error("Expected Left");
242
264
  }
243
265
  });
244
266
 
245
- it('handles single key', async () => {
267
+ it("handles single key", async () => {
246
268
  const model = new MockLanguageModelV3({
247
269
  doGenerate: async () => ({
248
- text: '',
249
- content: [{
250
- type: 'tool-call',
251
- toolCallId: 'call-1',
252
- toolName: 'submitTranslations',
253
- input: JSON.stringify({ greeting: 'Hallo' }),
254
- }],
255
- finishReason: { unified: 'tool-calls' as const, raw: 'tool_calls' },
256
- usage: { inputTokens: { total: 1, noCache: 1, cacheRead: 0, cacheWrite: 0 }, outputTokens: { total: 1, text: 0, reasoning: 0 } },
257
- response: { modelId: 'mock', timestamp: new Date() },
270
+ text: "",
271
+ content: [
272
+ {
273
+ type: "tool-call",
274
+ toolCallId: "call-1",
275
+ toolName: "submitTranslations",
276
+ input: JSON.stringify({ greeting: "Hallo" }),
277
+ },
278
+ ],
279
+ finishReason: { unified: "tool-calls" as const, raw: "tool_calls" },
280
+ usage: {
281
+ inputTokens: { total: 1, noCache: 1, cacheRead: 0, cacheWrite: 0 },
282
+ outputTokens: { total: 1, text: 0, reasoning: 0 },
283
+ },
284
+ response: { modelId: "mock", timestamp: new Date() },
258
285
  request: { body: {} },
259
286
  warnings: [],
260
287
  }),
@@ -266,14 +293,14 @@ describe('createToolLoopStrategy', () => {
266
293
  });
267
294
 
268
295
  const ctx = {
269
- sourceLocale: 'en',
270
- targetLocale: 'de',
271
- sourceMap: { greeting: 'Hello' },
296
+ sourceLocale: "en",
297
+ targetLocale: "de",
298
+ sourceMap: { greeting: "Hello" },
272
299
  targetMap: {},
273
- keys: ['greeting'],
300
+ keys: ["greeting"],
274
301
  };
275
302
 
276
303
  const result = await Effect.runPromise(strategy.translateChunk(ctx));
277
- expect(result).toEqual({ greeting: 'Hallo' });
304
+ expect(result).toEqual({ greeting: "Hallo" });
278
305
  });
279
306
  });
@@ -1,24 +1,22 @@
1
- import { ToolLoopAgent, tool, hasToolCall } from 'ai';
2
- import { Effect, Schedule } from 'effect';
3
- import { z } from 'zod';
4
- import type { LanguageModel } from 'ai';
5
- import type { TranslationContext, TranslationStrategy } from './types.js';
6
- import { TranslationFailedError } from './types.js';
7
- import { buildSystemPrompt, buildUserPrompt } from './prompt.js';
1
+ import { ToolLoopAgent, tool, hasToolCall } from "ai";
2
+ import { Effect, Schedule } from "effect";
3
+ import { z } from "zod";
4
+ import type { LanguageModel } from "ai";
5
+ import type { TranslationContext, TranslationStrategy } from "./types.js";
6
+ import { TranslationFailedError } from "./types.js";
7
+ import { buildSystemPrompt, buildUserPrompt } from "./prompt.js";
8
8
 
9
9
  async function tryTranslateChunk(
10
10
  model: LanguageModel,
11
11
  ctx: TranslationContext,
12
12
  ): Promise<Record<string, string>> {
13
- const schema = z.object(
14
- Object.fromEntries(ctx.keys.map((key: string) => [key, z.string()])),
15
- );
13
+ const schema = z.object(Object.fromEntries(ctx.keys.map((key: string) => [key, z.string()])));
16
14
 
17
15
  let captured: Record<string, string> | null = null;
18
16
 
19
17
  const submitTranslations = tool({
20
18
  description:
21
- 'Submit the final translations for every requested key. Call this exactly once, with every key filled in.',
19
+ "Submit the final translations for every requested key. Call this exactly once, with every key filled in.",
22
20
  inputSchema: schema,
23
21
  execute: async (input) => {
24
22
  captured = input as Record<string, string>;
@@ -30,18 +28,16 @@ async function tryTranslateChunk(
30
28
  model,
31
29
  instructions: buildSystemPrompt(ctx.sourceLocale, ctx.targetLocale),
32
30
  tools: { submitTranslations },
33
- stopWhen: hasToolCall('submitTranslations'),
31
+ stopWhen: hasToolCall("submitTranslations"),
34
32
  });
35
33
 
36
34
  await agent.generate({ prompt: buildUserPrompt(ctx) });
37
35
  if (captured === null) {
38
- throw new Error('Agent finished without calling submitTranslations');
36
+ throw new Error("Agent finished without calling submitTranslations");
39
37
  }
40
- const missing = ctx.keys.filter(
41
- (key: string) => !(key in (captured as Record<string, string>)),
42
- );
38
+ const missing = ctx.keys.filter((key: string) => !(key in (captured as Record<string, string>)));
43
39
  if (missing.length > 0) {
44
- throw new Error(`Model omitted keys: ${missing.join(', ')}`);
40
+ throw new Error(`Model omitted keys: ${missing.join(", ")}`);
45
41
  }
46
42
  return captured;
47
43
  }
@@ -51,7 +47,7 @@ export function createToolLoopStrategy(deps: {
51
47
  retry: { maxAttempts: number; baseDelayMs: number };
52
48
  }): TranslationStrategy {
53
49
  return {
54
- name: 'tool-loop-agent',
50
+ name: "tool-loop-agent",
55
51
  translateChunk: (ctx: TranslationContext) =>
56
52
  Effect.tryPromise({
57
53
  try: () => tryTranslateChunk(deps.model, ctx),
@@ -1,37 +1,37 @@
1
- import { describe, expect, it } from 'vitest';
2
- import { TranslationFailedError } from './types.js';
1
+ import { describe, expect, it } from "vitest";
2
+ import { TranslationFailedError } from "./types.js";
3
3
 
4
- describe('TranslationFailedError', () => {
5
- it('carries keys and cause', () => {
6
- const err = new TranslationFailedError({ keys: ['a'], cause: new Error('boom') });
7
- expect(err._tag).toBe('TranslationFailedError');
8
- expect(err.keys).toEqual(['a']);
4
+ describe("TranslationFailedError", () => {
5
+ it("carries keys and cause", () => {
6
+ const err = new TranslationFailedError({ keys: ["a"], cause: new Error("boom") });
7
+ expect(err._tag).toBe("TranslationFailedError");
8
+ expect(err.keys).toEqual(["a"]);
9
9
  });
10
10
 
11
- it('carries multiple keys', () => {
12
- const err = new TranslationFailedError({ keys: ['a', 'b', 'c'], cause: 'network timeout' });
13
- expect(err.keys).toEqual(['a', 'b', 'c']);
11
+ it("carries multiple keys", () => {
12
+ const err = new TranslationFailedError({ keys: ["a", "b", "c"], cause: "network timeout" });
13
+ expect(err.keys).toEqual(["a", "b", "c"]);
14
14
  });
15
15
 
16
- it('accepts string cause', () => {
17
- const err = new TranslationFailedError({ keys: ['x'], cause: 'rate limited' });
18
- expect(err._tag).toBe('TranslationFailedError');
16
+ it("accepts string cause", () => {
17
+ const err = new TranslationFailedError({ keys: ["x"], cause: "rate limited" });
18
+ expect(err._tag).toBe("TranslationFailedError");
19
19
  });
20
20
 
21
- it('accepts Error cause', () => {
22
- const cause = new Error('model rejected');
23
- const err = new TranslationFailedError({ keys: ['y'], cause });
24
- expect(err._tag).toBe('TranslationFailedError');
21
+ it("accepts Error cause", () => {
22
+ const cause = new Error("model rejected");
23
+ const err = new TranslationFailedError({ keys: ["y"], cause });
24
+ expect(err._tag).toBe("TranslationFailedError");
25
25
  });
26
26
 
27
- it('accepts empty keys array', () => {
28
- const err = new TranslationFailedError({ keys: [], cause: 'unknown' });
27
+ it("accepts empty keys array", () => {
28
+ const err = new TranslationFailedError({ keys: [], cause: "unknown" });
29
29
  expect(err.keys).toEqual([]);
30
30
  });
31
31
 
32
- it('preserves cause object identity when Error', () => {
33
- const cause = new Error('specific');
34
- const err = new TranslationFailedError({ keys: ['z'], cause });
32
+ it("preserves cause object identity when Error", () => {
33
+ const cause = new Error("specific");
34
+ const err = new TranslationFailedError({ keys: ["z"], cause });
35
35
  expect(err.cause).toBe(cause);
36
36
  });
37
37
  });
@@ -1,4 +1,4 @@
1
- import { Data, Effect } from 'effect';
1
+ import { Data, Effect } from "effect";
2
2
 
3
3
  export interface TranslationContext {
4
4
  readonly sourceLocale: string;
@@ -8,13 +8,13 @@ export interface TranslationContext {
8
8
  readonly keys: readonly string[]; // the specific keys to translate in this call
9
9
  }
10
10
 
11
- export class TranslationFailedError extends Data.TaggedError('TranslationFailedError')<{
11
+ export class TranslationFailedError extends Data.TaggedError("TranslationFailedError")<{
12
12
  readonly keys: readonly string[];
13
13
  readonly cause: unknown;
14
14
  }> {}
15
15
 
16
16
  export interface TranslationStrategy {
17
- readonly name: 'one-shot' | 'tool-loop-agent';
17
+ readonly name: "one-shot" | "tool-loop-agent";
18
18
  translateChunk(
19
19
  ctx: TranslationContext,
20
20
  ): Effect.Effect<Record<string, string>, TranslationFailedError>;
package/tsdown.config.ts CHANGED
@@ -1,7 +1,7 @@
1
- import { defineConfig } from 'tsdown';
1
+ import { defineConfig } from "tsdown";
2
2
 
3
3
  export default defineConfig({
4
- entry: ['src/index.ts', 'src/cli/main.ts'],
5
- format: 'esm',
4
+ entry: ["src/index.ts", "src/cli/main.ts"],
5
+ format: "esm",
6
6
  dts: true,
7
7
  });
package/vitest.config.ts CHANGED
@@ -1,8 +1,8 @@
1
- import { defineConfig } from 'vitest/config';
1
+ import { defineConfig } from "vitest/config";
2
2
 
3
3
  export default defineConfig({
4
4
  test: {
5
- include: ['src/**/*.test.ts'],
6
- environment: 'node',
5
+ include: ["src/**/*.test.ts"],
6
+ environment: "node",
7
7
  },
8
8
  });