Skip to content

feat(ohos): add phone and desktop support with shared responsive UI - #283

Merged
shihuili1218 merged 31 commits into
mainfrom
feat/ohos-port
Oct 23, 2026
Merged

shihuili1218 merged 31 commits into
mainfrom
feat/ohos-port

Conversation

@shihuili1218

@shihuili1218 shihuili1218 commented Sep 17, 2026 •

Copy link
Copy Markdown
Collaborator

概述

为 RSSH 增加鸿蒙手机/平板和电脑支持。两类设备使用独立的 entry HAP,共用 HAR、Rust 业务核心和前端;构建生成一个 App Pack,按设备类型分发。

OHOS 框架依赖和原生实现放在独立适配层。共享业务代码调用统一接口:布局只由窗口/容器宽度决定,输入按实际事件处理,原生功能由宿主能力查询决定。

主要改动

  • OHOS 使用独立的 Tauri/Tao/Wry/ability 依赖覆盖、固定提交、补丁与 Cargo lock;普通平台保留官方依赖,普通桌面 PTY 保留 0.8,OHOS 使用其独立的 0.9 适配。
  • 文件选择和读写统一使用 PickedLocation { location, name },位置保持不透明,名称来自宿主元数据。打开的文件同时持有流和访问授权;保留普通桌面的临时文件与重命名行为,OHOS 适配原生 URI 和文件描述符。
  • 剪贴板、外链、窗口及运行时能力下沉到平台接口。OHOS 原生窗口创建等待实际结果,失败回滚;原生剪贴板按宿主能力选择,浏览器/IDE 保留其桥接方式。
  • 资源关闭、取消和重试共用生命周期抽象,保留 owner/nonce 校验,失败的原生关闭仍保留资源供后续重试。OHOS 串口支持 API 19/26 的能力差异,本地 PTY 探测成功后才开放。
  • 页面按宽度响应,删除前端 isMobile 布局分支;触摸、键鼠和软键盘入口独立于断点。终端控制按 tab 注册,避免关闭后台 tab 后影响当前终端输入。
  • 终端渲染、图像与输出积压默认值来自后端 terminalPolicy,OHOS 按运行时设备类型区分;桌面输出积压上限为 128 MiB,受限平台为 32 MiB,用户显式 GPU 设置优先。
  • Rust 源码使用互斥的 linux、macos、windows、android、ios、ohos 条件;Linux 明确排除 OHOS。手机和电脑共用 Rust 库,不伪造编译期 OS。
  • 新安装使用 Asset Store 保存加密主密钥,保留既有数据库、密钥和 sticky backend 行为;移除旧原型界面偏好的兼容链。
  • 提交源码、锁文件、品牌资源和回归测试;忽略 HAP/App Pack、动态库、生成资源、缓存、本机 SDK 配置和签名材料。

四条入口

入口 行为
桌面 GUI macOS/Windows/Linux 使用普通平台适配;OHOS 电脑使用独立 HAP。窗口宽度决定布局,原生窗口、串口等按实际能力开放。
移动 GUI Android/iOS 保留现有原生路径;OHOS 手机/平板使用独立 HAP。宽屏采用宽布局,保留软键盘、外接键鼠及多文件选择能力。
CLI 无新增 CLI 命令;继续复用业务、存储和平台代码。OHOS HAP 不提供 CLI 安装或 SSH Agent 功能。
Headless/JetBrains server dispatcher 返回同一能力契约,复用响应式前端;文件、剪贴板和窗口操作保留浏览器/IDE 的宿主接口。

验证

  • 已通过前端单测、Vite production build、Rust 单测、格式检查、CLI/server feature check、Android cross-check,以及 76 项 OHOS 框架测试。
  • ./build-ohos.sh --unsigned 已生成手机 HAP、电脑 HAP 和 App Pack。这些是本地验收包,尚非商店签名包。
  • 使用华为官方 Emulator、hdc、uitest,在手机和电脑模拟器回归;所有 SSH 连接仅使用本机 Docker。两端覆盖安装后保留原配置并重新连接成功。
  • 两端通过 SSH 输入输出/重连、原生文件选择器取消后重开、SFTP 上传下载、原生剪贴板复制粘贴。中文、空格及字面 %25/%2F 文件名完整保留,传输后字节数和 SHA-256 一致。
  • 电脑通过宽窄窗口布局切换、多窗口创建与关闭隔离;手机通过软键盘、中文 IME、横竖屏布局及标签关闭隔离;两端设置页的注入滑动事件正常。
  • tsc --noEmit 仍有 39 条既有诊断,相对本轮重构前 HEAD 的 42 条未新增,不能标记为通过。
  • iOS cross-check 仍受现有 Swift/SDK target 混用阻塞;Windows/Linux 本地构建尚未完成。

