# Changelog

English | [简体中文](CHANGELOG.zh-CN.md)

All notable changes to Translator, newest first. A routine release raises only the last version number; see the [design and iteration guidelines](../../CONTRIBUTING.md#design-and-iteration-guidelines).

## 0.6.10 — 2026-10-12

### Fixed

- **Claude Code recalls Chinese, then replays English.** Up/Down history drafts with a known, unambiguous original are restored to Chinese without rewriting Claude's history file or changing its synchronized transcript display. Sending the original unchanged replays the saved translation without a model call, including with automatic cache off or an older cache contract; edited text follows normal translation. Ordinary typing/pasting and other plugins' fills are not rewritten. The terminal-only composer check runs locally while a draft and known originals exist; recent shared/session history and memory-only reload state supply those pairs.
- **Originals appear only after delivery.** Pi now waits for the translated prompt's actual user-message lifecycle and stored row, then adds its display-only original once, after that row. Translation completion, cache hits and steer/follow-up queue acceptance no longer publish early cards, RPC notifications or stderr previews that intervening tools could bury. Claude Code's already synchronized prompt-row/original display is unchanged; Pi now matches that experience. Failures still show immediately, and journals plus enabled caches are written before submission.
- **Conservative delivery association.** Pi discards pending display associations on navigation, reload or session replacement and does not replay them from history. Exact text/images and live message identity prevent unrelated rows from inheriting originals. Without a public input-to-queue ID, ambiguous originals or rewritten/normalized content may omit a card rather than guess; the journal/cache remains. Display errors after delivery cannot claim the prompt was not sent.

### Changed

- **One preflight scanner protects both directions.** Certain filenames, including bare Chinese filenames such as `报告.md`, paths and literal-like identifiers/settings/mentions are now identified and masked before input and output translation, alongside code, math and links. Their source bytes are restored after translation instead of relying on the model to preserve names that only the language gate recognized. Ambiguous prose remains visible to the model; quoted Chinese prose remains translatable.
- **Literal-only text makes no translation request or log.** Input and output containing only recognized literals skip locally, even without prose in the other language. Plain `OK` output still translates, and real mixed-language prose is not hidden by a blanket name or Chinese-character-ratio exception.
- **One completion, no AI audit or repair.** Each fresh input translation or output part needing translation gets one completion, including native Claude and long answers through Pi. Language decisions happen only before translation: no post-translation stray-Chinese or no-Han rejection, no language/semantic audit and no repair call. Literal content cannot trigger language rejection.
- **Response and restoration safeguards remain.** Replies must be completed and nonempty; native Claude still requires its terminal marker. Exact placeholder counts and protected input code-block order remain enforced before restoring literals. Failures block input or leave the original answer intact, and cancellation still prevents late publication. These are structural safeguards, not a semantic quality guarantee: an accepted result may still be inaccurate or untranslated.
- **Cache reuse checks source literals, not language.** Keys remain exact source plus scanner/prompt contract. Nonempty current and unversioned legacy candidates are checked only for source-literal byte/count integrity, not order, language or semantic quality. The contract bump isolates older versioned entries without deleting history; literal-changing candidates trigger a fresh translation.

### Notes

- This is routine patch **0.6.10**. Configuration and installation links do not need to change. After updating the installed copy, reload Pi with `/reload`; use `/reload-plugins` in a Claude Code session still running the old code. An older versioned cache hit may now require a fresh translation; no manual cache reset is needed.
- Verified offline with **1,013 Node tests and 48 Claude plugin tests passing, none skipped**, on Pi 1.1.0 and Claude Code 2.1.296. Real Pi queue and Claude terminal history/replay regressions use local synthetic model fixtures. See [the verification record](docs/testing.md#verification-record-for-0610) for commands and remaining host/version limits.

## 0.6.9 — 2026-10-11

### Fixed

- **Chinese technical answers no longer pay for an identical translation.** The output gate now recognizes the exact, case-sensitive names and labels `Markdown`, `Mermaid`, `Downloads`, `Token` and `Tokens`, alongside existing acronym/identifier handling. Chinese document deliveries, links, tables and storage summaries containing only those terms skip before model/config/history/trace/UI work. Pi, both Claude backends and Claude's generated in-plugin gate share the fix.
- **Keep real mixed-language text translated.** This is not a Chinese-character ratio or a blanket exemption for capitalized words. English prose, unknown plain-word names and answers with no Chinese prose still take the existing translation path. Input detection, literal protection, fail-closed submission and valid input caches remain unchanged.
- **Correct the Pi language-check documentation.** Quoted Chinese input remains prose, and English output prose still translates when Chinese is also present; the old adapter text described an obsolete gate.

### Upgrading from 0.6.8

- Install the GitHub release's `orbit-labs-ai-translator-0.6.9.tgz` asset with `npm install -g --ignore-scripts /path/to/orbit-labs-ai-translator-0.6.9.tgz`, or update a stable release checkout. This does not imply npm registry publication. Existing configuration, installation links and input history remain valid; no cache reset or switch change is required.
- After updating the installed copy, run `/reload` in Pi, or `/reload-plugins` in a Claude Code session that still uses the old code. Updating a development checkout alone does not update a separately installed npm package.

## 0.6.8 — 2026-10-11

### Fixed

- **Pi gateway/automation isolation.** Launchers can now set `TRANSLATOR_PI_BYPASS=1` only in their Pi child's environment to skip the entire Translator extension before hooks, controls or configuration are read. Both task input and final answers remain unchanged, without translation requests, language suffixes or new translation records. Translation outages, invalid config and saved branch switches cannot block these opted-out tasks. Normal Pi chat and Claude Code remain unchanged; `TRANSLATOR_DISABLE=1` keeps its input-only meaning. Both the launcher and installed Translator must support the new marker; no global settings change is needed.

### Upgrading from 0.6.7

- This release is distributed on GitHub. Download its `orbit-labs-ai-translator-0.6.8.tgz` asset and install with `npm install -g --ignore-scripts /path/to/orbit-labs-ai-translator-0.6.8.tgz`, or update a stable release checkout. Existing links, configuration and history remain intact; reload running Pi sessions afterward. This GitHub release does not imply publication to the npm registry.
- Install Translator 0.6.8 before deploying WeChat Gateway 0.2.7. Gateway 0.2.7 supplies the process-local marker automatically; an older gateway does not. No global environment export or settings change is needed.

## 0.6.7 — 2026-10-10

In Pi, long answers are now translated into Chinese too: an answer of several thousand characters no longer fails with `Translation timed out`.

### Fixed

- **Pi: long answers timed out.** Translator sent a whole answer in one request, and `timeoutMs` (30 seconds by default) bounds each request, so an answer of several thousand characters failed with `Output translation unavailable: Translation timed out` while short ones worked. An answer longer than 2,000 characters is now translated in parts of about equal length, up to four at a time, each a request with its own deadline, and the Chinese is joined back in order. Parts are cut between paragraphs, or between lines in a very long block, never inside code. A 7,000-character answer now takes about as long as a 2,000-character one, which also shortens the wait before Pi ends the turn. If a part fails, the warning names it (`part 2 of 4`) and the answer stays as it is.
- **Pi: the status line could stay on.** After an answer translation that needed a repair pass, `Translator · Output: translating to Chinese…` stayed in the status line. It now clears when the answer is done.

### Changed

- Claude Code's Pi backend (`claudeBackend: "pi"`) translates long answers in parts too. Claude Code's native backend still translates an answer in one request.

### Upgrading from 0.6.6

- **Clone:** run `git pull` on `main`, then `/reload` in running Pi sessions.
- **npm:** run `npm install -g @orbit-labs-ai/translator@latest`, then `/reload` in running Pi sessions.

## 0.6.6 — 2026-10-10

In the Claude Code desktop app, Translator now shows what the terminal shows: your prompt as the English that was sent, your Chinese once under it, and the Chinese under each answer, also for prompts you send while Claude is working.

### Fixed

- **Desktop app: the prompt row showed the Chinese twice.** The app draws a prompt from its own copy of what you sent, so the row showed your Chinese, the original drawn under it repeated it, and the English the model read appeared nowhere. A row that shows the original now gets the prompt as it was sent, as the terminal's row shows it, and the original stays under it.
- **Desktop app: no Chinese under answers.** The app names an answer's text block after the API message (`<message id>-t<n>`), while Translator linked the translation to the transcript row. It now reads the app's id from the session's transcript and draws the Chinese under that block too, and only under a block that shows exactly the linked row's text.
- **Desktop app: no original under prompts sent mid-turn.** A prompt folded into a running turn is stored as a row with a new ID, while the app keeps the id it sent the prompt with, which the row records as `source_uuid`. The original is now drawn under that id as well.

### Changed

- Rows translated before the update are drawn again in the app the first time it shows a row of the session, and after a resume or a reload of the mod; if that lookup fails, a later draw tries again 30 seconds on. The terminal is unchanged, and so is everything the model reads.
- The worker gained a read-only `ids` operation, which finds the session's transcript by its session ID and parses only the rows it needs, and the journal's display rows now include the prompt as it was sent.

### Upgrading from 0.6.5

- **Clone:** run `git pull` on `main`. Running terminal sessions load the new version by themselves; in a session of the desktop app, run `/reload-plugins` or start a new session. Pi is unchanged.
- **npm:** run `npm install -g @orbit-labs-ai/translator@latest`. If a Claude Code session, such as one in the desktop app, still runs the old version, run `/reload-plugins` once.

## 0.6.5 — 2026-10-10

### Added

- Added the `pi-package` npm keyword so the published package is eligible for discovery in Pi's official package catalog. Translation behavior is unchanged.

## 0.6.4 — 2026-10-09

In Pi, Translator's cards now show only the Chinese, rendered as Markdown, so nothing on screen is repeated.

### Changed

- **Pi cards show only what the transcript lacks.** The card before a translated prompt now holds only your Chinese original: the prompt itself shows the English that was sent, instruction included. The card after an answer holds only the Chinese translation: the English answer is right above it. A blocked prompt's card still shows the reason and your original. Expand cards (Ctrl+O) for the translator model, history reuse and trace.
- **Pi cards render Markdown.** Links, paths, inline code, code blocks and lists in a card are drawn with Pi's own Markdown renderer and theme, instead of as raw text.

### Upgrading from 0.6.3

- **Clone:** run `git pull` on `main`, then `/reload` in Pi.
- **npm:** run `npm install -g @orbit-labs-ai/translator@latest`, then `/reload` in Pi.
- Claude Code is unchanged. Cards already in your Pi sessions are drawn the new way.

## 0.6.3 — 2026-10-09

Translator now translates whenever a prompt or an answer is not entirely in one language, so mixed Chinese and English is no longer missed.

### Highlights

- **Mixed answers get their Chinese copy.** An English answer that mentions Chinese names or phrases in plain text, such as table cells or labels, is now translated for display. Only an answer that is already entirely Chinese is skipped; acronyms, camelCase names, versions, mentions, links and paths do not count as English.
- **Quoted Chinese in English prompts is translated.** A prompt is sent as typed only when it is entirely English once code, math, links, paths and names are set aside. The translator may still keep a quoted value as it is.

### Upgrading from 0.6.2

- **Clone:** run `git pull` on `main`. Running Claude Code sessions load the new version by themselves; in Pi, run `/reload`.
- **npm:** run `npm install -g @orbit-labs-ai/translator@latest`, then `/reload` in Pi. If a Claude Code session still runs the old version, run `/reload-plugins` once.
- The literal rules changed, so translations cached by 0.6.2 are not reused: the first identical prompt after the upgrade is translated afresh.

### Fixed

- **Mixed answers were left untranslated.** Output translation skipped any answer with Chinese prose outside code, even one label in an English table. It now skips only when no English prose remains.
- **Prompts quoting Chinese were sent untranslated.** Quoted Chinese counted as a literal, so an English prompt that quoted Chinese prose reached the model in Chinese. Quoted Chinese now counts as prose; the translator keeps literal values in their quotes, and the check accepts that copy.
- **Uncertain names hid prose from the language check.** Text that only looks like a name was set aside: Chinese glued straight to Latin letters (`请查看data.csv`, `…/docs然后`) or tied to a name by `：` or `、` (`问题：src/app.ts`), a link or path that ends in Chinese (`https://example.com/文档里的第三节`, `D:\备份里面`), a mention that runs on into a sentence, an address with a Chinese local part, and a join by slashes or `#` alone (`English/中文`, `src/组件/按钮`, `问题#3`). The language check now reads these as prose and translates.
- **A word after a slash was masked as a path.** In `项目/Orbit` or `前端/backend`, the part from the slash on was protected as an absolute path, so the translator saw half a phrase. After Chinese, a slash now starts a path only when a second slash follows.
- **A kept name in quotes could block a prompt.** When the translator kept a Chinese name such as `docs/中文指南` but put it in backticks or ASCII quotes, the check after translation reported it as untranslated Chinese.
- **Long runs of punctuation or letters slowed the language check.** A 100,000-character run could hold up a prompt or an answer for four to seven seconds per check; the check now takes milliseconds.

### Changed

- A Chinese answer that uses a plain English word, even a product name such as `Orbit`, now gets a Chinese copy too. Acronyms, camelCase names, dotfiles, versions, links and paths still do not count as English.
- The literal rules version is now `literal-whitelist-v5`.

## 0.6.2 — 2026-10-09

Updates no longer break a running Claude Code session, and prompts you send while Claude is working show their original too.

### Highlights

- **Prompts sent mid-turn show their original.** In Claude Code, a prompt you send while a turn runs now has your Chinese original drawn under it, like any other prompt, and again after a resume. This covers Ctrl+X Ctrl+S (or Ctrl+Enter), which sends it into the running turn, and Enter, which queues it for the next turn.
- **Updates apply without a restart.** Claude Code reloads Translator by itself when its files change, sometimes in the middle of a turn. The answer of that turn is still translated once and drawn under the reply, and settings and pending originals survive the reload. No restart, `/reload-plugins` or re-linking is needed.

### Upgrading from 0.6.1

- **Clone:** run `git pull` on `main`. Running Claude Code sessions load the new version by themselves; in Pi, run `/reload`.
- **npm:** run `npm install -g @orbit-labs-ai/translator@latest`, then `/reload` in Pi. If a Claude Code session still runs the old version, run `/reload-plugins` once.

### Fixed

- **Claude Code: no original under prompts sent mid-turn.** Claude Code stores such a prompt only after Translator has handed it on: folded into the running turn, or when its own turn begins. Translator dropped the translation before that row existed. It now keeps each translation until the row that holds it is stored, recognizes both kinds of row, and links the row for resume.
- **Claude Code: Chinese answer missing after an update mid-turn.** When Translator's files changed during a turn and Claude Code reloaded it before the turn ended (for example because `/translator` was used), the answer was translated twice and drawn under neither copy. Both copies now share what they need through the session: the answer is translated once, drawn and linked for resume.
- **Claude Code: each copy of the mod runs its own worker.** The mod now runs the `bridge.mjs` beside it, not the one under `~/.agents/hooks/translator`, so a development copy loaded with `--plugin-dir` or a moved installation cannot pair with another version's worker. A `bridgePath` option still takes precedence.
- **Claude Code: settings from another version are ignored, not an error.** A session setting saved by an older or newer copy of the mod no longer stops translation in that session.
- **Claude Code: memory-only settings survive a reload.** With `TRANSLATOR_NO_PERSIST=1`, session settings now survive a reload of the mod; they still stay in memory only.

### Changed

- **Documented how updates reach running agents.** Agents load whatever the installed copy holds, so a checkout that switches branches, such as this repository's tool branches, changes every running agent with it: install the released npm package for everyday use and load a development checkout only for testing. Claude Code reloads the mod when its files change; a running Pi keeps the version it loaded until `/reload`, because Pi lets only commands reload extensions.

## 0.6.1 — 2026-10-09

One name everywhere, more precise translations, and your original prompt stays in view.

### Highlights

- **One name: Translator.** The package, the Claude Code plugin, the commands, the environment variables and the three features (Input, Instruction, Output) now have the same names on Pi and Claude Code.
- **No more half-translated prompts.** Only text that is certainly not prose is protected locally. Everything else goes to the translator, and a check catches any Chinese left behind before the prompt is sent.
- **See what you wrote.** Claude Code draws your original Chinese under the English prompt, for display only, and draws it again when you resume a session.
- **One settings command.** `/translator` opens a settings panel on both agents, including a model and thinking level for the translator alone.

### Upgrading from 0.6.0

Everything was renamed, and the installer does not remove the 0.6.0 entries. Do this once:

1. Remove the old entries: the `~/.agents/hooks/prompt-translate` and `~/.local/bin/agent-translate` links, the `skills/local-translation` link in each Claude Code account, and the `…/prompt-translate/pi/index.ts` entry in Pi's `settings.json`.
2. **Clone:** run `git pull`, then move `config.json`, `history/` and `claude-sessions/` from `Hooks/prompt-translate/` to `Hooks/translator/`; Git does not move ignored files. **npm:** run `npm uninstall -g @orbit-labs-ai/prompt-translate` and `npm install -g @orbit-labs-ai/translator`, then move the contents of `~/.agents/prompt-translate/` to `~/.agents/translator/`.
3. Run the installer again: `./install.sh` in the clone, or `translator install`.
4. Rename any `AGENT_TRANSLATE_*` environment variables to `TRANSLATOR_*`.
5. Restart Claude Code and reload Pi.

The [README](README.md#upgrading-from-earlier-versions) has the details.

### Added

- **A `/translator` settings panel** on both agents, with Input, Instruction, Output, Model and Thinking:
  - **Pi:** a compact native list with a searchable model picker and `?` for help.
  - **Claude Code:** a pane where every row has a hotkey (`1` `2` `3`, `m`, `t`, `i`, Esc), so there is no Tab navigation.
- **Translator-only model and thinking level**, per Pi branch or Claude Code session (`/translator model …`, `/translator thinking …`). They never change the main conversation's model.
- **Your original under the prompt.** Claude Code draws your Chinese original under the English prompt, labelled `Translator · Input · original · display only`. The model never reads it.
- **Drawings survive a restart.** Claude Code saves which transcript row shows each translation in the session journal, and draws originals and Chinese answers again after a restart or resume. Before, Chinese answers disappeared after a restart.
- **Cancel in Claude Code.** A **Cancel translation** button (key 4) appears while a translation runs.
- **A check after every translation.** Each protected literal must come back exactly once, and no Chinese prose may remain. A failing draft gets one repair pass; if it fails again, the prompt is blocked and the error names the leftover Chinese.
- **A hard test corpus.** 43 prompts and 5 answers mix Chinese with URLs, code, formulas and symbols, and run through both agents. `npm run eval:live` tries the corpus against a real model; it makes paid calls, so it is opt-in.

### Changed

- **Renamed to Translator:**

  | 0.6.0 | 0.6.1 |
  |---|---|
  | npm package `@orbit-labs-ai/prompt-translate` | `@orbit-labs-ai/translator` |
  | npm installer command `prompt-translate` | `translator install` |
  | `agent-translate input\|language\|output\|cache` | `translator input\|instruction\|output\|cache` |
  | Claude Code plugin `local-translation` | `translator` |
  | `/translate`, `/translate-language`, `/translate-output`, `/translation-status`, `/translate-cancel` | `/translator` and its subcommands |
  | `AGENT_TRANSLATE_CONFIG`, `…_DISABLE`, `…_NO_PERSIST`, `…_PI` | `TRANSLATOR_CONFIG`, `…_DISABLE`, `…_NO_PERSIST`, `…_PI` |
  | `~/.agents/hooks/prompt-translate` and the npm data directory `~/.agents/prompt-translate/` | `~/.agents/hooks/translator` and `~/.agents/translator/` |
  | Pi buttons `Input EN`, `Language`, `Output ZH` | Input, Instruction, Output |

- **Local protection is now a whitelist.** Only code, math, URLs, emails, explicit paths and Markdown link targets are masked. Chinese file names in running text, JSON, HTML attributes and quoted strings now go to the translator; wrap text in backticks when it must stay exactly as typed.
- **Word order.** The translator may move short literals to fit English word order. Code blocks keep their order.
- **Cheaper requests.** Placeholders are less than half as long (`__PT_` plus 8 hex digits instead of 32).
- **Fresh translations once.** The new rules set older cache entries aside, so each prompt is translated again the first time you send it.
- **Quieter status in Claude Code.** The status now sits at the end of the hint line under the prompt, for example `Translator · Input + Output`. The pinned status line with a warning sign is gone.
- **Pi:** Ctrl+Alt+C now cancels pending answer translations too, not only input.

### Fixed

- A URL glued to Chinese text, such as `请阅读https://…`, no longer hides that Chinese from the translator, so `请阅读` is translated.
- Pi cancels pending translations before switching branches, so a late result cannot land on the new branch.

### Removed

- The `/translate-cancel` command. Use Ctrl+Alt+C in Pi or key 4 in Claude Code.

## 0.6.0 — 2026-10-08

- **Literal-aware language checks.** A Chinese file name or path alone no longer triggers input translation, and no longer stops an English answer from being translated.
- **Pi:**
  - a toggle bar below the editor
  - loading that survives `/reload` after an upgrade
  - `/translate-cancel` and Ctrl+Alt+C to cancel a pending input translation
- **Claude Code:**
  - Chinese answers are tied to stored reply IDs, never to repeated text
  - overlapping setting changes are handled one at a time per session
- **Safer files:**
  - the installer locks files, keeps symlinks and permissions, checks for changes right before it writes, and keeps its recovery backups
  - damaged cache records are rejected

## 0.5.0 — 2026-10-08

First npm release, as `@orbit-labs-ai/prompt-translate` with a `prompt-translate` installer command. For Pi and Claude Code, it included:

- input translation through an isolated request that fails closed
- optional display-only Chinese answers, drawn under the reply in Claude Code
- the optional language instruction
- an exact-match input cache
- local bilingual records
- a native Claude Code backend
- translation on the session's model at a separate thinking level (default `medium`)

npm installs keep their data in `~/.agents/prompt-translate/`.

Earlier work is in the Git history.
