opencode-translate 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.
- package/README.md +3 -3
- package/package.json +1 -1
- package/src/activation.ts +29 -10
package/README.md
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
## What It Does
|
|
6
6
|
|
|
7
|
-
- Activates once per root session when
|
|
7
|
+
- Activates once per root session when any root-session user message contains a trigger keyword such as `$en`.
|
|
8
8
|
- Translates user-authored text parts from `sourceLanguage` to English before the main LLM sees them.
|
|
9
9
|
- Stores the original user text, plus a cached English translation in part metadata.
|
|
10
10
|
- Shows a visible `→ EN: ...` preview under each translated user text part.
|
|
@@ -42,7 +42,7 @@ Hooks never throw. If the translator fails (network error, auth failure, provide
|
|
|
42
42
|
1. Logs the error via `client.app.log` (visible with `verbose: true`).
|
|
43
43
|
2. Emits a `⚠️ Translation failed: …` synthetic part.
|
|
44
44
|
3. Falls back to sending the original (untranslated) user text to the model.
|
|
45
|
-
4. On
|
|
45
|
+
4. On activation-turn failure, it also rolls back activation so the next turn retries cleanly.
|
|
46
46
|
|
|
47
47
|
A stalled provider request is additionally bounded by a 60s hard timeout per translation call, so a hung upstream cannot block the OpenCode session.
|
|
48
48
|
|
|
@@ -75,7 +75,7 @@ opencode auth login anthropic
|
|
|
75
75
|
export ANTHROPIC_API_KEY=...
|
|
76
76
|
```
|
|
77
77
|
|
|
78
|
-
|
|
78
|
+
Put the trigger in the message where translation should begin. Earlier messages in the session are left as-is:
|
|
79
79
|
|
|
80
80
|
```text
|
|
81
81
|
$en 프로젝트 루트의 package.json을 읽고 요약해줘
|
package/package.json
CHANGED
package/src/activation.ts
CHANGED
|
@@ -32,7 +32,12 @@ import {
|
|
|
32
32
|
} from "./question-tool"
|
|
33
33
|
import { createSyntheticPartID, createTranslator, hashText } from "./translator"
|
|
34
34
|
|
|
35
|
-
const
|
|
35
|
+
const INACTIVE_ROOT_SESSION = "inactive-root"
|
|
36
|
+
const INACTIVE_CHILD_SESSION = "inactive-child"
|
|
37
|
+
|
|
38
|
+
type CachedSessionState = TranslateState | typeof INACTIVE_ROOT_SESSION | typeof INACTIVE_CHILD_SESSION
|
|
39
|
+
|
|
40
|
+
const sessionStateCache = new Map<string, CachedSessionState>()
|
|
36
41
|
const questionSnapshots = new Map<string, QuestionSnapshot>()
|
|
37
42
|
const QUESTION_TOOL_ID = "question"
|
|
38
43
|
|
|
@@ -249,10 +254,26 @@ async function resolveSessionState(
|
|
|
249
254
|
): Promise<ResolvedSessionState> {
|
|
250
255
|
const cached = sessionStateCache.get(sessionID)
|
|
251
256
|
if (cached !== undefined) {
|
|
257
|
+
if (cached === INACTIVE_ROOT_SESSION) {
|
|
258
|
+
return {
|
|
259
|
+
sessionActive: false,
|
|
260
|
+
canActivate: true,
|
|
261
|
+
storedMessages: [],
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
if (cached === INACTIVE_CHILD_SESSION) {
|
|
266
|
+
return {
|
|
267
|
+
sessionActive: false,
|
|
268
|
+
canActivate: false,
|
|
269
|
+
storedMessages: [],
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
|
|
252
273
|
return {
|
|
253
|
-
sessionActive:
|
|
274
|
+
sessionActive: true,
|
|
254
275
|
canActivate: false,
|
|
255
|
-
state: cached
|
|
276
|
+
state: cached,
|
|
256
277
|
storedMessages: [],
|
|
257
278
|
}
|
|
258
279
|
}
|
|
@@ -265,7 +286,7 @@ async function resolveSessionState(
|
|
|
265
286
|
}),
|
|
266
287
|
)
|
|
267
288
|
if (session.parentID != null) {
|
|
268
|
-
sessionStateCache.set(sessionID,
|
|
289
|
+
sessionStateCache.set(sessionID, INACTIVE_CHILD_SESSION)
|
|
269
290
|
return { sessionActive: false, canActivate: false, storedMessages: [] }
|
|
270
291
|
}
|
|
271
292
|
|
|
@@ -279,13 +300,13 @@ async function resolveSessionState(
|
|
|
279
300
|
const state = extractStoredState(storedMessages)
|
|
280
301
|
if (state) {
|
|
281
302
|
sessionStateCache.set(sessionID, state)
|
|
282
|
-
} else
|
|
283
|
-
sessionStateCache.set(sessionID,
|
|
303
|
+
} else {
|
|
304
|
+
sessionStateCache.set(sessionID, INACTIVE_ROOT_SESSION)
|
|
284
305
|
}
|
|
285
306
|
|
|
286
307
|
return {
|
|
287
308
|
sessionActive: Boolean(state),
|
|
288
|
-
canActivate:
|
|
309
|
+
canActivate: !state,
|
|
289
310
|
state: state ?? undefined,
|
|
290
311
|
storedMessages,
|
|
291
312
|
}
|
|
@@ -326,8 +347,6 @@ export function createHooks(ctx: PluginInput, rawOptions: PluginOptions = {}, de
|
|
|
326
347
|
}
|
|
327
348
|
activatedThisTurn = true
|
|
328
349
|
sessionStateCache.set(input.sessionID, activeState)
|
|
329
|
-
} else {
|
|
330
|
-
sessionStateCache.set(input.sessionID, null)
|
|
331
350
|
}
|
|
332
351
|
}
|
|
333
352
|
|
|
@@ -424,7 +443,7 @@ export function createHooks(ctx: PluginInput, rawOptions: PluginOptions = {}, de
|
|
|
424
443
|
// user-authored part, roll back activation so the next turn does a
|
|
425
444
|
// clean retry instead of cementing broken state.
|
|
426
445
|
if (activatedThisTurn && translationErrors.length > 0 && eligibleIndex === translationErrors.length) {
|
|
427
|
-
sessionStateCache.set(input.sessionID,
|
|
446
|
+
sessionStateCache.set(input.sessionID, INACTIVE_ROOT_SESSION)
|
|
428
447
|
return
|
|
429
448
|
}
|
|
430
449
|
|