From 23c9481af11c8ffd02352339206327d6d3e29d7c Mon Sep 17 00:00:00 2001 From: Hunter B Date: Wed, 3 Jun 2026 20:52:35 -0700 Subject: [PATCH] feat: add HarmonyOS OpenHarmony support Harvest the HarmonyOS/OpenHarmony port from PR #2634 and make it publish-safe by target-gating unsupported host dependencies out of the OHOS TUI graph. Self-update is disabled on OHOS, PTY shell mode reports unsupported, and Starlark execpolicy parsing returns an explicit unsupported-platform error until upstream starlark/rustyline/nix support catches up. Add OHOS SDK setup docs and launcher scripts, install the rustls ring provider for rustls-no-provider entrypoints, and keep the packaged codewhale-tui OHOS graph free of starlark, rustyline, nix@0.28, portable-pty, and arboard. Validation: cargo fmt --all -- --check; git diff --check; git diff --cached --check; cargo check -p codewhale-cli --locked; cargo check -p codewhale-app-server --locked; cargo check -p codewhale-tui --locked; cargo test -p codewhale-cli --locked update::tests::; cargo test -p codewhale-release --locked; cargo test -p codewhale-tui --locked background_tty_command_has_controlling_terminal; cargo test -p codewhale-tui --locked clipboard; cargo package -p codewhale-tui --allow-dirty --no-verify --locked; packaged OHOS cargo tree checks. OHOS target check still requires a loaded OpenHarmony SDK/sysroot and currently stops in ring with missing assert.h when CC/CFLAGS/linker are unset. Harvested from PR #2634 by @shenjackyuanjie. Co-authored-by: shenjackyuanjie <54507071+shenjackyuanjie@users.noreply.github.com> --- .cargo/config.toml | 18 + .gitignore | 2 + CHANGELOG.md | 11 +- Cargo.lock | 414 ++++++-------------- Cargo.toml | 3 +- README.ja-JP.md | 2 + README.md | 2 + README.vi.md | 2 + README.zh-CN.md | 2 + crates/app-server/Cargo.toml | 1 + crates/app-server/src/main.rs | 6 + crates/cli/Cargo.toml | 1 + crates/cli/src/lib.rs | 6 + crates/cli/src/update.rs | 8 + crates/release/Cargo.toml | 1 + crates/secrets/Cargo.toml | 2 +- crates/secrets/src/lib.rs | 56 ++- crates/tui/Cargo.toml | 14 +- crates/tui/src/child_env.rs | 1 + crates/tui/src/execpolicy/error.rs | 4 + crates/tui/src/execpolicy/mod.rs | 6 + crates/tui/src/execpolicy/parser_ohos.rs | 26 ++ crates/tui/src/main.rs | 5 + crates/tui/src/sandbox/mod.rs | 40 +- crates/tui/src/sandbox/process_hardening.rs | 6 +- crates/tui/src/tools/diagnostics.rs | 8 +- crates/tui/src/tools/shell.rs | 152 ++++--- crates/tui/src/tools/shell/tests.rs | 2 +- crates/tui/src/tui/clipboard.rs | 122 ++++-- crates/tui/src/utils.rs | 10 +- docs/HarmonyOS.md | 78 ++++ docs/INSTALL.md | 2 + docs/V0_9_0_EXECUTION_MAP.md | 9 +- ohos-clang.ps1 | 23 ++ ohos-clang.sh | 23 ++ ohos-clangxx.ps1 | 23 ++ ohos-clangxx.sh | 23 ++ scripts/ohos-env.ps1 | 57 +++ scripts/ohos-env.sh | 44 +++ 39 files changed, 784 insertions(+), 431 deletions(-) create mode 100644 .cargo/config.toml create mode 100644 crates/tui/src/execpolicy/parser_ohos.rs create mode 100644 docs/HarmonyOS.md create mode 100644 ohos-clang.ps1 create mode 100644 ohos-clang.sh create mode 100644 ohos-clangxx.ps1 create mode 100644 ohos-clangxx.sh create mode 100644 scripts/ohos-env.ps1 create mode 100644 scripts/ohos-env.sh diff --git a/.cargo/config.toml b/.cargo/config.toml new file mode 100644 index 00000000..869ef6c5 --- /dev/null +++ b/.cargo/config.toml @@ -0,0 +1,18 @@ +# HarmonyOS/OpenHarmony cross-build paths are intentionally not configured +# here. Cargo does not expand environment variables inside target linker paths +# or CMake toolchain paths, so checked-in absolute SDK paths make the workspace +# machine-specific. +# +# See docs/HarmonyOS.md for setup details. +# +# Set OHOS_NATIVE_SDK to the OpenHarmony native SDK directory, then load one of: +# +# PowerShell: +# . .\scripts\ohos-env.ps1 +# +# Linux/macOS: +# . ./scripts/ohos-env.sh +# +# The setup scripts export Cargo's target-specific linker, AR, CC, CXX, CFLAGS, +# CXXFLAGS, CARGO_ENCODED_RUSTFLAGS, CC_SHELL_ESCAPED_FLAGS, and +# CMAKE_TOOLCHAIN_FILE variables for aarch64-unknown-linux-ohos. diff --git a/.gitignore b/.gitignore index b14ca4b5..eb3b0887 100644 --- a/.gitignore +++ b/.gitignore @@ -50,6 +50,8 @@ docs/*.pdf # Local dev scripts and temp files *.sh *.cmd +!ohos-clang.sh +!ohos-clangxx.sh !scripts/** !.github/scripts/** test.txt diff --git a/CHANGELOG.md b/CHANGELOG.md index 8d76b627..b6212dc7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 `/restore` now shows the 20 most recent snapshots, numeric restore targets can reach beyond that default listing up to a bounded index, and list requests above the visible cap fail explicitly instead of silently truncating. +- Added HarmonyOS/OpenHarmony support scaffolding: environment-driven + `OHOS_NATIVE_SDK` setup scripts and compiler wrappers, platform docs, + explicit Rustls ring-provider installation for the no-provider TLS build, and + OHOS fallbacks for unsupported keyring, clipboard, sandbox, browser-open, TTY, + execpolicy Starlark parsing, and self-update surfaces. ### Changed @@ -33,13 +38,17 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 allowlist approval is merged. - Documented the agent and sub-agent stewardship ethos so future automation preserves human issue intake, careful PR review, and contributor credit. +- Moved the TUI Starlark execpolicy parser and PTY support behind non-OHOS + target dependencies so published OpenHarmony builds no longer pull `nix` 0.28 + through `rustyline` or `portable-pty`. ### Community Thanks to **@cyq1017** for the restore-listing implementation (#2513) and **@wywsoor** for the broader macOS/iTerm rollback UX report (#2494), and **@HUQIANTAO** for the `web_run` lock-splitting work (#2502) and turn-metadata -prefix-cache stability work (#2517). +prefix-cache stability work (#2517), and **@shenjackyuanjie** for the +HarmonyOS/OpenHarmony port and MatePad Edge validation trail (#2634). ## [0.8.53] - 2026-06-03 diff --git a/Cargo.lock b/Cargo.lock index 1bb14640..c0f6d0fa 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -97,7 +97,7 @@ checksum = "fe233a377643e0fc1a56421d7c90acdec45c291b30345eb9f08e8d0ddce5a4ab" dependencies = [ "proc-macro2", "quote", - "syn 2.0.114", + "syn 2.0.117", ] [[package]] @@ -160,7 +160,7 @@ version = "1.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "40c48f72fd53cd289104fc64099abca73db4166ad86ea0b4341abe65af83dadc" dependencies = [ - "windows-sys 0.61.2", + "windows-sys 0.60.2", ] [[package]] @@ -171,7 +171,7 @@ checksum = "291e6a250ff86cd4a820112fb8898808a366d8f9f58ce16d1f538353ad55747d" dependencies = [ "anstyle", "once_cell_polyfill", - "windows-sys 0.61.2", + "windows-sys 0.60.2", ] [[package]] @@ -322,7 +322,7 @@ checksum = "3b43422f69d8ff38f95f1b2bb76517c91589a924d1559a0e935d7c8ce0274c11" dependencies = [ "proc-macro2", "quote", - "syn 2.0.114", + "syn 2.0.117", ] [[package]] @@ -362,7 +362,7 @@ checksum = "c7c24de15d275a1ecfd47a380fb4d5ec9bfe0933f309ed5e705b775596a3574d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.114", + "syn 2.0.117", ] [[package]] @@ -379,7 +379,7 @@ checksum = "9035ad2d096bed7955a320ee7e2230574d28fd3c3a0f186cbea1ff3c7eed5dbb" dependencies = [ "proc-macro2", "quote", - "syn 2.0.114", + "syn 2.0.117", ] [[package]] @@ -403,28 +403,6 @@ version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" -[[package]] -name = "aws-lc-rs" -version = "1.16.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ec6fb3fe69024a75fa7e1bfb48aa6cf59706a101658ea01bfd33b2b248a038f" -dependencies = [ - "aws-lc-sys", - "zeroize", -] - -[[package]] -name = "aws-lc-sys" -version = "0.40.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f50037ee5e1e41e7b8f9d161680a725bd1626cb6f8c7e901f91f942850852fe7" -dependencies = [ - "cc", - "cmake", - "dunce", - "fs_extra", -] - [[package]] name = "axum" version = "0.8.8" @@ -527,9 +505,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" -version = "2.10.0" +version = "2.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "812e12b5285cc515a9c72a5c1d3b6d46a19dac5acfef5265968c166106e31dd3" +checksum = "84d7ced0ae9557296835c32bf1b1e02b44c746701f898460fb000d7eaa84f00a" [[package]] name = "block-buffer" @@ -669,8 +647,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cd4932aefd12402b36c60956a4fe0035421f544799057659ff86f923657aada3" dependencies = [ "find-msvc-tools", - "jobserver", - "libc", "shlex", ] @@ -768,7 +744,7 @@ dependencies = [ "heck", "proc-macro2", "quote", - "syn 2.0.114", + "syn 2.0.117", ] [[package]] @@ -786,15 +762,6 @@ dependencies = [ "error-code", ] -[[package]] -name = "cmake" -version = "0.1.57" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75443c44cd6b379beb8c5b45d85d0773baf31cce901fe7bb252f4eff3008ef7d" -dependencies = [ - "cc", -] - [[package]] name = "cmp_any" version = "0.8.1" @@ -825,6 +792,7 @@ dependencies = [ "codewhale-protocol", "codewhale-state", "codewhale-tools", + "rustls", "serde", "serde_json", "tempfile", @@ -852,6 +820,7 @@ dependencies = [ "codewhale-state", "dirs", "reqwest", + "rustls", "semver", "serde", "serde_json", @@ -939,6 +908,7 @@ version = "0.8.53" dependencies = [ "anyhow", "reqwest", + "rustls", "semver", "serde", "serde_json", @@ -1022,7 +992,7 @@ dependencies = [ "ratatui", "regex", "reqwest", - "rustyline 15.0.0", + "rustls", "schemars", "schemaui", "serde", @@ -1044,7 +1014,7 @@ dependencies = [ "tracing-appender", "tracing-subscriber", "unicode-segmentation", - "unicode-width 0.2.0", + "unicode-width 0.2.2", "uuid", "vt100", "wait-timeout", @@ -1234,7 +1204,7 @@ version = "0.28.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "829d955a0bb380ef178a640b91779e3987da38c9aea133b20614cfed8cdea9c6" dependencies = [ - "bitflags 2.10.0", + "bitflags 2.12.1", "crossterm_winapi", "mio", "parking_lot", @@ -1250,7 +1220,7 @@ version = "0.29.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d8b9f2e4c67f833b660cdb0a3523065869fb35570177239812ed4c905aeff87b" dependencies = [ - "bitflags 2.10.0", + "bitflags 2.12.1", "crossterm_winapi", "derive_more 2.1.1", "document-features", @@ -1336,7 +1306,7 @@ dependencies = [ "proc-macro2", "quote", "strsim 0.11.1", - "syn 2.0.114", + "syn 2.0.117", ] [[package]] @@ -1347,7 +1317,7 @@ checksum = "ac3984ec7bd6cfa798e62b4a642426a5be0e68f9401cfc2a01e3fa9ea2fcdb8d" dependencies = [ "darling_core", "quote", - "syn 2.0.114", + "syn 2.0.117", ] [[package]] @@ -1467,7 +1437,7 @@ dependencies = [ "convert_case 0.6.0", "proc-macro2", "quote", - "syn 2.0.114", + "syn 2.0.117", "unicode-xid", ] @@ -1481,7 +1451,7 @@ dependencies = [ "proc-macro2", "quote", "rustc_version", - "syn 2.0.114", + "syn 2.0.117", ] [[package]] @@ -1539,7 +1509,7 @@ dependencies = [ "libc", "option-ext", "redox_users 0.5.2", - "windows-sys 0.61.2", + "windows-sys 0.60.2", ] [[package]] @@ -1559,7 +1529,7 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "89a09f22a6c6069a18470eb92d2298acf25463f14256d24778e1230d789a2aec" dependencies = [ - "bitflags 2.10.0", + "bitflags 2.12.1", "objc2", ] @@ -1581,7 +1551,7 @@ checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.114", + "syn 2.0.117", ] [[package]] @@ -1605,12 +1575,6 @@ version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "75b325c5dbd37f80359721ad39aca5a29fb04c89279657cffdda8736d0c0b9d2" -[[package]] -name = "dunce" -version = "1.0.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92773504d58c093f6de2459af4af33faa518c13451eb8f2b5698ed3d36e7c813" - [[package]] name = "dupe" version = "0.9.1" @@ -1628,7 +1592,7 @@ checksum = "83e195b4945e88836d826124af44fdcb262ec01ef94d44f14f4fb5103f19892a" dependencies = [ "proc-macro2", "quote", - "syn 2.0.114", + "syn 2.0.117", ] [[package]] @@ -1654,9 +1618,9 @@ dependencies = [ [[package]] name = "ena" -version = "0.14.3" +version = "0.14.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d248bdd43ce613d87415282f69b9bb99d947d290b10962dd6c56233312c2ad5" +checksum = "eabffdaee24bd1bf95c5ef7cec31260444317e72ea56c4c91750e8b7ee58d5f1" dependencies = [ "log", ] @@ -1700,7 +1664,7 @@ checksum = "67c78a4d8fdf9953a5c9d458f9efe940fd97a0cab0941c075a813ac594733827" dependencies = [ "proc-macro2", "quote", - "syn 2.0.114", + "syn 2.0.117", ] [[package]] @@ -1725,7 +1689,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" dependencies = [ "libc", - "windows-sys 0.61.2", + "windows-sys 0.60.2", ] [[package]] @@ -1829,7 +1793,7 @@ checksum = "a0aca10fb742cb43f9e7bb8467c91aa9bcb8e3ffbc6a6f7389bb93ffc920577d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.114", + "syn 2.0.117", ] [[package]] @@ -1944,12 +1908,6 @@ dependencies = [ "num", ] -[[package]] -name = "fs_extra" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42703706b716c37f96a77aea830392ad231f44c9e9a67872fa5548707e11b11c" - [[package]] name = "futures" version = "0.3.31" @@ -2019,7 +1977,7 @@ checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" dependencies = [ "proc-macro2", "quote", - "syn 2.0.114", + "syn 2.0.117", ] [[package]] @@ -2088,10 +2046,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "335ff9f135e4384c8150d6f27c6daed433577f86b4750418338c01a1a2528592" dependencies = [ "cfg-if", - "js-sys", "libc", "wasi", - "wasm-bindgen", ] [[package]] @@ -2571,14 +2527,14 @@ dependencies = [ "indoc", "proc-macro2", "quote", - "syn 2.0.114", + "syn 2.0.117", ] [[package]] name = "inventory" -version = "0.3.21" +version = "0.3.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc61209c082fbeb19919bee74b176221b27223e27b65d781eb91af24eb1fb46e" +checksum = "a4f0c30c76f2f4ccee3fe55a2435f691ca00c0e4bd87abe4f4a851b1d4dac39b" dependencies = [ "rustversion", ] @@ -2607,7 +2563,7 @@ checksum = "3640c1c38b8e4e43584d8df18be5fc6b0aa314ce6ebf51b53313d4306cca8e46" dependencies = [ "hermit-abi", "libc", - "windows-sys 0.61.2", + "windows-sys 0.60.2", ] [[package]] @@ -2671,16 +2627,6 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8eaf4bc02d17cbdd7ff4c7438cafcdf7fb9a4613313ad11b4f8fefe7d3fa0130" -[[package]] -name = "jobserver" -version = "0.1.34" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9afb3de4395d6b3e67a780b6de64b51c978ecf11cb9a462c66be7d4ca9039d33" -dependencies = [ - "getrandom 0.3.4", - "libc", -] - [[package]] name = "js-sys" version = "0.3.83" @@ -2791,9 +2737,9 @@ checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" [[package]] name = "libc" -version = "0.2.180" +version = "0.2.186" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bcc35a38544a891a5f7c865aca548a982ccb3b8650a5b06d0fd33a10283c56fc" +checksum = "68ab91017fe16c622486840e4c83c9a37afeff978bd239b5293d61ece587de66" [[package]] name = "libdbus-sys" @@ -2810,7 +2756,7 @@ version = "0.1.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3d0b95e02c851351f877147b7deea7b1afb1df71b63aa5f8270716e0c5720616" dependencies = [ - "bitflags 2.10.0", + "bitflags 2.12.1", "libc", "redox_syscall 0.7.4", ] @@ -2832,7 +2778,7 @@ version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5f4de44e98ddbf09375cbf4d17714d18f39195f4f4894e8524501726fd9a8a4a" dependencies = [ - "bitflags 2.10.0", + "bitflags 2.12.1", ] [[package]] @@ -2841,7 +2787,7 @@ version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "83270a18e9f90d0707c41e9f35efada77b64c0e6f3f1810e71c8368a864d5590" dependencies = [ - "bitflags 2.10.0", + "bitflags 2.12.1", "libc", ] @@ -2934,12 +2880,6 @@ dependencies = [ "hashbrown 0.16.1", ] -[[package]] -name = "lru-slab" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "112b39cec0b298b6c1999fee3e31427f74f676e4cb9879ed1a121b43661a4154" - [[package]] name = "lsp-types" version = "0.94.1" @@ -2996,9 +2936,9 @@ dependencies = [ [[package]] name = "memchr" -version = "2.7.6" +version = "2.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f52b00d39961fc5b2736ea853c9cc86238e165017a493d1d5c8eac6bdc4cc273" +checksum = "6b947ae49db0d222b1dbc6b113ce7248a3fc3a6ca21b696717bfc000ba4484d8" [[package]] name = "memmem" @@ -3114,7 +3054,7 @@ version = "0.28.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ab2156c4fce2f8df6c499cc1c763e4394b7482525bf2a9701c9d79d215f519e4" dependencies = [ - "bitflags 2.10.0", + "bitflags 2.12.1", "cfg-if", "cfg_aliases 0.1.1", "libc", @@ -3126,7 +3066,7 @@ version = "0.29.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "71e2746dc3a24dd78b3cfcb7be93368c6de9963d30f43a6a73998a9cf4b17b46" dependencies = [ - "bitflags 2.10.0", + "bitflags 2.12.1", "cfg-if", "cfg_aliases 0.2.1", "libc", @@ -3149,7 +3089,7 @@ version = "0.50.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7957b9740744892f114936ab4a57b3f487491bbeafaf8083688b16841a4240e5" dependencies = [ - "windows-sys 0.61.2", + "windows-sys 0.60.2", ] [[package]] @@ -3205,7 +3145,7 @@ checksum = "ed3955f1a9c7c0c15e092f9c887db08b1fc683305fdf6eb6684f22555355e202" dependencies = [ "proc-macro2", "quote", - "syn 2.0.114", + "syn 2.0.117", ] [[package]] @@ -3282,7 +3222,7 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d49e936b501e5c5bf01fda3a9452ff86dc3ea98ad5f283e1455153142d97518c" dependencies = [ - "bitflags 2.10.0", + "bitflags 2.12.1", "objc2", "objc2-core-graphics", "objc2-foundation", @@ -3294,7 +3234,7 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2a180dd8642fa45cdb7dd721cd4c11b1cadd4929ce112ebd8b9f5803cc79d536" dependencies = [ - "bitflags 2.10.0", + "bitflags 2.12.1", "dispatch2", "objc2", ] @@ -3305,7 +3245,7 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e022c9d066895efa1345f8e33e584b9f958da2fd4cd116792e15e07e4720a807" dependencies = [ - "bitflags 2.10.0", + "bitflags 2.12.1", "dispatch2", "objc2", "objc2-core-foundation", @@ -3324,7 +3264,7 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e3e0adef53c21f888deb4fa59fc59f7eb17404926ee8a6f59f5df0fd7f9f3272" dependencies = [ - "bitflags 2.10.0", + "bitflags 2.12.1", "objc2", "objc2-core-foundation", ] @@ -3335,7 +3275,7 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "180788110936d59bab6bd83b6060ffdfffb3b922ba1396b312ae795e1de9d81d" dependencies = [ - "bitflags 2.10.0", + "bitflags 2.12.1", "objc2", "objc2-core-foundation", ] @@ -3475,7 +3415,7 @@ dependencies = [ "pest_meta", "proc-macro2", "quote", - "syn 2.0.114", + "syn 2.0.117", ] [[package]] @@ -3525,7 +3465,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3c80231409c20246a13fddb31776fb942c38553c51e871f8cbd687a4cfb5843d" dependencies = [ "phf_shared", - "rand 0.8.6", + "rand", ] [[package]] @@ -3538,7 +3478,7 @@ dependencies = [ "phf_shared", "proc-macro2", "quote", - "syn 2.0.114", + "syn 2.0.117", ] [[package]] @@ -3585,7 +3525,7 @@ version = "0.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "97baced388464909d42d89643fe4361939af9b7ce7a31ee32a168f832a70f2a0" dependencies = [ - "bitflags 2.10.0", + "bitflags 2.12.1", "crc32fast", "fdeflate", "flate2", @@ -3696,9 +3636,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.105" +version = "1.0.106" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "535d180e0ecab6268a3e718bb9fd44db66bbbc256257165fc699dadf70d16fe7" +checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934" dependencies = [ "unicode-ident", ] @@ -3724,67 +3664,11 @@ version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a993555f31e5a609f617c12db6250dedcac1b0a85076912c436e6fc9b2c8e6a3" -[[package]] -name = "quinn" -version = "0.11.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9e20a958963c291dc322d98411f541009df2ced7b5a4f2bd52337638cfccf20" -dependencies = [ - "bytes", - "cfg_aliases 0.2.1", - "pin-project-lite", - "quinn-proto", - "quinn-udp", - "rustc-hash", - "rustls", - "socket2", - "thiserror 2.0.18", - "tokio", - "tracing", - "web-time", -] - -[[package]] -name = "quinn-proto" -version = "0.11.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "434b42fec591c96ef50e21e886936e66d3cc3f737104fdb9b737c40ffb94c098" -dependencies = [ - "aws-lc-rs", - "bytes", - "getrandom 0.3.4", - "lru-slab", - "rand 0.9.3", - "ring", - "rustc-hash", - "rustls", - "rustls-pki-types", - "slab", - "thiserror 2.0.18", - "tinyvec", - "tracing", - "web-time", -] - -[[package]] -name = "quinn-udp" -version = "0.5.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "addec6a0dcad8a8d96a771f815f0eaf55f9d1805756410b39f5fa81332574cbd" -dependencies = [ - "cfg_aliases 0.2.1", - "libc", - "once_cell", - "socket2", - "tracing", - "windows-sys 0.60.2", -] - [[package]] name = "quote" -version = "1.0.43" +version = "1.0.45" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc74d9a594b72ae6656596548f56f667211f8a97b3d4c3d467150794690dc40a" +checksum = "41f2619966050689382d2b44f664f4bc593e129785a36d6ee376ddf37259b924" dependencies = [ "proc-macro2", ] @@ -3812,18 +3696,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5ca0ecfa931c29007047d1bc58e623ab12e5590e8c7cc53200d5202b69266d8a" dependencies = [ "libc", - "rand_chacha 0.3.1", - "rand_core 0.6.4", -] - -[[package]] -name = "rand" -version = "0.9.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ec095654a25171c2124e9e3393a930bddbffdc939556c914957a4c3e0a87166" -dependencies = [ - "rand_chacha 0.9.0", - "rand_core 0.9.5", + "rand_chacha", + "rand_core", ] [[package]] @@ -3833,17 +3707,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" dependencies = [ "ppv-lite86", - "rand_core 0.6.4", -] - -[[package]] -name = "rand_chacha" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb" -dependencies = [ - "ppv-lite86", - "rand_core 0.9.5", + "rand_core", ] [[package]] @@ -3855,15 +3719,6 @@ dependencies = [ "getrandom 0.2.16", ] -[[package]] -name = "rand_core" -version = "0.9.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76afc826de14238e6e8c374ddcc1fa19e374fd8dd986b0d2af0d02377261d83c" -dependencies = [ - "getrandom 0.3.4", -] - [[package]] name = "rangemap" version = "1.7.1" @@ -3890,7 +3745,7 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5ef8dea09a92caaf73bff7adb70b76162e5937524058a7e5bff37869cbbec293" dependencies = [ - "bitflags 2.10.0", + "bitflags 2.12.1", "compact_str", "hashbrown 0.16.1", "indoc", @@ -3901,7 +3756,7 @@ dependencies = [ "thiserror 2.0.18", "unicode-segmentation", "unicode-truncate", - "unicode-width 0.2.0", + "unicode-width 0.2.2", ] [[package]] @@ -3942,7 +3797,7 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d7dbfa023cd4e604c2553483820c5fe8aa9d71a42eea5aa77c6e7f35756612db" dependencies = [ - "bitflags 2.10.0", + "bitflags 2.12.1", "hashbrown 0.16.1", "indoc", "instability", @@ -3952,7 +3807,7 @@ dependencies = [ "strum", "time", "unicode-segmentation", - "unicode-width 0.2.0", + "unicode-width 0.2.2", ] [[package]] @@ -3961,7 +3816,7 @@ version = "0.5.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ed2bf2547551a7053d6fdfafda3f938979645c44812fbfcda098faae3f1a362d" dependencies = [ - "bitflags 2.10.0", + "bitflags 2.12.1", ] [[package]] @@ -3970,7 +3825,7 @@ version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f450ad9c3b1da563fb6948a8e0fb0fb9269711c9c73d9ea1de5058c79c8d643a" dependencies = [ - "bitflags 2.10.0", + "bitflags 2.12.1", ] [[package]] @@ -4012,7 +3867,7 @@ checksum = "b7186006dcb21920990093f30e3dea63b7d6e977bf1256be20c3563a5db070da" dependencies = [ "proc-macro2", "quote", - "syn 2.0.114", + "syn 2.0.117", ] [[package]] @@ -4090,7 +3945,6 @@ dependencies = [ "mime_guess", "percent-encoding", "pin-project-lite", - "quinn", "rustls", "rustls-pki-types", "rustls-platform-verifier", @@ -4131,7 +3985,7 @@ version = "0.32.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7753b721174eb8ff87a9a0e799e2d7bc3749323e773db92e0984debb00019d6e" dependencies = [ - "bitflags 2.10.0", + "bitflags 2.12.1", "fallible-iterator", "fallible-streaming-iterator", "hashlink", @@ -4139,12 +3993,6 @@ dependencies = [ "smallvec", ] -[[package]] -name = "rustc-hash" -version = "2.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "357703d41365b4b27c590e3ed91eabb1b663f07c4c084095e60cbed4362dff0d" - [[package]] name = "rustc_version" version = "0.4.1" @@ -4160,7 +4008,7 @@ version = "0.38.44" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fdb5bc1ae2baa591800df16c9ca78619bf65c0488b41b96ccec5d11220d8c154" dependencies = [ - "bitflags 2.10.0", + "bitflags 2.12.1", "errno", "libc", "linux-raw-sys 0.4.15", @@ -4173,11 +4021,11 @@ version = "1.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "146c9e247ccc180c1f61615433868c99f3de3ae256a30a43b49f67c2d9171f34" dependencies = [ - "bitflags 2.10.0", + "bitflags 2.12.1", "errno", "libc", "linux-raw-sys 0.11.0", - "windows-sys 0.61.2", + "windows-sys 0.60.2", ] [[package]] @@ -4186,8 +4034,8 @@ version = "0.23.36" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c665f33d38cea657d9614f766881e4d510e0eda4239891eea56b4cadcf01801b" dependencies = [ - "aws-lc-rs", "once_cell", + "ring", "rustls-pki-types", "rustls-webpki", "subtle", @@ -4212,7 +4060,6 @@ version = "1.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "21e6f2ab2928ca4291b86736a8bd920a277a399bba1589409d72154ff87c1282" dependencies = [ - "web-time", "zeroize", ] @@ -4234,7 +4081,7 @@ dependencies = [ "security-framework 3.5.1", "security-framework-sys", "webpki-root-certs", - "windows-sys 0.61.2", + "windows-sys 0.60.2", ] [[package]] @@ -4249,7 +4096,6 @@ version = "0.103.13" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "61c429a8649f110dddef65e2a5ad240f747e85f7758a6bccc7e5777bd33f756e" dependencies = [ - "aws-lc-rs", "ring", "rustls-pki-types", "untrusted", @@ -4267,7 +4113,7 @@ version = "14.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7803e8936da37efd9b6d4478277f4b2b9bb5cdb37a113e8d63222e58da647e63" dependencies = [ - "bitflags 2.10.0", + "bitflags 2.12.1", "cfg-if", "clipboard-win", "fd-lock", @@ -4283,28 +4129,6 @@ dependencies = [ "windows-sys 0.52.0", ] -[[package]] -name = "rustyline" -version = "15.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2ee1e066dc922e513bda599c6ccb5f3bb2b0ea5870a579448f2622993f0a9a2f" -dependencies = [ - "bitflags 2.10.0", - "cfg-if", - "clipboard-win", - "fd-lock", - "home", - "libc", - "log", - "memchr", - "nix 0.29.0", - "radix_trie", - "unicode-segmentation", - "unicode-width 0.2.0", - "utf8parse", - "windows-sys 0.59.0", -] - [[package]] name = "ryu" version = "1.0.22" @@ -4393,7 +4217,7 @@ dependencies = [ "proc-macro2", "quote", "serde_derive_internals", - "syn 2.0.114", + "syn 2.0.117", ] [[package]] @@ -4416,7 +4240,7 @@ dependencies = [ "sha2 0.11.0", "tokio", "toml 1.0.6+spec-1.1.0", - "unicode-width 0.2.0", + "unicode-width 0.2.2", ] [[package]] @@ -4438,7 +4262,7 @@ dependencies = [ "hkdf", "num", "once_cell", - "rand 0.8.6", + "rand", "serde", "sha2 0.10.9", "zbus", @@ -4450,7 +4274,7 @@ version = "2.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "897b2245f0b511c87893af39b033e5ca9cce68824c4d7e7630b5a1d339658d02" dependencies = [ - "bitflags 2.10.0", + "bitflags 2.12.1", "core-foundation 0.9.4", "core-foundation-sys", "libc", @@ -4463,7 +4287,7 @@ version = "3.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b3297343eaf830f66ede390ea39da1d462b6b0c1b000f420d0a83f898bbbe6ef" dependencies = [ - "bitflags 2.10.0", + "bitflags 2.12.1", "core-foundation 0.10.1", "core-foundation-sys", "libc", @@ -4513,7 +4337,7 @@ checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" dependencies = [ "proc-macro2", "quote", - "syn 2.0.114", + "syn 2.0.117", ] [[package]] @@ -4524,7 +4348,7 @@ checksum = "18d26a20a969b9e3fdf2fc2d9f21eda6c40e2de84c9408bb5d3b05d499aae711" dependencies = [ "proc-macro2", "quote", - "syn 2.0.114", + "syn 2.0.117", ] [[package]] @@ -4560,7 +4384,7 @@ checksum = "175ee3e80ae9982737ca543e96133087cbd9a485eecc3bc4de9c1a37b47ea59c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.114", + "syn 2.0.117", ] [[package]] @@ -4773,7 +4597,7 @@ dependencies = [ "paste", "ref-cast", "regex", - "rustyline 14.0.0", + "rustyline", "serde", "serde_json", "starlark_derive", @@ -4794,7 +4618,7 @@ dependencies = [ "dupe", "proc-macro2", "quote", - "syn 2.0.114", + "syn 2.0.117", ] [[package]] @@ -4883,7 +4707,7 @@ dependencies = [ "heck", "proc-macro2", "quote", - "syn 2.0.114", + "syn 2.0.117", ] [[package]] @@ -4905,9 +4729,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.114" +version = "2.0.117" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4d107df263a3013ef9b1879b0df87d706ff80f65a86ea879bd9c31f9b307c2a" +checksum = "e665b8803e7b1d2a727f4023456bbbbe74da67099c585258af0ad9c5013b9b99" dependencies = [ "proc-macro2", "quote", @@ -4931,7 +4755,7 @@ checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2" dependencies = [ "proc-macro2", "quote", - "syn 2.0.114", + "syn 2.0.117", ] [[package]] @@ -4955,7 +4779,7 @@ dependencies = [ "getrandom 0.3.4", "once_cell", "rustix 1.1.3", - "windows-sys 0.61.2", + "windows-sys 0.60.2", ] [[package]] @@ -4998,7 +4822,7 @@ checksum = "4676b37242ccbd1aabf56edb093a4827dc49086c0ffd764a5705899e0f35f8f7" dependencies = [ "anyhow", "base64", - "bitflags 2.10.0", + "bitflags 2.12.1", "fancy-regex 0.11.0", "filedescriptor", "finl_unicode", @@ -5067,7 +4891,7 @@ checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" dependencies = [ "proc-macro2", "quote", - "syn 2.0.114", + "syn 2.0.117", ] [[package]] @@ -5078,7 +4902,7 @@ checksum = "ebc4ee7f67670e9b64d05fa4253e753e016c6c95ff35b89b7941d6b856dec1d5" dependencies = [ "proc-macro2", "quote", - "syn 2.0.114", + "syn 2.0.117", ] [[package]] @@ -5208,7 +5032,7 @@ checksum = "af407857209536a95c8e56f8231ef2c2e2aff839b22e07a1ffcbc617e9db9fa5" dependencies = [ "proc-macro2", "quote", - "syn 2.0.114", + "syn 2.0.117", ] [[package]] @@ -5332,7 +5156,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d4e6559d53cc268e5031cd8429d05415bc4cb4aefc4aa5d6cc35fbf5b924a1f8" dependencies = [ "async-compression", - "bitflags 2.10.0", + "bitflags 2.12.1", "bytes", "futures-core", "futures-util", @@ -5392,7 +5216,7 @@ checksum = "7490cfa5ec963746568740651ac6781f701c9c5ea257c58e057f3ba8cf69e8da" dependencies = [ "proc-macro2", "quote", - "syn 2.0.114", + "syn 2.0.117", ] [[package]] @@ -5469,7 +5293,7 @@ checksum = "f2f6fb2847f6742cd76af783a2a2c49e9375d0a111c7bef6f71cd9e738c72d6e" dependencies = [ "memoffset 0.9.1", "tempfile", - "windows-sys 0.61.2", + "windows-sys 0.60.2", ] [[package]] @@ -5513,7 +5337,7 @@ checksum = "16b380a1238663e5f8a691f9039c73e1cdae598a30e9855f541d29b08b53e9a5" dependencies = [ "itertools 0.14.0", "unicode-segmentation", - "unicode-width 0.2.0", + "unicode-width 0.2.2", ] [[package]] @@ -5524,9 +5348,9 @@ checksum = "7dd6e30e90baa6f72411720665d41d89b9a3d039dc45b8faea1ddd07f617f6af" [[package]] name = "unicode-width" -version = "0.2.0" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fc81956842c57dac11422a97c3b8195a1ff727f06e85c84ed2e8aa277c9a0fd" +checksum = "b4ac048d71ede7ee76d585517add45da530660ef4390e49b098733c6e897f254" [[package]] name = "unicode-xid" @@ -5741,7 +5565,7 @@ dependencies = [ "bumpalo", "proc-macro2", "quote", - "syn 2.0.114", + "syn 2.0.117", "wasm-bindgen-shared", ] @@ -5777,16 +5601,6 @@ dependencies = [ "wasm-bindgen", ] -[[package]] -name = "web-time" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a6580f308b1fad9207618087a65c04e7a10bc77e02c8e84e9b00dd4b12fa0bb" -dependencies = [ - "js-sys", - "wasm-bindgen", -] - [[package]] name = "webpki-root-certs" version = "1.0.6" @@ -5896,7 +5710,7 @@ version = "0.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22" dependencies = [ - "windows-sys 0.61.2", + "windows-sys 0.60.2", ] [[package]] @@ -5971,7 +5785,7 @@ checksum = "83577b051e2f49a058c308f17f273b570a6a758386fc291b5f6a934dd84e48c1" dependencies = [ "proc-macro2", "quote", - "syn 2.0.114", + "syn 2.0.117", ] [[package]] @@ -5982,7 +5796,7 @@ checksum = "053e2e040ab57b9dc951b72c264860db7eb3b0200ba345b4e4c3b14f67855ddf" dependencies = [ "proc-macro2", "quote", - "syn 2.0.114", + "syn 2.0.117", ] [[package]] @@ -5993,7 +5807,7 @@ checksum = "3f316c4a2570ba26bbec722032c4099d8c8bc095efccdc15688708623367e358" dependencies = [ "proc-macro2", "quote", - "syn 2.0.114", + "syn 2.0.117", ] [[package]] @@ -6406,7 +6220,7 @@ checksum = "b659052874eb698efe5b9e8cf382204678a0086ebf46982b79d6ca3182927e5d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.114", + "syn 2.0.117", "synstructure", ] @@ -6428,7 +6242,7 @@ dependencies = [ "hex", "nix 0.29.0", "ordered-stream", - "rand 0.8.6", + "rand", "serde", "serde_repr", "sha1", @@ -6451,7 +6265,7 @@ dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.114", + "syn 2.0.117", "zvariant_utils", ] @@ -6483,7 +6297,7 @@ checksum = "2c7962b26b0a8685668b671ee4b54d007a67d4eaf05fda79ac0ecf41e32270f1" dependencies = [ "proc-macro2", "quote", - "syn 2.0.114", + "syn 2.0.117", ] [[package]] @@ -6503,7 +6317,7 @@ checksum = "d71e5d6e06ab090c67b5e44993ec16b72dcbaabc526db883a360057678b48502" dependencies = [ "proc-macro2", "quote", - "syn 2.0.114", + "syn 2.0.117", "synstructure", ] @@ -6524,7 +6338,7 @@ checksum = "85a5b4158499876c763cb03bc4e49185d3cccbabb15b33c627f7884f43db852e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.114", + "syn 2.0.117", ] [[package]] @@ -6557,7 +6371,7 @@ checksum = "eadce39539ca5cb3985590102671f2567e659fca9666581ad3411d59207951f3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.114", + "syn 2.0.117", ] [[package]] @@ -6603,7 +6417,7 @@ dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.114", + "syn 2.0.117", "zvariant_utils", ] @@ -6615,5 +6429,5 @@ checksum = "c51bcff7cc3dbb5055396bcf774748c3dab426b4b8659046963523cee4808340" dependencies = [ "proc-macro2", "quote", - "syn 2.0.114", + "syn 2.0.117", ] diff --git a/Cargo.toml b/Cargo.toml index 32f94939..7dae3432 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -38,7 +38,8 @@ chrono = { version = "0.4.43", features = ["serde"] } clap = { version = "4.5.54", features = ["derive"] } clap_complete = "4.5" dirs = "6.0.0" -reqwest = { version = "0.13.1", default-features = false, features = ["json", "rustls", "socks"] } +reqwest = { version = "0.13.1", default-features = false, features = ["json", "rustls-no-provider", "socks"] } +rustls = { version = "0.23.36", default-features = false, features = ["ring", "std", "tls12"] } rusqlite = { version = "0.32.1", features = ["bundled"] } serde = { version = "1.0.228", features = ["derive"] } serde_json = "1.0.149" diff --git a/README.ja-JP.md b/README.ja-JP.md index 92fdb3c3..937069f6 100644 --- a/README.ja-JP.md +++ b/README.ja-JP.md @@ -143,6 +143,8 @@ codewhale doctor # セットアップを検証 `npm i -g codewhale` は v0.8.8 以降、glibc ベースの ARM64 Linux で動作します。[Releases ページ](https://github.com/Hmbown/CodeWhale/releases) からビルド済みバイナリをダウンロードし、`PATH` 上に並べて配置することもできます。 +HarmonyOS PC と OpenHarmony クロスビルドの設定は [docs/HarmonyOS.md](docs/HarmonyOS.md) を参照してください。 + ### 中国 / ミラーフレンドリーなインストール 中国本土から GitHub または npm のダウンロードが遅い場合は、Cargo レジストリのミラーを利用してください: diff --git a/README.md b/README.md index b22d3ffc..1f481c47 100644 --- a/README.md +++ b/README.md @@ -221,6 +221,8 @@ Prebuilt binary pairs and platform archives are published for Linux x64, Linux ARM64, macOS x64, macOS ARM64, and Windows x64. For other targets, see [docs/INSTALL.md](docs/INSTALL.md). +For HarmonyOS PC and OpenHarmony cross-build setup, see [docs/HarmonyOS.md](docs/HarmonyOS.md). + ### China / Mirror-friendly Installation If GitHub or npm downloads are slow from mainland China, use diff --git a/README.vi.md b/README.vi.md index d4404475..c65f3daf 100644 --- a/README.vi.md +++ b/README.vi.md @@ -183,6 +183,8 @@ Hãy chỉ định mô hình hoặc cấp độ suy nghĩ cố định nếu b Lệnh cài đặt `npm i -g codewhale` hoạt động trên môi trường Linux ARM64 nền glibc từ phiên bản v0.8.8 trở đi. Bạn cũng có thể tải trực tiếp các tệp binary dựng sẵn từ [trang phát hành Releases](https://github.com/Hmbown/CodeWhale/releases) và đặt chúng cạnh nhau trong một thư mục thuộc biến `PATH`. +Xem [docs/HarmonyOS.md](docs/HarmonyOS.md) để cấu hình HarmonyOS PC và cross-build OpenHarmony. + ### Cài đặt thân thiện qua Mirror (Tại Trung Quốc) Nếu việc tải xuống từ GitHub hoặc npm bị chậm từ Trung Quốc đại lục, bạn hãy sử dụng mirror registry cho Cargo: diff --git a/README.zh-CN.md b/README.zh-CN.md index c5695357..7740cb4b 100644 --- a/README.zh-CN.md +++ b/README.zh-CN.md @@ -186,6 +186,8 @@ Auto 模式同时控制两个设置: 从 v0.8.8 起,`npm i -g codewhale` 直接支持 glibc 系的 ARM64 Linux。你也可以从 [Releases 页面](https://github.com/Hmbown/CodeWhale/releases) 下载预编译二进制,放到 `PATH` 目录中。 +HarmonyOS PC 运行和 OpenHarmony 交叉编译配置见 [docs/HarmonyOS.md](docs/HarmonyOS.md)。 + ### 中国大陆 / 镜像友好安装 如果在中国大陆访问 GitHub 或 npm 下载较慢,可以通过 Cargo 注册表镜像安装: diff --git a/crates/app-server/Cargo.toml b/crates/app-server/Cargo.toml index aa5a1cf3..39e37022 100644 --- a/crates/app-server/Cargo.toml +++ b/crates/app-server/Cargo.toml @@ -21,6 +21,7 @@ codewhale-state = { path = "../state", version = "0.8.53" } codewhale-tools = { path = "../tools", version = "0.8.53" } serde.workspace = true serde_json.workspace = true +rustls.workspace = true tokio.workspace = true tower-http.workspace = true uuid.workspace = true diff --git a/crates/app-server/src/main.rs b/crates/app-server/src/main.rs index 9627746e..8fcb8f19 100644 --- a/crates/app-server/src/main.rs +++ b/crates/app-server/src/main.rs @@ -27,6 +27,8 @@ struct Cli { #[tokio::main] async fn main() -> Result<()> { + install_rustls_crypto_provider(); + let cli = Cli::parse(); let listen: SocketAddr = format!("{}:{}", cli.host, cli.port) .parse() @@ -41,6 +43,10 @@ async fn main() -> Result<()> { .await } +fn install_rustls_crypto_provider() { + let _ = rustls::crypto::ring::default_provider().install_default(); +} + fn app_server_token_from_env() -> Option { std::env::var("CODEWHALE_APP_SERVER_TOKEN") .ok() diff --git a/crates/cli/Cargo.toml b/crates/cli/Cargo.toml index 8c23f204..f567b79b 100644 --- a/crates/cli/Cargo.toml +++ b/crates/cli/Cargo.toml @@ -38,6 +38,7 @@ dirs.workspace = true serde.workspace = true serde_json.workspace = true reqwest = { workspace = true, features = ["blocking"] } +rustls.workspace = true semver.workspace = true tokio.workspace = true sha2.workspace = true diff --git a/crates/cli/src/lib.rs b/crates/cli/src/lib.rs index ba94aeb5..209a6a43 100644 --- a/crates/cli/src/lib.rs +++ b/crates/cli/src/lib.rs @@ -471,7 +471,13 @@ struct AppServerArgs { const MCP_SERVER_DEFINITIONS_KEY: &str = "mcp.server_definitions"; +fn install_rustls_crypto_provider() { + let _ = rustls::crypto::ring::default_provider().install_default(); +} + pub fn run_cli() -> std::process::ExitCode { + install_rustls_crypto_provider(); + match run() { Ok(()) => std::process::ExitCode::SUCCESS, Err(err) => { diff --git a/crates/cli/src/update.rs b/crates/cli/src/update.rs index 2c90422b..c9d9ca7c 100644 --- a/crates/cli/src/update.rs +++ b/crates/cli/src/update.rs @@ -20,6 +20,12 @@ use std::io::Write; /// Run the self-update workflow. pub fn run_update(beta: bool, check_only: bool, proxy_arg: Option) -> Result<()> { + #[cfg(target_env = "ohos")] + { + let _ = (beta, check_only, proxy_arg); + bail!("self-update is not supported on HarmonyOS/OpenHarmony yet"); + } + let current_exe = std::env::current_exe().context("failed to determine current executable path")?; let targets = update_targets_for_exe(¤t_exe); @@ -353,6 +359,8 @@ pub(crate) fn validate_and_build_proxy(proxy_str: &str) -> Result { } fn update_http_client(proxy: Option<&Proxy>) -> Result { + let _ = rustls::crypto::ring::default_provider().install_default(); + let mut builder = reqwest::blocking::Client::builder(); if let Some(proxy) = proxy { builder = builder.proxy(proxy.clone()); diff --git a/crates/release/Cargo.toml b/crates/release/Cargo.toml index 67520686..699419bb 100644 --- a/crates/release/Cargo.toml +++ b/crates/release/Cargo.toml @@ -9,6 +9,7 @@ description = "Shared CodeWhale release discovery and version comparison helpers [dependencies] anyhow.workspace = true reqwest = { workspace = true, features = ["blocking"] } +rustls.workspace = true semver.workspace = true serde.workspace = true serde_json.workspace = true diff --git a/crates/secrets/Cargo.toml b/crates/secrets/Cargo.toml index 84817420..7db781eb 100644 --- a/crates/secrets/Cargo.toml +++ b/crates/secrets/Cargo.toml @@ -19,7 +19,7 @@ keyring = { version = "3", features = ["apple-native"] } [target.'cfg(target_os = "windows")'.dependencies] keyring = { version = "3", features = ["windows-native"] } -[target.'cfg(target_os = "linux")'.dependencies] +[target.'cfg(all(target_os = "linux", not(target_env = "ohos")))'.dependencies] keyring = { version = "3", features = ["linux-native-sync-persistent", "crypto-rust"] } [dev-dependencies] diff --git a/crates/secrets/src/lib.rs b/crates/secrets/src/lib.rs index 65c9c185..d9826b45 100644 --- a/crates/secrets/src/lib.rs +++ b/crates/secrets/src/lib.rs @@ -92,7 +92,7 @@ pub trait KeyringStore: Send + Sync { /// Wraps the platform credential store: /// - **macOS**: Keychain (via `security` framework) /// - **Windows**: Credential Manager -/// - **Linux**: Secret Service (GNOME Keyring / kwallet via dbus) +/// - **Linux**: Secret Service (GNOME Keyring / kwallet via dbus), excluding OHOS /// /// This backend is opt-in -- set the [`SECRET_BACKEND_ENV`] environment /// variable to `system` or `keyring` to activate it. On platforms without @@ -124,7 +124,11 @@ impl DefaultKeyringStore { /// Probe the OS keyring without writing anything. Returns `Ok(())` if /// a backend is reachable, otherwise an error describing why not. pub fn probe(&self) -> Result<(), SecretsError> { - #[cfg(any(target_os = "macos", target_os = "windows", target_os = "linux"))] + #[cfg(any( + target_os = "macos", + target_os = "windows", + all(target_os = "linux", not(target_env = "ohos")) + ))] { // `Entry::new` is enough to validate the native macOS/Windows // backend path. Avoid a dummy read there because it can trigger @@ -149,7 +153,11 @@ impl DefaultKeyringStore { Err(other) => Err(SecretsError::Keyring(other.to_string())), } } - #[cfg(not(any(target_os = "macos", target_os = "windows", target_os = "linux")))] + #[cfg(not(any( + target_os = "macos", + target_os = "windows", + all(target_os = "linux", not(target_env = "ohos")) + )))] { let _ = &self.service; Err(SecretsError::Keyring(unsupported_keyring_message())) @@ -159,7 +167,11 @@ impl DefaultKeyringStore { impl KeyringStore for DefaultKeyringStore { fn get(&self, key: &str) -> Result, SecretsError> { - #[cfg(any(target_os = "macos", target_os = "windows", target_os = "linux"))] + #[cfg(any( + target_os = "macos", + target_os = "windows", + all(target_os = "linux", not(target_env = "ohos")) + ))] { let entry = keyring::Entry::new(&self.service, key) .map_err(|err| SecretsError::Keyring(err.to_string()))?; @@ -169,7 +181,11 @@ impl KeyringStore for DefaultKeyringStore { Err(err) => Err(SecretsError::Keyring(err.to_string())), } } - #[cfg(not(any(target_os = "macos", target_os = "windows", target_os = "linux")))] + #[cfg(not(any( + target_os = "macos", + target_os = "windows", + all(target_os = "linux", not(target_env = "ohos")) + )))] { let _ = key; Err(SecretsError::Keyring(unsupported_keyring_message())) @@ -177,7 +193,11 @@ impl KeyringStore for DefaultKeyringStore { } fn set(&self, key: &str, value: &str) -> Result<(), SecretsError> { - #[cfg(any(target_os = "macos", target_os = "windows", target_os = "linux"))] + #[cfg(any( + target_os = "macos", + target_os = "windows", + all(target_os = "linux", not(target_env = "ohos")) + ))] { let entry = keyring::Entry::new(&self.service, key) .map_err(|err| SecretsError::Keyring(err.to_string()))?; @@ -185,7 +205,11 @@ impl KeyringStore for DefaultKeyringStore { .set_password(value) .map_err(|err| SecretsError::Keyring(err.to_string())) } - #[cfg(not(any(target_os = "macos", target_os = "windows", target_os = "linux")))] + #[cfg(not(any( + target_os = "macos", + target_os = "windows", + all(target_os = "linux", not(target_env = "ohos")) + )))] { let _ = (key, value); Err(SecretsError::Keyring(unsupported_keyring_message())) @@ -193,7 +217,11 @@ impl KeyringStore for DefaultKeyringStore { } fn delete(&self, key: &str) -> Result<(), SecretsError> { - #[cfg(any(target_os = "macos", target_os = "windows", target_os = "linux"))] + #[cfg(any( + target_os = "macos", + target_os = "windows", + all(target_os = "linux", not(target_env = "ohos")) + ))] { let entry = keyring::Entry::new(&self.service, key) .map_err(|err| SecretsError::Keyring(err.to_string()))?; @@ -202,7 +230,11 @@ impl KeyringStore for DefaultKeyringStore { Err(err) => Err(SecretsError::Keyring(err.to_string())), } } - #[cfg(not(any(target_os = "macos", target_os = "windows", target_os = "linux")))] + #[cfg(not(any( + target_os = "macos", + target_os = "windows", + all(target_os = "linux", not(target_env = "ohos")) + )))] { let _ = key; Err(SecretsError::Keyring(unsupported_keyring_message())) @@ -214,7 +246,11 @@ impl KeyringStore for DefaultKeyringStore { } } -#[cfg(not(any(target_os = "macos", target_os = "windows", target_os = "linux")))] +#[cfg(not(any( + target_os = "macos", + target_os = "windows", + all(target_os = "linux", not(target_env = "ohos")) +)))] fn unsupported_keyring_message() -> String { "system keyring backend is unsupported on this platform".to_string() } diff --git a/crates/tui/Cargo.toml b/crates/tui/Cargo.toml index ed9e8270..60ba2411 100644 --- a/crates/tui/Cargo.toml +++ b/crates/tui/Cargo.toml @@ -26,7 +26,6 @@ path = "src/bin/deepseek_tui_legacy_shim.rs" [dependencies] anyhow = "1.0.100" -arboard = "3.4" codewhale-config = { path = "../config", version = "0.8.53" } codewhale-protocol = { path = "../protocol", version = "0.8.53" } codewhale-release = { path = "../release", version = "0.8.53" } @@ -47,10 +46,10 @@ fd-lock = "4.0.4" futures-util = "0.3.31" ratatui = "0.30" regex = "1.11" -reqwest = { version = "0.13.1", default-features = false, features = ["blocking", "json", "stream", "multipart", "form", "rustls", "http2", "gzip", "brotli"] } +reqwest = { version = "0.13.1", default-features = false, features = ["blocking", "json", "stream", "multipart", "form", "rustls-no-provider", "http2", "gzip", "brotli"] } +rustls.workspace = true qrcode = { version = "0.14", default-features = false } similar = "2" -rustyline = "15.0.0" serde = { version = "1.0.228", features = ["derive"] } serde_json = { version = "1.0.149", features = ["preserve_order"] } schemars = { version = "1.2.1", features = ["derive", "preserve_order"] } @@ -71,9 +70,7 @@ tower-http = { version = "0.6", features = ["cors"] } wait-timeout = "0.2" multimap = "0.10.0" shlex = "1.3.0" -starlark = "0.13.0" tiny_http = "0.12" -portable-pty = "0.9" zeroize = "1.8.2" ignore = "0.4" image = { version = "0.25", default-features = false, features = ["png"] } @@ -91,6 +88,13 @@ vt100 = "0.15" [target.'cfg(unix)'.dependencies] libc = "0.2" +[target.'cfg(any(target_os = "macos", target_os = "windows", all(target_os = "linux", not(target_env = "ohos"))))'.dependencies] +arboard = "3.4" + +[target.'cfg(not(target_env = "ohos"))'.dependencies] +portable-pty = "0.9" +starlark = "0.13.0" + [target.'cfg(target_os = "macos")'.dependencies] objc2 = "0.6.3" objc2-foundation = { version = "0.3.2", default-features = false, features = ["std", "NSArray", "NSDictionary", "NSError", "NSObject", "NSString", "NSURL"] } diff --git a/crates/tui/src/child_env.rs b/crates/tui/src/child_env.rs index 21add459..70e4a2bc 100644 --- a/crates/tui/src/child_env.rs +++ b/crates/tui/src/child_env.rs @@ -62,6 +62,7 @@ where } } +#[cfg(not(target_env = "ohos"))] pub fn apply_to_pty_command(cmd: &mut portable_pty::CommandBuilder, overrides: I) where I: IntoIterator, diff --git a/crates/tui/src/execpolicy/error.rs b/crates/tui/src/execpolicy/error.rs index 9664e71a..17f6c8f2 100644 --- a/crates/tui/src/execpolicy/error.rs +++ b/crates/tui/src/execpolicy/error.rs @@ -1,3 +1,4 @@ +#[cfg(not(target_env = "ohos"))] use starlark::Error as StarlarkError; use thiserror::Error; @@ -23,6 +24,9 @@ pub enum Error { }, #[error("expected example to not match rule `{rule}`: {example}")] ExampleDidMatch { rule: String, example: String }, + #[error("{0}")] + UnsupportedPlatform(String), #[error("starlark error: {0}")] + #[cfg(not(target_env = "ohos"))] Starlark(StarlarkError), } diff --git a/crates/tui/src/execpolicy/mod.rs b/crates/tui/src/execpolicy/mod.rs index 00ced1aa..3f5926cf 100644 --- a/crates/tui/src/execpolicy/mod.rs +++ b/crates/tui/src/execpolicy/mod.rs @@ -6,7 +6,10 @@ pub mod decision; pub mod error; pub mod execpolicycheck; pub mod matcher; +#[cfg(not(target_env = "ohos"))] pub mod parser; +#[cfg(target_env = "ohos")] +pub mod parser_ohos; pub mod policy; pub mod rule; pub mod rules; @@ -17,7 +20,10 @@ pub use decision::Decision; pub use error::Error; pub use error::Result; pub use execpolicycheck::ExecPolicyCheckCommand; +#[cfg(not(target_env = "ohos"))] pub use parser::PolicyParser; +#[cfg(target_env = "ohos")] +pub use parser_ohos::PolicyParser; pub use policy::Evaluation; pub use policy::Policy; pub use rule::Rule; diff --git a/crates/tui/src/execpolicy/parser_ohos.rs b/crates/tui/src/execpolicy/parser_ohos.rs new file mode 100644 index 00000000..6400cd6b --- /dev/null +++ b/crates/tui/src/execpolicy/parser_ohos.rs @@ -0,0 +1,26 @@ +use super::error::Error; +use super::error::Result; + +pub struct PolicyParser; + +impl Default for PolicyParser { + fn default() -> Self { + Self::new() + } +} + +impl PolicyParser { + pub fn new() -> Self { + Self + } + + pub fn parse(&mut self, _policy_identifier: &str, _policy_file_contents: &str) -> Result<()> { + Err(Error::UnsupportedPlatform( + "Starlark execpolicy files are not supported on HarmonyOS/OpenHarmony yet because upstream starlark-rust still depends on a rustyline/nix chain that does not compile for OHOS.".to_string(), + )) + } + + pub fn build(self) -> super::policy::Policy { + super::policy::Policy::empty() + } +} diff --git a/crates/tui/src/main.rs b/crates/tui/src/main.rs index 56be54f1..6185232c 100644 --- a/crates/tui/src/main.rs +++ b/crates/tui/src/main.rs @@ -109,6 +109,10 @@ fn configure_windows_console_utf8() { #[cfg(not(windows))] fn configure_windows_console_utf8() {} +fn install_rustls_crypto_provider() { + let _ = rustls::crypto::ring::default_provider().install_default(); +} + #[derive(Parser, Debug)] #[command( name = "codewhale-tui", @@ -846,6 +850,7 @@ enum SandboxCommand { #[tokio::main] async fn main() -> Result<()> { configure_windows_console_utf8(); + install_rustls_crypto_provider(); // ── Process hardening (#2183) ───────────────────────────────────────── // MUST run before Tokio is booted and before any threads are spawned. diff --git a/crates/tui/src/sandbox/mod.rs b/crates/tui/src/sandbox/mod.rs index 22864c60..6f2be864 100644 --- a/crates/tui/src/sandbox/mod.rs +++ b/crates/tui/src/sandbox/mod.rs @@ -35,13 +35,13 @@ pub mod process_hardening; #[cfg(target_os = "macos")] pub mod seatbelt; -#[cfg(target_os = "linux")] +#[cfg(all(target_os = "linux", not(target_env = "ohos")))] pub mod landlock; -#[cfg(target_os = "linux")] +#[cfg(all(target_os = "linux", not(target_env = "ohos")))] pub mod seccomp; -#[cfg(target_os = "linux")] +#[cfg(all(target_os = "linux", not(target_env = "ohos")))] pub mod bwrap; #[cfg(target_os = "windows")] @@ -223,7 +223,7 @@ pub enum SandboxType { MacosSeatbelt, /// Linux Landlock sandboxing (kernel 5.13+). - #[cfg(target_os = "linux")] + #[cfg(all(target_os = "linux", not(target_env = "ohos")))] LinuxLandlock, /// Windows process-containment helper. @@ -240,7 +240,7 @@ impl std::fmt::Display for SandboxType { SandboxType::None => write!(f, "none"), #[cfg(target_os = "macos")] SandboxType::MacosSeatbelt => write!(f, "macos-seatbelt"), - #[cfg(target_os = "linux")] + #[cfg(all(target_os = "linux", not(target_env = "ohos")))] SandboxType::LinuxLandlock => write!(f, "linux-landlock"), #[cfg(target_os = "windows")] SandboxType::Windows => write!(f, "windows-sandbox"), @@ -305,7 +305,7 @@ pub fn get_platform_sandbox() -> Option { } } - #[cfg(target_os = "linux")] + #[cfg(all(target_os = "linux", not(target_env = "ohos")))] { if landlock::is_available() { return Some(SandboxType::LinuxLandlock); @@ -410,7 +410,7 @@ impl SandboxManager { #[cfg(target_os = "macos")] SandboxType::MacosSeatbelt => Self::prepare_seatbelt(spec), - #[cfg(target_os = "linux")] + #[cfg(all(target_os = "linux", not(target_env = "ohos")))] SandboxType::LinuxLandlock => self.prepare_landlock(spec), #[cfg(target_os = "windows")] @@ -467,7 +467,7 @@ impl SandboxManager { /// If `prefer_bwrap` is set and `/usr/bin/bwrap` is available, routes the /// command through bubblewrap for stronger filesystem isolation (#2184). /// Otherwise falls back to Landlock markers. - #[cfg(target_os = "linux")] + #[cfg(all(target_os = "linux", not(target_env = "ohos")))] fn prepare_landlock(&self, spec: &CommandSpec) -> ExecEnv { // Check if bwrap passthrough should be used (#2184). if self.prefer_bwrap && bwrap::is_available() { @@ -539,7 +539,10 @@ impl SandboxManager { /// This helps distinguish between legitimate command failures and /// sandbox-blocked operations. pub fn was_denied(sandbox_type: SandboxType, exit_code: i32, stderr: &str) -> bool { - #[cfg(not(any(target_os = "macos", target_os = "linux")))] + #[cfg(not(any( + target_os = "macos", + all(target_os = "linux", not(target_env = "ohos")) + )))] let _ = (exit_code, stderr); match sandbox_type { @@ -548,7 +551,7 @@ impl SandboxManager { #[cfg(target_os = "macos")] SandboxType::MacosSeatbelt => seatbelt::detect_denial(exit_code, stderr), - #[cfg(target_os = "linux")] + #[cfg(all(target_os = "linux", not(target_env = "ohos")))] SandboxType::LinuxLandlock => landlock::detect_denial(exit_code, stderr), #[cfg(target_os = "windows")] @@ -558,7 +561,10 @@ impl SandboxManager { /// Get a human-readable description of why a command was blocked. pub fn denial_message(sandbox_type: SandboxType, stderr: &str) -> String { - #[cfg(not(any(target_os = "macos", target_os = "linux")))] + #[cfg(not(any( + target_os = "macos", + all(target_os = "linux", not(target_env = "ohos")) + )))] let _ = stderr; match sandbox_type { @@ -578,7 +584,7 @@ impl SandboxManager { } } - #[cfg(target_os = "linux")] + #[cfg(all(target_os = "linux", not(target_env = "ohos")))] SandboxType::LinuxLandlock => { // Seccomp patterns checked first because they are more specific (#2182). if stderr.contains("Bad system call") @@ -825,7 +831,7 @@ mod tests { } #[test] - #[cfg(target_os = "linux")] + #[cfg(all(target_os = "linux", not(target_env = "ohos")))] fn test_parity_linux_landlock_available() { let st = get_platform_sandbox(); assert!(matches!(st, Some(SandboxType::LinuxLandlock))); @@ -844,7 +850,7 @@ mod tests { 0, "" )); - #[cfg(target_os = "linux")] + #[cfg(all(target_os = "linux", not(target_env = "ohos")))] assert!(!SandboxManager::was_denied( SandboxType::LinuxLandlock, 0, @@ -855,7 +861,7 @@ mod tests { } #[test] - #[cfg(target_os = "linux")] + #[cfg(all(target_os = "linux", not(target_env = "ohos")))] fn test_parity_seccomp_sigsys_detected() { assert!(SandboxManager::was_denied( SandboxType::LinuxLandlock, @@ -891,7 +897,7 @@ mod tests { let spec = CommandSpec::shell("true", PathBuf::from("/tmp"), Duration::from_secs(5)) .with_policy(SandboxPolicy::default()); let env = manager.prepare(&spec); - #[cfg(target_os = "linux")] + #[cfg(all(target_os = "linux", not(target_env = "ohos")))] { let marker = env.env.get("DEEPSEEK_SANDBOX"); assert!(marker.is_none_or(|v| v != "bwrap")); @@ -905,7 +911,7 @@ mod tests { let spec = CommandSpec::shell("true", PathBuf::from("/tmp"), Duration::from_secs(5)) .with_policy(SandboxPolicy::default()); let env = manager.prepare(&spec); - #[cfg(target_os = "linux")] + #[cfg(all(target_os = "linux", not(target_env = "ohos")))] { if crate::sandbox::bwrap::is_available() { let marker = env.env.get("DEEPSEEK_SANDBOX"); diff --git a/crates/tui/src/sandbox/process_hardening.rs b/crates/tui/src/sandbox/process_hardening.rs index 0c95b48a..aa90dc07 100644 --- a/crates/tui/src/sandbox/process_hardening.rs +++ b/crates/tui/src/sandbox/process_hardening.rs @@ -45,18 +45,18 @@ /// hardening is defense-in-depth — the sandbox still protects child processes /// even if these prctls fail (e.g., in a container where some are restricted). pub fn apply_process_hardening() { - #[cfg(target_os = "linux")] + #[cfg(all(target_os = "linux", not(target_env = "ohos")))] { apply_linux_hardening(); } - #[cfg(not(target_os = "linux"))] + #[cfg(not(all(target_os = "linux", not(target_env = "ohos"))))] { tracing::debug!("Process hardening skipped: not on Linux"); } } /// Linux-specific hardening implementation. -#[cfg(target_os = "linux")] +#[cfg(all(target_os = "linux", not(target_env = "ohos")))] fn apply_linux_hardening() { // ── PR_SET_DUMPABLE = 0 ──────────────────────────────────────────────── // diff --git a/crates/tui/src/tools/diagnostics.rs b/crates/tui/src/tools/diagnostics.rs index f09d0084..6a3d8db3 100644 --- a/crates/tui/src/tools/diagnostics.rs +++ b/crates/tui/src/tools/diagnostics.rs @@ -155,18 +155,18 @@ fn probe_git(workspace: &Path) -> GitProbe { } fn probe_bwrap_available() -> bool { - #[cfg(target_os = "linux")] + #[cfg(all(target_os = "linux", not(target_env = "ohos")))] { crate::sandbox::bwrap::is_available() } - #[cfg(not(target_os = "linux"))] + #[cfg(not(all(target_os = "linux", not(target_env = "ohos"))))] { false } } fn probe_cgroup_version() -> Option { - #[cfg(target_os = "linux")] + #[cfg(all(target_os = "linux", not(target_env = "ohos")))] { let path = std::path::Path::new("/sys/fs/cgroup/cgroup.controllers"); if path.exists() { @@ -178,7 +178,7 @@ fn probe_cgroup_version() -> Option { } None } - #[cfg(not(target_os = "linux"))] + #[cfg(not(all(target_os = "linux", not(target_env = "ohos"))))] { None } diff --git a/crates/tui/src/tools/shell.rs b/crates/tui/src/tools/shell.rs index 5d90c5eb..78c97333 100644 --- a/crates/tui/src/tools/shell.rs +++ b/crates/tui/src/tools/shell.rs @@ -34,6 +34,7 @@ use windows::Win32::System::JobObjects::{ #[cfg(windows)] use windows::core::PCWSTR; +#[cfg(not(target_env = "ohos"))] use portable_pty::{CommandBuilder, PtySize, native_pty_system}; use super::shell_output::{summarize_output, truncate_with_meta}; @@ -130,6 +131,7 @@ pub struct ShellDeltaResult { enum ShellChild { Process(Child), + #[cfg(not(target_env = "ohos"))] Pty(Box), } @@ -165,7 +167,7 @@ fn kill_child_process_group(child: &mut Child) -> std::io::Result<()> { /// path (`kill_child_process_group` from the cancellation token) still /// handles normal shutdown; abnormal exit can leak children — tracked as a /// follow-up watchdog item per the original issue's acceptance criteria. -#[cfg(target_os = "linux")] +#[cfg(all(target_os = "linux", not(target_env = "ohos")))] fn install_parent_death_signal(cmd: &mut Command) { use std::os::unix::process::CommandExt; // SAFETY: `pre_exec` runs in the child between fork and exec. The closure @@ -227,7 +229,7 @@ fn push_shell_args(cmd: &mut Command, _program: &str, args: &[String]) { cmd.args(args); } -#[cfg(not(target_os = "linux"))] +#[cfg(not(all(target_os = "linux", not(target_env = "ohos"))))] fn install_parent_death_signal(_cmd: &mut Command) { // No kernel-level equivalent on macOS / Windows. The cooperative // cancellation + process_group SIGKILL path covers normal shutdown; @@ -363,6 +365,7 @@ impl ShellExitStatus { } } + #[cfg(not(target_env = "ohos"))] fn from_pty(status: portable_pty::ExitStatus) -> Self { let code = i32::try_from(status.exit_code()).unwrap_or(i32::MAX); Self { @@ -378,6 +381,7 @@ impl ShellChild { ShellChild::Process(child) => child .try_wait() .map(|status| status.map(ShellExitStatus::from_std)), + #[cfg(not(target_env = "ohos"))] ShellChild::Pty(child) => child .try_wait() .map(|status| status.map(ShellExitStatus::from_pty)), @@ -387,6 +391,7 @@ impl ShellChild { fn wait(&mut self) -> std::io::Result { match self { ShellChild::Process(child) => child.wait().map(ShellExitStatus::from_std), + #[cfg(not(target_env = "ohos"))] ShellChild::Pty(child) => child.wait().map(ShellExitStatus::from_pty), } } @@ -397,6 +402,7 @@ impl ShellChild { ShellChild::Process(child) => kill_child_process_group(child), #[cfg(not(unix))] ShellChild::Process(child) => child.kill(), + #[cfg(not(target_env = "ohos"))] ShellChild::Pty(child) => child.kill(), } } @@ -404,6 +410,7 @@ impl ShellChild { enum StdinWriter { Pipe(ChildStdin), + #[cfg(not(target_env = "ohos"))] Pty(Box), } @@ -411,6 +418,7 @@ impl StdinWriter { fn write_all(&mut self, data: &[u8]) -> std::io::Result<()> { match self { StdinWriter::Pipe(stdin) => stdin.write_all(data), + #[cfg(not(target_env = "ohos"))] StdinWriter::Pty(writer) => writer.write_all(data), } } @@ -418,6 +426,7 @@ impl StdinWriter { fn flush(&mut self) -> std::io::Result<()> { match self { StdinWriter::Pipe(stdin) => stdin.flush(), + #[cfg(not(target_env = "ohos"))] StdinWriter::Pty(writer) => writer.flush(), } } @@ -523,8 +532,14 @@ impl BackgroundShell { // Without this kill, handle.join() blocks indefinitely, freezing the UI // event loop that calls list_jobs() → poll() → collect_output(). #[cfg(unix)] - if let Some(ShellChild::Process(ref mut proc)) = self.child { - let _ = kill_child_process_group(proc); + if let Some(child) = self.child.as_mut() { + match child { + ShellChild::Process(proc) => { + let _ = kill_child_process_group(proc); + } + #[cfg(not(target_env = "ohos"))] + ShellChild::Pty(_) => {} + } } #[cfg(windows)] terminate_and_close_windows_job(self.windows_job.take()); @@ -619,21 +634,25 @@ impl BackgroundShell { /// Kill the process fn kill(&mut self) -> Result<()> { if let Some(ref mut child) = self.child { - if let ShellChild::Process(proc) = child { - #[cfg(windows)] - { - terminate_windows_job(self.windows_job.as_ref(), proc) - .context("Failed to kill process tree")?; - let _ = proc.wait(); + match child { + ShellChild::Process(proc) => { + #[cfg(windows)] + { + terminate_windows_job(self.windows_job.as_ref(), proc) + .context("Failed to kill process tree")?; + let _ = proc.wait(); + } + #[cfg(not(windows))] + { + proc.kill().context("Failed to kill process")?; + let _ = proc.wait(); + } } - #[cfg(not(windows))] - { - proc.kill().context("Failed to kill process")?; - let _ = proc.wait(); + #[cfg(not(target_env = "ohos"))] + ShellChild::Pty(child) => { + child.kill().context("Failed to kill process")?; + let _ = child.wait(); } - } else { - child.kill().context("Failed to kill process")?; - let _ = child.wait(); } } self.status = ShellStatus::Killed; @@ -717,10 +736,14 @@ impl Drop for BackgroundShell { && let Some(ref mut child) = self.child { #[cfg(windows)] - if let ShellChild::Process(proc) = child { - let _ = terminate_windows_job(self.windows_job.as_ref(), proc); - } else { - let _ = child.kill(); + match child { + ShellChild::Process(proc) => { + let _ = terminate_windows_job(self.windows_job.as_ref(), proc); + } + #[cfg(not(target_env = "ohos"))] + ShellChild::Pty(child) => { + let _ = child.kill(); + } } #[cfg(not(windows))] let _ = child.kill(); @@ -1276,6 +1299,13 @@ impl ShellManager { let program = exec_env.program(); let args = exec_env.args(); + #[cfg(target_env = "ohos")] + if tty { + return Err(anyhow!( + "TTY shell mode is not supported on HarmonyOS/OpenHarmony yet." + )); + } + let stdout_buffer = Arc::new(Mutex::new(Vec::new())); let stderr_buffer = if tty { None @@ -1287,45 +1317,51 @@ impl ShellManager { let mut windows_job = None; let (child, stdin, stdout_thread, stderr_thread) = if tty { - let pty_system = native_pty_system(); - let pair = pty_system - .openpty(PtySize { - rows: 24, - cols: 80, - pixel_width: 0, - pixel_height: 0, - }) - .context("Failed to open PTY")?; + #[cfg(target_env = "ohos")] + unreachable!("OHOS TTY mode returns before PTY setup"); - let mut cmd = CommandBuilder::new(program); - for arg in args { - cmd.arg(arg); + #[cfg(not(target_env = "ohos"))] + { + let pty_system = native_pty_system(); + let pair = pty_system + .openpty(PtySize { + rows: 24, + cols: 80, + pixel_width: 0, + pixel_height: 0, + }) + .context("Failed to open PTY")?; + + let mut cmd = CommandBuilder::new(program); + for arg in args { + cmd.arg(arg); + } + cmd.cwd(working_dir); + child_env::apply_to_pty_command(&mut cmd, child_env::string_map_env(&exec_env.env)); + + let child = pair + .slave + .spawn_command(cmd) + .with_context(|| format!("Failed to spawn PTY command: {original_command}"))?; + drop(pair.slave); + + let reader = pair + .master + .try_clone_reader() + .context("Failed to clone PTY reader")?; + let stdout_thread = Some(spawn_reader_thread(reader, Arc::clone(&stdout_buffer))); + let writer = pair + .master + .take_writer() + .context("Failed to take PTY writer")?; + + ( + ShellChild::Pty(child), + Some(StdinWriter::Pty(writer)), + stdout_thread, + None, + ) } - cmd.cwd(working_dir); - child_env::apply_to_pty_command(&mut cmd, child_env::string_map_env(&exec_env.env)); - - let child = pair - .slave - .spawn_command(cmd) - .with_context(|| format!("Failed to spawn PTY command: {original_command}"))?; - drop(pair.slave); - - let reader = pair - .master - .try_clone_reader() - .context("Failed to clone PTY reader")?; - let stdout_thread = Some(spawn_reader_thread(reader, Arc::clone(&stdout_buffer))); - let writer = pair - .master - .take_writer() - .context("Failed to take PTY writer")?; - - ( - ShellChild::Pty(child), - Some(StdinWriter::Pty(writer)), - stdout_thread, - None, - ) } else { let mut cmd = Command::new(program); push_shell_args(&mut cmd, program, args); diff --git a/crates/tui/src/tools/shell/tests.rs b/crates/tui/src/tools/shell/tests.rs index 18d8f221..46b7c35b 100644 --- a/crates/tui/src/tools/shell/tests.rs +++ b/crates/tui/src/tools/shell/tests.rs @@ -285,7 +285,7 @@ fn test_write_stdin_streams_output() { } #[test] -#[cfg(unix)] +#[cfg(all(unix, not(target_env = "ohos")))] fn background_tty_command_has_controlling_terminal() { let tmp = tempdir().expect("tempdir"); let mut manager = ShellManager::new(tmp.path().to_path_buf()); diff --git a/crates/tui/src/tui/clipboard.rs b/crates/tui/src/tui/clipboard.rs index ac63e709..5e87846a 100644 --- a/crates/tui/src/tui/clipboard.rs +++ b/crates/tui/src/tui/clipboard.rs @@ -12,17 +12,34 @@ use std::io::{self, IsTerminal, Write}; use std::path::{Path, PathBuf}; #[cfg(any( all(test, unix), - all( - any(target_os = "macos", target_os = "windows", target_os = "linux"), - not(test) - ) + all(not(test), target_os = "macos"), + all(not(test), target_os = "windows"), + all(not(test), target_os = "linux", not(target_env = "ohos")) ))] use std::process::{Command, Stdio}; +#[cfg(any( + test, + target_os = "macos", + target_os = "windows", + all(target_os = "linux", not(target_env = "ohos")) +))] use std::time::{SystemTime, UNIX_EPOCH}; use anyhow::{Context, Result, bail}; +#[cfg(any( + test, + target_os = "macos", + target_os = "windows", + all(target_os = "linux", not(target_env = "ohos")) +))] use arboard::{Clipboard, ImageData}; use base64::Engine as _; +#[cfg(any( + test, + target_os = "macos", + target_os = "windows", + all(target_os = "linux", not(target_env = "ohos")) +))] use image::{ImageBuffer, Rgba}; const OSC52_MAX_BYTES: usize = 100 * 1024; @@ -53,6 +70,7 @@ impl PastedImage { } /// Clipboard payloads supported by the TUI. +#[cfg_attr(all(target_env = "ohos", not(test)), allow(dead_code))] pub enum ClipboardContent { Text(String), Image(PastedImage), @@ -60,7 +78,19 @@ pub enum ClipboardContent { /// Clipboard reader/writer helper. pub struct ClipboardHandler { + #[cfg(any( + test, + target_os = "macos", + target_os = "windows", + all(target_os = "linux", not(target_env = "ohos")) + ))] clipboard: Option, + #[cfg(any( + test, + target_os = "macos", + target_os = "windows", + all(target_os = "linux", not(target_env = "ohos")) + ))] clipboard_init_attempted: bool, #[cfg(test)] written_text: Vec, @@ -74,7 +104,19 @@ impl ClipboardHandler { /// server (headless, WSL2) never blocks the TUI event loop. pub fn new() -> Self { Self { + #[cfg(any( + test, + target_os = "macos", + target_os = "windows", + all(target_os = "linux", not(target_env = "ohos")) + ))] clipboard: None, + #[cfg(any( + test, + target_os = "macos", + target_os = "windows", + all(target_os = "linux", not(target_env = "ohos")) + ))] clipboard_init_attempted: false, #[cfg(test)] written_text: Vec::new(), @@ -89,6 +131,12 @@ impl ClipboardHandler { /// temporary thread and give it 500 ms; if it doesn't return in time the /// handler stays in fallback/no-op mode and `read`/`write_text` fall /// through to their OSC 52 and pbcopy/powershell fallbacks. + #[cfg(any( + test, + target_os = "macos", + target_os = "windows", + all(target_os = "linux", not(target_env = "ohos")) + ))] fn ensure_clipboard(&mut self) { if self.clipboard_init_attempted { return; @@ -110,23 +158,32 @@ impl ClipboardHandler { /// `workspace` is used as a fallback location when `~/.codewhale/` cannot /// be resolved (e.g. running with a stripped HOME in CI sandboxes). pub fn read(&mut self, workspace: &Path) -> Option { - #[cfg(all(target_os = "linux", not(test)))] + #[cfg(all(target_os = "linux", not(target_env = "ohos"), not(test)))] if let Ok(text) = read_text_with_wlpaste() { return Some(ClipboardContent::Text(text)); } - self.ensure_clipboard(); - let clipboard = self.clipboard.as_mut()?; - if let Ok(text) = clipboard.get_text() { - return Some(ClipboardContent::Text(text)); - } - - if let Ok(image) = clipboard.get_image() - && let Ok(pasted) = save_image_as_png(workspace, &image) + #[cfg(any( + test, + target_os = "macos", + target_os = "windows", + all(target_os = "linux", not(target_env = "ohos")) + ))] { - return Some(ClipboardContent::Image(pasted)); + self.ensure_clipboard(); + let clipboard = self.clipboard.as_mut()?; + if let Ok(text) = clipboard.get_text() { + return Some(ClipboardContent::Text(text)); + } + + if let Ok(image) = clipboard.get_image() + && let Ok(pasted) = save_image_as_png(workspace, &image) + { + return Some(ClipboardContent::Image(pasted)); + } } + let _ = workspace; None } @@ -140,16 +197,23 @@ impl ClipboardHandler { #[cfg(not(test))] { - #[cfg(target_os = "linux")] + #[cfg(all(target_os = "linux", not(target_env = "ohos")))] if write_text_with_wlcopy(text).is_ok() { return Ok(()); } - self.ensure_clipboard(); - if let Some(clipboard) = self.clipboard.as_mut() - && clipboard.set_text(text.to_string()).is_ok() + #[cfg(any( + target_os = "macos", + target_os = "windows", + all(target_os = "linux", not(target_env = "ohos")) + ))] { - return Ok(()); + self.ensure_clipboard(); + if let Some(clipboard) = self.clipboard.as_mut() + && clipboard.set_text(text.to_string()).is_ok() + { + return Ok(()); + } } #[cfg(target_os = "macos")] @@ -215,17 +279,17 @@ fn write_text_with_stdin_command( Ok(()) } -#[cfg(all(target_os = "linux", not(test)))] +#[cfg(all(target_os = "linux", not(target_env = "ohos"), not(test)))] fn write_text_with_wlcopy(text: &str) -> Result<()> { write_text_with_wlcopy_using_argv("wl-copy", text) } -#[cfg(all(target_os = "linux", not(test)))] +#[cfg(all(target_os = "linux", not(target_env = "ohos"), not(test)))] fn read_text_with_wlpaste() -> Result { read_text_with_wlpaste_using_argv("wl-paste") } -#[cfg(any(all(test, unix), target_os = "linux"))] +#[cfg(any(all(test, unix), all(target_os = "linux", not(target_env = "ohos"))))] fn read_text_with_wlpaste_using_argv(program: &str) -> Result { let output = Command::new(program) .arg("--no-newline") @@ -241,7 +305,7 @@ fn read_text_with_wlpaste_using_argv(program: &str) -> Result { String::from_utf8(output.stdout).context("wl-paste returned non-UTF-8 text") } -#[cfg(all(target_os = "linux", not(test)))] +#[cfg(all(target_os = "linux", not(target_env = "ohos"), not(test)))] fn write_text_with_wlcopy_using_argv(program: &str, text: &str) -> Result<()> { let mut child = Command::new(program) .stdin(Stdio::piped()) @@ -310,12 +374,24 @@ fn clipboard_images_dir_for_home(workspace: &Path, home: Option<&Path>) -> PathB /// Encode an RGBA `ImageData` from arboard as PNG and persist it. Returns /// the resulting path along with metadata used to render the paste hint. +#[cfg(any( + test, + target_os = "macos", + target_os = "windows", + all(target_os = "linux", not(target_env = "ohos")) +))] fn save_image_as_png(workspace: &Path, image: &ImageData) -> Result { save_image_as_png_in(&clipboard_images_dir(workspace), image) } /// Lower-level variant that writes into an explicit directory. Exposed so the /// unit tests don't have to scribble inside the user's real home directory. +#[cfg(any( + test, + target_os = "macos", + target_os = "windows", + all(target_os = "linux", not(target_env = "ohos")) +))] fn save_image_as_png_in(dir: &Path, image: &ImageData) -> Result { std::fs::create_dir_all(dir).context("create clipboard-images dir")?; diff --git a/crates/tui/src/utils.rs b/crates/tui/src/utils.rs index d674ca77..8fdf019d 100644 --- a/crates/tui/src/utils.rs +++ b/crates/tui/src/utils.rs @@ -242,7 +242,7 @@ fn browser_open_command(url: &str) -> Result { Ok(command) } - #[cfg(target_os = "linux")] + #[cfg(all(target_os = "linux", not(target_env = "ohos")))] { let mut command = Command::new("xdg-open"); command.arg(url); @@ -256,7 +256,11 @@ fn browser_open_command(url: &str) -> Result { Ok(cmd) } - #[cfg(not(any(target_os = "macos", target_os = "linux", target_os = "windows")))] + #[cfg(not(any( + target_os = "macos", + all(target_os = "linux", not(target_env = "ohos")), + target_os = "windows" + )))] Err(anyhow::anyhow!( "browser opening is unsupported on this platform" )) @@ -863,7 +867,7 @@ mod project_mapping_tests { ); } - #[cfg(target_os = "linux")] + #[cfg(all(target_os = "linux", not(target_env = "ohos")))] { assert_eq!(command.get_program(), "xdg-open"); assert_eq!( diff --git a/docs/HarmonyOS.md b/docs/HarmonyOS.md new file mode 100644 index 00000000..f3c091f8 --- /dev/null +++ b/docs/HarmonyOS.md @@ -0,0 +1,78 @@ +# HarmonyOS and OpenHarmony + +This page covers CodeWhale on HarmonyOS PC and OpenHarmony cross-build setups. + +## Running On HarmonyOS PC + +HarmonyOS PC can use the normal Linux ARM64 package when its userspace is +glibc-compatible: + +```bash +npm i -g codewhale +codewhale --version +``` + +You can also download `codewhale-linux-arm64` and +`codewhale-tui-linux-arm64` from the GitHub Releases page and place both +binaries on `PATH`. + +## Cross-Compiling To OpenHarmony + +The repository does not check in machine-specific SDK paths. Set +`OHOS_NATIVE_SDK` to the OpenHarmony native SDK directory, the directory that +contains `llvm/bin`, `sysroot`, and `build/cmake/ohos.toolchain.cmake`. + +On Windows PowerShell: + +```powershell +$env:OHOS_NATIVE_SDK="" +. .\scripts\ohos-env.ps1 +rustup target add aarch64-unknown-linux-ohos +cargo build --target aarch64-unknown-linux-ohos -p codewhale-cli +``` + +On Linux or macOS: + +```bash +export OHOS_NATIVE_SDK=/path/to/openharmony/native +. ./scripts/ohos-env.sh +rustup target add aarch64-unknown-linux-ohos +cargo build --target aarch64-unknown-linux-ohos -p codewhale-cli +``` + +The setup scripts export Cargo's target-specific `linker`, `AR`, `CC`, `CXX`, +`CFLAGS`, `CXXFLAGS`, `CARGO_ENCODED_RUSTFLAGS`, `CC_SHELL_ESCAPED_FLAGS`, and +CMake toolchain variables for `aarch64-unknown-linux-ohos`. + +## Compiler Wrappers + +For ad-hoc compiler calls, use the root wrappers. They read the same +`OHOS_NATIVE_SDK` variable and do not contain local paths. + +Windows PowerShell: + +```powershell +.\ohos-clang.ps1 --version +.\ohos-clangxx.ps1 --version +``` + +Linux or macOS: + +```bash +sh ./ohos-clang.sh --version +sh ./ohos-clangxx.sh --version +``` + +If you want to run the POSIX wrappers directly as `./ohos-clang.sh`, make them +executable first: + +```bash +chmod +x ./ohos-clang.sh ./ohos-clangxx.sh +``` + +## Cargo Config + +`.cargo/config.toml` intentionally does not set a checked-in linker path. +Cargo cannot expand environment variables inside `linker` or CMake toolchain +path values there, so those values are exported by `scripts/ohos-env.ps1` and +`scripts/ohos-env.sh` instead. diff --git a/docs/INSTALL.md b/docs/INSTALL.md index 6afab754..11be2e52 100644 --- a/docs/INSTALL.md +++ b/docs/INSTALL.md @@ -44,6 +44,8 @@ systems such as Alpine should use [Build from source](#7-build-from-source). > and `codewhale-tui-linux-arm64`, so a plain `npm i -g codewhale` works > on any glibc-based ARM64 Linux. If you're stuck on v0.8.7, jump to > [Build from source](#7-build-from-source) — `cargo install` works fine. +> For HarmonyOS PC and OpenHarmony cross-build setup, see +> [HarmonyOS and OpenHarmony](HarmonyOS.md). --- diff --git a/docs/V0_9_0_EXECUTION_MAP.md b/docs/V0_9_0_EXECUTION_MAP.md index 5d0bec7a..35a8b46b 100644 --- a/docs/V0_9_0_EXECUTION_MAP.md +++ b/docs/V0_9_0_EXECUTION_MAP.md @@ -19,8 +19,9 @@ PR is harvested, superseded, deferred, or closed. 1. Stabilization and PR harvest: finish #2721 and #2722 before new feature work. 2. Provider/model/auth correctness: land narrow correctness fixes that match the current provider architecture. -3. HarmonyOS/MatePad Edge intake: keep #2634 active, scoped, and credited while - the OHOS/Nix dependency clearance work finishes upstream. +3. HarmonyOS/MatePad Edge intake: keep #2634 credited while the local harvest + clears the OHOS/Nix dependency chain; full target-build success still needs a + host with the OpenHarmony native SDK loaded. 4. File decomposition Phase 1: split safe, test-covered config/provider and TUI view surfaces before adding larger workflow UX. 5. WhaleFlow MVP: typed IR, executor skeleton, replay, and pod monitor before @@ -42,7 +43,7 @@ harvest/stewardship commits: | #2708 Windows sub-agent completion halves TUI render width | Cherry-picked as `e933a11d7`; follow-up fix `72653f8ef` invalidates reused fanout-card rows. | `cargo test -p codewhale-tui --locked subagent`; `cargo test -p codewhale-tui --locked terminal_size`; `cargo clippy -p codewhale-tui --locked -- -D warnings` passed. | | #2627 Xiaomi MiMo Token Plan mode | Harvested only the auth-header behavior as `5aa68d986`; did not merge the conflicting mode/env changes. | `cargo test -p codewhale-tui --bin codewhale-tui --locked xiaomi_mimo`; `cargo test -p codewhale-secrets --locked xiaomi_mimo`; `cargo test -p codewhale-config --locked xiaomi_mimo`; `cargo clippy -p codewhale-tui --locked -- -D warnings` passed. | | #2636 project-context mtime cache | Defer direct merge; harvest only after cache key/signature is widened. | Must include constitution changes, auto-generated context deletion, canonical path equivalence, and overwrite detection before landing. | -| #2634 HarmonyOS port | Active HarmonyOS/MatePad Edge lane; do not close. | User-supplied MatePad Edge demo (`https://bilibili.com/video/av116689597368905`) confirms real-device interest. PR remains draft/blocked while the author waits on upstream Nix/dependency clearance and carries local patches; full port needs OHOS target checks plus sandbox, TLS, keyring, clipboard, browser-open, and self-update review before merge. | +| #2634 HarmonyOS port | Locally harvested with additional Nix-chain clearance; keep credited and do not close until the integration branch is public. | User-supplied MatePad Edge demo (`https://bilibili.com/video/av116689597368905`) confirms real-device interest. Added env-driven OpenHarmony SDK setup, OHOS platform guards/fallbacks, self-update disablement, and OHOS target gating for Starlark execpolicy parsing plus PTY support so published OHOS builds do not pull `nix` 0.28 through `rustyline` or `portable-pty`. `cargo check --workspace --all-features --locked`, focused PTY/clipboard tests, and `cargo tree --locked -p codewhale-tui --target aarch64-unknown-linux-ohos -i nix@0.28.0` passed; full OHOS target check is blocked on this host because `OHOS_NATIVE_SDK`/target CC/sysroot are not configured and `ring` cannot find `assert.h`. | | #2687 append-only mode/approval prompt | Defer direct merge; draft has compile failures and Plan-mode prompt correctness risks. | Any future harvest must keep stable `message[0]` genuinely mode-agnostic, preserve mode/approval suffixes after capacity replans, and distinguish external overrides from persisted generated prompts. | | #2581 provider fallback chain design doc | Manually harvested as `docs/rfcs/2574-provider-fallback-chain.md` because the current PR head has no net file changes. | Keep issue #2574 open for implementation; close/comment on #2581 after the integration branch is public, crediting @idling11 and reporter @hsdbeebou. | | #2530 mention depth-cap hint | Already present in the current v0.9 stack as `a97675824` and `29f57665e`. | `cargo test -p codewhale-tui --locked try_autocomplete_file_mention_no_match` passed. | @@ -99,7 +100,7 @@ harvest/stewardship commits: | #2631 estimated_input_tokens cache | Mergeable | Already harvested into the 22-commit stack. | | #2632 tool-catalog JSON cache | Mergeable | Already harvested into the 22-commit stack. | | #2633 capacity reverse scans | Mergeable | Already harvested into the 22-commit stack. | -| #2634 HarmonyOS port | Draft/blocked | Keep as active HarmonyOS/MatePad Edge lane. Do not merge wholesale until upstream Nix/dependency clearance, OHOS target checks, and sandbox/TLS/keyring/clipboard/browser/self-update review are complete. | +| #2634 HarmonyOS port | Draft / locally harvested | Harvested with credit and extra Nix-chain fixes. Keep the original PR open for now; comment after the integration branch is public and request a real OHOS SDK build confirmation from the contributor before closing. | | #2635 output rows cache | Mergeable | Already harvested into the 22-commit stack. | | #2636 project-context cache | Conflicting | Defer/harvest only after cache correctness fixes. | | #2639 POST /v1/sessions endpoint | Mergeable | Defer; app-server contract needs focused review. | diff --git a/ohos-clang.ps1 b/ohos-clang.ps1 new file mode 100644 index 00000000..72b1dbb6 --- /dev/null +++ b/ohos-clang.ps1 @@ -0,0 +1,23 @@ +$ErrorActionPreference = "Stop" + +if ([string]::IsNullOrWhiteSpace($env:OHOS_NATIVE_SDK)) { + [Console]::Error.WriteLine("error: set OHOS_NATIVE_SDK to the OpenHarmony native SDK directory. It must contain llvm\bin and sysroot.") + exit 1 +} + +$sdk = $env:OHOS_NATIVE_SDK +$clang = [System.IO.Path]::Combine($sdk, "llvm", "bin", "clang.exe") +$sysroot = [System.IO.Path]::Combine($sdk, "sysroot") + +if (-not (Test-Path -LiteralPath $clang -PathType Leaf -ErrorAction SilentlyContinue)) { + [Console]::Error.WriteLine("error: OHOS_NATIVE_SDK does not contain llvm\bin\clang.exe: $sdk") + exit 1 +} + +if (-not (Test-Path -LiteralPath $sysroot -PathType Container -ErrorAction SilentlyContinue)) { + [Console]::Error.WriteLine("error: OHOS_NATIVE_SDK does not contain sysroot: $sdk") + exit 1 +} + +& $clang -target aarch64-linux-ohos "--sysroot=$sysroot" -D__MUSL__ @args +exit $LASTEXITCODE diff --git a/ohos-clang.sh b/ohos-clang.sh new file mode 100644 index 00000000..9ca80059 --- /dev/null +++ b/ohos-clang.sh @@ -0,0 +1,23 @@ +#!/usr/bin/env sh +set -eu + +if [ -z "${OHOS_NATIVE_SDK:-}" ]; then + echo "error: set OHOS_NATIVE_SDK to the OpenHarmony native SDK directory. It must contain llvm/bin and sysroot." >&2 + exit 1 +fi + +sdk=$OHOS_NATIVE_SDK +clang=$sdk/llvm/bin/clang +sysroot=$sdk/sysroot + +if [ ! -x "$clang" ]; then + echo "error: OHOS_NATIVE_SDK does not contain executable llvm/bin/clang: $sdk" >&2 + exit 1 +fi + +if [ ! -d "$sysroot" ]; then + echo "error: OHOS_NATIVE_SDK does not contain sysroot: $sdk" >&2 + exit 1 +fi + +exec "$clang" -target aarch64-linux-ohos "--sysroot=$sysroot" -D__MUSL__ "$@" diff --git a/ohos-clangxx.ps1 b/ohos-clangxx.ps1 new file mode 100644 index 00000000..f1c48e17 --- /dev/null +++ b/ohos-clangxx.ps1 @@ -0,0 +1,23 @@ +$ErrorActionPreference = "Stop" + +if ([string]::IsNullOrWhiteSpace($env:OHOS_NATIVE_SDK)) { + [Console]::Error.WriteLine("error: set OHOS_NATIVE_SDK to the OpenHarmony native SDK directory. It must contain llvm\bin and sysroot.") + exit 1 +} + +$sdk = $env:OHOS_NATIVE_SDK +$clangxx = [System.IO.Path]::Combine($sdk, "llvm", "bin", "clang++.exe") +$sysroot = [System.IO.Path]::Combine($sdk, "sysroot") + +if (-not (Test-Path -LiteralPath $clangxx -PathType Leaf -ErrorAction SilentlyContinue)) { + [Console]::Error.WriteLine("error: OHOS_NATIVE_SDK does not contain llvm\bin\clang++.exe: $sdk") + exit 1 +} + +if (-not (Test-Path -LiteralPath $sysroot -PathType Container -ErrorAction SilentlyContinue)) { + [Console]::Error.WriteLine("error: OHOS_NATIVE_SDK does not contain sysroot: $sdk") + exit 1 +} + +& $clangxx -target aarch64-linux-ohos "--sysroot=$sysroot" -D__MUSL__ @args +exit $LASTEXITCODE diff --git a/ohos-clangxx.sh b/ohos-clangxx.sh new file mode 100644 index 00000000..db881823 --- /dev/null +++ b/ohos-clangxx.sh @@ -0,0 +1,23 @@ +#!/usr/bin/env sh +set -eu + +if [ -z "${OHOS_NATIVE_SDK:-}" ]; then + echo "error: set OHOS_NATIVE_SDK to the OpenHarmony native SDK directory. It must contain llvm/bin and sysroot." >&2 + exit 1 +fi + +sdk=$OHOS_NATIVE_SDK +clangxx=$sdk/llvm/bin/clang++ +sysroot=$sdk/sysroot + +if [ ! -x "$clangxx" ]; then + echo "error: OHOS_NATIVE_SDK does not contain executable llvm/bin/clang++: $sdk" >&2 + exit 1 +fi + +if [ ! -d "$sysroot" ]; then + echo "error: OHOS_NATIVE_SDK does not contain sysroot: $sdk" >&2 + exit 1 +fi + +exec "$clangxx" -target aarch64-linux-ohos "--sysroot=$sysroot" -D__MUSL__ "$@" diff --git a/scripts/ohos-env.ps1 b/scripts/ohos-env.ps1 new file mode 100644 index 00000000..99f8373a --- /dev/null +++ b/scripts/ohos-env.ps1 @@ -0,0 +1,57 @@ +$ErrorActionPreference = "Stop" + +function Stop-OhosEnv { + param([string]$Message) + + [Console]::Error.WriteLine("error: $Message") + throw "OpenHarmony Cargo environment setup failed." +} + +if ([string]::IsNullOrWhiteSpace($env:OHOS_NATIVE_SDK)) { + Stop-OhosEnv "set OHOS_NATIVE_SDK to the OpenHarmony native SDK directory." +} + +if (-not (Test-Path -LiteralPath $env:OHOS_NATIVE_SDK -PathType Container -ErrorAction SilentlyContinue)) { + Stop-OhosEnv "OHOS_NATIVE_SDK does not exist: $env:OHOS_NATIVE_SDK" +} + +$sdk = (Resolve-Path -LiteralPath $env:OHOS_NATIVE_SDK -ErrorAction Stop).Path +$clang = [System.IO.Path]::Combine($sdk, "llvm", "bin", "clang.exe") +$clangxx = [System.IO.Path]::Combine($sdk, "llvm", "bin", "clang++.exe") +$ar = [System.IO.Path]::Combine($sdk, "llvm", "bin", "llvm-ar.exe") +$sysroot = [System.IO.Path]::Combine($sdk, "sysroot") +$cmakeToolchain = [System.IO.Path]::Combine($sdk, "build", "cmake", "ohos.toolchain.cmake") + +$requiredFiles = @($clang, $clangxx, $ar, $cmakeToolchain) +foreach ($path in $requiredFiles) { + if (-not (Test-Path -LiteralPath $path -PathType Leaf -ErrorAction SilentlyContinue)) { + Stop-OhosEnv "required OpenHarmony SDK file is missing: $path" + } +} + +if (-not (Test-Path -LiteralPath $sysroot -PathType Container -ErrorAction SilentlyContinue)) { + Stop-OhosEnv "required OpenHarmony SDK sysroot is missing: $sysroot" +} + +$target = "aarch64_unknown_linux_ohos" +$targetUpper = "AARCH64_UNKNOWN_LINUX_OHOS" +$commonFlags = "-target aarch64-linux-ohos --sysroot=`"$sysroot`" -D__MUSL__" + +$env:CARGO_TARGET_AARCH64_UNKNOWN_LINUX_OHOS_LINKER = $clang +$env:AR_aarch64_unknown_linux_ohos = $ar +$env:CC_aarch64_unknown_linux_ohos = $clang +$env:CXX_aarch64_unknown_linux_ohos = $clangxx +$env:CC_SHELL_ESCAPED_FLAGS = "1" +Set-Item -Path "Env:CFLAGS_$target" -Value $commonFlags +Set-Item -Path "Env:CXXFLAGS_$target" -Value $commonFlags +Set-Item -Path "Env:CMAKE_TOOLCHAIN_FILE_$target" -Value $cmakeToolchain + +$separator = [char]0x1f +$env:CARGO_ENCODED_RUSTFLAGS = @( + "-Clink-arg=-target", + "-Clink-arg=aarch64-linux-ohos", + "-Clink-arg=--sysroot=$sysroot", + "-Clink-arg=-D__MUSL__" +) -join $separator + +Write-Host "Configured OpenHarmony Cargo environment for $targetUpper from $sdk" diff --git a/scripts/ohos-env.sh b/scripts/ohos-env.sh new file mode 100644 index 00000000..bf1e1eea --- /dev/null +++ b/scripts/ohos-env.sh @@ -0,0 +1,44 @@ +#!/usr/bin/env sh + +if [ -z "${OHOS_NATIVE_SDK:-}" ]; then + echo "error: set OHOS_NATIVE_SDK to the OpenHarmony native SDK directory." >&2 + return 1 2>/dev/null || exit 1 +fi + +if [ ! -d "$OHOS_NATIVE_SDK" ]; then + echo "error: OHOS_NATIVE_SDK does not exist: $OHOS_NATIVE_SDK" >&2 + return 1 2>/dev/null || exit 1 +fi + +sdk=$(cd "$OHOS_NATIVE_SDK" && pwd) +clang=$sdk/llvm/bin/clang +clangxx=$sdk/llvm/bin/clang++ +ar=$sdk/llvm/bin/llvm-ar +sysroot=$sdk/sysroot +cmake_toolchain=$sdk/build/cmake/ohos.toolchain.cmake + +for file in "$clang" "$clangxx" "$ar" "$cmake_toolchain"; do + if [ ! -f "$file" ]; then + echo "error: required OpenHarmony SDK file is missing: $file" >&2 + return 1 2>/dev/null || exit 1 + fi +done + +if [ ! -d "$sysroot" ]; then + echo "error: required OpenHarmony SDK sysroot is missing: $sysroot" >&2 + return 1 2>/dev/null || exit 1 +fi + +export CARGO_TARGET_AARCH64_UNKNOWN_LINUX_OHOS_LINKER=$clang +export AR_aarch64_unknown_linux_ohos=$ar +export CC_aarch64_unknown_linux_ohos=$clang +export CXX_aarch64_unknown_linux_ohos=$clangxx +export CC_SHELL_ESCAPED_FLAGS=1 +export CFLAGS_aarch64_unknown_linux_ohos="-target aarch64-linux-ohos --sysroot=\"$sysroot\" -D__MUSL__" +export CXXFLAGS_aarch64_unknown_linux_ohos="-target aarch64-linux-ohos --sysroot=\"$sysroot\" -D__MUSL__" +export CMAKE_TOOLCHAIN_FILE_aarch64_unknown_linux_ohos=$cmake_toolchain + +sep=$(printf '\037') +export CARGO_ENCODED_RUSTFLAGS="-Clink-arg=-target${sep}-Clink-arg=aarch64-linux-ohos${sep}-Clink-arg=--sysroot=$sysroot${sep}-Clink-arg=-D__MUSL__" + +echo "Configured OpenHarmony Cargo environment for AARCH64_UNKNOWN_LINUX_OHOS from $sdk"