Compare commits
16
Commits
@@ -0,0 +1,24 @@
|
||||
name: pkg-repo-sync
|
||||
|
||||
on:
|
||||
schedule:
|
||||
- cron: "17 */6 * * *"
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
sync:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
ref: quattro
|
||||
|
||||
- name: Mirror upstream [omarchy] stable into the Gitea Arch registry
|
||||
env:
|
||||
PKG_SYNC_TOKEN: ${{ secrets.PKG_SYNC_TOKEN }}
|
||||
run: |
|
||||
set -euo pipefail
|
||||
if ! command -v zstd > /dev/null; then
|
||||
apt-get update -qq && apt-get install -y -qq zstd
|
||||
fi
|
||||
bash packages/sync-omarchy-repo.sh
|
||||
@@ -19,12 +19,13 @@ This fork carries the OmarchyCN China-integration layer on top of upstream `base
|
||||
- `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/`
|
||||
- Upstream repo mirror: `packages/sync-omarchy-repo.sh` + `.gitea/workflows/pkg-repo-sync.yml` mirror the upstream `[omarchy]` stable channel into the Gitea Arch registry every 6h; `pacman-stable.conf` lists the mirror first (upstream fallback), clients must trust the registry key (install import + cn migration), `omarchycn doctor mirror --fix` re-heals the line; see `docs/pacman-repo.md`
|
||||
- ISO: `packages/omarchy-iso-cn.patch` must be applied to the sibling `omarchy-iso` checkout — Chinese installer (cage+foot graphical console with English VT fallback) and live-env packages
|
||||
- Release process: `docs/release-checklist.md`; signing: `docs/release-signing.md`; pacman repo: `docs/pacman-repo.md`
|
||||
- Chinese-first defaults: OmarchyCN ships Simplified Chinese as the default UX. User-visible strings in `default/omarchy/omarchy-menu.jsonc` (all labels), `default/hypr/bindings/*.lua` (bind descriptions, including the generated workspace/group/panel loops), `bin/omarchy-menu-keybindings` (its merge list and priority patterns must match the shipped Chinese descriptions), `bin/omarchy-update-confirm`, and `install/user/first-run/*` notifications are Chinese with brand names kept in English; menu search stays reachable in English through leaf ids. When syncing upstream, translate new strings in these files and resolve string conflicts toward our Chinese text.
|
||||
- Default set changes vs upstream: `install/omarchy-base.packages` adds fcitx5-rime/chinese-addons/configtool and drops aether/libreoffice-fresh/obs-studio; the Basecamp/Discord/HEY/Google/WhatsApp/X launchers, their webapp keybindings, the whatsapp-slim extension, and the HEY mailto handler are removed (preinstall add/remove lists, launcher.hides, chromium flags, and mimeapps stay in sync); `install/user/cn-chinese.sh` seeds IME/font config on zh_CN systems
|
||||
- AI: `cn/registry/` drives providers (DeepSeek/Kimi/Z.AI/MiniMax) with zero-code adapters; `omarchy-default-agent` also accepts kimi (official installer script, not mise) and deepcode (mise npm); the Default Agent menu carries them plus an AI Hub combo entry
|
||||
- Upstream sync: `.gitea/workflows/upstream-sync.yml` opens a PR per upstream change; keep upstream file edits minimal and inventoried (currently: one `GROUP_DESCRIPTIONS[cn]` line in `bin/omarchy`, the localized menu/bindings/update/first-run surfaces above, the western-app removals above, a rewritten `README.md` (known recurring sync conflict, resolve toward ours), `AGENTS.md` additions, and two `.gitignore` lines)
|
||||
- AI: `cn/registry/` drives providers (DeepSeek/Kimi/Z.AI/MiniMax/Ollama-local) with zero-code adapters; Ollama uses a fixed `static_token` and runtime-listed models (`models_dynamic`); `omarchy-default-agent` also accepts kimi (official installer script, not mise), deepcode, dim, and dsh (mise npm); the Default Agent menu carries them plus an AI Hub combo entry
|
||||
- Upstream sync: `.gitea/workflows/upstream-sync.yml` opens a PR per upstream change; keep upstream file edits minimal and inventoried (currently: one `GROUP_DESCRIPTIONS[cn]` line in `bin/omarchy`, the localized menu/bindings/update/first-run surfaces above, the western-app removals above, the cn agent roster in `bin/omarchy-default-agent` / `bin/omarchy-agent` (kimi/deepcode/dim/dsh), the `[omarchy]` mirror line in `default/pacman/pacman-stable.conf`, the registry-key import in `install/post-install/pacman.sh`, a rewritten `README.md` (known recurring sync conflict, resolve toward ours), `AGENTS.md` additions, and two `.gitignore` lines)
|
||||
- cn tests: `test/shell.d/omarchycn-test.sh`, `test/shell.d/omarchycn-ai-test.sh`; localized UI expectations live in the upstream suites (menu, keybindings-menu, hyprland-default-config, binding-conflicts, clock, screenrecording, update-disk-space)
|
||||
|
||||
# Documentation Layout
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
面向中国开发者的 [Omarchy](https://omarchy.org) 下游发行版:完整保留 Omarchy 的 Arch + Hyprland 桌面体验,为中国网络环境、中文使用习惯与国内 AI 服务做系统级增强。
|
||||
|
||||
当前版本 `4.0.0.alpha-cn.1`(基于上游 `quattro` 分支构建的基线 ISO)。
|
||||
当前版本 `4.0.0.alpha-cn.4`(基于上游 `quattro` 分支构建的基线 ISO)。
|
||||
|
||||
## 特性
|
||||
|
||||
@@ -15,8 +15,6 @@
|
||||
- Btrfs + Snapper 更新前快照与系统回滚
|
||||
- archiso 离线安装镜像,支持无人值守安装与双系统引导
|
||||
|
||||
OmarchyCN 增强(开发中,按路线图逐步交付):
|
||||
|
||||
- **中国镜像管理**:Arch / npm / pip / Cargo / Go 等软件源测速、自动选择与故障切换
|
||||
- **中文环境开箱即用**:zh_CN locale、思源黑体 / 宋体字体栈、高分屏分数缩放预设
|
||||
- **中文输入法**:Fcitx5 + Rime 预配置,Wayland / GTK / Qt / Electron 全栈兼容,快捷键冲突自动处理
|
||||
|
||||
@@ -107,6 +107,22 @@ deepcode)
|
||||
command=(deepcode)
|
||||
[[ -n ${prompt:-} ]] && command+=("$prompt")
|
||||
;;
|
||||
dim)
|
||||
# `dim exec` is the documented one-shot prompt form
|
||||
if [[ -n ${prompt:-} ]]; then
|
||||
command=(dim exec "$prompt")
|
||||
else
|
||||
command=(dim)
|
||||
fi
|
||||
;;
|
||||
dsh)
|
||||
# dsh has no TUI: `dsh web` is the interactive form, headless the one-shot
|
||||
if [[ -n ${prompt:-} ]]; then
|
||||
command=(dsh --profile headless "$prompt")
|
||||
else
|
||||
command=(dsh web)
|
||||
fi
|
||||
;;
|
||||
*)
|
||||
echo "Unsupported default agent: $agent" >&2
|
||||
exit 1
|
||||
|
||||
@@ -36,7 +36,7 @@ if omarchy-cmd-missing "$command"; then
|
||||
$install
|
||||
fi
|
||||
|
||||
key=$(omarchy-cn-ai-secret get "$provider")
|
||||
key=$(cn_ai_resolve_key "$provider")
|
||||
|
||||
case "$harness" in
|
||||
claude-code)
|
||||
@@ -45,7 +45,8 @@ claude-code)
|
||||
settings="$HOME/.claude/settings.json"
|
||||
mkdir -p "${settings%/*}"
|
||||
base=$(cn_ai_endpoint "$provider" anthropic)
|
||||
fast=$(cn_ai_fast_model "$provider")
|
||||
# Dynamic-model providers have no fast alias: every tier maps to the model
|
||||
fast=$(cn_ai_fast_model "$provider" 2>/dev/null || printf '%s' "$model")
|
||||
current="{}"
|
||||
if [[ -s $settings ]]; then
|
||||
current=$(cat "$settings")
|
||||
|
||||
@@ -38,6 +38,8 @@ fi
|
||||
|
||||
if [[ $proto == "native" ]]; then
|
||||
echo "INFO ai: $harness 自管鉴权,跳过 OmarchyCN Key 检查"
|
||||
elif cn_ai_static_token "$provider" > /dev/null 2>&1; then
|
||||
echo "PASS ai: $provider 使用内置 token,无需存储 Key"
|
||||
elif omarchy-cn-ai-secret get "$provider" > /dev/null 2>&1; then
|
||||
echo "PASS ai: $provider API Key stored"
|
||||
else
|
||||
@@ -47,7 +49,7 @@ fi
|
||||
|
||||
if [[ $proto != "native" ]]; then
|
||||
base=$(cn_ai_endpoint "$provider" "$proto")
|
||||
host=$(sed -E 's|https?://([^/]+).*|\1|' <<<"$base")
|
||||
host=$(sed -E 's|https?://([^/:]+).*|\1|' <<<"$base")
|
||||
if getent hosts "$host" > /dev/null 2>&1; then
|
||||
echo "PASS ai: endpoint DNS resolves ($host)"
|
||||
else
|
||||
|
||||
@@ -32,7 +32,7 @@ fi
|
||||
|
||||
case "$config_method" in
|
||||
env)
|
||||
key=$(omarchy-cn-ai-secret get "$provider")
|
||||
key=$(cn_ai_resolve_key "$provider")
|
||||
if [[ $harness == "codex" ]]; then
|
||||
cn_ai_render_codex_config "$provider" "$model" "$key"
|
||||
exec "$command"
|
||||
|
||||
@@ -33,7 +33,9 @@ if [[ $level == "unsupported" ]]; then
|
||||
fi
|
||||
|
||||
allowlist=$(cn_ai_combo_models "$harness" "$provider")
|
||||
if [[ -n $allowlist ]]; then
|
||||
if cn_ai_models_dynamic "$provider"; then
|
||||
: # runtime-listed models; omarchycn ai test validates against the live server
|
||||
elif [[ -n $allowlist ]]; then
|
||||
# Combo-restricted model set (e.g. codex uses its own catalog slugs)
|
||||
if ! grep -qxF "$model" <<<"$allowlist"; then
|
||||
echo "Model $model not supported for $harness x $provider" >&2
|
||||
@@ -68,6 +70,6 @@ secret_ref = "omarchycn://ai/$provider"
|
||||
EOF
|
||||
|
||||
echo "Profile $name: $harness x $provider x $model (compat: $level)"
|
||||
if ! omarchy-cn-ai-secret get "$provider" > /dev/null 2>&1; then
|
||||
if ! cn_ai_resolve_key "$provider" > /dev/null 2>&1; then
|
||||
echo "提示: 尚未存储 $provider 的 API Key,运行: omarchycn ai secret set $provider"
|
||||
fi
|
||||
|
||||
+30
-3
@@ -24,7 +24,31 @@ provider=$(printf '%s\n' "${providers[@]}" | gum choose --header "选择 Provide
|
||||
|
||||
harness_proto=$(cn_ai_harness_field "$harness" protocol)
|
||||
allowlist=$(cn_ai_combo_models "$harness" "$provider")
|
||||
if [[ -n $allowlist ]]; then
|
||||
if cn_ai_models_dynamic "$provider"; then
|
||||
base=$(cn_ai_endpoint "$provider" "$harness_proto")
|
||||
if [[ $provider == "ollama" ]]; then
|
||||
if omarchy-cmd-missing ollama; then
|
||||
gum confirm "Ollama 未安装,现在安装本地服务?" || exit 1
|
||||
if omarchy-cmd-present nvidia-smi; then
|
||||
ollama_pkg=ollama-cuda
|
||||
elif omarchy-cmd-present rocminfo; then
|
||||
ollama_pkg=ollama-rocm
|
||||
else
|
||||
ollama_pkg=ollama
|
||||
fi
|
||||
omarchy-pkg-add "$ollama_pkg"
|
||||
fi
|
||||
if ! curl -sf --connect-timeout 3 "$base/api/tags" > /dev/null; then
|
||||
sudo systemctl enable --now ollama
|
||||
fi
|
||||
fi
|
||||
models=$(curl -sf --connect-timeout 3 "$base/api/tags" | jq -r '.models[].name' || true)
|
||||
if [[ -z $models ]]; then
|
||||
echo "无法列出本地模型(服务未运行或尚未拉取):先 ollama pull <模型>(如 qwen3-coder)再重试" >&2
|
||||
exit 1
|
||||
fi
|
||||
model=$(gum choose --header "选择本地模型" <<<"$models")
|
||||
elif [[ -n $allowlist ]]; then
|
||||
model=$(gum choose --header "选择模型" <<<"$allowlist")
|
||||
else
|
||||
# Hide models bound to a different wire protocol than the harness speaks
|
||||
@@ -40,12 +64,15 @@ proto=$(cn_ai_harness_field "$harness" protocol)
|
||||
if [[ $proto == "native" ]]; then
|
||||
omarchy-cn-ai-profile-create "$name" "$harness" "$provider" "$model"
|
||||
omarchy-cn-ai-profile-use "$name"
|
||||
echo "$harness 自管鉴权:首次启动时按其官方流程登录/配置"
|
||||
echo "$harness 自管鉴权:首次启动时在 CLI 内完成官方登录"
|
||||
if gum confirm "立即启动并完成官方登录?"; then
|
||||
exec omarchy-cn-ai-launch "$name"
|
||||
fi
|
||||
echo "完成。启动: omarchycn ai launch"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
if ! omarchy-cn-ai-secret get "$provider" > /dev/null 2>&1; then
|
||||
if ! cn_ai_resolve_key "$provider" > /dev/null 2>&1; then
|
||||
key=$(gum input --password --header "$provider API Key(获取: $(jq -r --arg p "$provider" '.providers[$p].key_url' "$CN_AI_PROVIDERS"))")
|
||||
printf '%s' "$key" | omarchy-cn-ai-secret set "$provider"
|
||||
fi
|
||||
|
||||
@@ -31,7 +31,7 @@ fi
|
||||
base="${OMARCHYCN_AI_TEST_BASE_URL:-$(cn_ai_endpoint "$provider" "${proto%-responses}")}"
|
||||
echo "INFO ai-test: $profile ($harness x $provider x $model) -> $base"
|
||||
|
||||
if ! key=$(omarchy-cn-ai-secret get "$provider" 2>/dev/null); then
|
||||
if ! key=$(cn_ai_resolve_key "$provider" 2>/dev/null); then
|
||||
echo "FAIL ai-test: 未存储 $provider 的 API Key (omarchycn ai secret set $provider)"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
@@ -32,6 +32,17 @@ fi
|
||||
|
||||
case "$source_type" in
|
||||
aur)
|
||||
# Offline installs leave only offline.db in sync; without the official
|
||||
# repo dbs yay treats repo deps as AUR. Upgrades must go through the
|
||||
# omarchy-update pipeline (pacman guard).
|
||||
if [[ ! -f /var/lib/pacman/sync/core.db ]]; then
|
||||
if [[ ! -t 0 ]]; then
|
||||
echo "首次安装应用前请先完成一次系统更新: omarchy-update" >&2
|
||||
exit 1
|
||||
fi
|
||||
echo "首次安装应用前需要完成一次系统更新。"
|
||||
omarchy-update
|
||||
fi
|
||||
omarchy-pkg-aur-add "$(jq -r '.package' <<<"$entry")"
|
||||
;;
|
||||
webapp)
|
||||
|
||||
+26
-1
@@ -69,6 +69,27 @@ check_mirror() {
|
||||
fi
|
||||
}
|
||||
|
||||
# refresh-pacman restores the checkout's template, which on overlay installs
|
||||
# has no OmarchyCN mirror line; this check makes that loss visible and fixable
|
||||
check_omarchy_repo() {
|
||||
local conf="${OMARCHYCN_PACMAN_CONF:-/etc/pacman.conf}"
|
||||
|
||||
if ! grep -q "^Server = https://pkgs.omarchy.org/stable/" "$conf"; then
|
||||
echo "INFO omarchy-repo: 非 stable 通道,跳过 OmarchyCN 镜像检查"
|
||||
return 0
|
||||
fi
|
||||
if cn_mirror_omarchy_repo_ok; then
|
||||
echo "PASS omarchy-repo: OmarchyCN 镜像行在位"
|
||||
return 0
|
||||
fi
|
||||
if [[ $fix == "true" ]] && cn_mirror_omarchy_repo_fix && cn_mirror_omarchy_repo_ok; then
|
||||
echo "PASS omarchy-repo: 已重新插入 OmarchyCN 镜像行"
|
||||
return 0
|
||||
fi
|
||||
echo "FAIL omarchy-repo: [omarchy] 缺 OmarchyCN 镜像行(omarchycn doctor mirror --fix 可修复)"
|
||||
failures=$((failures + 1))
|
||||
}
|
||||
|
||||
check_dev_mirror() {
|
||||
omarchy-cn-dev-mirror-doctor || failures=$((failures + 1))
|
||||
}
|
||||
@@ -79,12 +100,16 @@ check_ime() {
|
||||
|
||||
case "$module" in
|
||||
network) check_network ;;
|
||||
mirror) check_mirror ;;
|
||||
mirror)
|
||||
check_mirror
|
||||
check_omarchy_repo
|
||||
;;
|
||||
dev-mirror) check_dev_mirror ;;
|
||||
ime) check_ime ;;
|
||||
all)
|
||||
check_network
|
||||
check_mirror
|
||||
check_omarchy_repo
|
||||
check_dev_mirror
|
||||
check_ime
|
||||
;;
|
||||
|
||||
Executable
+23
@@ -0,0 +1,23 @@
|
||||
#!/bin/bash
|
||||
# omarchy:summary=Install Kimi Code with the official installer script
|
||||
# omarchy:examples=omarchycn kimi install
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
if omarchy-cmd-present kimi; then
|
||||
echo "Kimi Code 已安装"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
installer=$(mktemp)
|
||||
trap 'rm -f "$installer"' EXIT
|
||||
curl -fsSL https://code.kimi.com/kimi-code/install.sh -o "$installer"
|
||||
bash "$installer"
|
||||
|
||||
# The official installer only touches .bashrc PATH; expose kimi now
|
||||
if [[ ! -x $HOME/.kimi-code/bin/kimi ]]; then
|
||||
echo "kimi binary missing after the official installer" >&2
|
||||
exit 1
|
||||
fi
|
||||
mkdir -p "$HOME/.local/bin"
|
||||
ln -sf "$HOME/.kimi-code/bin/kimi" "$HOME/.local/bin/kimi"
|
||||
@@ -1,7 +1,7 @@
|
||||
#!/bin/bash
|
||||
|
||||
# omarchy:summary=Set and launch the default coding agent
|
||||
# omarchy:args=[pi|omp|opencode|ori|claude|codex|grok|agy|copilot|crush|kimi|deepcode]
|
||||
# omarchy:args=[pi|omp|opencode|ori|claude|codex|grok|agy|copilot|crush|kimi|deepcode|dim|dsh]
|
||||
# omarchy:examples=omarchy default agent | omarchy default agent codex | omarchy default agent kimi
|
||||
|
||||
installing=false
|
||||
@@ -36,8 +36,10 @@ agy | antigravity | antigravity-cli | gemini | gemini-cli) agent="agy"; name="An
|
||||
copilot | github-copilot) agent="copilot"; name="GitHub Copilot" ;;
|
||||
kimi | kimi-code) agent="kimi"; name="Kimi Code" ;;
|
||||
deepcode | deep-code) agent="deepcode"; name="Deep Code"; agent_package="npm:@vegamo/deepcode-cli" ;;
|
||||
dim | dimcode | dim-agent) agent="dim"; name="Dim Agent"; agent_package="npm:dimcode" ;;
|
||||
dsh | deepseek-harness) agent="dsh"; name="DSH"; agent_package="npm:@deepseek-ai/dsh" ;;
|
||||
*)
|
||||
echo "Usage: omarchy-default-agent <pi|omp|opencode|ori|claude|codex|grok|agy|copilot|crush|kimi|deepcode>"
|
||||
echo "Usage: omarchy-default-agent <pi|omp|opencode|ori|claude|codex|grok|agy|copilot|crush|kimi|deepcode|dim|dsh>"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
@@ -50,13 +52,10 @@ if [[ $agent == "kimi" ]]; then
|
||||
if [[ $installing == "false" ]]; then
|
||||
exec omarchy-launch-floating-terminal-with-presentation omarchy-default-agent --install kimi
|
||||
fi
|
||||
installer=$(mktemp)
|
||||
if ! curl -fsSL https://code.kimi.com/kimi-code/install.sh -o "$installer" || ! bash "$installer"; then
|
||||
rm -f "$installer"
|
||||
if ! omarchy-cn-kimi-install; then
|
||||
echo "Could not install $name with the official installer" >&2
|
||||
exit 1
|
||||
fi
|
||||
rm -f "$installer"
|
||||
fi
|
||||
else
|
||||
if [[ $installing == "false" ]] && ! mise where "$agent_package" &>/dev/null; then
|
||||
|
||||
+17
-1
@@ -31,6 +31,21 @@ cn_ai_harness_field() {
|
||||
jq -re --arg h "$1" --arg f "$2" '.harnesses[$h][$f]' "$CN_AI_HARNESSES"
|
||||
}
|
||||
|
||||
# Providers with a fixed token (local servers) need no stored secret.
|
||||
# `// empty` keeps stdout clean when absent (bare -re would print "null").
|
||||
cn_ai_static_token() {
|
||||
jq -re --arg p "$1" '.providers[$p].static_token // empty' "$CN_AI_PROVIDERS"
|
||||
}
|
||||
|
||||
cn_ai_resolve_key() {
|
||||
cn_ai_static_token "$1" 2>/dev/null || omarchy-cn-ai-secret get "$1"
|
||||
}
|
||||
|
||||
# Dynamic-model providers list models at runtime, not in the registry
|
||||
cn_ai_models_dynamic() {
|
||||
jq -e --arg p "$1" '.providers[$p].models_dynamic == true' "$CN_AI_PROVIDERS" > /dev/null
|
||||
}
|
||||
|
||||
cn_ai_combo_level() {
|
||||
jq -r --arg h "$1" --arg p "$2" '.combos[$h][$p].level // "unsupported"' "$CN_AI_COMPAT"
|
||||
}
|
||||
@@ -68,7 +83,8 @@ cn_ai_render_env() {
|
||||
case "$harness" in
|
||||
claude-code)
|
||||
base=$(cn_ai_endpoint "$provider" anthropic)
|
||||
fast=$(cn_ai_fast_model "$provider")
|
||||
# Dynamic-model providers have no fast alias: every tier maps to the model
|
||||
fast=$(cn_ai_fast_model "$provider" 2>/dev/null || printf '%s' "$model")
|
||||
printf 'export ANTHROPIC_BASE_URL=%q\n' "$base"
|
||||
# Docs vary between AUTH_TOKEN (deepseek/zai) and API_KEY (kimi): set both
|
||||
printf 'export ANTHROPIC_AUTH_TOKEN=%q\n' "$key"
|
||||
|
||||
@@ -4,6 +4,19 @@
|
||||
CN_MIRRORS_JSON="$OMARCHY_PATH/cn/mirrors.json"
|
||||
CN_MIRRORLIST="/etc/pacman.d/mirrorlist"
|
||||
CN_PROFILE_FILE="$HOME/.config/omarchycn/mirror-profile"
|
||||
CN_OMARCHY_MIRROR="https://git.zacharyzhang.com/api/packages/ZacharyZhang-NY/arch/omarchy/x86_64"
|
||||
|
||||
# [omarchy] mirror line management (stable channel only); shared by the
|
||||
# rollout migration and doctor --fix so refresh-pacman resets stay healable
|
||||
cn_mirror_omarchy_repo_ok() {
|
||||
grep -qxF "Server = $CN_OMARCHY_MIRROR" "${OMARCHYCN_PACMAN_CONF:-/etc/pacman.conf}"
|
||||
}
|
||||
|
||||
cn_mirror_omarchy_repo_fix() {
|
||||
local conf="${OMARCHYCN_PACMAN_CONF:-/etc/pacman.conf}"
|
||||
cn_mirror_omarchy_repo_ok && return 0
|
||||
sudo sed -i "s|^Server = https://pkgs.omarchy.org/stable/|Server = $CN_OMARCHY_MIRROR\nServer = https://pkgs.omarchy.org/stable/|" "$conf"
|
||||
}
|
||||
|
||||
cn_mirror_ids() {
|
||||
jq -r '.mirrors[].id' "$CN_MIRRORS_JSON"
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
echo "Trust the OmarchyCN registry key and put the [omarchy] mirror first"
|
||||
|
||||
sudo pacman-key --add "$OMARCHY_PATH/cn/keys/omarchycn-registry.asc"
|
||||
sudo pacman-key --lsign-key 74DCF57ACD812B24D959F146BD386048867B33B4
|
||||
|
||||
# Only the stable channel is mirrored; edge/rc systems keep upstream directly
|
||||
source "$OMARCHY_PATH/cn/lib/mirror.sh"
|
||||
cn_mirror_omarchy_repo_fix
|
||||
@@ -21,6 +21,11 @@
|
||||
"level": "stable",
|
||||
"doc": "https://platform.minimax.io/docs/token-plan/claude-code",
|
||||
"adapter": true
|
||||
},
|
||||
"ollama": {
|
||||
"level": "stable",
|
||||
"doc": "https://docs.ollama.com/api/anthropic-compatibility",
|
||||
"adapter": true
|
||||
}
|
||||
},
|
||||
"codex": {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"_verified": "2026-08-24",
|
||||
"_verified": "2026-08-25",
|
||||
"harnesses": {
|
||||
"claude-code": {
|
||||
"display_name": "Claude Code",
|
||||
@@ -25,7 +25,7 @@
|
||||
"kimi-code": {
|
||||
"display_name": "Kimi Code CLI",
|
||||
"command": "kimi",
|
||||
"install": "doc:https://www.kimi.com/code/docs/en/",
|
||||
"install": "omarchy-cn-kimi-install",
|
||||
"config_method": "native",
|
||||
"protocol": "native"
|
||||
},
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"_verified": "2026-08-25, from official docs (see OmarchyCN PRD §27; minimax: platform.minimax.io/docs/token-plan/claude-code)",
|
||||
"_verified": "2026-08-27, from official docs (see OmarchyCN PRD §27; minimax: platform.minimax.io/docs/token-plan/claude-code; ollama: docs.ollama.com/api/anthropic-compatibility, fixed token \"ollama\", models are whatever is pulled locally)",
|
||||
"providers": {
|
||||
"deepseek": {
|
||||
"display_name": "DeepSeek",
|
||||
@@ -124,6 +124,18 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
"ollama": {
|
||||
"display_name": "Ollama 本地",
|
||||
"auth": [
|
||||
"none"
|
||||
],
|
||||
"static_token": "ollama",
|
||||
"endpoints": {
|
||||
"anthropic": "http://localhost:11434"
|
||||
},
|
||||
"models": [],
|
||||
"models_dynamic": true
|
||||
},
|
||||
"minimax": {
|
||||
"display_name": "MiniMax",
|
||||
"auth": [
|
||||
|
||||
+1
-1
@@ -1 +1 @@
|
||||
4
|
||||
6
|
||||
|
||||
@@ -141,6 +141,8 @@
|
||||
"setup.default.agent.copilot": {"icon":"","label":"Copilot","checked":"[[ \"$(omarchy-default-agent)\" == \"copilot\" ]]","action":"omarchy-default-agent copilot"},
|
||||
"setup.default.agent.crush": {"icon":"","label":"Crush","checked":"[[ \"$(omarchy-default-agent)\" == \"crush\" ]]","action":"omarchy-default-agent crush"},
|
||||
"setup.default.agent.deepcode": {"icon":"","label":"Deep Code","checked":"[[ \"$(omarchy-default-agent)\" == \"deepcode\" ]]","action":"omarchy-default-agent deepcode"},
|
||||
"setup.default.agent.dim": {"icon":"","label":"Dim Agent","checked":"[[ \"$(omarchy-default-agent)\" == \"dim\" ]]","action":"omarchy-default-agent dim"},
|
||||
"setup.default.agent.dsh": {"icon":"","label":"DSH","checked":"[[ \"$(omarchy-default-agent)\" == \"dsh\" ]]","action":"omarchy-default-agent dsh"},
|
||||
"setup.default.agent.grok": {"icon":"","iconFont":"omarchy","label":"Grok","checked":"[[ \"$(omarchy-default-agent)\" == \"grok\" ]]","action":"omarchy-default-agent grok"},
|
||||
"setup.default.agent.kimi": {"icon":"","label":"Kimi Code","checked":"[[ \"$(omarchy-default-agent)\" == \"kimi\" ]]","action":"omarchy-default-agent kimi"},
|
||||
"setup.default.agent.omp": {"icon":"","iconFont":"omarchy","label":"omp","checked":"[[ \"$(omarchy-default-agent)\" == \"omp\" ]]","action":"omarchy-default-agent omp"},
|
||||
@@ -240,11 +242,16 @@
|
||||
"install.terminal.ghostty": {"icon":"","label":"Ghostty","disabled":"omarchy-pkg-present ghostty","action":"omarchy-launch-floating-terminal-with-presentation 'omarchy-install-terminal ghostty'"},
|
||||
"install.terminal.kitty": {"icon":"","label":"Kitty","disabled":"omarchy-pkg-present kitty","action":"omarchy-launch-floating-terminal-with-presentation 'omarchy-install-terminal kitty'"},
|
||||
"install.ai.chatgpt": {"icon":"","iconFont":"omarchy","label":"ChatGPT Desktop","disabled":"omarchy-pkg-present openai-codex-desktop","action":"omarchy-launch-floating-terminal-with-presentation omarchy-install-ai-chatgpt"},
|
||||
"install.ai.deep-code": {"icon":"","label":"Deep Code","disabled":"omarchy-cmd-present deepcode","action":"omarchy-launch-floating-terminal-with-presentation 'omarchy-mise-install npm:@vegamo/deepcode-cli deepcode && deepcode'"},
|
||||
"install.ai.dictation": {"icon":"","label":"语音听写","disabled":"omarchy-pkg-present voxtype-bin","action":"omarchy-launch-floating-terminal-with-presentation omarchy-voxtype-install"},
|
||||
"install.ai.dim": {"icon":"","label":"Dim Agent","disabled":"omarchy-cmd-present dim","action":"omarchy-launch-floating-terminal-with-presentation 'omarchy-mise-install npm:dimcode dim && dim'"},
|
||||
"install.ai.dsh": {"icon":"","label":"DSH","disabled":"omarchy-cmd-present dsh","action":"omarchy-launch-floating-terminal-with-presentation 'omarchy-mise-install npm:@deepseek-ai/dsh dsh && dsh web'"},
|
||||
"install.ai.grok-bot": {"icon":"","iconFont":"omarchy","label":"Grok Bot","disabled":"omarchy-pkg-present grok-bot","action":"omarchy-install-and-launch 'Grok Bot' grok-bot grok-bot"},
|
||||
"install.ai.kimi-code": {"icon":"","label":"Kimi Code","disabled":"omarchy-cmd-present kimi","action":"omarchy-launch-floating-terminal-with-presentation 'omarchy-cn-kimi-install && kimi'"},
|
||||
"install.ai.lm-studio": {"icon":"","iconFont":"omarchy","label":"LM Studio","disabled":"omarchy-pkg-present lmstudio-bin","action":"omarchy-install-app 'LM Studio' lmstudio-bin"},
|
||||
"install.ai.ollama": {"icon":"","iconFont":"omarchy","label":"Ollama","disabled":"omarchy-cmd-present ollama","action":"if omarchy-cmd-present nvidia-smi; then ollama_pkg=ollama-cuda; elif omarchy-cmd-present rocminfo; then ollama_pkg=ollama-rocm; else ollama_pkg=ollama; fi; omarchy-install-app Ollama \"$ollama_pkg\""},
|
||||
"install.ai.t3-code": {"icon":"","iconFont":"omarchy","label":"T3 Code","disabled":"omarchy-pkg-present t3code-bin","action":"omarchy-install-and-launch 'T3 Code' t3code-bin t3code"},
|
||||
"install.ai.cn-hub": {"icon":"","label":"国产模型组合 (AI Hub)","action":"omarchy-launch-floating-terminal-with-presentation omarchy-cn-ai-setup"},
|
||||
"install.gaming.steam": {"icon":"","label":"Steam","disabled":"omarchy-pkg-present steam","action":"omarchy-launch-floating-terminal-with-presentation omarchy-install-gaming-steam"},
|
||||
"install.gaming.retroarch": {"icon":"","label":"RetroArch","disabled":"omarchy-pkg-present retroarch","action":"omarchy-launch-floating-terminal-with-presentation omarchy-install-gaming-retroarch"},
|
||||
"install.gaming.minecraft": {"icon":"","label":"Minecraft","disabled":"omarchy-pkg-present minecraft-launcher","action":"omarchy-install-and-launch Minecraft minecraft-launcher minecraft-launcher"},
|
||||
|
||||
@@ -27,4 +27,6 @@ Include = /etc/pacman.d/mirrorlist
|
||||
|
||||
[omarchy]
|
||||
SigLevel = Optional TrustAll
|
||||
# OmarchyCN mirror first (registry-signed db, key via cn/keys), upstream fallback
|
||||
Server = https://git.zacharyzhang.com/api/packages/ZacharyZhang-NY/arch/omarchy/x86_64
|
||||
Server = https://pkgs.omarchy.org/stable/$arch
|
||||
|
||||
@@ -3,6 +3,16 @@
|
||||
OmarchyCN 的 pacman 仓库托管在 Gitea Arch package registry,每个上传的包由
|
||||
registry 密钥自动签名,数据库同源生成。
|
||||
|
||||
# [omarchy] 上游仓库镜像
|
||||
|
||||
上游 `pkgs.omarchy.org`(Cloudflare 托管)的 stable 通道被完整镜像到同一 Gitea registry 的 `omarchy` 仓库。`packages/sync-omarchy-repo.sh` 按文件名对上游与镜像 db 做差集,缺失包转传、上游移除的按 name/version/arch 精确删除;`.gitea/workflows/pkg-repo-sync.yml` 每 6 小时调度一次(幂等,可手动 dispatch)。正常情况下镜像滞后不超过一个周期;调度失败或 runner 掉线时滞后会持续到下一次成功运行。注意 pacman 无法感知"陈旧":只要镜像可达,客户端就使用镜像的 db,看到的是滞后版本;只有镜像无法提供所请求的 db/包文件(宕机、404)时才回退到上游 Server。
|
||||
|
||||
客户端接线(`default/pacman/pacman-stable.conf`):`[omarchy]` 段镜像行在前、上游为兜底。镜像 db 由 registry 密钥签名,因此系统必须信任该公钥——安装期由 `install/post-install/pacman.sh` 导入,既有系统由 cn 迁移 `1787861071.sh` 处理。仅 stable 被镜像:Gitea 仓库名必须等于 pacman 段名(客户端固定请求 `omarchy.db`),edge/rc 通道保持上游直连。
|
||||
|
||||
`omarchy-refresh-pacman` 会用检出内模板覆写 `/etc/pacman.conf`:ISO/包安装系统的模板自带镜像行;overlay 系统的模板来自上游,覆写后镜像行丢失,用 `omarchycn doctor mirror --fix` 重新插入。
|
||||
|
||||
已知事实:上游仓库本身含 `omarchy`/`omarchy-dev` 包,当前版本(4.0.0.r1832)低于 cn 层自构建版本(r1955+)。常规 `pacman -Syu` 不会降级覆盖;但 `omarchy-refresh-pacman` 收尾运行的是 `pacman -Syyuu`,`-uu` 明确允许降级——在任何 cn 系统上执行都会把 `omarchy-dev` 降回上游版本、抹掉 cn 层(该风险先于本镜像存在,镜像只是如实转载上游内容)。若上游版本号超过 cn 构建,普通 `-Syu` 也会覆盖 cn 层——每次发布前需核对上游版本。
|
||||
|
||||
## 接入
|
||||
|
||||
```bash
|
||||
|
||||
@@ -3,6 +3,10 @@
|
||||
cp -f "$OMARCHY_PATH/default/pacman/pacman-${OMARCHY_MIRROR:-stable}.conf" /etc/pacman.conf
|
||||
cp -f "$OMARCHY_PATH/default/pacman/mirrorlist-${OMARCHY_MIRROR:-stable}" /etc/pacman.d/mirrorlist
|
||||
|
||||
# The [omarchy] mirror db is signed by the OmarchyCN registry key
|
||||
pacman-key --add "$OMARCHY_PATH/cn/keys/omarchycn-registry.asc"
|
||||
pacman-key --lsign-key 74DCF57ACD812B24D959F146BD386048867B33B4
|
||||
|
||||
# omarchy-settings skips this override until cups-browsed is actually present
|
||||
# to avoid pacman creating cups-browsed.conf.pacnew during ISO package install.
|
||||
if [[ -f $OMARCHY_PATH/etc-overrides/cups-cups-browsed.conf && -d /etc/cups ]]; then
|
||||
|
||||
@@ -0,0 +1,101 @@
|
||||
#!/bin/bash
|
||||
# Mirrors the upstream [omarchy] stable repo into the OmarchyCN Gitea Arch registry.
|
||||
# Maintainer/CI script (pkg-repo-sync.yml); needs a package-write token, network.
|
||||
|
||||
set -euo pipefail
|
||||
export LC_ALL=C
|
||||
|
||||
GITEA=${GITEA:-https://git.zacharyzhang.com}
|
||||
OWNER=${OWNER:-ZacharyZhang-NY}
|
||||
REPO=${REPO:-omarchy}
|
||||
UPSTREAM=${UPSTREAM:-https://pkgs.omarchy.org/stable/x86_64}
|
||||
: "${PKG_SYNC_TOKEN:?PKG_SYNC_TOKEN (Gitea package-write token) is required}"
|
||||
|
||||
registry="$GITEA/api/packages/$OWNER/arch"
|
||||
mirror="$registry/$REPO/x86_64"
|
||||
|
||||
workdir=$(mktemp -d)
|
||||
trap 'rm -rf "$workdir"' EXIT
|
||||
|
||||
# One "filename name version arch" line per package in a repo db (zstd or gzip tar)
|
||||
db_entries() {
|
||||
local db="$1" dir="$2" desc
|
||||
mkdir -p "$dir"
|
||||
tar --zstd -xf "$db" -C "$dir" 2>/dev/null || tar -xzf "$db" -C "$dir"
|
||||
for desc in "$dir"/*/desc; do
|
||||
[[ -f $desc ]] || continue
|
||||
awk '
|
||||
/^%FILENAME%$/ { getline; f = $0 }
|
||||
/^%NAME%$/ { getline; n = $0 }
|
||||
/^%VERSION%$/ { getline; v = $0 }
|
||||
/^%ARCH%$/ { getline; a = $0 }
|
||||
END {
|
||||
if (f == "" || n == "" || v == "" || a == "") {
|
||||
print "malformed desc: " FILENAME > "/dev/stderr"
|
||||
exit 1
|
||||
}
|
||||
print f, n, v, a
|
||||
}
|
||||
' "$desc"
|
||||
done
|
||||
}
|
||||
|
||||
curl -sSf --retry 3 -o "$workdir/upstream.db" "$UPSTREAM/omarchy.db"
|
||||
db_entries "$workdir/upstream.db" "$workdir/upstream" | sort > "$workdir/upstream.list"
|
||||
|
||||
# Only 404 means first sync; any other failure must not fake an empty mirror,
|
||||
# which would skip deletions and report a bogus success
|
||||
code=$(curl -sS --retry 3 -o "$workdir/mirror.db" -w '%{http_code}' "$mirror/$REPO.db" || true)
|
||||
[[ -z $code ]] && code=000
|
||||
case "$code" in
|
||||
200)
|
||||
db_entries "$workdir/mirror.db" "$workdir/mirror" | sort > "$workdir/mirror.list"
|
||||
;;
|
||||
404)
|
||||
: > "$workdir/mirror.list"
|
||||
;;
|
||||
*)
|
||||
echo "mirror db fetch failed (HTTP $code): $mirror/$REPO.db" >&2
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
comm -23 "$workdir/upstream.list" "$workdir/mirror.list" > "$workdir/to-add.list"
|
||||
comm -13 "$workdir/upstream.list" "$workdir/mirror.list" > "$workdir/to-remove.list"
|
||||
echo "upstream: $(wc -l < "$workdir/upstream.list") packages," \
|
||||
"mirror: $(wc -l < "$workdir/mirror.list")," \
|
||||
"to add: $(wc -l < "$workdir/to-add.list")," \
|
||||
"to remove: $(wc -l < "$workdir/to-remove.list")"
|
||||
|
||||
added=0
|
||||
while read -r filename name version arch; do
|
||||
echo "add: $filename"
|
||||
curl -sSf --retry 3 -o "$workdir/pkg" "$UPSTREAM/$filename"
|
||||
code=$(curl -sS --retry 2 -o "$workdir/put.out" -w '%{http_code}' -X PUT \
|
||||
-H "Authorization: token $PKG_SYNC_TOKEN" \
|
||||
--upload-file "$workdir/pkg" "$registry/$REPO")
|
||||
case "$code" in
|
||||
201) added=$((added + 1)) ;;
|
||||
409) echo " already present (409)" ;;
|
||||
*)
|
||||
echo "upload of $filename failed (HTTP $code): $(head -c 300 "$workdir/put.out")" >&2
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
rm -f "$workdir/pkg"
|
||||
done < "$workdir/to-add.list"
|
||||
|
||||
removed=0
|
||||
while read -r filename name version arch; do
|
||||
echo "remove: $filename"
|
||||
code=$(curl -sS --retry 2 -o "$workdir/del.out" -w '%{http_code}' -X DELETE \
|
||||
-H "Authorization: token $PKG_SYNC_TOKEN" \
|
||||
"$registry/$REPO/$name/$version/$arch")
|
||||
if [[ $code != 2?? && $code != 404 ]]; then
|
||||
echo "removal of $filename failed (HTTP $code): $(head -c 300 "$workdir/del.out")" >&2
|
||||
exit 1
|
||||
fi
|
||||
removed=$((removed + 1))
|
||||
done < "$workdir/to-remove.list"
|
||||
|
||||
echo "Sync complete: $added added, $removed removed"
|
||||
@@ -248,7 +248,7 @@ assertDeepEqual(
|
||||
defaultItems
|
||||
.filter(item => item.parent === 'setup.default.agent')
|
||||
.map(item => item.label),
|
||||
['Antigravity', 'Claude', 'Codex', 'Copilot', 'Crush', 'Deep Code', 'Grok', 'Kimi Code', 'omp', 'OpenCode', 'Ori', 'Pi', '国产模型组合 (AI Hub)'],
|
||||
['Antigravity', 'Claude', 'Codex', 'Copilot', 'Crush', 'Deep Code', 'Dim Agent', 'DSH', 'Grok', 'Kimi Code', 'omp', 'OpenCode', 'Ori', 'Pi', '国产模型组合 (AI Hub)'],
|
||||
'menu sorts coding agents alphabetically'
|
||||
)
|
||||
const expectedDefaults = {
|
||||
|
||||
@@ -38,6 +38,11 @@ for p in deepseek kimi zai minimax; do
|
||||
jq -e --arg p "$p" '.providers[$p].endpoints.anthropic // .providers[$p].endpoints.openai' \
|
||||
"$ROOT/cn/registry/ai-providers.json" > /dev/null || fail "provider $p has an endpoint"
|
||||
done
|
||||
jq -e '.providers.ollama | (.static_token == "ollama") and (.models_dynamic == true)
|
||||
and (.endpoints.anthropic == "http://localhost:11434")' \
|
||||
"$ROOT/cn/registry/ai-providers.json" > /dev/null || fail "ollama provider contract"
|
||||
jq -e '.combos["claude-code"].ollama.adapter' \
|
||||
"$ROOT/cn/registry/ai-compatibility.json" > /dev/null || fail "claude-code x ollama combo present"
|
||||
pass "AI registries parse with P0 providers"
|
||||
|
||||
# Secret file backend roundtrip with 0600
|
||||
@@ -59,8 +64,17 @@ fi
|
||||
if omarchy-cn-ai-profile-create bad codex deepseek "deepseek-v4-pro[1m]" > /dev/null 2>&1; then
|
||||
fail "codex rejects provider-namespace slug"
|
||||
fi
|
||||
omarchy-cn-ai-profile-create loc claude-code ollama qwen3-coder > /dev/null ||
|
||||
fail "dynamic-model provider accepts a runtime-listed model"
|
||||
pass "profile validation enforces combos, protocols, and allowlists"
|
||||
|
||||
# Static-token provider needs no stored secret; absent fields stay silent
|
||||
source "$ROOT/cn/lib/ai.sh"
|
||||
[[ $(cn_ai_resolve_key ollama) == "ollama" ]] || fail "ollama resolves its static token"
|
||||
static_out=$(cn_ai_static_token deepseek || true)
|
||||
[[ -z $static_out ]] || fail "absent static_token must print nothing" "$static_out"
|
||||
pass "static token resolution: fixed ollama key, silent absent field"
|
||||
|
||||
# claude-code env render for all three providers, exact endpoints
|
||||
source "$ROOT/cn/lib/ai.sh"
|
||||
declare -A bases=(
|
||||
@@ -77,6 +91,10 @@ for p in deepseek kimi zai minimax; do
|
||||
done
|
||||
out=$(cn_ai_render_env claude-code minimax "MiniMax-M3[1m]" sk-x)
|
||||
grep -qF "ANTHROPIC_DEFAULT_HAIKU_MODEL=MiniMax-M3" <<<"$out" || fail "minimax haiku slot falls back to default-coding"
|
||||
out=$(cn_ai_render_env claude-code ollama qwen3-coder "$(cn_ai_resolve_key ollama)")
|
||||
grep -qF "ANTHROPIC_BASE_URL=http://localhost:11434" <<<"$out" || fail "ollama base url" "$out"
|
||||
grep -q "ANTHROPIC_AUTH_TOKEN=ollama" <<<"$out" || fail "ollama static token rendered"
|
||||
grep -qF "ANTHROPIC_DEFAULT_HAIKU_MODEL=qwen3-coder" <<<"$out" || fail "ollama haiku slot falls back to the chosen model"
|
||||
out=$(cn_ai_render_env opencode deepseek test-model sk-x)
|
||||
grep -q "DEEPSEEK_API_KEY=sk-x" <<<"$out" || fail "opencode deepseek env"
|
||||
if cn_ai_render_env opencode zai m k > /dev/null 2>&1; then
|
||||
@@ -107,7 +125,7 @@ class H(http.server.BaseHTTPRequestHandler):
|
||||
def do_POST(self):
|
||||
body = self.rfile.read(int(self.headers.get("Content-Length", 0)))
|
||||
key = self.headers.get("x-api-key") or (self.headers.get("Authorization") or "").replace("Bearer ", "")
|
||||
if key != "sk-secret-1":
|
||||
if key not in ("sk-secret-1", "ollama"):
|
||||
code = 401
|
||||
elif self.path == "/v1/messages" and b"messages" in body and self.headers.get("anthropic-version"):
|
||||
code = 200
|
||||
@@ -131,6 +149,7 @@ done
|
||||
|
||||
OMARCHYCN_AI_TEST_BASE_URL="http://127.0.0.1:$port" omarchy-cn-ai-test good | grep -q "PASS" || fail "anthropic mock 200"
|
||||
OMARCHYCN_AI_TEST_BASE_URL="http://127.0.0.1:$port" omarchy-cn-ai-test cdx | grep -q "PASS" || fail "codex responses mock 200"
|
||||
OMARCHYCN_AI_TEST_BASE_URL="http://127.0.0.1:$port" omarchy-cn-ai-test loc | grep -q "PASS" || fail "ollama static-token mock 200"
|
||||
echo "wrong-key" | omarchy-cn-ai-secret set deepseek > /dev/null
|
||||
if OMARCHYCN_AI_TEST_BASE_URL="http://127.0.0.1:$port" omarchy-cn-ai-test good > /dev/null 2>&1; then
|
||||
fail "anthropic mock 401 fails the test"
|
||||
@@ -165,3 +184,11 @@ PATH="$restricted" omarchy-cn-ai-default good > /dev/null
|
||||
[[ $(stat -c %a "$HOME/.claude/settings.json") == 600 ]] || fail "claude settings 0600"
|
||||
[[ -f $TEST_HOME/installer-ran ]] || fail "missing harness triggered installer"
|
||||
pass "ai-default maps the profile onto the upstream agent entry"
|
||||
|
||||
# ai-default with the static-token local provider writes the official contract
|
||||
PATH="$restricted" omarchy-cn-ai-default loc > /dev/null
|
||||
[[ $(jq -r '.env.ANTHROPIC_BASE_URL' "$HOME/.claude/settings.json") == "http://localhost:11434" ]] || fail "ollama ai-default base url"
|
||||
[[ $(jq -r '.env.ANTHROPIC_AUTH_TOKEN' "$HOME/.claude/settings.json") == "ollama" ]] || fail "ollama ai-default static token"
|
||||
[[ $(jq -r '.env.ANTHROPIC_DEFAULT_HAIKU_MODEL' "$HOME/.claude/settings.json") == "qwen3-coder" ]] || fail "ollama ai-default haiku fallback"
|
||||
[[ $(jq -r '.env.KEEP' "$HOME/.claude/settings.json") == 1 ]] || fail "ollama ai-default preserves user env"
|
||||
pass "ai-default renders the ollama static-token contract"
|
||||
|
||||
@@ -80,6 +80,35 @@ if missing or not weak_appends:
|
||||
PYEOF
|
||||
pass "fontconfig priority file carries SC/JP/KR rules and weak fallback"
|
||||
|
||||
# [omarchy] mirror wiring: stable is mirror-first with upstream fallback
|
||||
mapfile -t stable_servers < <(sed -n '/^\[omarchy\]/,$p' "$ROOT/default/pacman/pacman-stable.conf" | grep '^Server = ')
|
||||
[[ ${stable_servers[0]:-} == "Server = https://git.zacharyzhang.com/api/packages/ZacharyZhang-NY/arch/omarchy/x86_64" ]] ||
|
||||
fail "stable conf lists the OmarchyCN mirror first" "${stable_servers[0]:-none}"
|
||||
[[ ${stable_servers[1]:-} == 'Server = https://pkgs.omarchy.org/stable/$arch' ]] ||
|
||||
fail "stable conf keeps the upstream fallback second" "${stable_servers[1]:-none}"
|
||||
for ch in edge rc; do
|
||||
if grep -q git.zacharyzhang.com "$ROOT/default/pacman/pacman-$ch.conf"; then
|
||||
fail "$ch conf must stay upstream-only (mirror carries stable only)"
|
||||
fi
|
||||
done
|
||||
bash -n "$ROOT/cn/migrations/1787861071.sh" || fail "mirror migration parses"
|
||||
grep -q "pacman-key --add" "$ROOT/install/post-install/pacman.sh" || fail "install imports the registry key"
|
||||
pass "[omarchy] mirror wiring: stable mirror-first, edge/rc untouched, key import present"
|
||||
|
||||
# Mirror-line guard: comments and substrings must not count as present
|
||||
tmpconf=$(mktemp)
|
||||
printf 'Server = https://pkgs.omarchy.org/stable/$arch\n' > "$tmpconf"
|
||||
(
|
||||
source "$ROOT/cn/lib/mirror.sh"
|
||||
OMARCHYCN_PACMAN_CONF=$tmpconf cn_mirror_omarchy_repo_ok && exit 1
|
||||
printf '# Server = %s\n' "$CN_OMARCHY_MIRROR" >> "$tmpconf"
|
||||
OMARCHYCN_PACMAN_CONF=$tmpconf cn_mirror_omarchy_repo_ok && exit 1
|
||||
printf 'Server = %s\n' "$CN_OMARCHY_MIRROR" >> "$tmpconf"
|
||||
OMARCHYCN_PACMAN_CONF=$tmpconf cn_mirror_omarchy_repo_ok
|
||||
) || fail "omarchy repo guard exact-line semantics"
|
||||
rm -f "$tmpconf"
|
||||
pass "omarchy mirror guard ignores comments and matches only the exact line"
|
||||
|
||||
# Menu: OmarchyCN entries parse and reference only existing commands
|
||||
node -e '
|
||||
const fs = require("fs");
|
||||
|
||||
Reference in New Issue
Block a user