opencode-translate 0.0.12 → 0.0.13
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/package.json +1 -1
- package/src/activation.ts +45 -24
package/package.json
CHANGED
package/src/activation.ts
CHANGED
|
@@ -137,26 +137,14 @@ function mergeTranslatedMetadata(state: TranslateState, part: TextPartLike, engl
|
|
|
137
137
|
// OpenCode's flag semantics, observed from packages/opencode and packages/ui:
|
|
138
138
|
// synthetic: true -> hidden from the user UI, still sent to the LLM
|
|
139
139
|
// ignored: true -> hidden from the LLM, still shown in the user UI
|
|
140
|
-
//
|
|
141
|
-
//
|
|
142
|
-
//
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
): TextPartLike {
|
|
149
|
-
return {
|
|
150
|
-
id: createSyntheticPartID(),
|
|
151
|
-
sessionID,
|
|
152
|
-
messageID,
|
|
153
|
-
type: "text",
|
|
154
|
-
text,
|
|
155
|
-
synthetic: false,
|
|
156
|
-
ignored: true,
|
|
157
|
-
metadata,
|
|
158
|
-
}
|
|
159
|
-
}
|
|
140
|
+
// both true -> hidden from both (used for metadata-only marker
|
|
141
|
+
// parts like the activation banner that exist purely
|
|
142
|
+
// to carry state across reloads)
|
|
143
|
+
// The plugin's user-facing status text (translation preview, activation
|
|
144
|
+
// banner, failure notice) lives inline on the source-language user part
|
|
145
|
+
// itself rather than as sibling parts, because OpenCode's
|
|
146
|
+
// `UserMessageDisplay` renders only the first non-synthetic text part
|
|
147
|
+
// per user message.
|
|
160
148
|
|
|
161
149
|
// LLM-only text part: hidden from the TUI but the only LLM-visible
|
|
162
150
|
// representation of the user's source-language text. The original
|
|
@@ -337,11 +325,21 @@ export function createHooks(ctx: PluginInput, rawOptions: PluginOptions = {}, de
|
|
|
337
325
|
const nextParts: TextPartLike[] = []
|
|
338
326
|
let eligibleIndex = 0
|
|
339
327
|
const translationErrors: { part: TextPartLike; error: unknown }[] = []
|
|
328
|
+
// Track the first user-authored text part so the activation
|
|
329
|
+
// banner can be inlined onto it. OpenCode's `UserMessageDisplay`
|
|
330
|
+
// renders only the first non-synthetic text part per user
|
|
331
|
+
// message, so any standalone banner part is never visible in
|
|
332
|
+
// the TUI.
|
|
333
|
+
let firstUserTextPart: (TextPartLike & { text: string }) | undefined
|
|
340
334
|
|
|
341
335
|
for (const part of output.parts as TextPartLike[]) {
|
|
342
336
|
nextParts.push(part)
|
|
343
337
|
if (!isUserAuthoredTextPart(part)) continue
|
|
344
338
|
|
|
339
|
+
if (firstUserTextPart === undefined) {
|
|
340
|
+
firstUserTextPart = part
|
|
341
|
+
}
|
|
342
|
+
|
|
345
343
|
const currentEligibleIndex = eligibleIndex
|
|
346
344
|
eligibleIndex += 1
|
|
347
345
|
if (part.text.trim().length === 0) continue
|
|
@@ -421,13 +419,36 @@ export function createHooks(ctx: PluginInput, rawOptions: PluginOptions = {}, de
|
|
|
421
419
|
}
|
|
422
420
|
|
|
423
421
|
if (activatedThisTurn) {
|
|
424
|
-
|
|
425
|
-
|
|
422
|
+
const bannerText = createActivationBannerText(options)
|
|
423
|
+
// Inline the activation banner into the first user-authored
|
|
424
|
+
// text part so it actually reaches the TUI (see comment above
|
|
425
|
+
// for the single-text-part rendering constraint). The banner
|
|
426
|
+
// sits underneath the inline `→ EN: ...` preview that was
|
|
427
|
+
// appended during translation, giving the user a one-time
|
|
428
|
+
// confirmation that translation mode just turned on.
|
|
429
|
+
if (firstUserTextPart !== undefined) {
|
|
430
|
+
firstUserTextPart.text = `${firstUserTextPart.text}\n\n_${bannerText}_`
|
|
431
|
+
}
|
|
432
|
+
// Also emit the banner as a metadata-only synthetic part so
|
|
433
|
+
// `extractStoredState`'s canonical `translate_role ===
|
|
434
|
+
// "activation_banner"` marker is preserved across reloads.
|
|
435
|
+
// `synthetic:true + ignored:true` keeps it hidden from both
|
|
436
|
+
// the TUI and the LLM serializer; it exists purely as a
|
|
437
|
+
// database row carrying state metadata.
|
|
438
|
+
nextParts.push({
|
|
439
|
+
id: createSyntheticPartID(),
|
|
440
|
+
sessionID: input.sessionID,
|
|
441
|
+
messageID: output.message.id,
|
|
442
|
+
type: "text",
|
|
443
|
+
text: bannerText,
|
|
444
|
+
synthetic: true,
|
|
445
|
+
ignored: true,
|
|
446
|
+
metadata: {
|
|
426
447
|
...activeState,
|
|
427
448
|
translate_role: "activation_banner",
|
|
428
449
|
translate_spec_version: SPEC_VERSION,
|
|
429
|
-
}
|
|
430
|
-
)
|
|
450
|
+
},
|
|
451
|
+
})
|
|
431
452
|
}
|
|
432
453
|
|
|
433
454
|
output.parts.splice(0, output.parts.length, ...(nextParts as typeof output.parts))
|