Files
DeepSeek-Reasonix/docs/terminal-text-encoding.md
T
SivanCola b17c1b5c3b Restore ProjectTree and integrate session recovery fixes / 恢复项目树并整合会话恢复修复 (#10380)
* fix(session): keep history index checkpoints on complete batches

Bound history and search scans to their captured log snapshot and persist
the byte offset and sequence from the same validated complete transaction.
Reject replaced history logs before publishing. Rebuild a mismatched derived
history checkpoint from the authoritative log, preserving real corruption
errors instead of discarding session data.

Treat history preparation as pending during startup and pagination. Stop
polling after navigation or generation changes and keep lifecycle callbacks
out of IPC payloads.

Add deterministic regressions for append interleavings, persisted mismatched
checkpoints, partial tails, replacement, corruption and preparation lifecycle.
Verified a disposable copy of the reported session recovers 32 messages.

Frontend initial raw bundle: 2498286 B at base to 2499170 B (+884 B, 0.035%).
Raise only its budget from 2439.9 to 2440.7 KiB with 0.1 KiB headroom; gzip,
CSS and individual chunk budgets remain unchanged.

* fix(desktop): bind session navigation to its canonical workspace

* test(session): model replaced readers without renaming open files

* fix(desktop): preserve active sessions across navigation

Transfer active controllers, event sinks, writer leases and shared-host references to detached ownership when navigating. Reattach the exact owner on return and replay pending prompts. Build independent runtimes for blank targets, isolate display and telemetry, and fence retired sinks. Cover running, pending approval, background jobs, shared hosts, failed opens, rapid navigation and repeated active-owner swaps.

* fix(session): derive catalog previews from authored user text

Problem: Session lists displayed truncated internal prompt wrappers instead of user requests.

Root cause: Shared message previews preferred provider content and truncated it before display extraction; persistent projections retained those previews.

Fix: Reuse authored-message extraction before truncation, exclude host messages and steers from catalog labels, and rebuild older catalog, history, search, and recovery projections. Preserve custom titles and durable conversation content.

Verification: Session package tests, authored-text and legacy-checkpoint regressions, root Go suite excluding the subsequently repaired stale inventory gate, and desktop workspace-list tests passed.

* fix(desktop): restore compact workspace navigation and recovery access

Problem: The SessionID sidebar lost compact rows, project ordering, and its bottom Trash entry; archive access occupied a separate sidebar row.

Root cause: The replacement workspace browser omitted existing presentation and navigation behaviors.

Fix: Restore single-line titles and folder names with full-name tooltips, durable drag ordering with insertion feedback, and the bottom Trash entry. Combine archived and deleted sessions in that page while preserving their distinct actions. Share archive notification behavior across browser fixtures and isolate workspace styles with their component.

Verification: Browser checks cover light and dark themes, narrow layouts, drag ordering, failed saves, archive/restore and deleted-session navigation. Workspace persistence tests, Trash management regressions, typecheck, frontend production build and repository lint passed.

* docs(desktop): refresh generated migration inventory

Synchronize generated source locations after the session navigation changes. The inventory content and classification remain unchanged.

Verification: go test ./tools/desktopinventory -count=1 passed.

* fix(desktop): route sidebar sessions through navigation owner

Problem: Sidebar session clicks can change the backend session while leaving the previous transcript visible.

Root cause: Direct OpenSession and CreateSession calls bypass the frontend navigation owner. Ready events for a different active tab are correctly ignored as background events, leaving the visible surface stale.

Fix: Route canonical session opening and blank-session creation through the shared navigation queue, synchronize the active surface after a successful open, and preserve last-intent-wins behavior. Load the navigation executor on demand to retain the existing startup bundle budget.

Verification: Frontend build, type and hook checks, bundle budgets, repository lint, navigation lifecycle tests, browser lifecycle checks, and packaged macOS sidebar and startup smoke tests passed. The packaged sidebar regression reproduces the stale transcript on the prior build and passes with this source tree.

* fix(desktop): render authored chat text across history readers

Problem: Chat history exposes host context and prompt wrappers as user bubbles.

Root cause: The canonical message adapter renders provider content without respecting message origin or authored raw text; reference-only previews can retain the same internal content.

Fix: Centralize authored-text projection for inline and hydrated messages, hide host messages, unwrap legacy protocol content, and rebuild derived preview caches. Keep durable messages unchanged and load SVG preview styles with their component.

Verification: Root Go suite, owning session regressions, transcript tests, browser transcript and authored-text scenarios, type checks, frontend build and bundle budgets, and repository lint passed.

* test(desktop): verify history errors through shared reader

Problem: CI checks for slice error handling in a file that no longer owns it.

Root cause: History preparation moved fetching and failure propagation into the shared reader while the source-only assertion retained the old location.

Fix: Assert the store delegates to the shared reader and verify that reader rejects an actual error response.

Verification: History failure and preparation lifecycle tests passed.

* fix(shell): preserve non-ASCII commands across interactive PTYs

Problem: Desktop launches without a UTF-8 locale can hang on Chinese
commands until the persistent Bash deadline expires.

Root cause: Readline interprets raw high bytes as meta input before Bash
parses the command wrapper. Variable-width control escapes can also absorb
following octal digits.

Fix: Encode non-ASCII and control bytes as fixed-width octal escapes in
the shared ANSI-C quoting boundary. Preserve the original command bytes,
user locale, and persistent shell state.

Verification: Reproduced the pre-fix timeout; passed locale, Unicode path,
grep, emoji, quoting, heredoc, long-input and cancellation/recovery PTY
regressions, Bash/Zsh byte round trips, public Bash tool/schema tests,
the persistent-shell race suite, and targeted Go vet.

* fix(runtime): preserve UTF-8 across terminal and output boundaries

Problem: Integrated Bash still corrupts non-ASCII keystrokes under C locale,
tool progress can split characters into invalid JSON text, and GUI-launched
children without a locale use unintended byte-oriented text semantics.

Root cause: Terminal and subprocess environments lacked explicit text
defaults, while progress and bounded output sliced arbitrary byte offsets.

Fix: Select an installed UTF-8 locale only for unconfigured child environments.
Preserve user inputrc settings while enabling eight-bit Bash terminal input.
Buffer incomplete progress characters through EOF/cancellation and align
bounded output slices without raising byte limits. Preserve the head on the
first oversized write and document the shared contracts bilingually.

Verification: Native Bash PTY tests cover missing/C/UTF-8 locales and retained
editing preferences. JSON round-trip, byte-cap, head/tail, cancellation, locale
priority, sed character semantics, tool schema and focused race tests pass.
Targeted Go vet and documentation/cache metadata guards pass.

* fix(locale): use the shared background process constructor

Problem: The desktop process-constructor guard rejected the new locale probe.
Root cause: The helper called os/exec directly instead of the repository's
shared process entry point.
Fix: Route the bounded locale discovery through internal/proc while retaining
its explicit environment and deadline.
Verification: The desktop constructor guard, native Unicode terminal tests,
locale/secrets package tests and targeted Go vet pass.

* docs(desktop): refresh terminal migration inventory locations

Problem: The generated desktop inventory was stale after the terminal edit.
Root cause: Source line locations changed when locale defaults were wired in.
Fix: Regenerate both inventory artifacts with their owning generator.
Verification: go test ./tools/desktopinventory passes, including the no-Git
reproducibility check.

* fix(session): restore cold history without clicks and bound catalog rebuild memory

Problem: Cold historical sessions could remain loading or appear as empty new
sessions until another navigation action refreshed them.

Root cause: Busy rebuild slots dropped metadata work, pending metadata was
treated as blank, and completion did not refresh the sidebar. Each workspace
also scanned the entire catalog, while metadata replay retained full bodies.

Fix: Queue deduplicated metadata work with two workers, preserve pending titles,
refresh only while metadata is pending, and prepare obsolete history indexes
asynchronously. Read workspace members directly and stream catalog reduction
while retaining only IDs, short previews, and required metadata.

Verification: Root Go suite, Desktop workspace/history tests, targeted race
tests, Windows amd64 session suite, sidebar and transcript browser tests,
frontend build and typechecks, and repository lint passed. Repeated 512 MiB
synthetic history reductions passed retained-heap and reclamation checks.

* fix(windows): disable restricted Bash and validate native shell startup

Problem: Windows Git Bash can fail during MSYS initialization before even a
simple command executes, and repeated startup attempts hide the useful error.

Root cause: host discovery does not validate the actual sandbox environment;
automatic selection favored MSYS, persistent startup discarded its diagnostics,
and interactive shells used a different Windows sandbox lane than one-shot shells.

Fix: use only native PowerShell for Windows auto selection, reject explicit
POSIX shells in restricted execution, and retain explicit Bash in full-access
mode. Preflight shells and child processes under the actual policy, retain
bounded startup evidence, suppress repeated failed starts, and align interactive
shell sandbox selection with one-shot execution. Preserve sandbox enforcement.

Verification: full root Go suite, owning-package tests, race tests, go vet,
Desktop Shell/Terminal tests and frontend TypeScript checks passed on the local
fix branch. Windows test binaries cross-compiled. Added native Windows policy
and write-boundary acceptance tests; real Windows execution remains pending.
This change does not claim to repair MSYS restricted-token compatibility.

* Restore the v1.38.6 project-tree sidebar and drop the creation layout / 恢复 v1.38.6 项目树侧边栏并移除创作布局

Problem: The SessionID cutover replaced the workbench sidebar session list
with the workspace-browser grouping (archived toggle, per-workspace rows),
which lost the v1.38.6 project-tree UI and interactions.

Fix: Render the ProjectTree in the workbench sidebar again (variant
workbench, trash entry restored) while keeping the current SessionID-era
bridge underneath. Delete the creation layout end to end — sidebar feature
zone, creation geometry clamps, dock/panel creation modes, the composer
context-ring gate and the desktopLayoutStyle preference chain — so the
desktop ships the workbench layout only, and remove the "Desktop style"
settings row with its locale copy and mocks. WorkspaceSessionBrowser and
its CSS/test/locale keys are removed with it.

The Go config field and host bindings stay untouched for config
compatibility; the frontend simply no longer reads or writes them.

Verification: pnpm typecheck; pnpm build (lint/check gates + bundle
budgets); node scripts/run-tests.mjs --keep-going (368/369; the single
topicbar-actions-lifecycle failure reproduces identically on the pristine
base commit under suite load and passes standalone).

问题:SessionID 切换把工作台侧边栏的会话列表换成了 workspace-browser
分组(已归档开关、按工作区行展示),丢失了 v1.38.6 的项目树 UI 与交互。

修复:工作台侧边栏重新渲染 ProjectTree(workbench 变体,恢复回收站入口),
底层继续使用当前 SessionID 架构的 bridge。端到端删除创作布局 —— 侧边栏
功能区、创作几何钳制、dock/面板 creation 模式、composer 上下文环开关以及
desktopLayoutStyle 偏好链路 —— 桌面端固定只提供工作台布局,并移除设置中的
「桌面风格」行及其文案与 mock。WorkspaceSessionBrowser 及其 CSS/测试/文案
一并删除。

Go 侧配置字段与宿主绑定保持不变以兼容既有配置,前端不再读写。

验证:pnpm typecheck;pnpm build(lint/check 门禁 + bundle 预算);
node scripts/run-tests.mjs --keep-going(368/369;唯一失败的
topicbar-actions-lifecycle 在未改动的基线提交上同样复现,单测独立通过)。

* fix(desktop): keep running sessions switchable after archive and project change / 归档与跨项目切换时保留正在运行的会话

Problem: Archiving a session, or creating a new session in another project
and then switching back to a running session, froze the Desktop UI.

Root cause: GetRuntimeStateSnapshot held its projection mutex across
controller reads, so archive emission deadlocked with a live turn.
keepOnlyVisibleTab snapshotted running sessions before detaching them.
ActivateTopic and OpenSession looked up detached runtimes by file path
only, so they built a competing controller instead of reattaching the
session:<id> owner.

Fix: Sample runtime projection off the projection mutex. Detach running
sessions without snapshotting. Look up live runtimes by session identity
and unique topic, and reattach that owner on ActivateTopic/OpenSession.
Prove OpenSession identity with Stat instead of a full live history
snapshot.

Verification: go vet .; go test -count=1 -run
TestRuntimeStateProjectionDoesNotHoldMutexAcrossControllerRead|TestPruneRunningSessionDoesNotSnapshot|TestActivateTopicReattachesDetachedRunningSession|TestBlankOnOtherProjectThenOpenSessionReattaches

* refactor(shell): keep launch validation within repository lint limits

Problem: The integrated shell fixes exceed function-size limits and introduce
small file-size and comment-budget regressions detected by pre-push repolint.

Root cause: Launch preflight and result classification expanded existing
execution functions; UTF-8 and Windows probe wiring added three source lines
across two already-baselined files.

Fix: Extract Bash launch validation and foreground result classification while
preserving execution order, environment selection, failure metadata, and lease
ownership. Shorten the octal-escape comment without losing its invariant.
Adjust only terminal.go's measured file-size baseline by two lines and
controller.go's by one; retain function-size and global ceilings.

Verification: Repository lint, Go vet for the three affected shell packages,
their full package tests, and git diff --check pass.

* fix(shell): acknowledge bounded PTY input before executing long commands

Problem: Linux CI exposed silent truncation of long Unicode commands, while
root/Desktop lint and Windows fixtures rejected the integrated branch.

Root cause: ASCII escaping expanded a command beyond canonical PTY input
limits. Readline mode changes also made queued multiline input unreliable.
An interrupted staging attempt could fall back to one-shot execution because
the user command had not started. Windows fixtures still expected restricted
Bash execution and an auto-selected Bash cache contract.

Fix: Stage bounded ASCII blocks with per-block acknowledgements, then eval the
assembled value in the same shell. Keep partial commands unexecuted on failure
and prevent fallback after the persistent runtime resets. Align Windows policy
assertions with native shell selection and pin the existing Bash golden fixture
without changing its artifacts. Resolve root/Desktop lint findings using range,
slices.Contains, and strings.CutPrefix without weakening checks.

Verification: Long-line contract regression failed before the transport fix;
the fallback regression failed before its guard. Five repeated Unicode/native
PTY runs, full persistent-shell/builtin/sandbox suites, focused race tests,
boot goldens, navigation/terminal regressions, root/Desktop lint, repository
lint, inventory freshness, and whitespace checks pass locally. Native Linux
and Windows acceptance is delegated to the replacement CI run.

Cache-impact: No new provider-visible changes; the golden fixture explicitly
selects Bash while existing Windows auto-selection changes remain documented.

* test(shell): select canonical input mode before Bash starts reading

Problem: The Linux canonical-input regression exited during setup before
submitting its long command.

Root cause: Switching off Readline inside eval with stdin redirected to
/dev/null changes Bash's input reader during a temporary descriptor binding.
The fixture unintentionally tested that transition instead of canonical input.

Fix: Launch the fixture with --noediting so its input mode is established
before setup. Retain long Unicode input, shell-state, and output assertions.

Verification: The focused native PTY regression passed five consecutive runs;
package lint, repository lint, and whitespace checks passed. Native Linux
acceptance is checked by the replacement CI run.

* fix(ci): isolate native Windows desktop test groups

Problem: Native Windows desktop checks exhausted a shared 25-minute step deadline before the final group completed.

Root cause: The first two sequential groups consumed about 19 minutes 42 seconds including build overhead; the first group itself approached the default package timeout.

Fix: Partition the suite across four independent Windows runners. Validate current native inventory for unique coverage, preserve the required aggregate check and existing deadlines, and retain the separate ConPTY probe and systray test once.

Verification: All 17 partition/workflow tests, actionlint, release workflow contracts, repository lint, native inventory validation, and whitespace checks passed.

* fix(ci): classify Windows shards and remove duplicate full sweep

Problem: The new native Windows matrix was missing from the desktop migration inventory. Non-PR Windows runs also executed the entire root module before executing the same coverage through partitioned jobs.

Root cause: The explicit migration classifier was not updated with the new job, and the generic full-suite condition included Windows despite its existing disjoint selectors.

Fix: Classify the matrix and its aggregate, regenerate both inventory artifacts, and restrict the generic full sweep to Linux and non-PR macOS runs. Windows retains full plus agent, boot, and control groups.

Verification: Full root Go tests, 18 partition/workflow contracts, inventory freshness, actionlint, repository lint, and whitespace checks passed. The unchanged protocol-recovery test also passed ten consecutive native local runs.

* fix(ci): let superseded Windows workers cancel

Problem: Superseded native Windows desktop groups kept their concurrency slot and blocked the next PR run.

Root cause: always() kept the costly matrix workers running even after workflow cancellation.

Fix: Gate workers with !cancelled() while retaining preparation checks and the always-running result aggregate.

Verification: The cancellation regression, all 18 workflow/partition tests, actionlint, inventory freshness, repository lint, and whitespace checks passed.

* test(ci): verify macOS routing by behavior

Problem: The macOS workflow contract rejected the corrected Windows deduplication condition even though macOS routing was unchanged.

Root cause: The assertion matched the obsolete expression text instead of evaluating platform and event behavior.

Fix: Check actual macOS PR, push, manual-run, and disabled-step conditions for the full and platform suites.

Verification: The exact complete release workflow contracts CI step passed locally, along with repository lint and whitespace checks.
2026-09-16 07:06:32 +08:00

3.6 KiB

Terminal text encoding / 终端文本编码

Child-process locale / 子进程 locale

When LANG, LC_ALL and LC_CTYPE are all empty or absent, Reasonix selects an installed UTF-8 locale for child processes. It prefers C.UTF-8, then en_US.UTF-8, then another installed UTF-8 locale. Discovery is bounded and cached per process. If discovery fails or no UTF-8 locale is installed, the environment is retained. Windows continues to use its existing encoding-specific process handling.

当 LANG、LC_ALL、LC_CTYPE 均为空或未设置时,Reasonix 为子进程选择已安装的 UTF-8 locale,优先 C.UTF-8,其次 en_US.UTF-8,再选择其他已安装的 UTF-8 locale。 探测有时间限制,并在进程内缓存。探测失败或没有可用 UTF-8 locale 时,保留原环境。 Windows 继续使用既有的编码处理。

Explicit values, including C/POSIX and category overrides, remain unchanged. Reasonix does not change the parent process environment or force LC_ALL. Thus an explicit LC_ALL=C still requests byte-oriented sed/grep/sort semantics.

用户显式设置的值(包括 C/POSIX 和各分类覆盖)保持不变;不会修改父进程环境或强制 设置 LC_ALL。因此显式 LC_ALL=C 仍然要求 sed、grep、sort 等工具使用对应的字节语义。

Interactive input / 交互输入

Machine-submitted persistent-shell commands use ASCII-only byte escapes. The integrated Bash terminal instead uses a private, temporary Readline configuration: it includes the user's existing inputrc and then enables eight-bit input/output without meta conversion. Other editing preferences remain in place. This accepts Chinese and emoji even with an explicitly selected C locale. The temporary file is removed on launch failure, terminal closure or process exit.

机器提交给持久 Shell 的命令使用纯 ASCII 字节转义。内置 Bash 终端则使用私有临时 Readline 配置:先包含用户原有 inputrc,再开启八位输入输出并关闭 meta 转换,保留 其他编辑偏好。这样在显式 C locale 下也能接收中文和 emoji。临时文件会在启动失败、 终端关闭或进程退出时清理。

Long persistent-shell commands are sent as bounded ASCII blocks. Each block must be acknowledged before the next is submitted; only the final step executes the assembled command in the current shell. This avoids canonical terminal input truncation while preserving variables, directory, exit status and stdin isolation. Cancellation during staging retires the shell without executing the partial command.

较长的持久 Shell 命令会拆成有长度上限的 ASCII 块,每块确认接收后才发送下一块, 最后在当前 Shell 中执行完整命令。这样可避免终端规范模式截断输入,同时保留变量、 工作目录、退出码与标准输入隔离。分块传输期间取消操作会关闭该 Shell,不执行未完整 传输的命令。

Tool output / 工具输出

Shared live output buffers incomplete UTF-8 characters across reads before emitting JSON events. Completion and cancellation flush an unfinished character as one replacement character. Progress limits and retained output head/tail stop at character boundaries; byte budgets are not increased. Durable protocol fields, tool schemas and model prompt prefixes are unchanged.

共享实时输出层会缓存跨读取的不完整 UTF-8 字符,完整后才发送 JSON 事件。正常结束和 取消时,未完成字符以一个替代字符收尾。进度限额及最终保留的头尾内容都在字符边界 截断,不提高字节预算。持久协议字段、工具定义和模型提示前缀保持不变。