Author SHA1 Message Date
ZacharyZhang-NYandClaude Fable 5 c4dcd2b63a Document and test the [omarchy] mirror wiring
Static suite assertions pin the stable conf's server order and keep
edge/rc upstream-only; the guard test proves exact-line semantics.
docs/pacman-repo.md gains the mirror section with the honest
operational contract: staleness is invisible to pacman, fallback
fires only on retrieval failure, and omarchy-refresh-pacman's -Syyuu
downgrade wipes the cn layer while upstream ships older omarchy-dev.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019hLK3wsDuKVAC37GgDqg6H
2026-08-27 16:29:34 -04:00
ZacharyZhang-NYandClaude Fable 5 b183be2832 Put the OmarchyCN [omarchy] mirror first on the stable channel
The Gitea mirror db is registry-signed, so installs trust the registry
key right after the pacman.conf restore, and a cn migration does the
same on existing systems with an idempotent exact-line guard. The
insertion lives in cn/lib/mirror.sh so 'omarchycn doctor mirror --fix'
can restore the line after omarchy-refresh-pacman resets an overlay
system's conf. Only stable is mirrored: the Gitea repository name must
equal the pacman section name, and edge/rc stay on upstream directly.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019hLK3wsDuKVAC37GgDqg6H
2026-08-27 16:20:48 -04:00
ZacharyZhang-NYandClaude Fable 5 fc9afae2b6 Cover the ollama provider paths in the AI mock regression suite
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019hLK3wsDuKVAC37GgDqg6H
2026-08-27 16:02:06 -04:00
ZacharyZhang-NYandClaude Fable 5 111b857cda Add local Ollama as an AI Hub provider for claude-code
Ollama v0.14+ speaks the Anthropic Messages API natively, so the
registry drives it with a fixed 'ollama' token and runtime-listed
models: static_token skips secret storage everywhere keys resolve,
models_dynamic defers model validation to the live /api/tags list,
and the setup wizard installs the right GPU variant and starts the
service before listing local models. Doctor stops treating the
endpoint port as part of the hostname.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019hLK3wsDuKVAC37GgDqg6H
2026-08-27 15:55:15 -04:00
ZacharyZhang-NYandClaude Fable 5 4b280a1767 Add DSH to the agent roster and Install > AI
Official npm @deepseek-ai/dsh (bin: dsh) rides the mise path like Dim.
dsh has no TUI, so the interactive launch is the documented 'dsh web'
and one-shot prompts use 'dsh --profile headless'. Auth is dsh-managed,
so it stays out of the AI Hub registry.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019hLK3wsDuKVAC37GgDqg6H
2026-08-27 15:42:46 -04:00
ZacharyZhang-NYandClaude Fable 5 602a82621a Run the package repo mirror sync from CI every six hours
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019hLK3wsDuKVAC37GgDqg6H
2026-08-27 15:34:44 -04:00
ZacharyZhang-NYandClaude Fable 5 87b4cc4da1 Mirror the upstream stable package repo into the Gitea Arch registry
packages/sync-omarchy-repo.sh diffs the upstream omarchy.db against the
registry's own db by filename, streams missing packages through (409 =
already present), and deletes entries upstream no longer lists. Only a
404 counts as first sync; any other mirror-db failure aborts rather
than faking an empty mirror.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019hLK3wsDuKVAC37GgDqg6H
2026-08-27 15:34:01 -04:00
ZacharyZhang-NYandClaude Fable 5 70895d4f1c Bump cn/release to 6 after publishing 4.0.0.alpha-cn.5
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QKxGW1raAWaqeU8WdHsMsp
2026-08-25 22:36:59 -04:00
ZacharyZhang-NYandClaude Fable 5 aa87ed97c1 Dim prompts use the documented dim exec form
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QKxGW1raAWaqeU8WdHsMsp
2026-08-25 15:03:35 -04:00
ZacharyZhang-NYandClaude Fable 5 a3cd27dba3 Add Dim Agent CLI to the agent roster and Install > AI
npm dimcode (bin: dim) rides the mise path like Deep Code; entries
land alphabetically in the Default Agent and Install > AI menus.
CLI-only per dimagent.cn, login handled by the CLI itself.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QKxGW1raAWaqeU8WdHsMsp
2026-08-25 14:59:18 -04:00
ZacharyZhang-NYandClaude Fable 5 0812b28527 Detect the missing official repo dbs by core.db, not any db
pacstrap leaves the offline repo's db in the target's sync dir, so
the any-db glob skipped the first-run update path on real installs.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QKxGW1raAWaqeU8WdHsMsp
2026-08-25 13:50:11 -04:00
ZacharyZhang-NYandClaude Fable 5 9bf870449b Link kimi into ~/.local/bin after the official install
The installer only appends PATH to .bashrc, so the fresh binary was
invisible to the launching process and the login never started.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QKxGW1raAWaqeU8WdHsMsp
2026-08-25 13:46:23 -04:00
ZacharyZhang-NYandClaude Fable 5 9be4d24d6d App installs route first-time updates through omarchy-update
Direct pacman -Syu trips the update pacman guard once real upgrades
exist; the catalog installer now runs the upstream update pipeline
interactively and fails fast with instructions when non-interactive.
omarchy-cn-kimi-install gains its executable bit.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QKxGW1raAWaqeU8WdHsMsp
2026-08-25 13:27:38 -04:00
ZacharyZhang-NYandClaude Fable 5 a317bfb36f Fix China app installs and wire the CN AI stack into Install > AI
Offline installs ship no pacman sync db, so yay resolved official
repo dependencies as AUR packages and every catalog install failed;
omarchy-cn-app-install now runs a full -Syu first (verified end to
end: WeChat builds and installs in the VM). Kimi Code gains a real
installer command reused by the harness registry, the default-agent
path, and new Install > AI entries (Kimi Code, Deep Code, AI Hub),
and the AI Hub wizard offers to launch native harnesses immediately
so their official CLI login runs, matching how Claude Code works.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QKxGW1raAWaqeU8WdHsMsp
2026-08-25 13:17:52 -04:00
ZacharyZhang-NYandClaude Fable 5 0f888ffe31 Bump cn/release to 5 after publishing 4.0.0.alpha-cn.4
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QKxGW1raAWaqeU8WdHsMsp
2026-08-25 12:25:27 -04:00
ZacharyZhang-NY 41ddd9052a Update README.md 2026-08-25 16:14:20 +00:00
29 changed files with 392 additions and 29 deletions
+24
View File
@@ -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
+3 -2
View File
@@ -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
+1 -3
View File
@@ -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 全栈兼容,快捷键冲突自动处理
+16
View File
@@ -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
+3 -2
View File
@@ -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")
+3 -1
View File
@@ -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
+1 -1
View File
@@ -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"
+4 -2
View File
@@ -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
View File
@@ -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
+1 -1
View File
@@ -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
+11
View File
@@ -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
View File
@@ -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
;;
+23
View File
@@ -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"
+5 -6
View File
@@ -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
View File
@@ -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"
+13
View File
@@ -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"
+8
View File
@@ -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
+5
View File
@@ -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": {
+2 -2
View File
@@ -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"
},
+13 -1
View File
@@ -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
View File
@@ -1 +1 @@
4
6
+7
View File
@@ -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"},
+2
View File
@@ -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
+10
View File
@@ -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
+4
View File
@@ -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
+101
View File
@@ -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"
+1 -1
View File
@@ -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 = {
+28 -1
View File
@@ -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"
+29
View File
@@ -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");