mirror of
https://github.com/nyakang/nyaterm.git
synced 2026-11-06 16:07:55 +00:00
Merge branch 'nyakang:main' into main
This commit is contained in:
@@ -1,91 +0,0 @@
|
||||
# Native AI migration to rust-genai 0.7.3
|
||||
|
||||
Implementation branch: `feat/ai-rust-genai-073`, based on `15908b7204ccd05616754fd21a58ea907933a5f5`.
|
||||
|
||||
## Dependency boundary
|
||||
|
||||
`nyaterm-desktop` uses `genai = "=0.7.3"`, default features disabled, with `rustls-tls` and `system-proxy`. Its separate `reqwest 0.13.5` dependency enables `json`, `query`, `stream`, `socks`, and `system-proxy`. SDK features additionally enable HTTP/2, gzip, charset, and rustls with aws-lc. The existing `zed-reqwest 0.12.15-zed` and other consumers of reqwest remain in place. No existing locked package version was removed or replaced. Bedrock, OTel, and native TLS are not enabled for genai.
|
||||
|
||||
SDK types appear only inside `nyaterm-desktop/src/http/ai`. `nyaterm-core::ai::completion` contains SDK-independent, ephemeral generation options, response context, usage, and safe typed errors. There are no new settings or database fields. Generation options and Agent assistant turns use `serde(skip)`; conversation response metadata is held by desktop state only.
|
||||
|
||||
## Call chain and lifetime
|
||||
|
||||
Previously, native chat and Agent continuations ran synchronous `zed-reqwest` calls and NyaTerm SSE folding inside `BlockingJobScheduler` workers, then forwarded unbounded worker events to GPUI.
|
||||
|
||||
`start_ai_ask` / native continuation → `launch_native_chat` → process-owned `AiRuntime` → short `BlockingJobScheduler` preparation → async `stream_chat` → short scheduler result/persistence stage → bounded GPUI drain → existing `AiChatWorkerEvent` state transitions and Agent Harness.
|
||||
|
||||
`DesktopController` owns one shared Tokio runtime. The conversation owns a cancellation/abort guard. Native Agent network requests are children of the existing run cancellation token. Dropping the conversation or cancelling the run drops the HTTP future and interrupts channel backpressure. The native stream channel has capacity 64; UTF-8 text, reasoning, and tool-argument fragments are split at 16 KiB. Final captures replace the result projection rather than appending text again. Scope, session, job and native run identity gate delivery.
|
||||
|
||||
Each conversation/run holds an immutable provider settings/client snapshot. Editing credentials, endpoints, defaults, or reasoning settings affects subsequent runs. New requests reset the snapshot; Agent continuations reuse it. Removing/disabling the selected credential cancels affected active and inactive conversations when the settings change is applied, including shared settings refresh in other windows. External Codex/Claude Code workers keep their existing protocol.
|
||||
|
||||
The snapshot also governs native permission/risk policy, step limits, execution timeout, output limits and history recording. Existing live session execution gates remain authoritative.
|
||||
|
||||
## Changed responsibilities
|
||||
|
||||
| Location | Responsibility |
|
||||
| --- | --- |
|
||||
| `nyaterm-core/src/ai/completion.rs`, AI request/result types, Harness registry | Ephemeral generation options, typed errors, usage and ordered assistant turns; serialization compatibility and redacted diagnostics. |
|
||||
| `nyaterm-desktop/src/http/ai/{client,async_proxy,request,response}.rs` | Explicit routing, account/client snapshots, authentication, proxy policy and SDK/domain conversion. |
|
||||
| `nyaterm-desktop/src/http/ai/{adapter,frames,error}.rs` | Async completion/streaming, bounded frame supplements, tool identity/JSON validation, termination and safe errors. |
|
||||
| `nyaterm-desktop/src/http/ai/{discovery,ollama_compat}.rs` | Dynamic model discovery and the limited native Ollama path. |
|
||||
| `nyaterm-desktop/src/ai_runtime.rs`, `app_shell/controller.rs` | Shared process runtime and cancellation/abort ownership. |
|
||||
| `nyaterm-desktop/src/features/ai/{native_jobs,ai_jobs,provider_runtime}.rs`, chat/Harness/state integration | Preparation/network/persistence split, GPUI delivery, per-run snapshots, cancellation, discovery and connection tests. |
|
||||
| `nyaterm-desktop/src/features/capability_runtime*` | Apply the retained native run policy to tool approval/execution and auditing. |
|
||||
| `nyaterm-app/src/main.rs` | Global SDK/HTTP log filtering for console and JSONL files, with subprocess tests. |
|
||||
|
||||
The old desktop blocking HTTP implementation, SSE reader and proxy/provider modules were removed after differential validation. Pure core wire contracts remain for parity/compatibility tests and the native Ollama response conversion. No architecture allowlist exception was added; no existing AI-specific exception needed removal. `zed-reqwest` remains required by other desktop features.
|
||||
|
||||
## Provider routing
|
||||
|
||||
| Capability | Backend and retained behavior |
|
||||
| --- | --- |
|
||||
| OpenAI / compatible providers | Explicit OpenAI adapter; includes DeepSeek, Groq, xAI, Cohere, MiMo, Z.AI, custom services and Ollama `/v1` routing. Cohere remains on its compatibility protocol. DeepSeek `-none` normalization remains in core. |
|
||||
| Anthropic | Anthropic adapter; captures ordered native blocks and signed/redacted thinking; replays custom `tool_result` with `is_error`. Thinking-compatible tool choice is `auto`, with the one-decision rule enforced by the Harness. |
|
||||
| Gemini | Gemini adapter; raw ordered parts preserve function IDs, names, signatures and unknown fields. Synthetic SDK IDs are unique across turns; original provider IDs remain in native continuation parts. |
|
||||
| Responses | OpenAIResp adapter; `store:false`, encrypted reasoning inclusion, ordered output-item replay and exact call/output association. |
|
||||
| Ollama native | Ollama adapter for ordinary models. A preselected asynchronous NDJSON compatibility path handles literal `::` model names and extra request parameters that SDK 0.7.3 cannot represent. It never activates after a network failure. |
|
||||
| Model discovery | Async dynamic discovery; existing protocol URL, pagination, duplicate-cursor guard, deduplication and model-ID contracts. No SDK static catalog replacement. |
|
||||
|
||||
`ServiceTarget` and `AuthData::RequestOverride` specify the selected account and exact URL. Existing URL joining preserves paths and query. HeaderMap performs case-insensitive authentication/custom-header merging before SDK handoff. Custom credentials stay on their origin during redirects. System/direct/custom proxy behavior, SOCKS remote DNS, proxy authentication, bypasses, timeouts and user agent are retained. SDK model-name convenience suffix inference is neutralized while restoring the literal wire model; `Auto` does not request reasoning. Historical `None` uses SDK `Zero`. `Ultra` is passed through only where the existing raw protocol represents it, otherwise the request returns an unsupported-capability error.
|
||||
|
||||
Streaming uses the SDK decoder and a bounded request-local frame observer, not a second SSE parser. Native terminal evidence is required before accepting synthesized SDK End events. Tool identities, cumulative arguments and final JSON are validated before a completion reaches the Harness. Adjacent unsigned Gemini text fragments with identical metadata coalesce, while signed/tool blocks retain their boundaries. Multiple calls are fully received, then rejected by the existing “exactly one decision” rule; no parallel tool execution is added.
|
||||
|
||||
Model POST automatic retries are disabled. JSON tool-protocol fallback requires an explicit unsupported-tools machine code, no generated content and no executed tool, and remains on the same backend. SDK/HTTP diagnostics are blocked at the logging entry point for both console and file sinks, independently of `RUST_LOG`; only safe classifications/status/Retry-After leave the HTTP boundary.
|
||||
|
||||
## Validation
|
||||
|
||||
Mock fixtures contain no live keys. Before removal, the old Native HTTP baseline passed 17 tests and the SDK/legacy business request/completion comparison passed. The retained comparison now uses the same pure core request/response contracts without the old HTTP backend.
|
||||
|
||||
All Cargo validation used `--locked --offline` and the existing shared target directory, after fetching the new registry dependencies. No existing locked package version was removed or replaced; 28 packages were added.
|
||||
|
||||
| Check | Result |
|
||||
| --- | --- |
|
||||
| `cargo fmt --all -- --check` | Passed. |
|
||||
| `cargo check -p nyaterm-core`, `cargo check -p nyaterm-desktop` | Passed. |
|
||||
| `cargo check --workspace` | Passed, including application and both helper crates. |
|
||||
| `cargo test -p nyaterm-core --lib` | 582 passed, 1 pre-existing ignored. |
|
||||
| `cargo test -p nyaterm-desktop --lib` (final source) | 2,583 passed, 12 pre-existing ignored. |
|
||||
| `cargo test -p nyaterm-core --test ai_parity` | 5 passed. |
|
||||
| AI-related Store tests | 36 passed; full workspace Store library: 233 passed, 1 pre-existing ignored. |
|
||||
| `cargo clippy -p nyaterm-desktop --all-targets` | Passed; initial new warnings were corrected. |
|
||||
| `cargo clippy --workspace --all-targets` | Passed with no warnings. |
|
||||
| `python3 scripts/ci/check_architecture.py`, `git diff --check` | Passed. |
|
||||
| `cargo test --workspace` with the root-container runner described below | 5,118 passed, 0 failed, 27 pre-existing ignored across unit, integration and doc-test summaries. Includes console/JSONL logging subprocess tests. |
|
||||
| Latest AI HTTP suite from the workspace-built Desktop test binary (`http::ai`) | 36 passed, including the subsequently added long-Gemini-stream and authenticated SOCKS tests. |
|
||||
| `cargo test --workspace --no-run` | Passed for the final source, including those two additional tests. |
|
||||
|
||||
The first root-run workspace test passed Core, Desktop, app logging, Store and the helper suites, then exposed existing transport test environment assumptions: a read-only file was writable through root's DAC override, and concurrent temporary shell fixtures intermittently reported `ETXTBSY`. Removing DAC privileges for the entire suite is insufficient because another root-specific test deliberately changes file ownership; the system `nobody` account also lacks the home directory required by PTY tests. A root login-shell fixture also exceeded its timeout; selecting `/bin/sh` passed it. The successful workspace run used `CARGO_TARGET_X86_64_UNKNOWN_LINUX_GNU_RUNNER='python3 /tmp/nyaterm-ai-test-runner.py'` to run transport serially with `SHELL=/bin/sh` in two batches: 687 cases in the ordinary root environment, and `staged_write_preserves_existing_permissions` alone with `setpriv --bounding-set=-dac_override,-dac_read_search` (1 passed). Every test runs; no Cargo feature is disabled. Other workspace test binaries run normally. No transport production/test source was changed for this migration. The unmodified root invocation is not claimed to pass.
|
||||
|
||||
Compatibility coverage includes the existing Store tests for legacy embedded AI settings, v6 unknown fields, encrypted/masked provider keys and custom headers, Tauri account/model extensions through reorder/delete/backup, history metadata and unknown fields, and encrypted portable/Tauri snapshots. New ephemeral fields are checked against the old serialized request/Agent contracts.
|
||||
|
||||
Mock protocol tests cover all routing matrix entries, account/header/query isolation, same/cross-origin redirects, discovery pagination, explicit reasoning values and thinking budgets, 64-token connectivity requests, typed HTTP errors, incomplete arguments, synthetic End/EOF, UTF-8 splitting, full queues and cancellation, signed/redacted Anthropic turns, stateless Responses items, and Gemini function identity/signature replay. The SOCKS test checks real username/password negotiation and a domain-name CONNECT for an unresolvable `.invalid` origin. Existing Harness/capability tests exercise approval/rejection, risk escalation, step limits, execution and multi-scope cancellation; new state tests cover immutable provider/policy snapshots and provider deletion.
|
||||
|
||||
| Platform | Automated evidence and remaining manual checks |
|
||||
| --- | --- |
|
||||
| Linux (Ubuntu 26.04, Rust 1.99.0) | Native workspace builds and mock/unit/integration tests below. Still verify actual GPUI windows, closing/switching sessions during live streaming, system proxy settings, and native trust-store integration on a desktop. |
|
||||
| macOS | No macOS SDK or native build environment available here. Build and run on macOS; check system proxy/Keychain trust, multiple windows, cancellation and application exit. |
|
||||
| Windows | No Windows MSVC/ATL build environment available here. Build and run with the supported Windows toolchain; check system proxy/bypass, SOCKS authentication, certificate trust, cancellation and application exit. |
|
||||
|
||||
Live API account tests remain manual/optional on all platforms; no real provider credential was used. No latency, binary-size or compile-time comparison is claimed.
|
||||
|
||||
Reference: [genai 0.7.3 source](https://docs.rs/crate/genai/0.7.3/source/), [Responses function calling](https://developers.openai.com/api/docs/guides/function-calling), [stateless reasoning](https://developers.openai.com/api/docs/guides/reasoning).
|
||||
@@ -1,75 +0,0 @@
|
||||
# Fork 上游同步报告:2026-11-03
|
||||
|
||||
本轮固定计划中的七个上游目标,重放 NyaTerm 补丁并发布 `nyakang/*:nyaterm`。主项目仅保留工作区差异,不创建提交。原有未提交修改作为集成基线;`temp/vendor` 未编辑。
|
||||
|
||||
## Revision 与回退
|
||||
|
||||
| 仓库 | 原 nyaterm / 回退 revision | 固定上游目标 | 发布 revision |
|
||||
| --- | --- | --- | --- |
|
||||
| russh | `3092e06cc827fc0f8d4c991280478f6e53c121a3` | `183a22e8f8f490fa09b6eb7bd044ef99d8c4414f` | `831c8ddd2898f472fb88e80a93cbf9beb40a0fe2` |
|
||||
| vnc-rs | `336ed94c9cce7cba93fa8cba33b5a5d01ef2c227` | `45f6d3688ec77ec7f4976dc313ce28ed82a375a5` | `7f9f0e5b57eec212f0926c54cdc7ae579dfe322a` |
|
||||
| alacritty | `3b60b2ed9544cad2cbba9e92fa0785e885cb4af1` | `aecf0f600fa840a415b55da5cf34fbeaec39ac32` | `86ff089983b93700c065ae3ae57273addf561fe7` |
|
||||
| sspi-rs | `d2b04e63ca9a72f2a70b456186e2472b27f0d45d` | `1cd2febae1efebf5d7337e17ca410bee94ff97df` | `582bd37e355d710a0888faded5f4f6da4667c3c8` |
|
||||
| IronRDP | `b10cd243bc9442a07fcd776568a5fdaf1c64492f` | `37ce7d1b6957b9901edfc511aedba8e8d548cb55` | `a15d5faa54192ad0eb2a1f9f4c9d8e1f06295970` |
|
||||
| zed | `597ca983eb6facf1a8528a56204aeeb7c857eaf6` | `f4d40a2ccb88dd660abd81b85256c0ffe7e25efb` | `a755e55acb90229c687e64e6a84877fb70d21619` |
|
||||
| gpui-kit | `7952df45d0f719525fe969b8991b39f7692f7f58` | `4cbbc0190c03a4a5e875785b45a00174609ffa84` | `9143df9774d0190162053defc9b1faac3f8ab907` |
|
||||
|
||||
每个远端均保留 `backup/nyaterm-20261103`,指向上述原 revision。首次发布以原 SHA 为 lease,后续补丁和文档提交以已发布 SHA 为 lease;远端 tip 均再次读取核对。回退需撤回本任务的 API/测试适配并恢复整组旧 pins 与锁文件,同时保留用户原有及后续修改;仅改 revision 会与新 API 适配冲突。SSPI/IronRDP、Zed/Kit 必须成组恢复。旧 SHA 由备份分支保留,主项目回退不必移动远端 nyaterm。
|
||||
|
||||
russh-sftp 仍为 `b638b4896de6a0efd699e4c3833873221b3b3f01`;zmodem2 仍为 `87a80216179f29d90e0b8c06ee5b4a6a0132c763`。
|
||||
|
||||
## 补丁审计与主项目适配
|
||||
|
||||
- russh:融合上游认证前 keepalive 定时器重置;保留 Strict/Compatible、严格超时计数、无需回复的探测不占响应队列;测试 handler 适配 VerifiedPublicKey。
|
||||
- VNC:保留上游先发布服务器布局再交付像素的顺序;客户端 resize 确认仍整包原子提交。资源上限、RA2 信任、安全类型选择未放宽。
|
||||
- Alacritty:scroll epoch 与 screen/reset generation 两项补丁原样重放;未引入应用层。
|
||||
- SSPI:0.23.1、picky rc.27;保留 ASN.1 最低版本 0.5.7/0.15.5 对旧 consumer lock 的兼容约束,独立 aes-gcm 0.11 消费验证通过。
|
||||
- IronRDP:保留有序全帧请求、认证 loopback relay、原 TLS/CredSSP 身份、证书回调权威性与 relay 重定向拒绝。旧 SSPI 版本升级补丁由上游 0.23.1/rc.27 替代,独立保留 fork 来源覆盖;智能卡路径继续排除。独立审查未发现生产策略差异的新缺陷。
|
||||
- Zed:保留动态纹理、原生拖放/file promise、取消手势、模态窗口、IME、Native RDP 浮层与游标补丁;融合 upstream objc2 Metal 迁移及 entity access tracking。旧 Metal 原始分配 workaround 被上游 typed/fallible allocation 完整替代,DirectX 检查保留。旧纯导入格式补丁由本轮 rustfmt 替代。
|
||||
- DirectX:构造目标为 lower 时 above_children 同步初始化为 false;回归测试走真实构造路径并验证双目标切换。失败回滚和设备恢复保留。macOS 游标状态锁在 AppKit 调用前释放。
|
||||
- Kit:升至 0.9.0,菜单外观/行高、标签布局、scrollbar hover、宏路径、原生浮层完整保留。融合 checkable 菜单状态、安全边距与关闭动画。关闭动画保留视觉但释放模态输入;既有点击穿透测试先失败、修复后通过。新增逻辑生命周期句柄,让解锁流程在弹窗开始关闭时立即拒绝旧结果,同时保留退出画面。
|
||||
- 主项目:适配 ScrollEvent、on_scroll、ScrollSource;动态快捷键改用 KeyBinding::load 并保留原存储格式;滚动视口测试标记放入受限 shell;插件取消测试显式等待调度器释放接收端;只读菜单测试按上游跳过禁用项的导航规则验证禁用 Cut 与可用 Copy;RDP Input 0.9、PDU 0.11、SVC 0.10、Clipboard 0.9、Connector 0.12。所有 IronRDP patch 固定同一 revision,直接 GPUI 与 Kit 六个 Zed 依赖固定同一 revision。
|
||||
|
||||
最终全量测试编译还发现一处测试辅助函数接收普通 &str,但新 Keystroke::parse 要求静态输入;其所有调用点均为字面量,已收窄参数寿命并重跑。
|
||||
|
||||
未改变持久化格式、helper IPC 或产品功能开关。每个 fork 的 NYATERM.md 记录基线、补丁融合与本轮实际验证。独立工作区保留旧补丁完整 diff、旧日志、最终 range-diff 和相对固定上游的 diff。
|
||||
|
||||
## 验证
|
||||
|
||||
除另列 WSL 外,命令均在 Windows x86_64/MSVC 上执行;各 fork 使用其工具链配置,主项目使用 Rust 1.99。
|
||||
|
||||
| 范围 | 实际结果 |
|
||||
| --- | --- |
|
||||
| russh | 201 库测试、认证前 keepalive、窗口计数、signer failure 回归、fmt、lib Clippy 通过。 |
|
||||
| VNC | all-features debug/release 各 79 测试、fmt、all-target all-feature Clippy 通过。 |
|
||||
| Alacritty | 137 库测试、45 个参考终端、1 doc test、all-target Clippy 通过。 |
|
||||
| SSPI | 451 库测试、check、fmt、稳定 aes-gcm 0.11 外部消费通过。 |
|
||||
| IronRDP | rustls / clipboard / UDP 组合、connector/acceptor/VMConnect check、fmt、client Clippy 通过;显式 --lib 的 30 个客户端测试在 Windows 与 WSL 均通过。 |
|
||||
| Zed | Windows 串行:GPUI 428 通过、2 ignored;gpui_windows 60 通过、1 ignored(subprocess fixture);gpui_platform check、限定格式检查通过。 |
|
||||
| Kit | Windows 串行:Base 1554 单元 + 2 外部测试,Component 757,facade export 编译检查通过;统一 GPUI pin 检查通过。 |
|
||||
| 批次集成 | 第一批 package check、第二批 transport/terminal/helpers/remote-desktop 测试、第三批 workspace check 通过。 |
|
||||
| 最终 `cargo check --workspace --locked` | 通过;日志 `integration-complete-check-0.log`。 |
|
||||
| 最终 `cargo test --workspace --locked -- --test-threads=1` | 通过;日志 `integration-complete-check-1.log`。 |
|
||||
| 最终 `cargo fmt --all -- --check` | 通过;日志 `integration-complete-check-2.log`。 |
|
||||
| 最终 `cargo clippy --workspace --all-targets --locked` | 通过;日志 `integration-complete-check-3.log`。 |
|
||||
| 最终 `cargo build -p nyaterm-rdp-helper -p nyaterm-vnc-helper --locked` | 通过;日志 `integration-complete-check-4.log`。 |
|
||||
|
||||
最终 workspace 测试按各目标汇总:5053 项通过,42 项忽略,0 失败。
|
||||
|
||||
Clippy 使用仓库默认警告策略;上游警告保留,未全局禁用。正式验证使用已发布 git revision,并以 --locked 固定依赖图。
|
||||
|
||||
## 验证边界
|
||||
|
||||
- Windows Native RDP 的真实画面、浮层、点击、游标、焦点、IME、关闭流程均未完成真实会话验收。桌面自动化初始化返回 native pipe 不存在(os error 2);OS 级自动化窗口测试不能替代真实 RDP 会话。
|
||||
- 未连接真实 SSH/VNC/RDP/NLA/relay/clipboard 服务器。宏观互操作性和 GPU/驱动组合仍需人工验收。
|
||||
- WSL 覆盖 IronRDP 客户端 30 项;Zed/Kit 的 Linux 图形后端与 macOS 原生路径未本地执行。
|
||||
- IronRDP GitHub Actions 仍禁用;未修改仓库设置,未宣称远端 CI 成功。
|
||||
- 忽略项及上游不启用的测试目标不计为已执行;IronRDP 使用显式 --lib,避免 test=false 漏测。
|
||||
|
||||
## 工作区、证据与复现
|
||||
|
||||
主项目原始 HEAD:`e855789e2269841a4e84c9ffb78c2808c30cc793`。验证工作副本继承当时所有未提交改动;回填逐文件与原字节/HEAD 比较,只应用任务差异,并保留期间新增的 docs/windows-native-rdp.md 修改。主项目未 stage、未 commit。
|
||||
|
||||
独立工作区:`E:/Projects/Rust/nyaterm-fork-sync-20261103`。`artifacts/` 下保存 baseline.json、原字节备份、每仓 published.json、final-range-diff.txt、final-delta.patch、检查日志/结果、依赖图、回填前文件备份与 task-files.json。`run_checks.py` 和 checks-*.json 可复现本轮命令。
|
||||
|
||||
远端依赖图检查结果见 artifacts/dependency-audit.json;helper 有效 feature 图无 smart-card/scard/winscard/cryptoki 路径。Cargo.lock 中可包含跨平台或未启用的可选包,不能据此推断运行时启用。
|
||||
@@ -1,324 +0,0 @@
|
||||
# OpenDAL cloud sync migration
|
||||
|
||||
## Source audit (2026-11-04)
|
||||
|
||||
Initial audit base: origin/main, 9fed0698c. Worktree: ../nyaterm-opendal; branch:
|
||||
feat/opendal-cloud-sync. The original index and working files are untouched.
|
||||
|
||||
The current source has a separate nyaterm-sync crate for V4 merge/publication
|
||||
contracts. The synchronous CloudSyncRemote remains in nyaterm-core. Desktop
|
||||
blocking jobs construct remotes per operation, inside the existing operation
|
||||
registration/lock. GPUI only receives job results. CloudSyncOperationControl
|
||||
arbitrates Preparing -> Cancelled/Committing; committing is not interrupted.
|
||||
|
||||
The desktop provider facade reloads credentials and checks their identity before
|
||||
constructing a remote. Token sinks persist rotated credentials through the Store
|
||||
actor and reject superseded accounts. ObservedRemote and CachedMetadataRemote
|
||||
wrap the backend, with process-owned caches keyed by database/account/password/
|
||||
root. V3 publishes verified encrypted snapshots, causal heads and pointers. V4
|
||||
publishes immutable writer objects, verifies read-back, then registers the writer;
|
||||
Store retains pending publications for recovery. None of these contracts should
|
||||
move into OpenDAL.
|
||||
|
||||
The Tauri reference used OpenDAL 0.58, timeout/retry/tracing, a custom Digest
|
||||
transport, and gist adapters. Its generic retries and error formatting are not
|
||||
suitable for the stronger GPUI commit, credential and diagnostic contracts.
|
||||
The published version selected here is 0.59.5 (Rust >=1.91). Its blocking API
|
||||
captures a runtime handle and calls block_on: it cannot safely be called from an
|
||||
arbitrary existing runtime. Use a joinable, operation-owned worker with one
|
||||
current-thread runtime instead. A bounded mailbox prevents detached requests;
|
||||
dropping the remote closes the mailbox and joins the worker. The worker also
|
||||
owns, constructs and drops the retained blocking directory clients outside
|
||||
block_on, avoiding nested-runtime creation/destruction. Its compatibility HTTP
|
||||
requests bind to the same statistics scope as OpenDAL requests. Cancellation
|
||||
remains at the existing protocol checkpoints, including the non-interruptible
|
||||
commit.
|
||||
|
||||
## Risk matrix
|
||||
|
||||
| Area | Risk | Migration gate |
|
||||
| --- | --- | --- |
|
||||
| WebDAV | Digest, NAS collection slashes, redirects losing methods/bodies or credentials | Reuse the native redirect policy and Digest signer in an explicit HTTP transport; local HTTP fixtures |
|
||||
| TLS | Losing Windows/system roots or disabling certificate validation | Reuse zed-reqwest with rustls native roots; never accept invalid certificates |
|
||||
| S3 | Lost ETag/304 optimization, bad pagination interpreted as deletion | Explicit conditional reads; retain strict list-page validation, prefix, token and capacity guards |
|
||||
| Publication | Retry of an ambiguous mutation, overwriting immutable bytes | No automatic mutation retry; explicit immutable checks and read-back; keep protocol commit/recovery |
|
||||
| OAuth | Rotated refresh token retained only inside OpenDAL | NyaTerm owns refresh; save via Store Token Sink before installing tokens or issuing another authenticated request |
|
||||
| Diagnostics | OpenDAL errors/spans expose URL, root, body or credentials | Controlled classifications and fixed operation labels; no raw OpenDAL Debug/Display in user diagnostics |
|
||||
| Compatibility | Provider root applied twice, snapshot/path/encryption drift | Preserve provider-root + remote-root composition and cross-backend tests |
|
||||
|
||||
Implementation and validation results are recorded below as each gate is checked.
|
||||
|
||||
|
||||
## Implemented architecture and provider status
|
||||
|
||||
Production call chain:
|
||||
|
||||
`GPUI background job -> existing operation control/credential identity checks
|
||||
-> provider facade -> ObservedRemote -> CachedMetadataRemote -> OpenDalRemote / OpenDalDriveRemote
|
||||
-> bounded joined worker -> OpenDAL Operator / fixed compatibility adapter
|
||||
-> zed-reqwest HTTP transport -> remote service`.
|
||||
|
||||
The synchronous trait and every explicit method remain available. No serialized
|
||||
settings, Store schema, encryption, master-password wrapping, account identity,
|
||||
V3/V4 wire document or published object name changes. Provider root is applied
|
||||
once, before the unchanged protocol remote root. There is no user-visible backend
|
||||
switch and no error-triggered fallback to a second writer.
|
||||
|
||||
| Provider/capability | Production implementation | Reason for retained code |
|
||||
| --- | --- | --- |
|
||||
| WebDAV object GET/conditional GET/PUT/DELETE | OpenDAL WebDAV 0.59.5 | Custom HTTP transport preserves Digest, safe redirects, native TLS roots, byte statistics and sanitized failures |
|
||||
| WebDAV create_dir | Native recursive MKCOL on the joined worker | Preserve NAS collection slash and existing-directory semantics without a mandatory timestamp |
|
||||
| WebDAV list_files/list_sync_files/list_metadata | Native strict PROPFIND parser on the joined worker | OpenDAL requires getlastmodified even when a server returns only resourcetype; absent optional metadata must remain acceptable |
|
||||
| WebDAV write_sync_file | OpenDAL staging PUT, direct MOVE with Overwrite: F on the same HTTP transport, read-back verification | OpenDAL rename first PROPFINDs the source and requires optional metadata; no unsafe metadata fabrication |
|
||||
| S3 GET/conditional GET/PUT/DELETE | OpenDAL S3 0.59.5 | Explicit credentials/session token, region, endpoint, root and virtual-host settings; no environment/instance credential discovery |
|
||||
| S3 write_sync_file | OpenDAL conditional PUT (If-None-Match: *), idempotent byte check and read-back verification | An explicit create race is accepted only when the existing bytes match |
|
||||
| S3 create_dir | Explicit no-op | S3 has object prefixes rather than directories |
|
||||
| S3 list_files/list_sync_files/list_metadata | Native strict paginated ListObjectsV2 adapter on the joined worker | Preserve optional metadata, prefix filtering, duplicate/token/capacity guards and malformed-page fail-closed behavior |
|
||||
| Google Drive | OpenDAL GDrive, NyaTerm OAuth and strict directory/publication adapters | Complete raw query pagination prevents OpenDAL's pageSize=1 resolver choosing an ambiguous name; move complete staged objects by ID and recheck uniqueness |
|
||||
| OneDrive | OpenDAL OneDrive, NyaTerm OAuth and strict directory/publication adapters | Fail-on-conflict publication; normalize only valid completed final-fragment HTTP 200 responses; validate signed URLs and nextLink |
|
||||
| AliyunDrive | OpenDAL AliyunDrive, NyaTerm OAuth and strict directory/publication adapters | Move completed staging objects with refuse; never enter destructive replacement; explicitly handle empty uploads |
|
||||
| GitHub Gist / Gitee snippet / local directory | Existing implementation | Explicitly outside the storage-backend migration |
|
||||
|
||||
All five storage services now use OpenDAL for ordinary object access. Fixed
|
||||
compatibility adapters provide directory traversal and immutable publication
|
||||
where stock service semantics are insufficient. Native Drive remotes remain as
|
||||
comparison oracles in tests, with no production fallback.
|
||||
|
||||
Drive services receive only a non-secret placeholder access token. The HTTP
|
||||
boundary replaces it with the NyaTerm token for exact trusted provider API
|
||||
origins. OpenDAL receives no refresh token, client ID or client secret. A 401
|
||||
from an authenticated API request permits one refresh/replay; generic 403,
|
||||
rate limits, signed URL failures and ambiguous mutation failures do not refresh
|
||||
or replay mutations. Google and Microsoft refresh credentials are sent in form
|
||||
bodies, Aliyun credentials in JSON, never in URL queries. The synchronous Store
|
||||
sink runs on the joined storage worker with no await between persistence and
|
||||
installation. Superseded-account and persistence failures retain their exact
|
||||
CloudSyncError variants across the OpenDAL boundary.
|
||||
|
||||
Drive publication uploads the final basename into an isolated
|
||||
`.sync-v4-staging/<random>/` subdirectory, verifies every byte, then moves by ID
|
||||
to the final parent and verifies again. Google permits duplicate names: complete
|
||||
query validation detects ambiguity before or after publication and stops without
|
||||
deleting either object. OneDrive and Aliyun request fail/refuse conflict modes.
|
||||
These narrow primitives use the same authenticated OpenDAL HTTP transport;
|
||||
stock rename implementations that replace or delete destinations are not used.
|
||||
Each operation uses fresh lightweight OpenDAL service/path caches while retaining
|
||||
the same HTTP client, authoritative token manager and joined runtime.
|
||||
|
||||
**Accepted Aliyun limitation:** existing identical bytes are idempotent, but
|
||||
replacing different bytes (including a V3 mutable pointer or a damaged V4 pending
|
||||
object) fails closed. Old objects and durable pending remain intact; automatic
|
||||
repair requires a future verified safe replacement primitive. V3 reading/import
|
||||
and new V4 publications work without changing the old data. No backend fallback,
|
||||
remote reset or destructive overwrite is used to hide this limitation.
|
||||
|
||||
## Execution, publication and diagnostics
|
||||
|
||||
Each operation owns one remote, one bounded mailbox (capacity one), and one
|
||||
current-thread Tokio runtime. Requests await their reply; no detached sync work
|
||||
is introduced. Blocking compatibility requests execute on the same worker but
|
||||
outside the runtime. Destruction joins the worker and destroys its blocking
|
||||
clients there. GPUI render/update callbacks do not perform storage I/O.
|
||||
Cancellation remains cooperative at existing protocol checkpoints; an in-flight
|
||||
request is bounded by HTTP timeouts rather than force-aborted. Once committing,
|
||||
existing operation control continues to reject cancellation. Pending publication
|
||||
and recovery remain in the protocol/Store owners.
|
||||
|
||||
TimeoutLayer uses 30-second operation/I/O limits. HTTP transport also has a
|
||||
30-second request timeout and a 10-second connect timeout. RetryLayer applies
|
||||
only to object reads (up to two retries, jitter). Rate limits/Retry-After are
|
||||
returned to the existing scheduler; mutations are never automatically replayed
|
||||
on network failure. WebDAV Digest challenges and approved redirects retain the
|
||||
original method/body. Cross-origin redirects, HTTPS downgrades and mutation 303
|
||||
responses cannot replay credentials or upload bodies. S3 redirects are rejected, including by the retained Native listing client, so
|
||||
custom x-amz-security-token headers cannot travel to another origin.
|
||||
|
||||
For V4, existing identical bytes are idempotent and differing bytes conflict.
|
||||
WebDAV stages under a hidden child directory, outside direct-child protocol
|
||||
enumeration; MOVE forbids overwrite. Staging is deliberately retained after an
|
||||
ambiguous failure, without deleting user objects. S3 uses a single conditional
|
||||
PUT. Successful publication is read back and compared. Network failures remain
|
||||
errors even if the server might have accepted the object, allowing existing
|
||||
pending-publication recovery to make the next decision.
|
||||
|
||||
HTTP status and Retry-After are sanitized; authentication, permission, DNS,
|
||||
connect, TLS, timeout and connection-reset categories reach CloudSyncError and
|
||||
the automatic sync classifier. The retained Native request helpers use the same
|
||||
transport classification, eliminating generic HTTP 0 for unclassified connection
|
||||
failures in directory requests too. OpenDAL error messages/source bodies and raw
|
||||
URLs never enter user diagnostics. Fixed provider/operation tracing spans replace
|
||||
stock TracingLayer, which records object paths. Retry notifications contain only
|
||||
attempt counters. Operator construction suppresses upstream builder debug logs
|
||||
that otherwise include endpoint/root configuration in the app log bridge. HTTP body statistics are shared across worker boundaries and
|
||||
count partial received bodies and authentication/redirect attempts.
|
||||
|
||||
## Changed file responsibilities
|
||||
|
||||
| Files | Responsibility |
|
||||
| --- | --- |
|
||||
| Cargo.toml, Cargo.lock, desktop/Cargo.toml | Pin OpenDAL, select minimal services/layers, reuse HTTP types; test-only TLS fixture dependencies |
|
||||
| core/src/cloud_sync/error.rs and mod.rs | UI-independent sanitized storage categories; no persisted format changes |
|
||||
| desktop/src/http/cloud_sync/opendal/mod.rs | Full CloudSyncRemote facade, configuration, conditional reads and immutable publication |
|
||||
| opendal/worker.rs | Bounded synchronous/async bridge and joined ownership of runtime/compatibility clients |
|
||||
| opendal/transport.rs | Existing zed-reqwest TLS stack, safe redirects/Digest, request/body accounting |
|
||||
| opendal/error.rs | Controlled OpenDAL-to-domain conversion, no backend diagnostic leakage |
|
||||
| http/cloud_sync/helpers.rs, metrics.rs, webdav.rs, s3.rs, mod.rs | Share Digest/header parsing, transport classification, worker statistics scope, narrow redirect adapter and S3 redirect isolation |
|
||||
| features/sync/cloud_sync_provider.rs | Select OpenDAL for WebDAV/S3 while preserving credential, observation and cache wrappers |
|
||||
| app_shell/controller/auto_sync/coordinator.rs and tests.rs | Permanent versus retryable typed storage errors |
|
||||
| opendal/tests.rs, tests/fixture.rs | Stateful native/OpenDAL HTTP compatibility, TLS, errors and publication fault tests |
|
||||
| features/sync/cloud_sync_v4/tests.rs | Production-factory V3 migration, two-device stale preview/conflicts, cancellation and historical bytes |
|
||||
|
||||
## Dependencies and platform scope
|
||||
|
||||
OpenDAL is pinned to **=0.59.5**, default features disabled. Enabled features:
|
||||
`executors-tokio`, `services-webdav`, `services-s3`, `services-gdrive`,
|
||||
`services-onedrive`, `services-aliyun-drive`, `layers-timeout`, `layers-retry`.
|
||||
No stock reqwest transport, tracing layer or new fork patches are enabled.
|
||||
`http = 1` bridges its HTTP API to the existing zed-reqwest client. TLS continues to use the workspace's
|
||||
`rustls-tls-native-roots` feature, including Windows system trust.
|
||||
`rcgen = 0.14` and `rustls = 0.23` are test-only dependencies for a generated
|
||||
localhost certificate; no private-key fixture is committed. OpenDAL's MSRV is
|
||||
Rust 1.91; this run uses Rust/Cargo 1.99 on Windows, and CI selects stable.
|
||||
Linux/macOS runtime behavior still needs their existing CI jobs.
|
||||
|
||||
## Previous WebDAV/S3 validation results
|
||||
|
||||
Executed on Windows x86_64/MSVC, Rust/Cargo 1.99.0. Logs are untracked under
|
||||
`target/opendal-*.log`.
|
||||
|
||||
| Command | Result |
|
||||
| --- | --- |
|
||||
| `python scripts/ci/check_architecture.py` | Passed |
|
||||
| `cargo fmt --all -- --check` | Passed |
|
||||
| `git diff --check` | Passed |
|
||||
| `cargo check --workspace` | Passed, including application and both helpers |
|
||||
| `cargo test -p nyaterm-core --lib` | 582 passed, 1 ignored |
|
||||
| `cargo test -p nyaterm-desktop --lib` | 2619 passed, 12 ignored |
|
||||
| `cargo test --workspace` | 5173 passed, 43 ignored across 51 suites (including doctests) |
|
||||
| `cargo clippy --workspace --all-targets` | Passed without warnings |
|
||||
| `cargo check -p nyaterm-desktop` | Passed |
|
||||
|
||||
The workspace total is from the broader run; the final desktop rerun includes
|
||||
the subsequently added S3 listing redirect regression. Clippy and the desktop
|
||||
check were repeated after final source cleanup.
|
||||
|
||||
The desktop run includes 18 OpenDAL storage tests and one production-factory
|
||||
V3-to-V4 integration test that runs against both WebDAV and S3. Coverage:
|
||||
|
||||
- Native -> OpenDAL -> Native encrypted V3 round trips, old revision bytes
|
||||
retained, provider-root/remote-root paths and direct-child V4 listings.
|
||||
- Basic/Digest, 301/302/307/308 mutation body preservation, rejected 303
|
||||
mutation/cross-origin replay, generated HTTPS certificate rejection and
|
||||
explicitly trusted test CA success.
|
||||
- NAS responses without timestamps, recursive MKCOL, strict malformed XML and
|
||||
repeated pagination-token rejection, S3 multi-page Prefix/metadata/session
|
||||
credentials, default/custom/virtual-host endpoint and Unicode/percent paths.
|
||||
- Conditional GET ETag/304 across adapter reconstruction, changed/deleted
|
||||
objects, no HEAD race, compatible 400/405/501 fallback, HTTP status and
|
||||
Retry-After, timeout/reset/partial-body counters, redacted error content.
|
||||
- Acknowledgement loss after an accepted upload returns an error without
|
||||
replaying mutations or deleting legacy objects. WebDAV retains staging;
|
||||
subsequent explicit S3 recovery recognizes the exact complete bytes.
|
||||
- Joined worker construction, directory requests, statistics and destruction
|
||||
from within an existing Tokio runtime, without nested block_on.
|
||||
- Production-factory V3 migration, two-device V4 synchronization, stale preview
|
||||
rejection/conflicts, cancellation before publication and old bytes retained.
|
||||
Existing core tests exercise cancellation versus commit races; existing V4
|
||||
tests exercise durable pending publication, response loss, new edits during
|
||||
recovery and rotated-password compatibility.
|
||||
- Existing Drive parser/token-sink tests run in the full desktop suite, including
|
||||
Store-write failure before token installation and refresh-token retention.
|
||||
Live OAuth service behavior still requires the external checks below.
|
||||
|
||||
The initial local fixture inherited nonblocking sockets on Windows and produced
|
||||
spurious connection resets. Accepted sockets are now explicitly blocking with
|
||||
bounded reads; this fixture correction was necessary to make fault tests
|
||||
represent actual HTTP failures. No production TLS checks were relaxed.
|
||||
|
||||
## External integration checks and remaining limits
|
||||
|
||||
Use disposable accounts/buckets/NAS directories and a separate application
|
||||
configuration. Never use production snapshots for fault injection.
|
||||
|
||||
1. Flying Bull NAS 1.2.0800 (Issue #1067): on Windows, compare 1.3.2/2.0.0 and
|
||||
this branch with the same certificate/network; test Basic/Digest, HTTP/HTTPS,
|
||||
collection slash redirects, sleep/reconnect and transient connection resets.
|
||||
Confirm the error category and I/O counters without collecting terminal data
|
||||
or credentials. Local equivalents do **not** establish that #1067 is fixed.
|
||||
2. AWS S3 plus a compatible service (e.g. MinIO): test endpoint/path/virtual host,
|
||||
region/session credentials, trusted TLS, >1 listing page, ETag/304, limits,
|
||||
offline interruption and recovery. Compare old/new object names and verify
|
||||
both clients can read their encrypted snapshots.
|
||||
3. Google Drive/OneDrive/AliyunDrive: use a disposable account and a fresh provider
|
||||
root; configure existing OAuth settings and select V4 through the existing UI.
|
||||
Test access expiry, optional refresh-token rotation, revoked access, account
|
||||
replacement and Store-write failure. Verify that refreshed tokens survive an
|
||||
application restart. Populate multiple pages, exercise empty/4 MiB/64 MiB
|
||||
uploads, interrupt upload/final move, then recover durable pending on restart.
|
||||
In OneDrive Personal and Business, verify fail-on-conflict moves and final
|
||||
upload-session 200/201 responses. In Aliyun default/resource/backup drives,
|
||||
verify refuse-on-conflict moves and that an existing different object is
|
||||
preserved and reported as a conflict. In Google, inject a duplicate file or
|
||||
folder in the disposable root and confirm synchronization stops without
|
||||
deleting or merging either copy. Signed URL traffic must contain no Bearer.
|
||||
Use only a test account for token revocation or refresh-rotation fault tests.
|
||||
4. For each migrated service, import existing V3 data, join two V4 devices,
|
||||
create offline edits/conflicts, cancel before commit, attempt cancel during
|
||||
commit, lose an upload acknowledgement and restart with pending recovery.
|
||||
Verify old revisions remain readable and the master password is unchanged.
|
||||
|
||||
Snapshots remain buffered as required by the existing byte-vector trait; this
|
||||
change does not introduce a persistent resumable-upload journal. OneDrive uses
|
||||
OpenDAL upload-session fragments and Aliyun uses its upload/complete protocol;
|
||||
interrupted work is recovered by the existing immutable pending bytes, not by
|
||||
blindly replaying unknown mutations. Interrupted WebDAV/Drive staging objects
|
||||
and empty staging directories can accumulate and are intentionally not
|
||||
auto-cleaned. S3-compatible services must implement conditional PUT correctly; unsupported
|
||||
publication fails closed. MOVE atomicity/Overwrite enforcement and correct TLS
|
||||
root installation must be verified on real services. No real external account or
|
||||
NAS was accessed, and no issue is claimed fixed solely from adopting OpenDAL.
|
||||
|
||||
## Drive migration validation
|
||||
|
||||
Drive read retries wrap individual read-only HTTP exchanges rather than entire
|
||||
OpenDAL operations. This prevents RetryLayer/TimeoutLayer interactions from
|
||||
replaying a refresh-token rotation whose response was lost. API 401 refresh is
|
||||
bounded to once per rejected request; refresh errors retain their safe category
|
||||
but are not automatically retried inside the operation.
|
||||
|
||||
The additional local HTTP fixture executes real OpenDAL GDrive/OneDrive/
|
||||
AliyunDrive service requests and test-only routed Native requests against the
|
||||
same state. It covers all nine remote methods, multi-page listings, invalid
|
||||
cursors and nextLink origins, duplicate Google paths/incompleteSearch, refresh
|
||||
success/invalid grant/omitted rotation, Store persistence and account replacement,
|
||||
403/429 + Retry-After, empty/4 MiB/64 MiB uploads, failed upload without replay,
|
||||
OneDrive completed 200 versus incomplete 202, signed download redirects, immutable
|
||||
conflicts and lost publication acknowledgements. Production-factory tests import
|
||||
Native V3 snapshots, recover durable pending and synchronize conflicting offline
|
||||
edits between two V4 devices while retaining the original bytes.
|
||||
|
||||
No real OAuth account has been accessed by these tests. The fixture validates
|
||||
client contracts, not undocumented server atomicity or real-account permissions.
|
||||
The external checks above remain necessary on Windows and Linux/macOS.
|
||||
|
||||
Final validation on Windows x86_64/MSVC, Rust/Cargo 1.99.0, after merging
|
||||
main cb3997d3e (including its AI dependency migration):
|
||||
|
||||
| Command | Result |
|
||||
| --- | --- |
|
||||
| `cargo check --locked --workspace` | Passed |
|
||||
| `cargo test --locked --workspace` | 5230 passed, 43 ignored, 51 suites including doctests |
|
||||
| Desktop library tests (workspace run) | 2667 passed, 12 ignored |
|
||||
| Core library tests (workspace run) | 585 passed, 1 ignored |
|
||||
| `cargo clippy --locked --workspace --all-targets` | Passed without warnings |
|
||||
| `cargo fmt --all -- --check` | Passed |
|
||||
| Architecture check and `git diff --check` | Passed |
|
||||
|
||||
The final complete workspace run includes the read-retry/OAuth classification
|
||||
cleanup and both refresh-failure regressions. The Cargo.lock merge preserves
|
||||
both branches' dependency additions without adding versions outside their union;
|
||||
locked metadata, workspace check, tests and Clippy validate the resolved graph.
|
||||
Test-only URL routing is compiled out of production; it lets Native and OpenDAL
|
||||
execute their actual HTTP protocols against the same fixture. The merge retains
|
||||
main's unrelated changes; the PR diff contains the cloud-sync implementation and
|
||||
its tests and documentation.
|
||||
@@ -1,68 +0,0 @@
|
||||
# Terminal wrapping
|
||||
|
||||
Terminal general settings expose **Character wrap** (default), **No wrap**, and
|
||||
**Show wrap markers** (off by default). These are local preferences and use the
|
||||
ordinary settings preview, cancel, and save workflow.
|
||||
|
||||
No wrap joins retained soft-wrapped grid rows for display. Real newlines remain
|
||||
separate. Horizontal position belongs to each terminal surface; use a trackpad,
|
||||
Shift + wheel, or the horizontal scrollbar, which appears on hover. Search and
|
||||
keyboard input reveal the target column. Copy uses source cells and adds neither
|
||||
soft newlines nor marker glyphs.
|
||||
|
||||
Alternate screen, mouse reporting, application cursor/keypad modes, Kitty keyboard
|
||||
modes, partial scroll regions, and active graphics use the ordinary grid and show a short status
|
||||
hint. Leaving those modes restores the selected display policy. PTY columns and
|
||||
VT autowrap remain controlled by the normal window geometry and terminal
|
||||
protocol. A wide character's wrap spacer is not a logical column.
|
||||
|
||||
Wrap markers occupy a separate one-cell lane after the grid and appear only
|
||||
after an actual soft wrap. With no wrap selected, glyphs are hidden but the
|
||||
enabled lane stays reserved, so switching the display mode never resizes the PTY. Explicitly
|
||||
toggling the marker preference updates the normal grid/PTY geometry.
|
||||
Vertical wheel input scrolls history only. Horizontal trackpad input, Shift +
|
||||
wheel, and dragging the horizontal scrollbar pan long lines; the scrollbar's
|
||||
measuring container does not consume wheel input a second time.
|
||||
|
||||
Only retained soft wraps can be joined. Hard newlines and overwritten or evicted
|
||||
content cannot be reconstructed. Existing keyword limits for pathological long
|
||||
lines still apply.
|
||||
|
||||
## Automated coverage
|
||||
|
||||
Tests cover old/default settings, document round trips and unsupported values,
|
||||
draft save/cancel, worker session inheritance, immutable logical indices,
|
||||
history rotation, resize/clear, hard versus soft breaks, wide/combining text,
|
||||
protocol/graphics fallback, logical scrolling, bounded visible paint segments,
|
||||
marker timing, the marker lane's painted bounds, independent horizontal offsets,
|
||||
one-axis wheel dispatch without duplicate panning, and word selection/copy after
|
||||
horizontal scrolling.
|
||||
Rendering tests also cover retaining unchanged output colors and glyph layouts
|
||||
while a new input frame waits for batch highlighting, including horizontal
|
||||
offsets and soft wraps. A changed wrapped matching context invalidates old colors.
|
||||
|
||||
Windows ConPTY integration also verifies that real CMD output preserves soft
|
||||
wraps and hard newlines for logical display while retaining the original PTY
|
||||
dimensions. This opt-in test passed on Windows on 2026-11-03:
|
||||
|
||||
```powershell
|
||||
cargo test -p nyaterm-transport --test local_shell_integration conpty_long_output_retains_soft_wraps_and_hard_newlines_for_logical_display -- --ignored --exact
|
||||
```
|
||||
|
||||
## Windows interactive acceptance (pending)
|
||||
|
||||
Use a disposable local shell and an explicitly selected SSH test host. These
|
||||
checks require a real window and interactive input; passing Rust tests does not
|
||||
complete them.
|
||||
|
||||
| Scenario | Expected result |
|
||||
| --- | --- |
|
||||
| Local shell and SSH: print a long line, then a hard newline | Only the soft-wrapped segments join; styles and spaces survive |
|
||||
| Trackpad, Shift + wheel, scrollbar drag, two panes | Smooth horizontal movement; offsets remain independent |
|
||||
| Drag, double/triple click, copy, OSC 8/action links, search | Targets agree with the painted columns, including across soft wraps |
|
||||
| Chinese IME after scrolling a long prompt | Cursor and candidate/composition anchor agree; input reveals cursor |
|
||||
| Scroll history during continuous output; change wrap mode | Content anchor and selection survive; manual horizontal position survives output; switching mode resets horizontal position |
|
||||
| Enter/exit Vim and tmux, toggle mouse/keypad modes | Grid fallback hint appears; selected mode returns afterwards; PTY size stays stable |
|
||||
| Display then delete terminal graphics | Grid is used while placements remain, then logical display returns |
|
||||
| Enable markers, fill exactly the last column, then print another character | No premature marker; marker appears after the real soft wrap; copying contains no glyph |
|
||||
| Resize and clear with markers enabled | Marker and click geometry refresh together |
|
||||
@@ -1,329 +0,0 @@
|
||||
# Windows Native RDP
|
||||
|
||||
Windows Native 使用系统安装的 `MsRdpClient9NotSafeForScripting`,要求
|
||||
`IMsRdpClient9`。它是用户明确选择的进程内系统组件;Builtin/IronRDP 和
|
||||
VNC 仍使用隔离 helper。系统 `mstscax.dll` 不随应用分发。
|
||||
|
||||
## 所有权与线程
|
||||
|
||||
`nyaterm-windows-rdp` 的生产依赖不包含 GPUI。Rust 宿主不可 Send/Sync,
|
||||
窄 C ABI 不公开 COM 指针。C++17 ATL shim 从本机系统类型库生成接口。
|
||||
事件回调只记录类型化事件,桌面层通过 generation 校验提交结果。
|
||||
|
||||
桌面维护循环先从 Entity 提取操作,释放 GPUI 借用,再在创建控件的
|
||||
UI/STA 线程执行操作,最后提交。布局阶段只记录与窗口客户区相交后的
|
||||
bounds,不调用 COM。初始化取消、会话替换和迟到事件不能恢复旧会话。
|
||||
|
||||
Connected、登录完成、重连和绘制子树就绪分开处理;连接建立且绘制子树
|
||||
有效后即显示登录界面,避免等待用户输入时被隐藏;登录完成仍单独推进
|
||||
会话状态。切页签只改变可见性。FitWindow 使用测量后的物理尺寸和
|
||||
DPI,动态更新防抖 400 ms,每个尺寸最多尝试四次;确认接口不支持后才
|
||||
启用 SmartSizing。固定分辨率保持配置尺寸。
|
||||
|
||||
## 浮层与输入
|
||||
|
||||
GPUI fork 将原窗口同一组件树中的浮层绘制到主窗口拥有的透明 Win32
|
||||
视觉 HWND,另用按交互区域裁剪的输入 HWND 接收鼠标。两者均为 owned
|
||||
popup,不是全局置顶窗口,也不拥有独立业务状态。视觉层与主窗口共用
|
||||
Direct3D 设备、纹理图集和渲染管线,设备重建后重建合成资源。
|
||||
|
||||
`nyaterm-ui` 提供区域、被动和模态三种呈现封装。菜单控件区域接收
|
||||
输入;定位用的整窗壳、阴影和 tooltip 不扩大输入区域;模态层阻断整个
|
||||
客户区。菜单外原始按下先通知关闭菜单,再交由原命中目标处理。原生子
|
||||
窗口的原始输入通过在 UI 线程回调的低层鼠标 hook 观察,仅处理注册
|
||||
owner 的子窗口点击;不重放、不再分发 GPUI bubble。
|
||||
原生键鼠、IME 和 Windows 快捷键继续由 ActiveX 处理,Canvas 全局键盘
|
||||
捕获在 Native 会话上禁用。Ctrl+Alt+Home 返回本地焦点。
|
||||
|
||||
合成初始化或运行失败会使 Native 会话显示明确错误。失败界面提供手动
|
||||
切换 Builtin;仅改变当前会话,不修改保存的连接。系统认证授权、服务器
|
||||
身份验证和剪贴板/资源授权继续执行,不能通过自动降级绕过。
|
||||
|
||||
## 认证与剪贴板策略
|
||||
|
||||
选择 Windows 后端即使用系统证书验证,`AuthenticationLevel = 2`。验证失败时,
|
||||
由系统控件提示用户继续或取消连接,不再使用严格拒绝模式。“不再询问”复选框
|
||||
及其保存行为以本机系统控件为准,不承诺与独立 mstsc 完全一致;不增加自动信任
|
||||
或绕过提示的逻辑。认证弹窗通过 `UIParentWindowHandle` 关联应用主窗口,
|
||||
避免默认关联隐藏的 ActiveX 子窗口;调用 Connect 前先设置控件尺寸。旧数据中缺失的
|
||||
`windows_authentication` 在启动配置中补为 `system`,未知值仍拒绝使用。
|
||||
保存的 Builtin 证书策略保持不变,不转换为系统信任授权。
|
||||
|
||||
RDP 剪贴板始终开启,连接编辑器不再提供模式选项。Builtin 始终启用文本和文件/目录通道;Native 将 `RedirectClipboard` 设置为 true,由微软控件处理完整重定向,实际格式能力仍受控件及服务端策略限制。应用的剪贴板轮询继续跳过 Native,避免重复处理。
|
||||
|
||||
保存字段与旧值继续兼容读写;只在临时启动配置中归一化为 `TextAndFiles`,覆盖启动、恢复、重连和后端切换,不批量改写旧连接。新连接默认保存完整模式。本机离线真实控件测试读回确认剪贴板已开启、动态资源仍关闭;该结果不能代替真实双向复制验收。
|
||||
|
||||
光标诊断默认关闭;设置 `RUST_LOG=warn,gpui::native_cursor=trace,nyaterm_windows_rdp::presentation=trace` 可记录消息来源 HWND、命中窗口、焦点 HWND、光标句柄,以及实际视口/远程分辨率更新,不记录窗口标题、连接数据或剪贴板内容。GPUI 不覆盖原生子树的光标,owned popup 菜单仍使用 GPUI 光标。相同视口继续去重,动态分辨率继续防抖。
|
||||
|
||||
动态驱动器和设备重定向通过 `IMsRdpClientNonScriptable3` 关闭;其他设置使用
|
||||
类型库的强类型接口,初始化失败返回具体属性和 HRESULT,不包含连接数据。
|
||||
|
||||
## 关闭与发布
|
||||
|
||||
关闭期间停止新输入和操作,将焦点归还父窗口。优先 RequestClose 并等待
|
||||
断开确认,正常等待预算为 3 秒。注销事件和释放前检查回调计数;无法
|
||||
安全释放的宿主留在 UI 线程退休队列,每秒重试,最长再等待 60 秒。
|
||||
最终仍不安全时保留上下文并记录脱敏计数,避免悬空回调。
|
||||
同步 COM 调用本身若卡死,截止时间无法抢占它。
|
||||
|
||||
应用退出先处理 Native 宿主和退休队列,再等待后台任务退出。旧
|
||||
`nyaterm-activex-helper`、专用 IPC 和环境变量入口已移除;IronRDP/VNC
|
||||
共享 IPC 版本保持不变。便携包、NSIS 和 MSI 更新均清理旧 helper。
|
||||
CI 安装 x64/ARM64 MSVC ATL 工具链。Windows 发布脚本统一为应用和 helper
|
||||
启用 `target-feature=+crt-static`,使 Rust 与 C++ 使用同一种静态 CRT,
|
||||
避免增加 VC++ redistributable DLL 的必需依赖。开发构建继续使用默认
|
||||
工具链运行库;无需手动进入 developer shell 即可发现本机 MSVC/ATL。
|
||||
|
||||
## 验收记录
|
||||
|
||||
用户已授权使用 computer-use 验证真实会话,Windows x64 桌面已可访问。
|
||||
测试连接使用已有保存项;不要
|
||||
将密码放入命令行、日志或测试文件。独立 smoke 程序启动方式:
|
||||
|
||||
```powershell
|
||||
cargo run -p nyaterm-windows-rdp --example native_overlay_smoke -- <保存的连接名称>
|
||||
```
|
||||
|
||||
此前在严格拒绝模式下,真实连接到达 Windows 证书验证界面,但服务器证书被
|
||||
系统拒绝。改为提示模式后的继续/取消行为仍待真实连接验收。此前结果只说明
|
||||
创建/连接已到达系统验证阶段,不能
|
||||
视为远程画面或交互验收通过。
|
||||
|
||||
| 项目 | 验收要求 |
|
||||
| --- | --- |
|
||||
| 登录与安全 | 真实登录、失败认证、证书警告后的继续/取消、剪贴板双向文本及文件/目录传输 |
|
||||
| 输入 | 中文 IME、系统快捷键、Ctrl+Alt+Home、无双重输入 |
|
||||
| 浮层 | 菜单区域命中、外部点击只执行一次、tooltip 穿透、模态阻断;远程画面持续更新 |
|
||||
| 布局 | 连续切页签、分屏、最大化、跨 DPI 显示器、动态/固定分辨率 |
|
||||
| 生命周期 | 断网重连、正常/强制关闭、退出、100 次循环后 HWND/句柄/内存无持续增长 |
|
||||
| ARM64 实机 | 在 ARM64 Windows 上单独记录真实会话;交叉编译不能替代 |
|
||||
|
||||
自动化检查结果在交付说明中列明。编译、日志和 HRESULT 不能替代上表的
|
||||
真实画面与交互验收。
|
||||
|
||||
## Fork revision
|
||||
|
||||
- GPUI/Zed `nyaterm`: `8ecf76c3abf4f3c564b14ce9de5181c9b42244b5`。
|
||||
- gpui-kit `nyaterm`: `30552806c6baf9e86b5ee5e087f462c6a1332972`。
|
||||
|
||||
两者的补丁、验证和剩余实机验收均记录在各自 `NYATERM.md`;主仓库
|
||||
`Cargo.toml` / `Cargo.lock` 固定远端 revision,不使用本地路径覆盖。
|
||||
|
||||
## 本轮自动化验证(Windows x64)
|
||||
|
||||
- `cargo check --workspace --locked` 已通过。
|
||||
- `cargo test --workspace --locked` 通过:5037 项通过、0 失败、42 项忽略,
|
||||
包含 IronRDP/VNC helper 握手、正常断开和崩溃/挂起回收测试,以及
|
||||
RDP 历史后端别名、未知值、认证和剪贴板限制的备份/同步往返。
|
||||
- `cargo clippy --workspace --all-targets --locked -- -D warnings` 已通过。
|
||||
- `cargo fmt --all -- --check` 和 `git diff --check` 已通过。
|
||||
- `cargo build -p nyaterm-app -p nyaterm-rdp-helper -p nyaterm-vnc-helper
|
||||
--bins --locked` 已通过;本机调试版为 `target/debug/nyaterm.exe`。
|
||||
本轮构建使用单任务以避开 Windows 页面文件并发压力。
|
||||
- Native 控制器/生命周期/显示/清理测试 10 项通过,包含退出发生在已提取
|
||||
操作期间的取消与等待;GPUI 浮层测试 5 项、Windows HWND 生命周期测试
|
||||
1 项通过。这些测试不连接远程服务器。
|
||||
- Python 脚本测试共 141 项,135 项通过、6 项因本机工具条件跳过,包含两种 Windows
|
||||
架构的包契约、旧 helper 清理和静态 CRT 构建参数。
|
||||
- 新 crate 的 Linux 生产路径检查通过:
|
||||
`cargo check -p nyaterm-windows-rdp --lib --target x86_64-unknown-linux-gnu --locked`。
|
||||
这不代表 Linux/macOS 整个应用的构建已在本机验证。
|
||||
- 独立 Windows x64 静态 CRT 链接程序已执行;无效父 HWND 被明确拒绝。
|
||||
正式发布脚本的 x64 `build_application` 已完整通过,包含主程序、IronRDP/VNC
|
||||
helper 和已有的 MCP 可执行文件。产物位于
|
||||
`target/x86_64-pc-windows-msvc/release/`;主程序为 `nyaterm.exe`。
|
||||
`dumpbin /DEPENDENTS` 确认这四个产物均无 MSVCP/VCRUNTIME 动态依赖。
|
||||
这些检查不能替代安装包和真实 RDP 画面的验收。
|
||||
- ARM64 交叉检查因本机缺少 `atlmfc/lib/arm64/atls.lib` 停止;自动安装
|
||||
ATL 返回 5007。CI 已增加 ATL/ARM64 组件安装,但尚未在本轮运行远端
|
||||
发布任务,不能记录为 ARM64 构建通过。
|
||||
|
||||
## ActiveX 初始化与设置联动修复验证(Windows x64)
|
||||
|
||||
- 本机真实 ActiveX 控件离线初始化、策略读回及释放测试通过,不连接服务器。
|
||||
- `cargo check --workspace --locked -j 1` 通过。
|
||||
- `cargo test --workspace --locked -j 1`:5046 项通过、0 失败、42 项忽略;
|
||||
包含旧配置归一化、未知认证拒绝、编辑器联动及启动/重试回归。
|
||||
- `cargo clippy --workspace --all-targets --locked -j 1 -- -D warnings` 通过。
|
||||
- `cargo fmt --all -- --check` 和 `git diff --check` 通过。
|
||||
- 尚未完成真实服务器登录、证书警告后的继续/取消、断网重连、剪贴板双向不传输及 ARM64 实机验收。
|
||||
|
||||
## 系统证书提示模式修复验证(Windows x64)
|
||||
|
||||
- `AuthenticationLevel = 2` 的真实控件离线读回测试通过;按当时策略,剪贴板及动态资源保持禁用(现行剪贴板策略见上文)。
|
||||
- workspace check、test、Clippy(`-D warnings`)、fmt 和 diff 检查均通过。
|
||||
- workspace 测试:5046 项通过、0 失败、42 项忽略。
|
||||
- `cargo build -p nyaterm-app --bin nyaterm --locked -j 1` 通过,调试版程序已更新。
|
||||
- 真实服务器证书警告的继续/取消,以及“不再询问”复选框和记忆行为,仍待实机验证。
|
||||
|
||||
## 登录界面与认证弹窗修复验证(Windows x64)
|
||||
|
||||
- 系统控件离线读回确认 `UIParentWindowHandle` 为应用父窗口,证书提示模式为 2。
|
||||
- 状态回归覆盖连接建立但尚未登录完成、绘制未就绪、重连及关闭时的显示条件。
|
||||
- Connect 前先设置控件视口尺寸;Connected 时允许显示并聚焦远端登录界面。
|
||||
- workspace 测试 5046 项通过、0 失败、42 项忽略;check、Clippy(`-D warnings`)、fmt 和 diff 检查通过。
|
||||
- 调试版 `target/debug/nyaterm.exe` 已重新构建。
|
||||
- computer-use 启动因 `GetCursorPos` 返回拒绝访问(0x80070005)受阻,停止 UI 操作;
|
||||
待用户解锁可访问桌面后,再验证真实会话画面和认证弹窗。尚未宣称现场问题已复现或验收通过。
|
||||
|
||||
## 持续显示“正在协商”的后续排查(Windows x64)
|
||||
|
||||
- 用户确认同一连接在 mstsc 可登录;NyaTerm 无认证弹窗且会打断同账号既有会话。
|
||||
此现象说明不能仅凭应用占位文案判定仍处于安全协商,尚需核对控件事件与画面。
|
||||
- 修正 OLE 宿主顺序:`CoCreateInstance` → `IPersistStreamInit::InitNew` →
|
||||
订阅事件 → `AtlAxAttachControl` → 配置。ATL 的 AttachControl 假定调用者已初始化,
|
||||
不会代为调用 InitNew;失败时返回对应接口/方法及 HRESULT。
|
||||
- 新增开始连接、认证警告显示/关闭、登录通知的事件诊断,以及连接数字状态、
|
||||
实际控件画面尺寸/可见性和显示条件的变更日志。不记录地址、账号、凭据或会话内容。
|
||||
`drawing_ready` 改为检查控件报告的实际子窗口及有效尺寸,连接状态读取失败不再默认为未连接。
|
||||
- 离线真实控件测试检查 800×600 画面布局;回环 TCP 测试验证开始连接及断开回调,
|
||||
不传输凭据,也不连接真实服务器。回环事件测试在补 InitNew 之前也能通过,
|
||||
因此它只验证事件链路,不能证明 InitNew 是现场卡住的唯一原因。
|
||||
- 解锁桌面后已通过 computer-use 复现占位文案持续显示;同次连接的脱敏事件
|
||||
依次到达 `Connected`、`LoginComplete`,`get_Connected = 1`,实际子窗口尺寸
|
||||
有效且可见。由此确认远端已登录,问题在本地画面合成层级。
|
||||
- GPUI owner 的 DirectComposition target 原先固定在 HWND 子窗口上方,遮住
|
||||
ActiveX 画面。原生子窗口模式现在切换到下方 target;菜单和弹窗继续使用
|
||||
独立 owned popup。切换时先从旧 target 移除 visual root,再挂到新 target 并
|
||||
一次提交,避免同一 visual 同时挂载导致 `E_INVALIDARG`;设备恢复也保留层级。
|
||||
- Zed Windows 测试通过:55 项通过、0 失败、1 项忽略,包含真实 compositor
|
||||
的反复切换和幂等回归。真实远程画面与交互验收在主程序依赖同步后进行。
|
||||
|
||||
## 合成层修复后的自动化验证(Windows x64)
|
||||
|
||||
- 使用远端固定 revision,`Cargo.lock` 中 GPUI 与 gpui-kit 各只有一套来源。
|
||||
- `cargo check --workspace --locked -j 1` 通过。
|
||||
- `cargo test --workspace --locked -j 1`:5048 项通过、0 失败、42 项忽略。
|
||||
原生 RDP 13 项测试全部通过,包括真实系统控件离线初始化、策略读回、
|
||||
有效绘图窗口尺寸及回环连接事件测试。
|
||||
- `cargo clippy --workspace --all-targets --locked -j 1 -- -D warnings` 通过。
|
||||
- `cargo fmt --all -- --check` 和 `git diff --check` 通过。
|
||||
- `cargo build -p nyaterm-app --bin nyaterm --locked -j 1` 通过,
|
||||
调试版程序位于 `target/debug/nyaterm.exe`。
|
||||
|
||||
## 主窗口重定向的后续修正(Windows x64)
|
||||
|
||||
- 仅调整 DirectComposition target 层级后,实机依然显示占位文字;同次连接
|
||||
已完成 `LoginComplete`。此前自动化通过不能视为画面问题已修复。
|
||||
- GPUI 主窗口创建时的 `WS_EX_NOREDIRECTIONBITMAP` 也会妨碍传统 HWND
|
||||
子窗口绘制。Windows 拒绝运行中切换该标志,因此在窗口创建参数增加
|
||||
`native_child_surfaces`,NyaTerm 工作区和 smoke 窗口在创建时启用。
|
||||
- 未声明原生子窗口支持的窗口拒绝进入原生浮层模式,并返回明确提示。
|
||||
普通 GPUI 窗口默认保持原有创建样式。
|
||||
- 主窗口保留重定向表面后,实机仍显示占位文字;还必须启用父窗口的
|
||||
`WS_CLIPCHILDREN`,使 DirectComposition 遵循 HWND 子窗口裁剪。
|
||||
原生宿主创建时补上该样式,并保留到父窗口销毁,避免同一父窗口的多个
|
||||
宿主互相还原样式。离线真实控件测试检查父窗口确实已启用该标志。
|
||||
|
||||
## 父窗口裁剪修复的实机验证(Windows x64,2026-11-02)
|
||||
|
||||
- 使用上述固定 fork revision 重新构建 `target/debug/nyaterm.exe`。
|
||||
computer-use 已观察到启动恢复的真实远程 Windows 桌面,持续协商占位
|
||||
不再遮挡画面;修复前同一连接已到达 `LoginComplete`,由此区分登录
|
||||
状态与本地合成故障。未将连接信息或远程桌面内容保存到仓库。
|
||||
- 远程键盘 `Ctrl+Escape` 打开开始菜单,`Escape` 关闭;本地文件菜单
|
||||
正常显示在远程桌面上方。窗口还原后远程分辨率跟随视口调整,再次
|
||||
最大化后恢复布局。
|
||||
- 关闭连接页签后原生画面正常释放;从同一保存项重新连接后再次显示
|
||||
远程桌面。启动恢复和手动重新打开均已验证;尚未模拟断网自动重连。
|
||||
- 真实控件离线初始化、策略读回、父窗口裁剪和回环事件测试 13 项通过。
|
||||
当前 revision 的 workspace check、fmt 和 diff 检查通过。
|
||||
- 后续用户确认鼠标点击无效,不能将画面恢复视为完整交互验收;证书提示的继续/取消和记忆行为、
|
||||
剪贴板双向不传输、跨 DPI、长时间循环与 ARM64 实机仍未验收。
|
||||
|
||||
## 原生浮层鼠标修正(Windows x64)
|
||||
|
||||
- 全窗口 owned popup 的 `HTTRANSPARENT` 未使实际鼠标消息到达 ActiveX。
|
||||
将浮层拆为带 `WS_EX_TRANSPARENT` 的视觉 HWND,以及仅覆盖交互区域的
|
||||
输入 HWND。输入区域按当前 DPI 缩放后通过 `SetWindowRgn` 替换;空区域
|
||||
隐藏输入窗口,被动提示继续由视觉窗口显示,不向远端重放鼠标消息。
|
||||
- 在 Zed `e33b65da` / Kit `8c068ea2` 的实机验证中,远端开始按钮、
|
||||
空白点击和右键菜单均响应,本地菜单仍能显示;同时发现点击远端未关闭
|
||||
本地菜单。原 UI 线程 `WH_MOUSE` 钩子无法观察 ActiveX 私有线程输入,
|
||||
改为在安装 UI 线程回调的低层钩子,并仅通知注册 owner 的原生子窗口
|
||||
点击;原始鼠标消息继续传递。
|
||||
- 当前固定版本:Zed `fa96acbd51d347ba7a4fff2053036a1559ef9387`、
|
||||
Kit `e87ad22ca5590ed1c30e52113cfb09b1b87c6a77`,均为 `nyaterm` 分支。
|
||||
Windows fork 测试 57 项通过、0 失败、1 项忽略,包括输入区域缩放、
|
||||
替换、清空和父窗口销毁后的两个浮层 HWND 清理。
|
||||
|
||||
## 最终鼠标交互实机验收(Windows x64,2026-11-03)
|
||||
|
||||
- 使用上述最终固定 revision 构建的 `target/debug/nyaterm.exe`,启动恢复后
|
||||
显示真实远程桌面。鼠标点击远端开始按钮能打开菜单,右键能打开远端
|
||||
桌面上下文菜单;键盘 Escape 能关闭开始菜单。
|
||||
- 本地文件菜单正常显示在远端画面上方。菜单打开时,一次点击远端开始
|
||||
按钮会关闭本地菜单并打开远端开始菜单,没有重复点击或消息重放。
|
||||
被动连接提示显示时,鼠标仍能操作远端。
|
||||
- 退出确认弹窗及遮罩显示正常。点击遮罩覆盖的远端开始位置只取消本地
|
||||
弹窗,未打开远端开始菜单,确认模态输入不会穿透。
|
||||
- 最大化后远端分辨率跟随视口,稳定后画面填满视口。关闭连接页签后
|
||||
原生画面释放,从同一保存项重新连接能恢复画面,鼠标开始按钮仍响应。
|
||||
- 上述验证未将连接信息或远端桌面内容保存到仓库。尚未验证证书警告的
|
||||
继续/取消及记忆行为、模拟断网自动重连、剪贴板双向不传输、跨 DPI、
|
||||
长时间循环与 ARM64;离线策略读回或编译通过不代表这些项目已验收。
|
||||
|
||||
## 最终固定版本自动化验证(Windows x64,2026-11-03)
|
||||
|
||||
- Zed `fa96acbd51d347ba7a4fff2053036a1559ef9387` 和 Kit
|
||||
`e87ad22ca5590ed1c30e52113cfb09b1b87c6a77` 已提交并推送到各自 fork
|
||||
的 `nyaterm` 分支,主仓库 manifest 和 lock 同步引用这两个 revision。
|
||||
- `cargo build -p nyaterm-app --bin nyaterm --locked -j1` 通过。
|
||||
- `cargo check --workspace --locked -j1` 通过。
|
||||
- `cargo test --workspace --locked -j1`:5048 项通过、0 失败、42 项忽略,
|
||||
包含原生 RDP 的 13 项回归测试。
|
||||
- `cargo clippy --workspace --all-targets --locked -j1 -- -D warnings` 通过。
|
||||
- `cargo fmt --all -- --check` 和 `git diff --check` 通过。
|
||||
- 主仓库改动保持未提交;未修改 `temp/`。
|
||||
|
||||
|
||||
## 剪贴板默认全开与光标归属修复(Windows x64,2026-11-03)
|
||||
|
||||
- 当前 Zed revision 为 `597ca983eb6facf1a8528a56204aeeb7c857eaf6`,
|
||||
Kit revision 为 `7952df45d0f719525fe969b8991b39f7692f7f58`;均已推送到
|
||||
`nyakang` fork 的 `nyaterm` 分支。主项目同步 manifest 和 lock,未修改
|
||||
`temp/` 或 Cargo 缓存中的依赖源码。
|
||||
- 删除两个 RDP 后端的剪贴板选择器及旧禁用校验;磁盘、打印机和设备
|
||||
重定向策略保持原样。Builtin 的完整能力仍限于文本和文件/目录,
|
||||
本次未增加图片、HTML 或其他富文本协议。Native 交由微软控件协商格式。
|
||||
- 旧连接和编辑草稿的剪贴板值继续往返保存,临时启动配置统一全开;
|
||||
没有数据库迁移或批量重写。helper 入口始终注册支持文件的 CLIPRDR,
|
||||
Native 入口始终启用 RedirectClipboard。
|
||||
- 静态分析发现父窗口 WM_SETCURSOR 及异步样式/隐藏恢复路径可覆盖
|
||||
原生子窗口光标。修复保留消息来源 HWND,并在原生子树拥有光标时跳过
|
||||
SetCursor;真实 HWND 测试覆盖嵌套子窗口、父窗口、owned popup 和隐藏
|
||||
光标。视口去重和动态分辨率防抖保持原样,尚无实机会话日志证明存在
|
||||
重复缩放,也没有据此更改分辨率调用链。
|
||||
- 相关四个 crate 测试共 775 项通过、0 失败、1 项忽略;包含旧值兼容、
|
||||
两个后端启动策略、Builtin 文件能力和取消/错误回归,以及 Windows
|
||||
真实控件离线重定向策略读回。Zed Windows 测试 58 项通过、0 失败、
|
||||
1 项忽略。这些离线结果不代表真实远程会话已验收。
|
||||
- 本次 computer-use 原生管道不可用(os error 2),浏览器宿主也不可用。
|
||||
因此尚未完成新版真实会话的双向文本、文件/目录复制、光标形状和大小、
|
||||
停留与移动、菜单开关、切换页签、缩放及跨 DPI 验收;无法确认用户报告
|
||||
的闪变已完全消失。其他平台文件剪贴板和 ARM64 本次也未实测。
|
||||
|
||||
- 最终依赖下 `cargo check --workspace -j 2`、
|
||||
`cargo fmt --all -- --check`、`git diff --check` 通过;锁文件中 GPUI 和
|
||||
GPUI Platform 各只有一个来源。首轮默认并行的 workspace test 在桌面
|
||||
套件遇到四项失败:AI 模拟服务管道关闭、安全列表排序超时、壁纸加载
|
||||
超时、凭据回调未完成。当时另有 workspace 构建并行运行;本次 RDP
|
||||
启动/重连及旧配置兼容回归均通过。后续串行复跑结果另列,不将首轮
|
||||
失败隐藏,也不据此修改无关模块。
|
||||
|
||||
- 中间复跑发现共享 target 中的 core 测试产物缺少新增兼容回归,该轮已
|
||||
中止且不计入最终结果。重新编译改动涉及的 crate 后,最终日志确认
|
||||
core 兼容、两个后端启动/重连、helper 文件能力及 Native 策略读回
|
||||
回归全部实际执行并通过。
|
||||
- 最终 `cargo test --workspace --locked -j 2 -- --test-threads=1` 通过:
|
||||
5053 项通过、0 失败、42 项忽略;首轮失败的四项均在这轮通过。
|
||||
- 最终 `cargo check --workspace --locked -j 1` 通过。
|
||||
- `cargo build -p nyaterm-app -p nyaterm-rdp-helper -p nyaterm-vnc-helper
|
||||
--locked -j 1` 通过,三个最新可执行文件均位于 `target/debug/`:
|
||||
`nyaterm.exe`、`nyaterm-rdp-helper.exe`、`nyaterm-vnc-helper.exe`。
|
||||
- 最终 `cargo fmt --all -- --check` 和 `git diff --check` 通过。
|
||||
- 最终 `cargo clippy --workspace --all-targets --locked -j 1 -- -D warnings`
|
||||
通过。两个 fork 工作区干净;主仓库保留未提交改动以供审阅。
|
||||
- 上述结果均为构建、单元/集成或离线真实控件验证;本次真实远程会话
|
||||
验收仍受桌面控制服务不可用阻塞,不能据此确认用户报告的光标闪变已
|
||||
完全消除,双向复制和跨 DPI 等待实机补验。
|
||||
Reference in New Issue
Block a user