尚待实机/专项验收

  • 真实 USB 串口授权、收发、取消、拔插及重连;模拟器仅验证枚举、刷新和无设备提示。
  • Mac 触摸板双指滚动经模拟器转发;命令注入的滑动测试不能替代该路径。
  • 跨应用剪贴板、触摸长按选字、嵌套目录传输、大文件中断恢复。
  • 窄屏 Ctrl/Alt 锁定后跨断点输入、分屏控制目标,以及实机窗口置顶和最大化。

构建与验收说明见 BUILD_OHOS.md。

rssh's core (russh + rusqlite + xterm.js in a WebView) has no OHOS
story upstream: Tauri does not ship a HarmonyOS target. This wires the
app onto the feat/open-harmony fork (yangyongzhen/tauri @ e3bf6eb1,
base 2.11.5, wry/tao ohos branches, openharmony-ability pinned to the
0.3-compatible rev) via [patch.crates-io], with every ohos-specific
path behind cfg(target_env = "ohos"):

- setup(): resolve the sandbox files dir directly on ohos —
  app_data_dir() aborts at startup there (no HOME, the linux resolver
  returns UnknownPath and kills the process before any UI)
- official plugins (opener/dialog/fs) have no ohos backend; they moved
  to a positive-OS target table that excludes ohos and registration is
  cfg'd out. Frontend save/pick paths degrade until a filePicker
  bridge exists (phase D)
- keyring + PTY/serial/arboard tables exclude ohos (target_os="linux"
  is true there but none of it links); secrets fall back to the DB
  file backend exactly like Android
