opencode-translate 2.0.2 → 2.0.4

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 (3) hide show
  1. package/README.md +13 -0
  2. package/dist/index.js +13 -5
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -64,6 +64,7 @@ $en 프로젝트 루트의 package.json을 읽고 요약해줘
64
64
  All subsequent messages in the same session are translated automatically — no need to repeat `$en`.
65
65
 
66
66
  - Your original message and its English translation remain visible in the transcript.
67
+ - Web composer presentation metadata is synchronized with the translated prompt, including failure notices; review-comment cards are preserved.
67
68
  - The first successful `$en` prompt includes a `Translation enabled:` confirmation with the language and translator model.
68
69
  - English assistant text streams normally; a translated Markdown section is appended when the text segment completes.
69
70
  - Both the **terminal and web UI** display the same persisted bilingual assistant text. No UI-specific plugin is needed.
@@ -87,6 +88,16 @@ package, not an old pinned `opencode-translate@1.x`. Also check the configured *
87
88
  the main-chat model does not change the translator. An API-key login or OAuth connection must exist on that server.
88
89
  The server log message `[opencode-translate] inbound translation failed` contains the underlying generation error.
89
90
 
91
+ If replies translate but your own prompt still looks untranslated in the **Web UI**, inspect the stored user message's
92
+ `text` and `metadata.displayText`. The Web UI prefers `displayText`, which versions up to 2.0.2 left at the original
93
+ composer input even when `text` contained the English translation. The prompt hook now synchronizes that presentation
94
+ field. This applies to newly admitted prompts; it does not rewrite presentation metadata on older messages.
95
+
96
+ For the Question tool, OpenCode can freeze the provider-owned question arrays. Versions up to 2.0.3 tried to mutate
97
+ those arrays and fell back to English even after obtaining a valid translation. The before-tool hook now translates a
98
+ copy and replaces `event.input`, preserving the original provider data. Already pending questions need a new tool
99
+ invocation to pick up this fix.
100
+
90
101
  OpenCode 2.0.3 also normalizes the legacy `"plugin": [["package", { ...options }]]` tuple syntax; that syntax alone
91
102
  does not prevent this plugin from loading. The `plugins` object form shown above is the recommended v2 format.
92
103
  Make sure the configuration is a complete JSON/JSONC object, including its opening `{`.
@@ -182,6 +193,8 @@ OPENCODE_BINARY=/path/to/opencode OPENCODE_TRANSLATE_REQUIRE_SESSION=0 bun run t
182
193
  Tests include OpenCode's actual native protocol parsers. The real-host smoke test loads the built plugin, creates and
183
194
  rotates a test credential in an isolated SQLite database, checks bilingual persisted messages and English-only model
184
195
  requests, and restarts the server to verify recovery. It does not use your live server, credentials, or paid models.
196
+ It also executes the real Question tool, checks translated form fields, submits selected options and a Korean custom
197
+ answer, and verifies that the next model request contains the original English questions and English answers.
185
198
  CI covers both configuration formats and both generation paths. The publish workflow tests the candidate before
186
199
  publishing, then installs the exact version from npm in OpenCode before creating its GitHub release.
187
200
 
package/dist/index.js CHANGED
@@ -300,13 +300,16 @@ async function registerQuestionHooks(ctx, state, translator) {
300
300
  const lang = await state.language(event.sessionID);
301
301
  if (!lang)
302
302
  return;
303
- const original = snapshotQuestions(event.input);
303
+ const args = event.input;
304
+ const original = snapshotQuestions(args);
305
+ const translated = { ...args, questions: snapshotQuestions(args) };
304
306
  try {
305
307
  await ctx.storage.set(`questions/${event.sessionID}/${event.id}`, JSON.stringify({ questions: original }));
306
- await translateQuestionArgs(event.input, (texts) => translator.texts(texts, LLM_LANGUAGE, lang));
308
+ await translateQuestionArgs(translated, (texts) => translator.texts(texts, LLM_LANGUAGE, lang));
309
+ event.input = translated;
307
310
  snapshots.set(`${event.sessionID}/${event.id}`, {
308
311
  original,
309
- translated: snapshotQuestions(event.input),
312
+ translated: snapshotQuestions(translated),
310
313
  userLanguage: lang
311
314
  });
312
315
  if (snapshots.size > 1000)
@@ -837,7 +840,8 @@ async function setup(ctx) {
837
840
  if (source === undefined)
838
841
  return;
839
842
  const userLanguage = lang ?? options.lang;
840
- function apply(display, english, enabled) {
843
+ const apply = (display, english, enabled) => {
844
+ const presentation = event.metadata?.displayText;
841
845
  event.prompt.text = display;
842
846
  for (const attachment of [
843
847
  ...event.prompt.files ?? [],
@@ -847,7 +851,11 @@ async function setup(ctx) {
847
851
  delete attachment.mention;
848
852
  }
849
853
  event.metadata = { ...event.metadata, [METADATA_KEY]: { lang: userLanguage, english, display, enabled } };
850
- }
854
+ if (typeof presentation === "string") {
855
+ const visible = lang ? presentation : stripTrigger(presentation, options.trigger) ?? presentation;
856
+ event.metadata.displayText = `${visible}${display.slice(source.length)}`;
857
+ }
858
+ };
851
859
  try {
852
860
  const english = await translator.text(source, userLanguage, LLM_LANGUAGE);
853
861
  const content = source === english ? source : `${source}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "opencode-translate",
3
- "version": "2.0.2",
3
+ "version": "2.0.4",
4
4
  "description": "OpenCode plugin that lets the user chat in a configured language while the main chat loop only sees English.",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",