项目文件夹

文件
AI不止语 9254572c68 feat: 新增 CodeWhale(原 DeepSeek-TUI)工具支持 (#81)
CodeWhale(Hmbown/CodeWhale,38k,Rust 终端编程 Agent)从
~/.codewhale/skills/<slug>/SKILL.md 加载技能,格式与 WorkBuddy/Hermes 一致。

- convert.sh:新增 convert_codewhale(输出 SKILL.md,name+description frontmatter)
  + 加入 valid_tools / tools_to_run / dispatch
- install.sh:新增 install_codewhale(装到 ~/.codewhale/skills/)
  + detect_codewhale(查 ~/.codewhale 或旧 ~/.deepseek)+ tool_label + ALL_TOOLS + dispatch
- README(中文+繁体):工具数 17→18,安装命令块/工具表/详细说明补 CodeWhale
- AGENT-LIST:支持工具 17→18

已端到端验证:convert 出 266 个 SKILL.md、install 到临时 HOME 成功、
integrations/codewhale 已被 gitignore 不会误提交。

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-18 09:03:16 +08:00

622 行
23 KiB
Bash
可执行文件

此文件含有模棱两可的 Unicode 字符
此文件含有可能会与其他字符混淆的 Unicode 字符。 如果您是想特意这样的,可以安全地忽略该警告。 使用 Escape 按钮显示他们。
#!/usr/bin/env bash
#
# install.sh -- 将智能体安装到本地 AI 工具中(中文版适配)
#
# 读取 integrations/ 中的转换文件,复制到各工具的配置目录。
# 请先运行 scripts/convert.sh 生成集成文件。
#
# 用法:
# ./scripts/install.sh [--tool <name>] [--no-interactive] [--help]
#
# 支持的工具:
# claude-code -- 复制到 ~/.claude/agents/
# copilot -- 复制到 ~/.github/agents/
# antigravity -- 复制到 ~/.gemini/antigravity/skills/
# gemini-cli -- 安装到 ~/.gemini/extensions/agency-agents/
# opencode -- 复制到 .opencode/agent/(当前目录)
# cursor -- 复制到 .cursor/rules/(当前目录)
# trae -- 复制到 .trae/rules/(当前目录)
# aider -- 复制 CONVENTIONS.md(当前目录)
# windsurf -- 复制 .windsurfrules(当前目录)
# openclaw -- 复制到 ~/.openclaw/agency-agents/
# qwen -- 复制 SubAgent 到 .qwen/agents/(项目级)
# codex -- 复制到 .codex/agents/(项目级)
# deerflow -- 复制到 DeerFlow custom skills 目录(Docker 项目级)
# workbuddy -- 复制到 ~/.workbuddy/skills/(全局)
# codewhale -- 复制到 ~/.codewhale/skills/(全局,原 DeepSeek-TUI
# hermes -- 复制到 ~/.hermes/skills/(全局)
# kiro -- 复制到 ~/.kiro/agents/(全局)
# qoder -- 复制到 .qoder/agents/(项目级)
# all -- 安装所有已检测到的工具(默认)
#
# Hermes 专属参数:
# --category <名称> 只安装某一分类下的 skills,可重复传入多次。
# 分类取 integrations/hermes/ 下的目录名,例如:
# --category marketing
# --category engineering --category design
# Discord 模式下 Hermes 会把每个 skill 注册为斜杠命令,
# 总 JSON 超过 8000 字符会被 Discord API 拒绝 (error 50035),
# 若需要在 Discord 中使用建议按分类分批安装。
set -euo pipefail
# --- 颜色 ---
if [[ -t 1 ]]; then
C_GREEN=$'\033[0;32m'; C_YELLOW=$'\033[1;33m'; C_RED=$'\033[0;31m'
C_CYAN=$'\033[0;36m'; C_BOLD=$'\033[1m'; C_DIM=$'\033[2m'; C_RESET=$'\033[0m'
else
C_GREEN=''; C_YELLOW=''; C_RED=''; C_CYAN=''; C_BOLD=''; C_DIM=''; C_RESET=''
fi
ok() { printf "${C_GREEN}[OK]${C_RESET} %s\n" "$*"; }
warn() { printf "${C_YELLOW}[!!]${C_RESET} %s\n" "$*"; }
err() { printf "${C_RED}[ERR]${C_RESET} %s\n" "$*" >&2; }
header() { printf "\n${C_BOLD}%s${C_RESET}\n" "$*"; }
dim() { printf "${C_DIM}%s${C_RESET}\n" "$*"; }
# --- 路径 ---
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
REPO_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
INTEGRATIONS="$REPO_ROOT/integrations"
ALL_TOOLS=(claude-code copilot antigravity gemini-cli opencode openclaw cursor trae aider windsurf qwen codex deerflow workbuddy codewhale hermes kiro qoder)
# --- 用法 ---
usage() {
sed -n '3,26p' "$0" | sed 's/^# \{0,1\}//'
exit 0
}
# --- 预检 ---
check_integrations() {
if [[ ! -d "$INTEGRATIONS" ]]; then
err "integrations/ 不存在。请先运行 ./scripts/convert.sh"
exit 1
fi
}
# --- 工具检测 ---
detect_claude_code() { [[ -d "${HOME}/.claude" ]]; }
detect_copilot() { command -v code >/dev/null 2>&1 || [[ -d "${HOME}/.github" ]] || [[ -d "${HOME}/.copilot" ]]; }
detect_antigravity() { [[ -d "${HOME}/.gemini/antigravity/skills" ]]; }
detect_gemini_cli() { command -v gemini >/dev/null 2>&1 || [[ -d "${HOME}/.gemini" ]]; }
detect_cursor() { command -v cursor >/dev/null 2>&1 || [[ -d "${HOME}/.cursor" ]]; }
detect_trae() { command -v trae >/dev/null 2>&1 || [[ -d "${HOME}/.trae" ]]; }
detect_opencode() { command -v opencode >/dev/null 2>&1 || [[ -d "${HOME}/.config/opencode" ]]; }
detect_aider() { command -v aider >/dev/null 2>&1; }
detect_openclaw() { command -v openclaw >/dev/null 2>&1 || [[ -d "${HOME}/.openclaw" ]]; }
detect_windsurf() { command -v windsurf >/dev/null 2>&1 || [[ -d "${HOME}/.codeium" ]]; }
detect_qwen() { command -v qwen >/dev/null 2>&1 || [[ -d "${HOME}/.qwen" ]]; }
detect_codex() { command -v codex >/dev/null 2>&1 || [[ -d "${HOME}/.codex" ]]; }
detect_deerflow() { command -v deerflow >/dev/null 2>&1 || [[ -d "${HOME}/.deerflow" ]] || docker ps --format '{{.Names}}' 2>/dev/null | grep -q deerflow; }
detect_workbuddy() { command -v workbuddy >/dev/null 2>&1 || [[ -d "${HOME}/.workbuddy" ]]; }
detect_codewhale() { command -v codewhale >/dev/null 2>&1 || [[ -d "${HOME}/.codewhale" ]] || [[ -d "${HOME}/.deepseek" ]]; }
detect_hermes() { command -v hermes >/dev/null 2>&1 || [[ -d "${HOME}/.hermes" ]]; }
detect_kiro() { command -v kiro >/dev/null 2>&1 || command -v kiro-cli >/dev/null 2>&1 || [[ -d "${HOME}/.kiro" ]]; }
detect_qoder() { command -v qoder >/dev/null 2>&1 || [[ -d "${HOME}/.qoder" ]]; }
is_detected() {
case "$1" in
claude-code) detect_claude_code ;;
copilot) detect_copilot ;;
antigravity) detect_antigravity ;;
gemini-cli) detect_gemini_cli ;;
opencode) detect_opencode ;;
openclaw) detect_openclaw ;;
cursor) detect_cursor ;;
trae) detect_trae ;;
aider) detect_aider ;;
windsurf) detect_windsurf ;;
qwen) detect_qwen ;;
codex) detect_codex ;;
deerflow) detect_deerflow ;;
workbuddy) detect_workbuddy ;;
codewhale) detect_codewhale ;;
hermes) detect_hermes ;;
kiro) detect_kiro ;;
qoder) detect_qoder ;;
*) return 1 ;;
esac
}
tool_label() {
case "$1" in
claude-code) printf "%-14s %s" "Claude Code" "(~/.claude/agents)" ;;
copilot) printf "%-14s %s" "Copilot" "(~/.github + ~/.copilot)" ;;
antigravity) printf "%-14s %s" "Antigravity" "(~/.gemini/antigravity)" ;;
gemini-cli) printf "%-14s %s" "Gemini CLI" "(gemini 扩展)" ;;
opencode) printf "%-14s %s" "OpenCode" "(opencode.ai)" ;;
openclaw) printf "%-14s %s" "OpenClaw" "(~/.openclaw)" ;;
cursor) printf "%-14s %s" "Cursor" "(.cursor/rules)" ;;
trae) printf "%-14s %s" "Trae" "(.trae/rules)" ;;
aider) printf "%-14s %s" "Aider" "(CONVENTIONS.md)" ;;
windsurf) printf "%-14s %s" "Windsurf" "(.windsurfrules)" ;;
qwen) printf "%-14s %s" "Qwen Code" "(~/.qwen/agents)" ;;
codex) printf "%-14s %s" "Codex CLI" "(.codex/agents)" ;;
deerflow) printf "%-14s %s" "DeerFlow" "(skills/custom)" ;;
workbuddy) printf "%-14s %s" "WorkBuddy" "(~/.workbuddy/skills)" ;;
codewhale) printf "%-14s %s" "CodeWhale" "(~/.codewhale/skills)" ;;
hermes) printf "%-14s %s" "Hermes Agent" "(~/.hermes/skills)" ;;
kiro) printf "%-14s %s" "Kiro" "(~/.kiro/agents)" ;;
qoder) printf "%-14s %s" "Qoder" "(.qoder/agents)" ;;
esac
}
# --- 安装器 ---
install_claude_code() {
local dest="${HOME}/.claude/agents"
local count=0
mkdir -p "$dest"
local dir f first_line
for dir in academic design engineering finance game-development gis hr legal marketing paid-media sales product \
project-management security supply-chain testing support spatial-computing specialized; do
[[ -d "$REPO_ROOT/$dir" ]] || continue
while IFS= read -r -d '' f; do
first_line="$(head -1 "$f")"
[[ "$first_line" == "---" ]] || continue
cp "$f" "$dest/"
(( count++ )) || true
done < <(find "$REPO_ROOT/$dir" -name "*.md" -type f -print0)
done
ok "Claude Code: $count 个智能体 -> $dest"
}
install_copilot() {
local dest1="${HOME}/.github/agents"
local dest2="${HOME}/.copilot/agents"
local count=0
mkdir -p "$dest1" "$dest2"
local dir f first_line
for dir in academic design engineering finance game-development gis hr legal marketing paid-media sales product \
project-management security supply-chain testing support spatial-computing specialized; do
[[ -d "$REPO_ROOT/$dir" ]] || continue
while IFS= read -r -d '' f; do
first_line="$(head -1 "$f")"
[[ "$first_line" == "---" ]] || continue
cp "$f" "$dest1/"
cp "$f" "$dest2/"
(( count++ )) || true
done < <(find "$REPO_ROOT/$dir" -name "*.md" -type f -print0)
done
ok "Copilot: $count 个智能体 -> $dest1 + $dest2"
}
install_antigravity() {
local src="$INTEGRATIONS/antigravity"
local dest="${HOME}/.gemini/antigravity/skills"
local count=0
[[ -d "$src" ]] || { err "integrations/antigravity 不存在。请先运行 convert.sh"; return 1; }
mkdir -p "$dest"
local d
while IFS= read -r -d '' d; do
local name; name="$(basename "$d")"
mkdir -p "$dest/$name"
cp "$d/SKILL.md" "$dest/$name/SKILL.md"
(( count++ )) || true
done < <(find "$src" -mindepth 1 -maxdepth 1 -type d -print0)
ok "Antigravity: $count 个 skills -> $dest"
}
install_gemini_cli() {
local src="$INTEGRATIONS/gemini-cli"
local dest="${HOME}/.gemini/extensions/agency-agents"
local count=0
[[ -d "$src" ]] || { err "integrations/gemini-cli 不存在。请先运行 convert.sh --tool gemini-cli"; return 1; }
[[ -f "$src/gemini-extension.json" ]] || { err "gemini-extension.json 缺失。请先运行 convert.sh --tool gemini-cli"; return 1; }
[[ -d "$src/skills" ]] || { err "skills/ 目录缺失。请先运行 convert.sh --tool gemini-cli"; return 1; }
mkdir -p "$dest/skills"
cp "$src/gemini-extension.json" "$dest/gemini-extension.json"
local d
while IFS= read -r -d '' d; do
local name; name="$(basename "$d")"
mkdir -p "$dest/skills/$name"
cp "$d/SKILL.md" "$dest/skills/$name/SKILL.md"
(( count++ )) || true
done < <(find "$src/skills" -mindepth 1 -maxdepth 1 -type d -print0)
ok "Gemini CLI: $count 个 skills -> $dest"
}
install_opencode() {
local src="$INTEGRATIONS/opencode/agents"
local dest="${PWD}/.opencode/agents"
local count=0
[[ -d "$src" ]] || { err "integrations/opencode 不存在。请先运行 convert.sh"; return 1; }
mkdir -p "$dest"
local f
while IFS= read -r -d '' f; do
cp "$f" "$dest/"; (( count++ )) || true
done < <(find "$src" -maxdepth 1 -name "*.md" -print0)
ok "OpenCode: $count 个智能体 -> $dest"
warn "OpenCode: 项目级安装。请在项目根目录运行。"
}
install_openclaw() {
local src="$INTEGRATIONS/openclaw"
local dest="${HOME}/.openclaw/agency-agents"
local count=0
[[ -d "$src" ]] || { err "integrations/openclaw 不存在。请先运行 convert.sh"; return 1; }
mkdir -p "$dest"
local d
while IFS= read -r -d '' d; do
local name; name="$(basename "$d")"
mkdir -p "$dest/$name"
cp "$d/SOUL.md" "$dest/$name/SOUL.md"
cp "$d/AGENTS.md" "$dest/$name/AGENTS.md"
cp "$d/IDENTITY.md" "$dest/$name/IDENTITY.md"
if command -v openclaw >/dev/null 2>&1; then
# 跳过已注册的智能体,避免重复 add 导致阻塞(#34)
if openclaw agents list 2>/dev/null | grep -q "$name"; then
dim " 跳过已注册: $name"
else
# 超时 30s 防止命令挂起(macOS 兼容写法)
if command -v timeout >/dev/null 2>&1; then
timeout 30 openclaw agents add "$name" --workspace "$dest/$name" --non-interactive 2>/dev/null || true
else
openclaw agents add "$name" --workspace "$dest/$name" --non-interactive 2>/dev/null &
local pid=$!
( sleep 30 && kill "$pid" 2>/dev/null ) &
wait "$pid" 2>/dev/null || true
fi
fi
fi
(( count++ )) || true
done < <(find "$src" -mindepth 1 -maxdepth 1 -type d -print0)
ok "OpenClaw: $count 个工作空间 -> $dest"
if command -v openclaw >/dev/null 2>&1; then
warn "OpenClaw: 运行 'openclaw gateway restart' 激活新智能体"
fi
}
install_cursor() {
local src="$INTEGRATIONS/cursor/rules"
local dest="${PWD}/.cursor/rules"
local count=0
[[ -d "$src" ]] || { err "integrations/cursor 不存在。请先运行 convert.sh"; return 1; }
mkdir -p "$dest"
local f
while IFS= read -r -d '' f; do
cp "$f" "$dest/"; (( count++ )) || true
done < <(find "$src" -maxdepth 1 -name "*.mdc" -print0)
ok "Cursor: $count 个规则 -> $dest"
warn "Cursor: 项目级安装。请在项目根目录运行。"
}
install_trae() {
local src="$INTEGRATIONS/trae/rules"
local dest="${PWD}/.trae/rules"
local count=0
[[ -d "$src" ]] || { err "integrations/trae 不存在。请先运行 convert.sh --tool trae"; return 1; }
mkdir -p "$dest"
local f
while IFS= read -r -d '' f; do
cp "$f" "$dest/"; (( count++ )) || true
done < <(find "$src" -maxdepth 1 -name "*.md" -print0)
ok "Trae: $count 个规则 -> $dest"
warn "Trae: 项目级安装。请在项目根目录运行。"
}
install_aider() {
local src="$INTEGRATIONS/aider/CONVENTIONS.md"
local dest="${PWD}/CONVENTIONS.md"
[[ -f "$src" ]] || { err "integrations/aider/CONVENTIONS.md 不存在。请先运行 convert.sh"; return 1; }
if [[ -f "$dest" ]]; then
warn "Aider: CONVENTIONS.md 已存在 ($dest),删除后重试。"
return 0
fi
cp "$src" "$dest"
ok "Aider: 已安装 -> $dest"
warn "Aider: 项目级安装。请在项目根目录运行。"
}
install_windsurf() {
local src="$INTEGRATIONS/windsurf/.windsurfrules"
local dest="${PWD}/.windsurfrules"
[[ -f "$src" ]] || { err "integrations/windsurf/.windsurfrules 不存在。请先运行 convert.sh"; return 1; }
if [[ -f "$dest" ]]; then
warn "Windsurf: .windsurfrules 已存在 ($dest),删除后重试。"
return 0
fi
cp "$src" "$dest"
ok "Windsurf: 已安装 -> $dest"
warn "Windsurf: 项目级安装。请在项目根目录运行。"
}
install_qwen() {
local src="$INTEGRATIONS/qwen/agents"
local dest="${PWD}/.qwen/agents"
local count=0
[[ -d "$src" ]] || { err "integrations/qwen 不存在。请先运行 convert.sh"; return 1; }
mkdir -p "$dest"
local f
while IFS= read -r -d '' f; do
cp "$f" "$dest/"
(( count++ )) || true
done < <(find "$src" -maxdepth 1 -name "*.md" -print0)
ok "Qwen Code: $count 个智能体 -> $dest"
warn "Qwen Code: 项目级安装。请在项目根目录运行。"
warn "提示: 在 Qwen Code 中运行 '/agents manage' 刷新,或重启会话"
}
install_codex() {
local src="$INTEGRATIONS/codex/agents"
local dest="${PWD}/.codex/agents"
local count=0
[[ -d "$src" ]] || { err "integrations/codex 不存在。请先运行 convert.sh --tool codex"; return 1; }
mkdir -p "$dest"
local f
while IFS= read -r -d '' f; do
cp "$f" "$dest/"
(( count++ )) || true
done < <(find "$src" -maxdepth 1 -name "*.toml" -print0)
ok "Codex CLI: $count 个智能体 -> $dest"
warn "Codex CLI: 项目级安装。请在项目根目录运行。"
}
install_deerflow() {
local src="$INTEGRATIONS/deerflow"
local dest="${DEERFLOW_SKILLS_DIR:-./skills/custom}"
local count=0
[[ -d "$src" ]] || { err "integrations/deerflow 不存在。请先运行 convert.sh --tool deerflow"; return 1; }
mkdir -p "$dest"
local d
while IFS= read -r -d '' d; do
local name; name="$(basename "$d")"
[[ -f "$d/SKILL.md" ]] || continue
mkdir -p "$dest/$name"
cp "$d/SKILL.md" "$dest/$name/SKILL.md"
(( count++ )) || true
done < <(find "$src" -mindepth 1 -maxdepth 1 -type d -print0)
ok "DeerFlow: $count 个 skills -> $dest"
warn "DeerFlow: 默认安装到 ./skills/custom/。设置 DEERFLOW_SKILLS_DIR 可自定义路径。"
}
install_workbuddy() {
local src="$INTEGRATIONS/workbuddy"
local dest="${HOME}/.workbuddy/skills"
local count=0
[[ -d "$src" ]] || { err "integrations/workbuddy 不存在。请先运行 convert.sh --tool workbuddy"; return 1; }
mkdir -p "$dest"
local d
while IFS= read -r -d '' d; do
local name; name="$(basename "$d")"
[[ -f "$d/SKILL.md" ]] || continue
mkdir -p "$dest/$name"
cp "$d/SKILL.md" "$dest/$name/SKILL.md"
(( count++ )) || true
done < <(find "$src" -mindepth 1 -maxdepth 1 -type d -print0)
ok "WorkBuddy: $count 个 skills -> $dest"
}
install_codewhale() {
local src="$INTEGRATIONS/codewhale"
local dest="${HOME}/.codewhale/skills"
local count=0
[[ -d "$src" ]] || { err "integrations/codewhale 不存在。请先运行 convert.sh --tool codewhale"; return 1; }
mkdir -p "$dest"
local d
while IFS= read -r -d '' d; do
local name; name="$(basename "$d")"
[[ -f "$d/SKILL.md" ]] || continue
mkdir -p "$dest/$name"
cp "$d/SKILL.md" "$dest/$name/SKILL.md"
(( count++ )) || true
done < <(find "$src" -mindepth 1 -maxdepth 1 -type d -print0)
ok "CodeWhale: $count 个 skills -> $dest"
}
install_hermes() {
local src="$INTEGRATIONS/hermes"
# 安装目录优先级(issue #82):官方环境变量 HERMES_HOME > Windows 新版默认位置 > 传统位置
local dest
if [[ -n "${HERMES_HOME:-}" ]]; then
dest="${HERMES_HOME}/skills"
elif [[ -n "${LOCALAPPDATA:-}" && -d "${LOCALAPPDATA}/hermes" ]]; then
dest="${LOCALAPPDATA}/hermes/skills"
else
dest="${HOME}/.hermes/skills"
fi
local count=0
[[ -d "$src" ]] || { err "integrations/hermes 不存在。请先运行 convert.sh --tool hermes"; return 1; }
# 若指定了 --category,只安装命中的分类;否则安装全部
local filter_note=""
if [[ ${#HERMES_CATEGORIES[@]} -gt 0 ]]; then
local c
for c in "${HERMES_CATEGORIES[@]}"; do
[[ -d "$src/$c" ]] || { err "hermes 分类不存在: ${c}(可选: $(ls "$src" | tr '\n' ' ')"; return 1; }
done
filter_note=" [分类: ${HERMES_CATEGORIES[*]}]"
fi
mkdir -p "$dest"
# Hermes 保留两级目录结构:category/skill-name/SKILL.md
local catdir
while IFS= read -r -d '' catdir; do
local catname; catname="$(basename "$catdir")"
if [[ ${#HERMES_CATEGORIES[@]} -gt 0 ]]; then
local matched=false c
for c in "${HERMES_CATEGORIES[@]}"; do [[ "$c" == "$catname" ]] && matched=true && break; done
$matched || continue
fi
local skilldir
while IFS= read -r -d '' skilldir; do
local skillname; skillname="$(basename "$skilldir")"
[[ -f "$skilldir/SKILL.md" ]] || continue
mkdir -p "$dest/$catname/$skillname"
cp "$skilldir/SKILL.md" "$dest/$catname/$skillname/SKILL.md"
(( count++ )) || true
done < <(find "$catdir" -mindepth 1 -maxdepth 1 -type d -print0)
done < <(find "$src" -mindepth 1 -maxdepth 1 -type d -print0)
ok "Hermes Agent: $count 个 skills -> $dest$filter_note"
if [[ ${#HERMES_CATEGORIES[@]} -eq 0 && $count -gt 80 ]]; then
warn "Hermes Discord 模式对斜杠命令总长有 8000 字符上限(error 50035)。"
warn "若要在 Discord 中使用,建议用 --category <名称> 按分类分批安装。"
fi
}
install_kiro() {
local src="$INTEGRATIONS/kiro"
local dest="${HOME}/.kiro/agents"
local count=0
[[ -d "$src" ]] || { err "integrations/kiro 不存在。请先运行 convert.sh --tool kiro"; return 1; }
mkdir -p "$dest"
# Kiro 自定义智能体格式:.md 文件(带 YAML frontmatter
# 参考:https://kiro.dev/docs/chat/subagents/
local f
while IFS= read -r -d '' f; do
cp "$f" "$dest/"
(( count++ )) || true
done < <(find "$src" -maxdepth 1 -name "*.md" -print0)
ok "Kiro: $count 个智能体 -> $dest"
warn "提示: Kiro 会自动识别 ~/.kiro/agents/ 下的 .md 文件作为自定义子智能体"
warn "提示: 在对话中使用 '/<agent-name>' 或让 Kiro 自动选择合适的子智能体"
}
install_qoder() {
local src="$INTEGRATIONS/qoder/agents"
local dest="${PWD}/.qoder/agents"
local count=0
[[ -d "$src" ]] || { err "integrations/qoder 不存在。请先运行 convert.sh --tool qoder"; return 1; }
mkdir -p "$dest"
local f
while IFS= read -r -d '' f; do
cp "$f" "$dest/"
(( count++ )) || true
done < <(find "$src" -maxdepth 1 -name "*.md" -print0)
ok "Qoder: $count 个智能体 -> $dest"
warn "Qoder: 项目级安装。请在项目根目录运行。"
}
install_tool() {
case "$1" in
claude-code) install_claude_code ;;
copilot) install_copilot ;;
antigravity) install_antigravity ;;
gemini-cli) install_gemini_cli ;;
opencode) install_opencode ;;
openclaw) install_openclaw ;;
cursor) install_cursor ;;
trae) install_trae ;;
aider) install_aider ;;
windsurf) install_windsurf ;;
qwen) install_qwen ;;
codex) install_codex ;;
deerflow) install_deerflow ;;
workbuddy) install_workbuddy ;;
codewhale) install_codewhale ;;
hermes) install_hermes ;;
kiro) install_kiro ;;
qoder) install_qoder ;;
esac
}
# --- 入口 ---
main() {
local tool="all"
HERMES_CATEGORIES=()
while [[ $# -gt 0 ]]; do
case "$1" in
--tool) tool="${2:?'--tool 需要一个值'}"; shift 2 ;;
--category) HERMES_CATEGORIES+=("${2:?'--category 需要一个值'}"); shift 2 ;;
--no-interactive) shift ;;
--help|-h) usage ;;
*) err "未知选项: $1"; usage ;;
esac
done
if [[ ${#HERMES_CATEGORIES[@]} -gt 0 && "$tool" != "hermes" ]]; then
warn "--category 仅对 --tool hermes 生效,已忽略。"
HERMES_CATEGORIES=()
fi
check_integrations
if [[ "$tool" != "all" ]]; then
local valid=false t
for t in "${ALL_TOOLS[@]}"; do [[ "$t" == "$tool" ]] && valid=true && break; done
if ! $valid; then
err "未知工具 '$tool'。可选: ${ALL_TOOLS[*]}"
exit 1
fi
fi
SELECTED_TOOLS=()
if [[ "$tool" != "all" ]]; then
SELECTED_TOOLS=("$tool")
else
header "AI 智能体专家团队 -- 扫描已安装的工具..."
printf "\n"
local t
for t in "${ALL_TOOLS[@]}"; do
if is_detected "$t" 2>/dev/null; then
SELECTED_TOOLS+=("$t")
printf " ${C_GREEN}[*]${C_RESET} %s ${C_DIM}已检测到${C_RESET}\n" "$(tool_label "$t")"
else
printf " ${C_DIM}[ ] %s 未找到${C_RESET}\n" "$(tool_label "$t")"
fi
done
fi
if [[ ${#SELECTED_TOOLS[@]} -eq 0 ]]; then
warn "未选择或检测到任何工具。"
printf "\n"
dim " 提示: 使用 --tool <名称> 强制安装指定工具。"
dim " 可选: ${ALL_TOOLS[*]}"
exit 0
fi
printf "\n"
header "AI 智能体专家团队 -- 安装智能体"
printf " 仓库: %s\n" "$REPO_ROOT"
printf " 安装到: %s\n" "${SELECTED_TOOLS[*]}"
printf "\n"
local installed=0 t
for t in "${SELECTED_TOOLS[@]}"; do
install_tool "$t"
(( installed++ )) || true
done
printf "\n"
ok "完成!已安装 $installed 个工具。"
printf "\n"
dim " 运行 ./scripts/convert.sh 重新生成集成文件。"
printf "\n"
}
main "$@"