- reqwest rides the mobile table on ohos (webpki-roots fallback)
- ArkWeb: withGlobalTauri on; guarded in-memory localStorage polyfill
  inlined before any ES module (the AI store reads it at module load,
  ArkWeb serves null for it under the tauri:// scheme)
- platform.ts recognizes OpenHarmony/HarmonyOS UAs as mobile
- build-ohos.sh: env-driven NDK linker/CC setup + cargo tauri ohos
  build; the crates.io CLI has no ohos subcommand, see script header

Desktop verification on the patched stack: cargo check, cargo test
(744 passed), vitest (781 passed) all green. Deferred to a
DevEco-equipped machine: aws-lc-sys (via russh) cross-compile,
xterm.js behavior under ArkWeb (WebGL/IME/long-press), HAP assembly
and on-device run.
Covers prerequisites, one-time fork CLI install, DevEco auto-signing,
build-ohos.sh usage, the Windows-specific HAP assembly pitfalls (from
the verified real-device porting record), on-device install, the exact
things this PoC needs answered (xterm.js under ArkWeb), known
limitations, and the aws-lc-sys escalation path.
The whole chain now compiles on this macOS host against DevEco's embedded
SDK: rust aarch64-unknown-linux-ohos (aws-lc-sys, bundled sqlite and
tree-sitter all cross-compile clean), 29MB librssh_lib.so, DevEco
project assembly, and a 41MB HAP containing the frontend.

What the first four build rounds surfaced and how each is fixed:

- capabilities/default.json referenced opener/dialog/fs permissions,
  which tauri-build rejects on ohos (plugin crates absent). Split into
  a core capability (all platforms) and capabilities/plugins.json gated
  to the five plugin platforms.
- sftp.rs touched plugin types outside the desktop-only dialogs:
  FileAccessGuard, fs_open_read/write and the sftp_download_to/
  sftp_upload_from commands now compile wherever the plugin table does;
  ohos gets same-signature stubs returning ohos_file_bridge_pending, so
  the invoke_handler list stays shared and the frontend gets a clear
  error instead of a missing command.
- external.rs open_external_url: same treatment (ohos_opener_pending).
- secret: the KeyringStore re-export needed the same cfg as its mod.
- build-ohos.sh: probe DevEco-Studio.app (hyphenated bundle name),
  require ohrs, tolerate the Windows-only initial-assembly failure,
  then auto-sync dist into rawfile (the fork never copies it), strip
  the daemon-dependent cargo hook from entry/hvigorfile.ts, and
  re-assemble via node hvigorw.js with DEVECO_SDK_HOME derived.

Desktop regression: cargo check, cargo test (744), fmt all clean.
ArkWeb serves the app under tauri://localhost where window.localStorage
is null; the polyfill was in-memory only, so every restart reset UI
state (theme choice, panel layout, plugin toggles). The polyfill now
restores its Map from a new ui_state_load command before any app module
evaluates (index.html imports the entry dynamically behind
__rsshLsReady — store modules read localStorage at import time), and
flushes it back debounced through ui_state_save. Rust side is a single
atomic-write JSON blob at <data_dir>/ui_state.json with corrupt-file =
fresh-start semantics; every platform with a real localStorage runs
none of this.

Also renames the on_window_event closure arg to _window — on ohos the
only use is cfg(desktop) out, which trips an unused-variable warning in
the ohos build.

Tests: 5 new ui_state roundtrip/corruption cases; suite at 749 green,
vitest 781 green, desktop check clean.
hvigor wants the SDK root that CONTAINS the version dir
(.../sdk with sdk/default/openharmony below it); peeling only
/openharmony left it at .../sdk/default and the re-assembly step
died with configuration error 00303312.
Replaces the ohos_file_bridge_pending stubs with a real, picker-free
design: transfers stage through the PUBLIC Downloads directory, gated
by READ_WRITE_DOWNLOAD_DIRECTORY (declared in module.json5, requested
once at startup from EntryAbility via abilityAccessCtrl).

- Rust (ohos impls of existing command names, frontend flows shared):
  sftp_pick_save_path returns Downloads/rssh/<name>, sftp_pick_open_files
  lists the staged files for upload queueing, download/upload stream to
  plain paths (no content:// URIs on this target). Huawei moved the
  public layout across API versions, so the dir resolves by probing
  known candidates (/storage/Users/currentUser/Download, then
  /storage/media/100/local/files/Download).
- write_text_file: plain command for text exports where plugin-fs is
  absent; registered everywhere (desktop already exposes equivalent
  writes through plugin-fs, no new surface).
- Frontend: isHarmony export (platform.ts, TDD) — SFTP download rides
  the invoke-based desktop branch instead of SAF, upload queues every
  staged file, saveTextFile gains the ohos branch. New i18n key for the
  empty-stage hint.

Verified on the emulator end to end: permission prompt appears at first
launch (granted via atm for automation — the system dialog rejects
injected taps by design), Settings > Backup > Export writes
rssh-config-<ts>.json and the success toast names the file. The
SFTP transfer legs need a live session and stay for on-device testing.

Desktop regression: 749 rust tests, 782 vitest, check/fmt clean.
The generated ability declared no orientation, so the window (and the
webview with it) stayed portrait when the emulator/device rotated.
The ohos pick implementations were compiled into the .so but the
invoke_handler entries kept their historical #[cfg(desktop)] — the
commands existed and still answered 'Command not found'. The shared
pickers (save_path/open_files) now register on both; pick_folder gains
an ohos impl (fresh Downloads/rssh/folder-<uuid> target) so directory
downloads work too. pick_open_path stays desktop-only — no ohos caller.

Found the hard way by the user after two rebuilds; strings on the .so
cannot prove command-table membership (no literals), the handler list
is the only source of truth.
… error

Upload no longer blindly queues everything staged under Downloads/rssh:
several files now open an in-app picker list (one file still uploads
straight away). Downloads-side, grants reset on app updates/reinstalls
and create_dir_all is a no-op stat — so picking now write-probes the
staging dir and fails fast with a grant-storage-permission hint instead
of a bare EACCES mid-transfer.
Build HarmonyOS from pinned framework sources and reviewed patches in a
separate Cargo workspace so desktop, Android, iOS, CLI and headless keep
the official dependency graph. Preserve application data and secret paths.

Move file selection, file I/O and clipboard access behind shared native
commands, with ability plugins for HarmonyOS and official Tauri plugins
for the other native platforms. Keep browser and JetBrains handling in
the IPC adapter. Remove the prototype UI-state compatibility layer.

Cover framework lifecycle and build failure paths, document device checks
and the upstream callback metadata leak, and ignore generated artifacts,
local build state and signing material.

Validation: 817 frontend tests, 750 Rust tests and 22 OHOS build/framework
checks passed. Frontend production build, Rust formatting and CLI/server
binary checks passed. HarmonyOS release/ArkTS builds and Android/iOS
cross-checks passed during the migration; the emulator package was
installed and launched for user acceptance testing.
Keep one HarmonyOS package and shared business layer while separating device
layout from native capabilities. Add independent desktop windows, authorized
multi-file and directory transfers, and capability-probed PTY and serial.

Replay pinned framework patches, preserve window/session ownership, order
ArkWeb initialization, and use Tauri postMessage IPC without the upstream
unsafe request-body reader. Let user authorization dialogs wait for users.
Normalize release versions without changing locked dependency versions.

Validated with 858 frontend tests, 760 Rust tests, 41 framework tests,
18 build-script tests, CLI/server feature checks, macOS GUI smoke, and the
same production HAP on HarmonyOS phone and PC emulators. Device checks cover
SSH input, background resume, independent windows, split panes, window
controls, multi-file and nested-directory round trips, and 128 KiB IPC data.

Production signing and physical USB serial validation remain external release
requirements. Headless has automated coverage but no live smoke in this run.
Separate phone and desktop entry HAPs around a shared runtime. Complete serial lifecycle and AssetStore integration, restore module startup, and flush downloads before reporting completion.
Use viewport width for shared layouts, per-pane terminal input controls, and host-reported native capabilities. Define mutually exclusive OS aliases and classify HarmonyOS devices at runtime while preserving independent phone and desktop packages.
Load the real split ArkTS serial modules while mocking only native APIs, and assert that closing waits for pending authorization cleanup. Cover the API 19 fallback and use explicit capture options so input listener teardown works consistently in the Node test runtime.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔵 Needs a closer look

It contains unresolved filename and memory-limit regressions alongside extensive native and framework changes requiring device-level validation.

Pull request overview

Adds shared HarmonyOS phone and desktop support while separating responsive layout, input handling, and native host capabilities.

Changes:

  • Adds dual HarmonyOS HAP packaging, native integrations, and pinned framework patches.
  • Introduces runtime-capability, viewport-layout, and input-device abstractions.
  • Expands serial, file, clipboard, window, secret-storage, and regression-test coverage.
File summaries
File Description
AGENTS.md Updates platform guidance.
BUILD_OHOS.md Documents HarmonyOS builds.
build-ohos.sh Builds HAPs and App Pack.
idea-plugin/src/main/kotlin/sh/rssh/idea/RsshBridge.kt Updates IDE bridge capabilities.
package-lock.json Updates frontend lock data.
package.json Adds build/test scripts.
roadmap.md Updates HarmonyOS roadmap.
scripts/build-ohos.test.mjs Tests OHOS build orchestration.
scripts/prepare-ohos-sources.mjs Prepares pinned framework sources.
scripts/prepare-ohos-sources.test.mjs Tests source preparation.
scripts/prepare-ohos.mjs Prepares OHOS project files.
scripts/prepare-ohos.test.mjs Tests project preparation.
src-tauri/Cargo.lock Updates Rust dependencies.
src-tauri/Cargo.toml Adds conditional OHOS dependencies.
src-tauri/build.rs Defines platform configuration.
src-tauri/capabilities/default.json Updates Tauri permissions.
src-tauri/gen/ohos/.gitignore Excludes generated OHOS artifacts.
src-tauri/gen/ohos/AppScope/app.json5 Configures the OHOS application.
src-tauri/gen/ohos/AppScope/resources/base/element/string.json Adds application strings.
src-tauri/gen/ohos/AppScope/resources/base/media/rssh_icon.png Adds application branding.
src-tauri/gen/ohos/build-profile.json5 Configures product builds.
src-tauri/gen/ohos/code-linter.json5 Configures OHOS linting.
src-tauri/gen/ohos/common/runtime/Index.ets Exports shared runtime code.
src-tauri/gen/ohos/common/runtime/build-profile.json5 Configures the runtime HAR.
src-tauri/gen/ohos/common/runtime/hvigorfile.ts Defines runtime build tasks.
src-tauri/gen/ohos/common/runtime/oh-package-lock.json5 Locks runtime packages.
src-tauri/gen/ohos/common/runtime/oh-package.json5 Declares runtime packages.
src-tauri/gen/ohos/common/runtime/src/main/cpp/types/librssh_lib/Index.d.ts Declares native bindings.
src-tauri/gen/ohos/common/runtime/src/main/cpp/types/librssh_lib/oh-package.json5 Describes native library package.
src-tauri/gen/ohos/common/runtime/src/main/ets/ability/RsshAbility.ets Implements shared application ability.
src-tauri/gen/ohos/common/runtime/src/main/ets/ability/RsshBackupAbility.ets Adds backup integration.
src-tauri/gen/ohos/common/runtime/src/main/ets/plugins/ClipboardPlugin.ets Implements native clipboard access.
src-tauri/gen/ohos/common/runtime/src/main/ets/plugins/FilesAccessPlugin.ets Implements native file access.
src-tauri/gen/ohos/common/runtime/src/main/ets/plugins/RuntimePlugin.ets Reports host capabilities.
src-tauri/gen/ohos/common/runtime/src/main/ets/plugins/SerialPlugin.ets Exposes native serial operations.
src-tauri/gen/ohos/common/runtime/src/main/ets/plugins/serial/BusSerialPort.ets Implements bus serial support.
src-tauri/gen/ohos/common/runtime/src/main/ets/plugins/serial/SerialBackend.ets Selects serial backends.
src-tauri/gen/ohos/common/runtime/src/main/ets/plugins/serial/UsbSerialPort.ets Implements USB serial support.
src-tauri/gen/ohos/common/runtime/src/main/module.json5 Declares runtime module capabilities.
src-tauri/gen/ohos/common/runtime/src/main/resources/base/element/color.json Adds light theme resources.
src-tauri/gen/ohos/common/runtime/src/main/resources/base/element/string.json Adds runtime strings.
src-tauri/gen/ohos/common/runtime/src/main/resources/base/profile/backup_config.json Configures backups.
src-tauri/gen/ohos/common/runtime/src/main/resources/dark/element/color.json Adds dark theme resources.
src-tauri/gen/ohos/hvigor/hvigor-config.json5 Configures Hvigor.
src-tauri/gen/ohos/hvigorfile.ts Defines root OHOS tasks.
src-tauri/gen/ohos/oh-package-lock.json5 Locks workspace packages.
src-tauri/gen/ohos/oh-package.json5 Declares workspace packages.
src-tauri/gen/ohos/products/desktop/build-profile.json5 Configures desktop HAP builds.
src-tauri/gen/ohos/products/desktop/hvigorfile.ts Defines desktop build tasks.
src-tauri/gen/ohos/products/desktop/oh-package-lock.json5 Locks desktop packages.
src-tauri/gen/ohos/products/desktop/oh-package.json5 Declares desktop packages.
src-tauri/gen/ohos/products/desktop/src/main/ets/entryability/EntryAbility.ets Adds desktop entry ability.
src-tauri/gen/ohos/products/desktop/src/main/ets/entrybackupability/EntryBackupAbility.ets Adds desktop backup entry.
src-tauri/gen/ohos/products/desktop/src/main/ets/pages/Index.ets Adds desktop entry page.
src-tauri/gen/ohos/products/desktop/src/main/module.json5 Declares desktop module.
src-tauri/gen/ohos/products/desktop/src/main/resources/base/profile/main_pages.json Registers desktop pages.
src-tauri/gen/ohos/products/phone/build-profile.json5 Configures phone HAP builds.
src-tauri/gen/ohos/products/phone/hvigorfile.ts Defines phone build tasks.
src-tauri/gen/ohos/products/phone/oh-package-lock.json5 Locks phone packages.
src-tauri/gen/ohos/products/phone/oh-package.json5 Declares phone packages.
src-tauri/gen/ohos/products/phone/src/main/ets/entryability/EntryAbility.ets Adds phone entry ability.
src-tauri/gen/ohos/products/phone/src/main/ets/entrybackupability/EntryBackupAbility.ets Adds phone backup entry.
src-tauri/gen/ohos/products/phone/src/main/ets/pages/Index.ets Adds phone entry page.
src-tauri/gen/ohos/products/phone/src/main/module.json5 Declares phone module.
src-tauri/gen/ohos/products/phone/src/main/resources/base/profile/main_pages.json Registers phone pages.
src-tauri/ohos/Cargo.lock Locks OHOS Rust sources.
src-tauri/ohos/overlay.toml Defines source overlays.
src-tauri/ohos/patches/.gitattributes Configures patch handling.
src-tauri/ohos/patches/ability.patch Adds native ability integration.
src-tauri/ohos/patches/tao.patch Adds OHOS window support.
src-tauri/ohos/patches/tauri.patch Adapts Tauri for OHOS.
src-tauri/ohos/patches/wry.patch Adds ArkWeb lifecycle support.
src-tauri/ohos/sources.json Pins framework sources.
src-tauri/ohos/tests/framework-initialization.test.mjs Tests initialization ordering.
src-tauri/ohos/tests/framework-ipc-transport.test.mjs Tests IPC transport.
src-tauri/ohos/tests/framework-lifecycle.test.mjs Tests lifecycle handling.
src-tauri/ohos/tests/framework-patches.test.mjs Validates framework patches.
src-tauri/ohos/tests/framework-picker-timeout.test.mjs Tests picker timeouts.
src-tauri/ohos/tests/framework-waker.test.mjs Tests event-loop wakeups.
src-tauri/ohos/tests/framework-webview.test.mjs Tests WebView integration.
src-tauri/ohos/tests/framework-window-commands.test.mjs Tests window commands.
src-tauri/ohos/tests/framework-windows.test.mjs Tests native windows.
src-tauri/ohos/tests/wry-queue.test.mjs Tests WebView operation queues.
src-tauri/src/ai/commands.rs Updates AI platform conditions.
src-tauri/src/ai/session.rs Updates AI session conditions.
src-tauri/src/ai/skills.rs Updates AI skill conditions.
src-tauri/src/bin/rssh/main.rs Updates CLI platform handling.
src-tauri/src/commands/cli.rs Gates CLI installation capability.
src-tauri/src/commands/clipboard.rs Adds unified clipboard commands.
src-tauri/src/commands/discovery.rs Updates discovery availability.
src-tauri/src/commands/external.rs Adds unified external-link handling.
src-tauri/src/commands/files.rs Adds unified file operations.
src-tauri/src/commands/lifecycle.rs Updates resource lifecycle handling.
src-tauri/src/commands/mod.rs Registers command modules.
src-tauri/src/commands/plugin.rs Updates plugin capability handling.
src-tauri/src/commands/runtime.rs Reports runtime capabilities.
src-tauri/src/commands/serial.rs Adds serial capability APIs.
src-tauri/src/commands/sftp.rs Integrates unified file access.
src-tauri/src/commands/window.rs Adds native window commands.
src-tauri/src/emitter.rs Updates cross-host event emission.
src-tauri/src/error.rs Makes application errors cloneable.
src-tauri/src/lib.rs Registers commands and plugins.
src-tauri/src/ohos/clipboard.rs Implements OHOS clipboard access.
src-tauri/src/ohos/device.rs Classifies devices and probes PTY.
src-tauri/src/ohos/file_descriptor.rs Manages native descriptors.
src-tauri/src/ohos/file_grants.rs Tracks URI access grants.
src-tauri/src/ohos/file_name.rs Decodes native filenames.
src-tauri/src/ohos/files.rs Implements OHOS file operations.
src-tauri/src/ohos/mod.rs Exports OHOS modules.
src-tauri/src/ohos/runtime.rs Bridges native runtime services.
src-tauri/src/ohos/serial.rs Bridges native serial services.
src-tauri/src/secret/keyring_store.rs Updates keyring conditions.
src-tauri/src/secret/mod.rs Selects OHOS secret storage.
src-tauri/src/secret/ohos_asset.rs Stores master keys in Asset Store.
src-tauri/src/server.rs Adds headless capability adapters.
src-tauri/src/server_main.rs Updates server platform handling.
src-tauri/src/ssh/known_hosts.rs Updates platform paths.
src-tauri/src/ssh/sftp.rs Flushes native download destinations.
src-tauri/src/state.rs Updates shared application state.
src-tauri/src/terminal/mod.rs Exports platform terminal modules.
src-tauri/src/terminal/pty.rs Updates PTY platform support.
src-tauri/src/terminal/serial.rs Splits serial implementations.
src-tauri/src/terminal/serial/desktop.rs Contains desktop serial implementation.
src-tauri/tauri.conf.json Updates asset protocol configuration.
src/App.svelte Adds startup capability barrier.
src/global.d.ts Declares host bridge globals.
src/lib/ai/ChatPanel.svelte Adapts responsive chat layout.
src/lib/ai/store.svelte.test.ts Updates AI store tests.
src/lib/clipboard.test.ts Tests clipboard routing.
src/lib/clipboard.ts Routes clipboard by host.
src/lib/components/AppShell.svelte Applies responsive application layout.
src/lib/components/AppearanceSettings.svelte Updates responsive settings UI.
src/lib/components/ConnectionEditor.svelte Adapts connection editing layout.
src/lib/components/ConnectionList.svelte Adapts connection list layout.
src/lib/components/CredentialEditor.svelte Adapts credential editing layout.
src/lib/components/DownloadsScreen.svelte Adapts downloads layout.
src/lib/components/HomeScreen.svelte Gates features by capabilities.
src/lib/components/PlaybackScreen.svelte Adapts playback layout.
src/lib/components/SerialProfileEditor.svelte Uses serial host capabilities.
src/lib/components/SettingsLayout.svelte Implements responsive settings navigation.
src/lib/components/SftpBrowser.svelte Uses unified file selection.
src/lib/components/ShellSettings.svelte Gates shell capabilities.
src/lib/components/ShortcutsScreen.svelte Adapts shortcuts layout.
src/lib/components/TerminalKeybar.svelte Generalizes terminal key controls.
src/lib/components/TerminalPane.svelte Integrates input and keyboard routing.
src/lib/components/WelcomeScreen.svelte Updates onboarding capabilities.
src/lib/components/connection-editor.test.ts Tests editor behavior.
src/lib/components/connection-editor.ts Updates editor capability logic.
src/lib/components/welcome/SceneSync.svelte Updates platform onboarding.
src/lib/i18n/locales/en.ts Adds English UI strings.
src/lib/i18n/locales/zh.ts Adds Chinese UI strings.
src/lib/input.test.ts Tests input-device tracking.
src/lib/input.ts Tracks touch and pointer input.
src/lib/ipc-shim.test.ts Tests headless host adapters.
src/lib/ipc-shim.ts Adds headless capability bridges.
src/lib/ohos-entry-ability.test.ts Tests OHOS entry wiring.
src/lib/ohos-native-plugins.test.ts Tests native plugin integration.
src/lib/ohos-runtime-plugin.test.ts Tests runtime capability plugin.
src/lib/pick-file.ts Unifies host file picking.
src/lib/platform.test.ts Updates platform-detection tests.
src/lib/platform.ts Removes layout-oriented mobile detection.
src/lib/plugins/PluginSide.svelte Adds responsive plugin controls.
src/lib/plugins/PluginStrip.svelte Adds touch-accessible plugin controls.
src/lib/plugins/store.svelte.ts Gates plugins by capability.
src/lib/plugins/store.test.ts Tests plugin capability behavior.
src/lib/save-file.test.ts Tests unified save routing.
src/lib/save-file.ts Adds host-aware file saving.
src/lib/sftp-name.test.ts Tests upload-name extraction.
src/lib/sftp-name.ts Extracts names from native references.
src/lib/soft-keyboard-inset.ts Renames terminal keyboard references.
src/lib/stores/app.svelte.test.ts Tests responsive app state.
src/lib/stores/app.svelte.ts Adds per-tab terminal controls.
src/lib/stores/layout.svelte.test.ts Tests viewport breakpoints.
src/lib/stores/layout.svelte.ts Tracks viewport layout state.
src/lib/stores/runtime.svelte.test.ts Tests capability loading.
src/lib/stores/runtime.svelte.ts Stores runtime capabilities.
src/lib/stores/serial.svelte.ts Stores serial capabilities.
src/lib/terminal/limits.ts Unifies terminal queue limits.
src/lib/terminal/reserved-session-attempt.test.ts Tests close barriers.
src/lib/terminal/reserved-session-attempt.ts Serializes session replacement.
src/lib/terminal/soft-keyboard.test.ts Tests keyboard lifecycle.
src/lib/terminal/soft-keyboard.ts Generalizes soft-keyboard handling.
src/lib/terminal/touch-scroll.test.ts Tests scrollbar gesture ownership.
src/lib/terminal/touch-scroll.ts Generalizes touch scrolling.
src/lib/themes/store.svelte.test.ts Updates renderer-default tests.
src/lib/themes/store.svelte.ts Selects renderer by touch support.
src/main.ts Installs global input tracking.
Review details
  • Files reviewed: 174/187 changed files
  • Comments generated: 2
  • Review effort level: Balanced

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread src/lib/sftp-name.ts Outdated
Comment thread src/lib/terminal/limits.ts Outdated
Strip only the SAF document root prefix so colons in filenames cannot silently truncate names or cause upload collisions. Keep all hosts on a conservative 32 MiB terminal backlog budget without inferring memory from platform or viewport width.
@shihuili1218
shihuili1218 requested a lite review from Copilot September 18, 2026 02:27
@shihuili1218
shihuili1218 marked this pull request as ready for review September 18, 2026 02:27

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔵 Needs a closer look

Unresolved moderate findings affect OHOS capability detection and terminal modifier cleanup.

Review details

Suppressed comments (5)

Previously missed (1) — in code that hasn't changed since the last review.

src-tauri/src/commands/runtime.rs:67

  • local_discovery is unrelated to PTY availability: the discovery implementation invokes docker/kubectl directly and the settings page already probes those tools. On an OHOS desktop where openpty is unavailable but either CLI is installed, this assignment hides the discovery page and prevents valid discovery; keep this capability independent of the PTY probe (or probe the discovery tools themselves).

src-tauri/src/commands/runtime.rs:71

  • On HarmonyOS phone/tablet this drops the native folder_selection capability even when the host reports it. SftpBrowser uses directoryTransfer to hide folder upload and directory download, while the OHOS file adapter supports these operations independently of device class, so supported mobile pickers will be presented as unsupported. Derive this flag from device.folder_selection (and any picker bridge availability) without forcing pc.
    src-tauri/src/ohos/device.rs:42
  • deviceInfo.deviceType is also reported as "pc" by the native window adapter (the OHOS window implementation treats both "2in1" and "pc" as desktop), but this match classifies "pc" as Other. get_runtime_capabilities therefore disables PTY, serial, multi-window, window controls, and directory transfer on those HarmonyOS computers even though the desktop HAP is running. Include the "pc" device type in the desktop class.
    src/lib/components/TerminalKeybar.svelte:47
  • These setters mutate global modifier state, but every TerminalPane mounts its own keybar, including panes for background tabs. Closing any background pane therefore runs this cleanup and clears Ctrl/Alt locks belonging to the still-visible pane, changing active-terminal input unexpectedly. Make modifier cleanup owner-scoped (or only clear when this keybar owns the active modifier slot) instead of unconditionally resetting the global state.
    src/lib/components/welcome/SceneSync.svelte:194
  • This new platform label bypasses the existing localization layer: the same scene uses t(...) for every other endpoint, and both locales already define the Android/iOS keys. In the Chinese locale this will render an English-only label, and HarmonyOS has no locale key at all; add the HarmonyOS translation key to both locales and render all three labels through t(...).
  • Files reviewed: 174/188 changed files
  • Comments generated: 0 new
  • Review effort level: Lite

Route file access, clipboard, windows and runtime policy through shared interfaces while keeping OHOS implementations in the sidecar. Preserve opaque file locations, native authorization lifetimes and retryable resource cleanup.

Retain ordinary desktop PTY dependencies, synchronize both lockfiles, and add contract coverage for platform adapters. Verify phone and desktop simulator flows against the local Docker SSH fixture.
Use independent UIAbility windows with one application runtime so closing the first window does not destroy its peers. Preserve existing download targets with atomic replacement, report batch failures per file, and retain failed session cleanup for retry.
Disable raw system backups that cannot restore device-bound keys, and reactivate desktop windows through specified UIAbility instances.

Wait for session reconciliation and retain background cleanup retries. Keep desktop serial I/O off async workers and enqueue SFTP downloads in bounded batches.

Validation: 936 frontend tests, 814 Rust tests, 94 script/framework tests; frontend build, CLI/server checks, formatting, and unsigned phone/desktop HAP packaging passed.
Make closing missing or released sessions idempotent so failed opens cannot block retries. Preserve ownership checks and real cleanup failures, and render readable errors in the shared notification stack.

Show auxiliary terminal controls only in compact layouts and size AI message actions by width. Use the host release-update capability for both startup checks and the About screen, including browser clients.
@shihuili1218

Copy link
Copy Markdown
Collaborator Author

@codex

@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Sep 30, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-10-23T10:43:51.910827Z cd2566f New commits
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 7cb7ebeca3

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +48 to +50
// std::fs::rename replaces existing files on Unix and Windows. Do not
// unlink the original first: rename failure must leave it intact.
std::fs::rename(&self.temporary, &self.destination)?;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Use a Windows-capable atomic replacement

When a Windows user downloads over an existing destination, std::fs::rename fails because Windows does not allow it to replace an existing file. Consequently, the completed temporary download is deleted by Drop, the transfer reports an error, and the destination is never updated. Restore a Windows-specific replacement path or use an atomic replacement API that supports existing targets.

AGENTS.md reference: AGENTS.md:L77-L77

Useful? React with 👍 / 👎.

Comment on lines +127 to +129
let pc = device.class() == DeviceClass::Desktop;
let mut capabilities = RuntimeCapabilities::native();
capabilities.serial = pc && device.serial;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Honor the serial capability on OHOS mobile devices

On an OHOS phone or tablet where hasSerial() reports the USB serial system capability, device.serial is true but this pc conjunction forces the public capability back to false. Since the connection editor, saved profiles, and terminal entry points all gate on capabilities().serial, the implemented USB serial backend becomes completely unreachable solely because of the device class; expose the probed value and reserve the DeviceClass gate for genuinely desktop-only functions such as extra windows.

AGENTS.md reference: AGENTS.md:L89-L90

Useful? React with 👍 / 👎.

Load ignored signing.local.json through Hvigor's public build-context API so shared product configuration stays portable and signing credentials stay local. Add a placeholder example, setup instructions and regression coverage for signed and unsigned builds.
Keep the HarmonyOS R artwork in RGB format without an alpha channel for AppGallery submission. Other platform icons are unchanged.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: f7475094ed

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +1118 to 1119
if (!tab) return;
openCtxMenu(e, tab);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Ignore touch context menus on route panes

On a touch or pen device, a long-press anywhere in the Home, Edit, or Forward pane reaches this handler and opens the tab context menu; openCtxMenu then calls preventDefault(), replacing the native text-selection/context menu. The terminal-pane handler immediately above already filters isTouchContextMenu(e), so apply the same input-source check here.

AGENTS.md reference: AGENTS.md:L75-L75

Useful? React with 👍 / 👎.

capabilities.multi_window = pc && device.multi_window;
capabilities.window_controls = capabilities.multi_window;
capabilities.window_pin = capabilities.window_controls && window_label == "main";
capabilities.directory_transfer = pc && device.folder_selection;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Expose probed folder selection on OHOS mobile

When an OHOS phone or tablet reports folder_selection = true, this pc conjunction still publishes directoryTransfer = false. SftpBrowser consequently hides batch downloads and folder uploads even though the shared OHOS backend implements pick_folder for these devices; use the probed capability rather than the device class.

AGENTS.md reference: AGENTS.md:L77-L77

Useful? React with 👍 / 👎.

HarmonyOS main-window titles also replace the Recent Tasks label. Route title creation and updates through the platform window adapter so OHOS retains RSSH while other desktop hosts preserve content titles.

Keep browser and IDE titles host-owned in the IPC shim; unsupported mobile hosts remain gated by window capabilities. CLI behavior is unchanged. Add regressions for both native title policies and frontend dispatch.

Validated with 963 frontend tests, 819 Rust tests, formatting checks, and the signed code6 OHOS build. Device acceptance remains pending.
Integrate tab context menus, group terminal accents, and base64 terminal
events with the HarmonyOS sidecar and shared platform adapters.

Keep asynchronous serial lifecycle handling and apply the new stream
encoding to its active headless sink. Preserve width-based keyboard UI
and avoid stealing focus when terminal metadata finishes loading.
Align SSH test state with the explicit platform configuration.

Validation: 1002 frontend tests, 835 Rust tests, 94 OHOS build/framework
tests, production frontend build, Rust formatting, GUI/CLI/server checks,
and the OHOS release-target library check.
@shihuili1218
shihuili1218 merged commit d377d84 into main Oct 23, 2026
1 check passed
@shihuili1218
shihuili1218 deleted the feat/ohos-port branch October 23, 2026 10:32

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: cd2566f90a

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

if (!Number.isInteger(config.baudRate) || config.baudRate <= 0 ||
![5, 6, 7, 8].includes(config.dataBits) || ![1, 2].includes(config.stopBits) ||
!['none', 'odd', 'even'].includes(config.parity) ||
!['none', 'hardware', 'software'].includes(config.flowControl) || typeof config.xany !== 'boolean') {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Enforce the BusManager baud-rate ceiling

On API 26 devices using the BusManager backend, this validation accepts every positive u32, while an empty capability list makes the editor accept values up to 4294967295. Huawei's BusManager serial contract limits arbitrary positive baud rates to 115200, so profiles such as 230400 pass validation and save successfully but every connection attempt fails with error 35700002; reject values above the platform limit for this backend.

Useful? React with 👍 / 👎.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants