From 28a9de1a4650e6e5783f411598e523f608cd4eec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=9B=B7=E7=94=B5=E8=8A=BD=E8=A1=A3?= Date: Mon, 24 Aug 2026 20:20:54 -0400 Subject: [PATCH] Add AI secret backend with three-tier storage fallback Co-Authored-By: Claude Fable 5 Claude-Session: https://claude.ai/code/session_01QKxGW1raAWaqeU8WdHsMsp --- bin/omarchy-cn-ai-secret | 87 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 87 insertions(+) create mode 100755 bin/omarchy-cn-ai-secret diff --git a/bin/omarchy-cn-ai-secret b/bin/omarchy-cn-ai-secret new file mode 100755 index 00000000..733a8dd9 --- /dev/null +++ b/bin/omarchy-cn-ai-secret @@ -0,0 +1,87 @@ +#!/bin/bash +# omarchy:summary=Store, read, or delete AI provider API keys +# omarchy:args= +# omarchy:examples=omarchycn ai secret set deepseek | omarchycn ai secret get deepseek + +set -euo pipefail + +action="${1:?usage: omarchycn ai secret }" +provider="${2:?usage: omarchycn ai secret }" + +if [[ ! $provider =~ ^[a-z0-9-]+$ ]]; then + echo "Invalid provider name: $provider" >&2 + exit 1 +fi + +FILE_DIR="$HOME/.local/state/omarchycn/secrets" +FILE_PATH="$FILE_DIR/$provider" + +secret_service_ok() { + command -v secret-tool > /dev/null 2>&1 && secret-tool search service omarchycn > /dev/null 2>&1 +} + +pass_ok() { + command -v pass > /dev/null 2>&1 && pass ls > /dev/null 2>&1 +} + +case "$action" in +set) + if [[ -t 0 ]]; then + read -rs -p "API key for $provider: " key + echo + else + IFS= read -r key + fi + if [[ -z $key ]]; then + echo "Empty key refused" >&2 + exit 1 + fi + if secret_service_ok; then + printf '%s' "$key" | secret-tool store --label "OmarchyCN AI: $provider" service omarchycn key "ai/$provider" + echo "Stored in Secret Service (secret-tool)" + elif pass_ok; then + printf '%s\n' "$key" | pass insert -m -f "omarchycn/ai/$provider" > /dev/null + echo "Stored in pass (omarchycn/ai/$provider)" + else + mkdir -p -m 700 "$FILE_DIR" + (umask 177 && printf '%s' "$key" > "$FILE_PATH") + echo "Stored in $FILE_PATH (0600 file fallback — 安装 libsecret 或 pass 可获得更安全的存储)" + fi + ;; +get) + if secret_service_ok && secret-tool lookup service omarchycn key "ai/$provider" 2>/dev/null; then + exit 0 + fi + if pass_ok && pass show "omarchycn/ai/$provider" 2>/dev/null; then + exit 0 + fi + if [[ -f $FILE_PATH ]]; then + cat "$FILE_PATH" + exit 0 + fi + echo "No secret stored for $provider (run: omarchycn ai secret set $provider)" >&2 + exit 1 + ;; +rm) + removed=0 + if secret_service_ok && secret-tool clear service omarchycn key "ai/$provider" 2>/dev/null; then + removed=1 + fi + if pass_ok && pass rm -f "omarchycn/ai/$provider" > /dev/null 2>&1; then + removed=1 + fi + if [[ -f $FILE_PATH ]]; then + rm -f "$FILE_PATH" + removed=1 + fi + if (( removed == 0 )); then + echo "No secret stored for $provider" >&2 + exit 1 + fi + echo "Secret for $provider removed" + ;; +*) + echo "Unknown action: $action (expected set, get, or rm)" >&2 + exit 1 + ;; +esac