diff --git a/AGENTS.md b/AGENTS.md index d1f46040..1b31c682 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -15,7 +15,8 @@ matching guide before starting: This fork carries the OmarchyCN China-integration layer on top of upstream `basecamp/omarchy`: -- `bin/omarchycn` routes to `omarchy cn `; all cn commands are `bin/omarchy-cn-*` and follow the upstream bin conventions (metadata, helpers, `$OMARCHY_PATH` — sole exception: the overlay installer bootstraps by resolving its own checkout) +- `bin/omarchycn` routes to `omarchy cn `; all cn commands are `bin/omarchy-cn-*` and follow the upstream bin conventions (metadata, helpers, `$OMARCHY_PATH` — bootstrap exceptions: the overlay installer resolves its own checkout, and `omarchy-cn-convert` / `omarchy-cn-revert` are curl-able standalone scripts that default `OMARCHY_PATH` because they run before/while the cn tree exists) +- Convert/revert: `omarchy-cn-convert` turns a vanilla package-based Omarchy into OmarchyCN (registry key + [omarchycn] repo, `--ask=4` package swap to the cn-built omarchy-dev/omarchy-settings-dev published by `packages/publish-cn-packages.sh`, [omarchy] mirror line, zh_CN locale, fcitx5 seeding, plymouth rebrand) recording pre-state in `/var/lib/omarchycn/convert-state`; `omarchy-cn-revert` restores that state; checkout installs are refused toward the overlay - `cn/` holds the data layer: `mirrors.json`, `dev-mirrors.json`, `apps.json`, `registry/` (AI providers/harnesses/compatibility), `fcitx5/`, `fontconfig/`, `keys/`, `lib/` (sourced helpers), `release` (cn release number) - cn migrations live in `cn/migrations/*.sh`, run by `omarchy-cn-update` with per-file completion markers under `~/.local/state/omarchycn/` - Packaging: `packages/omarchy-pkgs-cn.patch` must be applied to the sibling `omarchy-pkgs` checkout so `omarchy-dev` ships `cn/`; keyring in `packages/omarchycn-keyring/` diff --git a/README.md b/README.md index 85ffc32c..c457c2ad 100644 --- a/README.md +++ b/README.md @@ -18,9 +18,10 @@ - **中国镜像管理**:Arch / npm / pip / Cargo / Go 等软件源测速、自动选择与故障切换 - **中文环境开箱即用**:zh_CN locale、思源黑体 / 宋体字体栈、高分屏分数缩放预设 - **中文输入法**:Fcitx5 + Rime 预配置,Wayland / GTK / Qt / Electron 全栈兼容,快捷键冲突自动处理 -- **AI Hub**:Kimi、DeepSeek、Z.AI/GLM 一等 Provider 支持,与 Claude Code、Codex、OpenCode、Kimi Code、Deep Code 等 Harness 的统一配置向导、凭据安全存储与连接诊断 +- **AI Hub**:Kimi、DeepSeek、Z.AI/GLM、MiniMax 与本地 Ollama 的一等 Provider 支持,与 Claude Code、Codex、OpenCode、Kimi Code、Deep Code 等 Harness 的统一配置向导、凭据安全存储与连接诊断;另有 Dim、DSH 等自管登录的 Agent CLI 一键安装 - **国内应用中心**:微信、QQ、飞书、钉钉、腾讯会议、WPS 等应用的可信安装入口 -- **Overlay 安装器**:在现有 Omarchy 上叠加 OmarchyCN,全程可逆、可卸载 +- **一键转换**:原版 Omarchy(包安装)一条命令转成 OmarchyCN,logo/菜单/键位/输入法/软件源全套切换,`omarchy cn revert` 一键还原 +- **Overlay 安装器**:在现有 Omarchy checkout 上叠加 OmarchyCN,全程可逆、可卸载 - **统一诊断**:`omarchycn doctor` 覆盖网络、镜像、输入法、显示与 AI 配置 ## 下载与安装 @@ -31,6 +32,22 @@ sha256sum -c SHA256SUMS.txt ``` +## 已有原版 Omarchy?一键转换 + +包安装的原版 Omarchy(quattro)可直接转换,无需重装系统: + +```bash +curl -fsSL https://git.zacharyzhang.com/ZacharyZhang-NY/omarchycn/raw/branch/quattro/bin/omarchy-cn-convert | bash +``` + +转换内容:换装 OmarchyCN 构建的系统包(中文菜单/键位/更新界面、OMARCHY CN 品牌、AI 全家桶)、启用 [omarchy] 自建镜像与 [omarchycn] 仓库、zh_CN 语言与 Fcitx5+Rime 输入法、国内 Arch 镜像自动测速。重新登录后生效。 + +随时一键还原(按转换时记录的状态逐项回退): + +```bash +omarchy cn revert +``` + ## 上游文档 Omarchy 完整英文手册在 [`manual/`](manual/) 目录,亦见 [learn.omacom.io](https://learn.omacom.io/2/the-omarchy-manual)。 diff --git a/bin/omarchy-cn-convert b/bin/omarchy-cn-convert new file mode 100644 index 00000000..0aca9eec --- /dev/null +++ b/bin/omarchy-cn-convert @@ -0,0 +1,107 @@ +#!/bin/bash +# omarchy:summary=Convert a vanilla package-based Omarchy install into OmarchyCN +# omarchy:examples=omarchy cn convert +# Curl-able bootstrap (like the overlay installer): everything before the +# package swap must run without the cn tree, so no $OMARCHY_PATH until then. + +set -euo pipefail + +GITEA=${GITEA:-https://git.zacharyzhang.com} +OWNER=${OWNER:-ZacharyZhang-NY} +REGISTRY="$GITEA/api/packages/$OWNER/arch" +REG_KEY_FPR=74DCF57ACD812B24D959F146BD386048867B33B4 +STATE_DIR=/var/lib/omarchycn +STATE=$STATE_DIR/convert-state +# Bootstrap exception: curl|bash runs outside a session, so default the path +export OMARCHY_PATH=${OMARCHY_PATH:-/usr/share/omarchy} + +main() { + command -v pacman > /dev/null || { echo "需要 Arch Linux(未找到 pacman)" >&2; exit 1; } + if (( EUID == 0 )); then + echo "请以普通用户运行(脚本内部按需 sudo)" >&2 + exit 1 + fi + + local prev_omarchy prev_settings + prev_omarchy=$(pacman -Q omarchy 2> /dev/null || pacman -Q omarchy-dev 2> /dev/null || true) + prev_settings=$(pacman -Q omarchy-settings 2> /dev/null || pacman -Q omarchy-settings-dev 2> /dev/null || true) + if [[ -z $prev_omarchy || -z $prev_settings ]]; then + if [[ -d $HOME/.local/share/omarchy/.git ]]; then + echo "检测到 checkout 安装(非包安装):请改用 overlay(bin/omarchycn-install-overlay)" >&2 + else + echo "未检测到 Omarchy 包安装(需要 omarchy 与 omarchy-settings)" >&2 + fi + exit 1 + fi + [[ -f $STATE ]] && echo "已转换过($STATE 在案):本次仅同步更新,不覆盖回退状态" + + echo "==> 信任 OmarchyCN registry 公钥并配置 [omarchycn] 仓库" + local tmpkey + tmpkey=$(mktemp) + curl -fsSL "$REGISTRY/repository.key" -o "$tmpkey" + sudo pacman-key --add "$tmpkey" + sudo pacman-key --lsign-key "$REG_KEY_FPR" + rm -f "$tmpkey" + if ! grep -q '^\[omarchycn\]' /etc/pacman.conf; then + printf '\n[omarchycn]\nSigLevel = Required DatabaseOptional\nServer = %s/omarchycn/x86_64\n' \ + "$REGISTRY" | sudo tee -a /etc/pacman.conf > /dev/null + fi + + if [[ ! -f $STATE ]]; then + echo "==> 记录转换前状态(供 omarchy cn revert 还原)" + sudo mkdir -p "$STATE_DIR" + if [[ -f /etc/locale.conf ]]; then + sudo cp /etc/locale.conf "$STATE_DIR/locale.conf.pre" + fi + sudo cp /etc/pacman.d/mirrorlist "$STATE_DIR/mirrorlist.pre" + local p new_pkgs="" + for p in fcitx5-rime fcitx5-chinese-addons fcitx5-configtool omarchycn-keyring; do + pacman -Q "$p" > /dev/null 2>&1 || new_pkgs+="$p " + done + # Values are quoted because revert sources this file; publish atomically + { + echo "prev_omarchy=\"${prev_omarchy%% *}\"" + echo "prev_settings=\"${prev_settings%% *}\"" + echo "new_pkgs=\"${new_pkgs% }\"" + echo "converted_at=\"$(date +%s)\"" + } | sudo tee "$STATE.new" > /dev/null + sudo mv "$STATE.new" "$STATE" + fi + + echo "==> 系统更新并换装 OmarchyCN 软件包(替换 ${prev_omarchy%% *}/${prev_settings%% *})" + sudo pacman -Syu --noconfirm + sudo pacman -S --noconfirm omarchycn/omarchycn-keyring + # --ask=4 auto-confirms removing the conflicting upstream omarchy packages + sudo pacman -S --noconfirm --ask=4 omarchycn/omarchy-dev omarchycn/omarchy-settings-dev + sudo pacman -S --needed --noconfirm fcitx5-rime fcitx5-chinese-addons fcitx5-configtool + + echo "==> [omarchy] 仓库启用自建镜像(Cloudflare 上游兜底)" + source /usr/share/omarchy/cn/lib/mirror.sh + cn_mirror_omarchy_repo_fix + + echo "==> 系统语言 zh_CN.UTF-8" + grep -q '^zh_CN.UTF-8 UTF-8' /etc/locale.gen || + echo 'zh_CN.UTF-8 UTF-8' | sudo tee -a /etc/locale.gen > /dev/null + sudo locale-gen > /dev/null + if grep -q '^LANG=' /etc/locale.conf 2> /dev/null; then + sudo sed -i 's/^LANG=.*/LANG=zh_CN.UTF-8/' /etc/locale.conf + else + echo 'LANG=zh_CN.UTF-8' | sudo tee -a /etc/locale.conf > /dev/null + fi + + echo "==> 中文输入法与字体(用户级)" + OMARCHY_PATH=/usr/share/omarchy bash /usr/share/omarchy/install/user/cn-chinese.sh + systemctl --user restart omarchy-fcitx5.service 2> /dev/null || true + + echo "==> Arch 官方仓库切换国内镜像(自动测速,失败则保留现状)" + omarchy-cn-mirror-apply china || echo "国内镜像不可达,保留当前 mirrorlist" + + echo "==> OMARCHY CN 开机画面" + omarchy-refresh-plymouth + + omarchy-notification-send "OmarchyCN" "转换完成:重新登录后菜单/键位/输入法全中文" 2> /dev/null || true + echo + echo "转换完成(重新登录生效)。回退: omarchy cn revert" +} + +main "$@" diff --git a/bin/omarchy-cn-revert b/bin/omarchy-cn-revert new file mode 100644 index 00000000..0c7d7f36 --- /dev/null +++ b/bin/omarchy-cn-revert @@ -0,0 +1,89 @@ +#!/bin/bash +# omarchy:summary=Revert an OmarchyCN conversion back to vanilla Omarchy +# omarchy:examples=omarchy cn revert +# Curl-able and self-deleting-safe: main() is fully parsed before the package +# swap removes this file from the cn tree it may be running from. + +set -euo pipefail + +STATE_DIR=/var/lib/omarchycn +STATE=$STATE_DIR/convert-state +MIRROR_LINE="Server = https://git.zacharyzhang.com/api/packages/ZacharyZhang-NY/arch/omarchy/x86_64" +REG_KEY_FPR=74DCF57ACD812B24D959F146BD386048867B33B4 +# Bootstrap exception: curl|bash runs outside a session, so default the path +export OMARCHY_PATH=${OMARCHY_PATH:-/usr/share/omarchy} + +main() { + if [[ ! -f $STATE ]]; then + echo "未发现转换状态($STATE):本机不是由 omarchy cn convert 转换而来" >&2 + exit 1 + fi + if (( EUID == 0 )); then + echo "请以普通用户运行(脚本内部按需 sudo)" >&2 + exit 1 + fi + + local prev_omarchy="" prev_settings="" new_pkgs="" + # State is trusted root-owned key=value lines written by convert + source "$STATE" + [[ -n $prev_omarchy && -n $prev_settings ]] || { echo "转换状态损坏: $STATE" >&2; exit 1; } + + echo "==> 清理转换时播种的用户配置(与 cn 层原件一致才删除)" + local seeded + for seeded in \ + "$HOME/.config/fcitx5/profile:/usr/share/omarchy/cn/fcitx5/profile" \ + "$HOME/.config/fontconfig/conf.d/64-omarchycn-cjk.conf:/usr/share/omarchy/cn/fontconfig/64-omarchycn-cjk.conf"; do + if cmp -s "${seeded%%:*}" "${seeded#*:}" 2> /dev/null; then + rm -f "${seeded%%:*}" + fi + done + + echo "==> 还原 mirrorlist 与系统语言" + sudo cp "$STATE_DIR/mirrorlist.pre" /etc/pacman.d/mirrorlist + if [[ -f $STATE_DIR/locale.conf.pre ]]; then + sudo cp "$STATE_DIR/locale.conf.pre" /etc/locale.conf + fi + + echo "==> pacman.conf 移除 [omarchycn] 与 [omarchy] 镜像行" + sudo sed -i "\|^$MIRROR_LINE\$|d" /etc/pacman.conf + # Delete the section header and body, but keep any section that follows + sudo sed -i '/^\[omarchycn\]$/,/^\[/{ /^\[omarchycn\]$/d; /^\[/!d; }' /etc/pacman.conf + + echo "==> 换回上游软件包($prev_omarchy/$prev_settings)" + sudo pacman -Sy + # --ask=4 auto-confirms removing the conflicting cn packages + sudo pacman -S --noconfirm --ask=4 "omarchy/$prev_omarchy" "omarchy/$prev_settings" + if [[ -n $new_pkgs ]]; then + # Only what is still installed: a user may have removed some already, + # and a -R failure here would strand the swap-completed system + local p still="" + for p in $new_pkgs; do + # grep without -q consumes the whole list: -q's early exit would + # SIGPIPE pacman and read as "not installed" under pipefail + pacman -Qq | grep -xF "$p" > /dev/null && still+="$p " + done + if [[ -n $still ]]; then + echo "==> 移除转换时新装的包: ${still% }" + # shellcheck disable=SC2086 + sudo pacman -R --noconfirm ${still% } + fi + fi + + echo "==> 移除 registry 公钥信任" + sudo pacman-key --delete "$REG_KEY_FPR" > /dev/null 2>&1 || true + + # The system is vanilla again: clear state before the cosmetic tail so a + # plymouth failure cannot strand a reverted machine in "converted" state + systemctl --user restart omarchy-fcitx5.service 2> /dev/null || true + sudo rm -rf "$STATE_DIR" + + echo "==> 还原上游开机画面" + if ! omarchy-refresh-plymouth; then + echo "开机画面还原失败:手动执行 omarchy-refresh-plymouth 即可" >&2 + exit 1 + fi + echo + echo "已回退为原版 Omarchy(重新登录生效)。再次转换: omarchy cn convert" +} + +main "$@" diff --git a/default/omarchy/omarchy-menu.jsonc b/default/omarchy/omarchy-menu.jsonc index 7046ee87..fa4e16fe 100644 --- a/default/omarchy/omarchy-menu.jsonc +++ b/default/omarchy/omarchy-menu.jsonc @@ -418,5 +418,6 @@ "omarchycn.diagnostics.mirror-fix": {"icon":"󰇧","label":"镜像修复","action":"omarchy-launch-floating-terminal-with-presentation 'omarchy-cn-doctor mirror --fix'"}, "omarchycn.diagnostics.ime": {"icon":"󰌌","label":"输入法状态","action":"omarchy-launch-floating-terminal-with-presentation omarchy-cn-ime-status"}, "omarchycn.update": {"icon":"","label":"更新","when":"[[ -f ~/.local/state/omarchycn/overlay-manifest ]]","action":"omarchy-launch-floating-terminal-with-presentation omarchy-cn-update"}, + "omarchycn.revert": {"icon":"󰕍","label":"回退为原版 Omarchy","when":"[[ -f /var/lib/omarchycn/convert-state ]]","action":"omarchy-launch-floating-terminal-with-presentation omarchy-cn-revert"}, "omarchycn.about": {"icon":"","label":"关于","action":"omarchy-launch-floating-terminal-with-presentation omarchy-cn-status"}, } diff --git a/manual/zh-cn/01-install.md b/manual/zh-cn/01-install.md index b1323b96..f161a710 100644 --- a/manual/zh-cn/01-install.md +++ b/manual/zh-cn/01-install.md @@ -24,7 +24,27 @@ omarchycn setup 向导依次配置:语言、时区、显示缩放、中文 locale、中文字体、Fcitx5+Rime 输入法、输入法切换键、pacman 镜像、开发工具镜像、国内应用、AI Hub、隐私说明。每一步都可跳过,中断后重跑会从未完成的步骤继续。 -## 现有 Omarchy 叠加安装(Overlay) +## 原版 Omarchy 一键转换(包安装) + +quattro 的原版 Omarchy 是包安装形态(`pacman -Q omarchy` 有输出),可以整机转换成 OmarchyCN,无需重装: + +```bash +curl -fsSL https://git.zacharyzhang.com/ZacharyZhang-NY/omarchycn/raw/branch/quattro/bin/omarchy-cn-convert | bash +``` + +转换做的事:信任 OmarchyCN registry 公钥并接入 [omarchycn] 仓库;把 `omarchy`/`omarchy-settings` 换成 OmarchyCN 构建的 `omarchy-dev`/`omarchy-settings-dev`(中文菜单、中文键位描述、OMARCHY CN 品牌、AI 全家桶随包生效);给 `[omarchy]` 仓库加自建镜像(Cloudflare 上游兜底);系统语言切到 zh_CN.UTF-8 并安装配置 Fcitx5+Rime;Arch 官方仓库自动测速切换国内镜像;刷新 OMARCHY CN 开机画面。重新登录后生效。 + +转换前的包名、语言与 mirrorlist 会记录在 `/var/lib/omarchycn/convert-state`,随时一键还原: + +```bash +omarchy cn revert +``` + +还原会换回上游软件包、恢复语言与 mirrorlist、移除 [omarchycn] 仓库与镜像行、卸载转换时新装的输入法包,并恢复上游开机画面。菜单 OmarchyCN 区段也有「回退为原版 Omarchy」入口。 + +## 现有 Omarchy 叠加安装(Overlay,checkout 形态) + +老的 checkout 安装(`~/.local/share/omarchy` 是 git 检出)用 Overlay 叠加,不走一键转换: ```bash git clone https://git.zacharyzhang.com/ZacharyZhang-NY/omarchycn.git diff --git a/test/shell.d/omarchycn-test.sh b/test/shell.d/omarchycn-test.sh index cb54b591..c917396c 100755 --- a/test/shell.d/omarchycn-test.sh +++ b/test/shell.d/omarchycn-test.sh @@ -109,6 +109,18 @@ printf 'Server = https://pkgs.omarchy.org/stable/$arch\n' > "$tmpconf" rm -f "$tmpconf" pass "omarchy mirror guard ignores comments and matches only the exact line" +# Convert/revert bootstrap pair: parse, self-delete guard, no constant drift +for s in omarchy-cn-convert omarchy-cn-revert; do + bash -n "$ROOT/bin/$s" || fail "$s parses" + grep -q '^main "\$@"$' "$ROOT/bin/$s" || fail "$s wraps work in main() against self-deletion" +done +grep -q -- '--ask=4' "$ROOT/bin/omarchy-cn-convert" || fail "convert auto-confirms the conflict swap" +lib_mirror=$(grep -m1 '^CN_OMARCHY_MIRROR=' "$ROOT/cn/lib/mirror.sh" | cut -d'"' -f2) +revert_mirror=$(grep -m1 '^MIRROR_LINE=' "$ROOT/bin/omarchy-cn-revert" | cut -d'"' -f2) +[[ "Server = $lib_mirror" == "$revert_mirror" ]] || + fail "revert MIRROR_LINE drifted from cn/lib/mirror.sh" "$revert_mirror" +pass "convert/revert pair: parse, main() guard, ask=4, mirror constant in sync" + # Menu: OmarchyCN entries parse and reference only existing commands node -e ' const fs = require("fs");