# 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.7.2 — 2026-10-28

### Added

- Pi `/translator usage` reports auxiliary translation tokens/cost separately from native totals. Numeric, non-context `orbit.translator.usage.v1` receipts identify each actual completion attempt—including failures, refusals, retries, concurrent answer parts and subagent previews—with no prompt/output text. Whole-session deduplication excludes cache hits, skips and legacy aggregates; `nativeAccounting` is always `false`.
- Cancellation, missing usage and persistence limits are explicit: pending attempts await returned usage; navigation/reload/session replacement seals unresolved attempts as unreported on the original branch. No private session API or direct session-file writes are used. There is no usage sidecar: before Pi saves its first conversation message (including a blocked first input), receipts are memory-only; `--no-session`, write failures and bare disposal/termination also limit durability.

### Fixed

- Reject malformed subagent batches and parallel batches exceeding Pi's eight-task limit before any translation or Chinese-preview call. Supported task preparation remains sequential; dispatch and native usage are unchanged.

### Notes

- Verified with unmodified official Pi 1.4.0 and Claude Code CLI 2.1.311 using isolated local fixtures: 1,387 Node tests and 61 native Claude plugin tests passed, zero failures/skips. Packaging checks explicitly require the new `pi/usage.mjs` helper and the complete MIT license, and exclude personal data, tests and generated host declarations. See the [0.7.2 verification record](docs/testing.md#verification-record-for-072) for checks, warnings and limits.
- Existing preferences, translation/cache contracts and Claude runtime behavior remain unchanged. No Pi core patch or configuration migration is required. Finish/cancel translations before updating a stable installed copy, preserve its data and registrations, then reload Pi and Claude plugins or start new sessions. Usage receipts begin with new attempts; old records are not backfilled. GitHub and npm publication are separate from local verification and do not update existing installations automatically.

## 0.7.1 — 2026-10-23

### Changed

- Preserve the packaging-test fix for both npm 11's array and npm 12's package-keyed pack reports; the shipped runtime is unchanged.
- Verified Pi 1.4.0 and Claude Code CLI 2.1.309 compatibility (npm latest checked on 2026-10-23): 1,353 Node tests and 61 native Claude plugin tests passed, zero skips. No runtime adapter change or configuration migration is needed for an existing npm installation. The focused Pi 1.3.0 UI suite also passed 8 tests; its earlier full release verification remains documented separately.
- Native UI regressions now use Pi's real custom-dialog implementation. Pi 1.4.0 checks cover another dialog above/below `/translator`, preserving focus and the unsent draft when the panel closes or is invalidated by navigation/SDK reload (with the UI retained, not the full TUI `/reload` reset). Documentation now describes dialog-stack focus restoration.

### Notes

- Publish the GitHub tag and packed package, not an npm registry update. Install into a fresh stable directory, preserve existing npm data/registrations and reload hosts when idle. Clone installs must preserve or explicitly migrate their source-local configuration and journals before switching to npm layout; do not apply the npm-only link procedure blindly.
- See the [0.7.1 verification record](docs/testing.md#verification-record-for-071) for actual checks and limits. Claude's validator retains a non-gating missing-icon warning and marketplace advice; physical GUI/terminal and Linux acceptance remain unverified.

## 0.7.0 — 2026-10-18

### Highlights

- **No wildcard child ownership.** With Input on, Pi chain tasks must include fixed non-whitespace task text outside `{previous}`; a placeholder-only task is blocked with an explanation. Such tickets are never published or accepted, so unrelated direct JSON children still translate even if they inherit older wildcard metadata. Input off preserves the original task without claiming child ownership.

- **Completed output survives ordinary interruptions.** Pi RPC, print/JSON and completed subagent batches now retain translations across run aborts, like the TUI. Claude starts question displays outside the waiting dialog and keeps headless output in a session-owned runner, preserving normal transcript notices. Explicit translation Cancel and safe shutdown/navigation boundaries still apply.
- **One automatic API retry in both directions.** API/transport failures, empty/incomplete replies and configured timeouts retry once per input/output part. Refusal fallback shares that two-attempt budget; cancellation, local config/storage and damaged literals do not retry. Claude's own HTTP retries are separate; lowering a native token cap consumes the plugin budget.
- **Child-session ownership is explicit.** Pi's hash-only prepared-task handoff avoids duplicate report translation and preserves original Chinese chain results without suppressing unrelated/custom JSON sessions. Claude remembers exact completed-child spawn identities so real `SendMessage` follow-ups translate, including after process restart. Unknown launchers without public task/results or without Translator remain outside parent-display guarantees.
- **Conservative language fixes.** `./old.ts改为new.ts` no longer hides the Chinese instruction as a filename. Uppercase warnings such as `DO NOT DELETE BACKUPS` are no longer mistaken for technical acronyms in output/task previews. Known technical labels and already-Chinese sections still skip redundant work.

- **Chinese previews for English subagent instructions.** Pi and Claude now show Chinese task instructions under Input, independently of Output, while dispatching existing English byte-for-byte. Chinese tasks still become English before delivery. Mixed-task previews retain existing Chinese, do not skip short English instructions as answer prefaces, and never become human prompt history or model context. Display-only translation failure warns and keeps valid English; cancellation still prevents dispatch.
- **Mixed-script path protection.** Explicit hard-ended paths such as `./src/组件Panel.vue` and `C:\项目\My文档.md` are masked whole; output additionally protects multilingual relative paths adjoining Chinese. The scanner is now `literal-whitelist-v9`. Ambiguous prose stays translatable; names/symbols outside recognized syntax need backticks for exact byte protection.
- **Actual Pi subprocess verification.** New local-fixture tests run the unmodified official subagent example in single, parallel and chain modes. Claude real-child tests now verify unchanged English instructions, Chinese previews, history and resume. No paid completions or personal configuration are used.

### Added

- **Subagent input and output.** Pi 1.3.0 translates the documented `subagent` tool's single, parallel and chain task arguments atomically before dispatch, protects `{previous}`, and draws completed public child answers in labelled display-only cards. Claude Code translates agent launches and identifiable parent-to-child follow-ups, including resumed/nested agents, and draws delivered child reports at child rows, matching Agent results or background notifications. Original tool results, report delivery and chain handoffs stay unchanged; no display translation enters model context. Cancellation/failure blocks undispatched task batches, not already-running children. Unknown Pi schemas and non-rewritable Claude workflow prompts fail closed when input translation is needed; remote children without local completion events cannot supply local output translations.
- **Independent startup defaults.** `translator --host pi …` and `translator --host claude …` persist Input, Instruction, Output, Model, Thinking and cache defaults independently under `hosts.pi` / `hosts.claude`. New sessions, Pi `/new` and Claude `/clear` start from those defaults; resumed branch/session overrides still win. `model follow` explicitly masks inherited pins; `inherit` / `reset` remove overrides. Old flat configuration and unscoped commands retain their common-default meaning. Locked atomic updates preserve symlinks, unknown fields and the other host.

### Fixed

- **Answers beside choice boxes no longer wait for the choice.** Steps whose tools are only `AskUserQuestion` and/or `ExitPlanMode` can start display translation before the turn ends. Questions/options also get annotations, with one unchanged native dialog reference and compatible plain-text decoration. Ordinary operational-tool chatter stays excluded; selection values and permission/plan approval controls never change. Optional task-event registration does not prevent the rest of the mod from loading on an older engine.
- **Parallel and resumed displays stay separate.** Pending jobs use version-checked state updates; task/tool drawings carry kind, ID, direction and turn identities instead of merging under a missing transcript UUID. Completed displays restore from journals, while cancellation/session-generation checks reject stale results. Claude uses delivered child completion reports, not raw pre-review output.
- **Agent tasks never become human prompt history.** Task/display provenance is excluded from Claude's history restoration and composer recall, even when tasks share the input cache. Legacy human records still work.

### Changed

- **Conservative input, tolerant output.** Input retains conservative literal boundaries. Output additionally masks ASCII paths/filenames against Chinese edges, contextual technical identifiers and a single Titlecase name between Han prose. Already-Chinese source units are protected and restored byte for byte instead of being sent for translation again; remaining English stays batched. A leading English preface of at most 12 words before an otherwise Chinese body of at least 80 unmasked Han characters skips the whole answer. Substantial English, English conclusions and standalone `OK` still translate. Missing/duplicated literal or Chinese-section placeholders fail safely; there is no repair-model call.
- The scanner version is **`literal-whitelist-v9`**. Older versioned input-cache entries are no longer reused automatically; journals are not deleted. No reinstall or flat-config migration is required. Finish/cancel active translations before updating, then use Pi `/reload` and Claude `/reload-plugins` or new sessions; an incompatible old continuation fails closed.

### Verification and release status

- This is the explicitly authorized **0.7.0 milestone**, with matching package and plugin versions. See the [verification record](docs/testing.md#verification-record-for-070) for local checks and acceptance limits; the GitHub Release records the release PR, merge commit and published artifact.
- Tested hosts: Pi **1.3.0**, Claude Code CLI **2.1.302**, and the desktop app's bundled engine **2.1.299**. Official Mods APIs and generated declarations were checked. Host tests use isolated local model fixtures; Pi subagent integration covers both a synthetic tool with the real SDK and actual child processes launched by the official example. Manual desktop painting, live-model quality, arbitrary third-party subagent schemas and older minimum hosts are not claimed verified.

## 0.6.16 — 2026-10-16

### Fixed

- **Answers are translated after their turn, so nothing interrupts them.** Claude Code translated an answer inside the turn's last step: the turn stayed busy (spinner, `esc to interrupt`), queued prompts and background-task notifications waited for it, and Esc, the desktop app's Stop or a new prompt sent in that window cancelled the Chinese for good and left `[Request interrupted by user]` in the model's context. The translation now runs once the answer is complete and after the turn has ended: you can go on at once, an interrupt, a later turn or a switch to another session never stops it (a `/branch` draws it), and the Chinese is drawn when it is ready. **Cancel translation** still stops it. A reload of the mod during it leaves it to the old copy while that copy still runs and otherwise starts it again in the new one, so it is never translated twice. Pi waits for an answer's translation only until you interrupt or send another prompt; in its terminal Esc no longer cancels it (Ctrl+Alt+C does), an RPC abort still does, and its card follows, naming its answer when later rows came first. When navigation, a session switch or `/reload` stops it, a card says so.
- **Prompt history keeps your Chinese.** In Claude Code's terminal, Up/Down showed the English first and swapped in the original about 150 ms later, and showed only English after a restart, with the cache off, in memory-only mode or past the last 500 records. Translator now lets the text you typed enter and rewrites only the stored prompt row into English, so Claude Code's own history saves your Chinese while the model and the transcript read English: Up/Down and Ctrl+R show it at once, in every session. The 150 ms poller is gone. A prompt with an image that you send while Claude works is the one exception: Claude Code keeps no rewrite of its row, so it goes out in English and the history keeps that English, which Up maps back to your Chinese from an empty box until the next start restores it. Entries that earlier releases saved in English in Claude Code's history file get your originals back when Claude Code next starts, so a second Up press in a row shows Chinese too: only a line that is exactly the English of a prompt the same session translated within ten minutes changes, and the file is replaced only under the lock Claude Code writes it under. When Esc or a rewind puts a sent prompt's English back in the box, its original replaces it at once; Claude Code gives a mod no earlier moment, so the English may still show for a frame. Pi's editor history kept the Chinese only until Pi refilled it from stored rows; Translator now maps those rows back to the originals after `pi -c`, `/tree` and a session switch, and only then, so English you type yourself stays English; `/tree` and `/fork` put a translated prompt back in the editor as your original.
- **Digits no longer change settings.** In Claude Code, typing `1`, `2` or `3` into an empty prompt and pausing pressed the Input, Instruction or Output button, switching that feature for the session and swallowing the digit; `4` cancelled a running translation. The buttons above the prompt have no keys any more; the settings pane keeps 1–4.
- **Drawings survive switching and forking conversations.** In-process `/resume` and `/branch` restored the previous session's settings and drawings, so every earlier drawing vanished and the button row showed defaults. A conversation that continues under a new session ID (`/branch`, `--fork-session`, the desktop app's Rewind or Fork, `← for agents`) lost every earlier original and Chinese answer, and its Translator settings. Going back to a session already opened in the same process (`/clear` then `/resume`, `/branch` then back) drew nothing and showed default settings. A session is now loaded on every visit once its ID is current, a fork draws the rows of the sessions it continues, up through a branch of a branch or a fork of a fork, and its parent's settings come along, in memory-only mode too. A fork whose transcript names no parent (`--fork-session`, the desktop app's Rewind) is tied to it by the rows it draws, never by which session was written last, and its kept rows are drawn as soon as its first prompt starts.
- **Long answers in Claude Code are translated in parts**, four at a time, as in Pi: a long answer's Chinese arrives several times sooner, a part cut short is asked again by itself, and a very long answer no longer exceeds the worker's reply limit.
- **Fewer failed translations.** In Claude Code, a reply a rate-limited, overloaded or unavailable model could not give (HTTP 429, 5xx or 404, a rejected request, an empty reply) gets the same single fallback to another model family as a reply cut short; a reply cap above a model's limit is lowered to it; a request past `timeoutMs` reports `Translation timed out` instead of being dropped as cancelled; failures name their cause. Pi asks the newest model of another family from the same provider once when a translation is refused by the model's safeguards, on the same route and API (never a `:batch` variant or another region), and names that model on the card. Claude Code's Pi backend and the command-line tool ask the other family (`sonnet`, or `haiku` after a Sonnet model) once at the provider that answered. An unreadable or unwritable input cache no longer blocks prompts.
- **Nothing missed or translated twice around answers.** An answer cut at the output limit and continued by Claude Code is translated whole, not only its last part; an identical answer repeated after a Stop hook is translated again; a subagent starting no longer clears the main turn's reply row; Pi translates an answer cut at its token limit.
- **Prompts typed while the agent works keep their originals.** A prompt that another plugin rewrote, or that you edited in the queue and sent again, no longer draws a wrong original or none. In the desktop app, context the app adds to a prompt (`system-reminder`, `widget_context_hint`) is no longer translated or drawn as your words, rows linked while the app was detached are drawn when it attaches again, and a prompt folded into a long step keeps its original. In the desktop app, Stop or Send now while such a prompt is being translated no longer drops it: it stays queued and is translated when it is sent. Pi shows the original of a prompt waiting in its queue above the editor, keeps the card of a run's starting prompt when other input arrives meanwhile, puts a prompt the run stopped mid-translation back in the editor, and, when Esc or Alt+Up puts its queue back in the editor, gives back your originals rather than their English.
- **Only your own words are translated.** Claude Code no longer translates a line it runs as a slash command, skill or template (it never applied the rewrite, so the call was wasted and its notice wrong), and Pi passes the skill and template lines it expands through as typed; a line that only starts with a slash, such as a path (`/tmp …`) or a mistyped command, is still translated. Prompts of scheduled tasks and `/loop`, and a plugin's prompt sent as your own words, are translated. A Chinese prompt starting with `!` is no longer refused: in Pi's terminal a `!` line you run with Enter still goes to the shell untouched, and one sent to the model is translated. A subagent's `pi -p` child, which a Pi terminal starts in JSON mode, is left untranslated; a `pi -p` you run yourself translates.
- **A resumed session redraws what it can.** A long session no longer restores nothing once its rows pass Claude Code's 4 MiB reply limit, or only 500 rows: the newest rows within the limit are drawn. Another session's journal that cannot be read no longer stops a session's own rows from being drawn.
- **A saved model pin the configuration no longer accepts** (a native pin after a switch to the Pi backend) is ignored instead of blocking every prompt.

### Changed

- A translation shows `translating…` and Cancel only once a model call starts, or after a moment, so a switched-off direction or a cached prompt flashes nothing.
- The input cache reads only its newest 8 MiB, so a cache grown over months costs the same for every prompt; an older entry is translated afresh.
- In Claude Code, other mods' `prompt.submit` hooks beneath Translator see the prompt as you typed it; settings `UserPromptSubmit` hooks see the English, and the model reads only the English.

### Notes

- This is routine patch **0.6.16**; see its [verification record](docs/testing.md#verification-record-for-0616). Scanner rules and the cache contract are unchanged, so existing caches and settings stay valid, and installation links do not change. Claude Code picks the new mod up by itself; in a session the desktop app runs, start a new session or run `/reload-plugins`. Run `/reload` in Pi. Entries an earlier release saved in English in Claude Code's prompt history get their originals the next time Claude Code starts with this release; see [Data and privacy](README.md#data-and-privacy) for what Translator changes there and the small lease files it keeps in the system's temporary directory. A translation that 0.6.15's worker prepared and the new one finishes during the update still completes.

## 0.6.15 — 2026-10-15

### Fixed

- **The original of a prompt sent while Claude works no longer disappears in the Claude Code desktop app.** A prompt you send mid-turn is translated when Claude reads it at the next tool boundary; the app then shows the English, and the Chinese you typed vanished from the bubble. The original was drawn under it only once Claude Code had written that prompt's row to the session file, which a long step puts off, often until the turn ended. It is now drawn as soon as the prompt is read, while the task keeps running, and stays after the turn. As in Pi, the prompt is recognized by exactly the text it shows; when the same English came from two different originals, neither is drawn rather than guessing. Pi already showed the original as soon as its row was delivered and is unchanged; a new real Pi test checks that this holds during a long task.

### Notes

- This is routine patch **0.6.15**; see its [verification record](docs/testing.md#verification-record-for-0615). Translation behavior, scanner rules and the cache contract are unchanged, so existing caches and settings stay valid, and installation links do not change. The desktop app's sessions do not reload mods by themselves: after updating the installed copy, start a new session or run `/reload-plugins` in one still running 0.6.14. Pi is unchanged.

## 0.6.14 — 2026-10-14

### Fixed

- **Claude Code no longer blocks prompts whose translation reply is cut short.** Since 2026-10-14, Opus 5.5's safeguards stop some translation replies partway, even on ordinary prompts: an English prompt naming a few Chinese files failed every time with `Translation incomplete: missing completion marker`, and some answers were left without their Chinese. Claude Code's `$.model.complete` returns such a reply as a normal answer and does not say why it stopped, so only the missing end marker shows it. The same masked request now goes once more to another model family (Sonnet, or Haiku when the translator already is a Sonnet model), and that answer is final. A translation that finishes on the first reply still makes one model call; there is still no audit or repair call. The record names the model that translated as `model` and the one cut short as `fallbackFrom`, and `usage` covers both replies. If the fallback is cut short too, nothing is sent, and the message names both models: `Translation incomplete: the reply stopped before its completion marker (claude-opus-5-5, then sonnet)`. The Pi backend is unchanged.

### Notes

- This is routine patch **0.6.14**; see its [verification record](docs/testing.md#verification-record-for-0614). Scanner rules, prompts and the cache contract are unchanged, so existing caches and settings stay valid, and installation links do not change. After updating the installed copy, start a new Claude Code session, or run `/reload-plugins` in one still running 0.6.13: in a session still running the old mod, a fallback the new worker asks for blocks the prompt as before. Pi is unchanged.

## 0.6.13 — 2026-10-14

### Added

- **`/translator` in the Claude Code desktop app's menu before a session starts.** The app lists a new session's slash commands from a short run of Claude Code with every hook off, so the command the mod registers when a session starts never appeared there, unlike skills and plugin commands. A `SKILL.md` beside the mod now lists `/translator` through the installer's `skills/` link without running anything. Picked on a new session's empty screen, it goes out as the first message: the session starts, the mod answers it without a model turn, the settings pane opens and the Input, Instruction and Output row appears. The app still starts Claude Code only when a session's first message is sent, so no mod can show the row before that.

### Changed

- **Through the `skills/` link, `/translator` is a skill the mod answers.** Claude Code reads `SKILL.md` as your own `/translator`, so it refuses the mod's registration of that name. The mod answers every run of the skill itself, failures included (`Translator: settings unavailable (…)`), so the skill's text never reaches the model, and the model is never offered the skill (`disable-model-invocation`). Typed in the terminal while Claude is working, `/translator` therefore runs when the turn ends, like other skills, instead of at once; the button row still works at any time. A `--plugin-dir` copy is unchanged: the manifest's `"skills": []` keeps Claude Code from reading `SKILL.md` there, and the mod registers `/translator` itself.
- **With hooks disabled** (`disableAllHooks`), `/translator` is now listed as well, and the model replies that Translator is not running instead of the command being unknown. Safe and bare modes skip your skills too, so `/translator` stays unavailable there.

### Notes

- This is routine patch **0.6.13**; see its [verification record](docs/testing.md#verification-record-for-0613). Translation behavior, scanner rules and the cache contract are unchanged, so existing caches and settings stay valid. After updating the installed copy, start a new Claude Code session, or run `/reload-plugins` in one still running 0.6.12. Pi is unchanged.
- Installation links do not change: the existing `skills/translator` link exposes `SKILL.md`. The installer now also requires `claude-code/SKILL.md` in the source. The desktop app keeps its command list for a while, so after updating, `/translator` can take a few minutes, or a restart of the app, to appear in a new session's menu.

## 0.6.12 — 2026-10-14

### Changed

- **No translation time limit by default.** `timeoutMs` now defaults to `null`, which sets no deadline: a long answer is no longer cut off after 30 seconds, and a translation runs until it finishes or you cancel it (**Cancel translation**, key **4**, in Claude Code; **Ctrl+Alt+C** in Pi). Claude Code's native backend sends no deadline with `$.model.complete`, and the mod no longer stops a translation worker after 125 seconds, so Pi-backend translations are not cut off either. The provider still ends a single native reply after about ten minutes. A number from `1` to `120000` still sets a deadline for each request. A configuration file that sets `"timeoutMs": 30000`, as `config.example.json` did, keeps that limit until you remove the field or set it to `null`.
- **Simpler internals, same behavior.** Removed code left over from the post-translation review that 0.6.10 dropped: the scanner's offline inspection helpers (also from Claude Code's generated copy), the native continuation's unread model field and its repair-ticket check, and a no-op that cleared a status line no released mod ever pinned. The shared translate functions run the language gate once instead of twice, the configuration path, the input lock and the Pi entry type are each read through one helper, Pi input and output share their preview code, and host texts take their names and thinking levels from the shared feature definitions. Scanner rules, the cache contract, prompts, settings and stored records are unchanged, so existing caches and sessions keep working.

### Fixed

- `node cli.mjs --help` names the configuration file in use. It always printed `~/.agents/hooks/translator/config.json`, which is wrong for npm installs (they keep it in `~/.agents/translator/`) and when `TRANSLATOR_CONFIG` is set.

### Notes

- This is routine patch **0.6.12**; see its [verification record](docs/testing.md#verification-record-for-0612). Scanner rules and the cache contract are unchanged, so existing caches stay valid. Besides the `timeoutMs` default above, behavior is unchanged. Installation links do not need to change. After updating the installed copy, run `/reload` in Pi and `/reload-plugins` in a Claude Code session still running the old code. To remove an inherited `30000` limit, delete the field or set it to `null` after reloading: 0.6.11 and earlier reject `null`.

## 0.6.11 — 2026-10-14

### Added

- **Settings before the first prompt in the Claude Code desktop app.** The app starts Claude Code for a project session only when its first message is sent, so the mod cannot draw the Input, Instruction and Output row on a new session's empty screen. The Claude Code guide and troubleshooting table now explain this and the way around it: send `/translator status`, or a setting such as `/translator input off`, as the first message. The mod answers it without a model turn, and the row appears. Translator's behavior is unchanged.

### Notes

- This is routine patch **0.6.11**, a documentation release: the code is the same as 0.6.10, so the [0.6.10 verification record](docs/testing.md#verification-record-for-0610) still applies. Configuration and installation links do not need to change, and running sessions need no reload.

## 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.
