set -e
shopt -s extglob
if [ -t 1 ]; then
GREEN='\033[0;32m'; YELLOW='\033[0;33m'; RED='\033[0;31m'
CYAN='\033[0;36m'; BOLD='\033[1m'; DIM='\033[2m'; NC='\033[0m'
else
GREEN=''; YELLOW=''; RED=''; CYAN=''; BOLD=''; DIM=''; NC=''
fi
ok() { echo -e " ${DIM}${GREEN}✓${NC}${DIM} $*${NC}"; }
warn() { echo -e " ${YELLOW}⚠${NC}${DIM} $*${NC}"; }
err() { echo -e " ${RED}✗${NC}${DIM} $*${NC}"; }
info() { echo -e " ${DIM}${CYAN}→${NC}${DIM} $*${NC}"; }
step() { echo -e "${DIM}$*${NC}"; }
detect_trae_variant() {
if [ -d "$HOME/.trae-cn" ]; then
TRAE_VARIANT="ide"
elif [ -d "$HOME/.marscode" ]; then
TRAE_VARIANT="plugin"
elif [ -d "$HOME/.traecli" ]; then
TRAE_VARIANT="cli"
else
TRAE_VARIANT="unknown"
fi
}
BRAND="cannbot"
VERSION="1.0.3"
EXCLUDED_SKILL=""
INCLUDED_SKILLS="ascendc-code-review ascendc-docs-search ascendc-task-focus ascendc-api-best-practices"
INCLUDED_AGENT_PATTERN="@(ascendc-ops-reviewer|ascendc-code-summarizer)"
show_banner() {
echo ""
echo -e "${CYAN}"
cat << 'BANNER'
____ _ _ _ _ _ ____ _
/ ___| / \ | \ | | \ | | __ ) ___ | |_
| | / _ \ | \| | \| | _ \ / _ \| __|
| |___ / ___ \| |\ | |\ | |_) | (_) | |_
\____/_/ \_\_| \_|_| \_|____/ \___/ \__|
BANNER
echo -e "${NC}"
echo -e " ${BOLD}Ascend C Code Review Team${NC}"
echo ""
}
show_help() {
cat << EOF
CANNBot - Ascend C Code Review Environment Installer
Usage: init.sh [level] [tool] [install_path]
Arguments:
level - Installation level: "project" (default) or "global"
tool - Target tool: "opencode" (default), "claude", "trae", or "cursor"
install_path - Project-level installation directory (default: current working directory)
Options:
--help - Show this help message
Examples:
init.sh # Project-level, OpenCode
init.sh project opencode # Project-level, OpenCode
init.sh global claude # Global-level, Claude Code
init.sh project claude # Project-level, Claude Code
init.sh project trae # Project-level, Trae
init.sh project cursor # Project-level, Cursor
init.sh project opencode /path/to/proj # Project-level, OpenCode, custom path
init.sh project trae /path/to/proj # Project-level, Trae, custom path
Installation paths (CANNBot brand):
OpenCode: .opencode/{skills,agents}/ + AGENTS.md in project root
Claude: .claude/{skills,agents}/ + CLAUDE.md in project root
Trae IDE: .trae/{skills,agents}/ + AGENTS.md in project root
Trae Plugin: .marscode/{skills,agents}/ + AGENTS.md in project root
Trae CLI: .traecli/{skills,agents}/ + AGENTS.md in project root
Cursor: .cursor/{skills,agents}/ + AGENTS.md in project root
After installation, launch directly:
OpenCode: opencode
Claude: claude
Trae: 通过 CLI 或 IDE 启动
Cursor: 通过 Cursor IDE 启动
EOF
}
LEVEL="project"
TOOL="opencode"
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PLUGIN_ROOT="$SCRIPT_DIR"
LOCAL_AGENT_ROOT="$PLUGIN_ROOT/agents"
SHARED_SKILL_ROOT="$(cd "$PLUGIN_ROOT/../../ops" && pwd)"
for arg in "$@"; do
case "$arg" in
--help) show_help; exit 0 ;;
global|project) LEVEL="$arg" ;;
opencode|claude|trae|cursor) TOOL="$arg" ;;
esac
done
if [ $# -gt 0 ]; then
last_arg="${!#}"
case "$last_arg" in
--help|global|project|opencode|claude|trae|cursor) ;;
*) INSTALL_PATH="$last_arg" ;;
esac
fi
if [ "$LEVEL" = "global" ]; then
if [ "$TOOL" = "opencode" ]; then
CONFIG_ROOT="$HOME/.config/opencode"
elif [ "$TOOL" = "trae" ]; then
detect_trae_variant
case "$TRAE_VARIANT" in
plugin) CONFIG_ROOT="$HOME/.marscode" ;;
cli) CONFIG_ROOT="$HOME/.traecli" ;;
*) CONFIG_ROOT="$HOME/.trae-cn" ;;
esac
elif [ "$TOOL" = "cursor" ]; then
CONFIG_ROOT="$HOME/.cursor"
else
CONFIG_ROOT="$HOME/.claude"
fi
else
if [ -n "$INSTALL_PATH" ]; then
INSTALL_BASE="$(cd "$INSTALL_PATH" && pwd)"
CONFIG_ROOT_BASE="$INSTALL_BASE"
else
INSTALL_BASE="$PWD"
CONFIG_ROOT_BASE="$INSTALL_BASE"
fi
if [ "$TOOL" = "opencode" ]; then
CONFIG_ROOT="$CONFIG_ROOT_BASE/.opencode"
elif [ "$TOOL" = "trae" ]; then
detect_trae_variant
case "$TRAE_VARIANT" in
plugin) CONFIG_ROOT="$CONFIG_ROOT_BASE/.marscode" ;;
cli) CONFIG_ROOT="$CONFIG_ROOT_BASE/.traecli" ;;
*) CONFIG_ROOT="$CONFIG_ROOT_BASE/.trae" ;;
esac
elif [ "$TOOL" = "cursor" ]; then
CONFIG_ROOT="$CONFIG_ROOT_BASE/.cursor"
else
CONFIG_ROOT="$CONFIG_ROOT_BASE/.claude"
fi
fi
CANNBOT_DIR="$CONFIG_ROOT"
if [ -e "$CONFIG_ROOT/$BRAND" ] || [ -L "$CONFIG_ROOT/$BRAND" ]; then
rm -rf "$CONFIG_ROOT/$BRAND"
fi
if [ "$TOOL" = "opencode" ] && [ -L "$CONFIG_ROOT/teams" ]; then
rm -f "$CONFIG_ROOT/teams"
fi
show_banner
echo " Tool: $TOOL"
echo " Level: $LEVEL"
echo " Path: $CONFIG_ROOT"
echo ""
if [ "$TOOL" = "trae" ]; then
case "$TRAE_VARIANT" in
ide)
info "Detected: TRAE IDE (.trae-cn / .trae)"
;;
plugin)
info "Detected: TRAE Plugin (.marscode)"
;;
cli)
info "Detected: TRAE CLI (.traecli)"
;;
unknown)
warn "TRAE variant not detected; defaulting to IDE path"
warn "If you use TRAE Plugin, ensure ~/.marscode exists before re-running"
warn "If you use TRAE CLI, ensure ~/.traecli exists before re-running"
;;
esac
echo ""
fi
step "[0/4] Checking items to be installed..."
SKILLS_TO_INSTALL=""
SKILL_COUNT=0
for skill_dir in "$SHARED_SKILL_ROOT"/*/; do
[ -d "$skill_dir" ] || continue
name=$(basename "$skill_dir")
echo "$INCLUDED_SKILLS" | grep -qw "$name" || continue
[ -n "$EXCLUDED_SKILL" ] && [ "$name" = "$EXCLUDED_SKILL" ] && continue
SKILLS_TO_INSTALL="$SKILLS_TO_INSTALL $name"
SKILL_COUNT=$((SKILL_COUNT + 1))
done
AGENTS_TO_INSTALL=""
AGENT_COUNT=0
for agent_entry in "$LOCAL_AGENT_ROOT"/*; do
[ -e "$agent_entry" ] || continue
name=$(basename "$agent_entry")
base="${name%.md}"
[[ "$base" != $INCLUDED_AGENT_PATTERN ]] && continue
AGENTS_TO_INSTALL="$AGENTS_TO_INSTALL $name"
AGENT_COUNT=$((AGENT_COUNT + 1))
done
echo ""
echo -e "${BOLD}以下内容将被安装/替换:${NC}"
echo ""
echo -e "${CYAN}Skills (${SKILL_COUNT} 项,来自共享 ops 目录):${NC}"
for name in $SKILLS_TO_INSTALL; do
target="$CANNBOT_DIR/skills/$name"
src="$SHARED_SKILL_ROOT/$name"
if [ -e "$target" ] || [ -L "$target" ]; then
echo -e " ${YELLOW}$name${NC} → 将被替换为软连接到 ${src}"
else
echo -e " ${GREEN}$name${NC} → 将创建软连接到 ${src}"
fi
echo -e " ${DIM}目标路径: $target${NC}"
done
echo ""
echo -e "${CYAN}Agents (${AGENT_COUNT} 项,来自本地 agents/):${NC}"
for name in $AGENTS_TO_INSTALL; do
target="$CANNBOT_DIR/agents/$name"
src="$LOCAL_AGENT_ROOT/$name"
if [ -e "$target" ] || [ -L "$target" ]; then
echo -e " ${YELLOW}$name${NC} → 将被替换为软连接到 ${src}"
else
echo -e " ${GREEN}$name${NC} → 将创建软连接到 ${src}"
fi
echo -e " ${DIM}目标路径: $target${NC}"
done
echo ""
echo -e "${CYAN}配置文件:${NC}"
config_src="$PLUGIN_ROOT/AGENTS.md"
if [ "$TOOL" = "opencode" ]; then
if [ "$LEVEL" = "project" ]; then
config_target="$INSTALL_BASE/AGENTS.md"
else
config_target="$CONFIG_ROOT/AGENTS.md"
fi
if [ "$LEVEL" = "project" ] && [ "$PLUGIN_ROOT" = "$INSTALL_BASE" ]; then
echo -e " ${GREEN}AGENTS.md${NC} → 已存在于项目目录,无需创建软链接"
elif [ -e "$config_target" ] || [ -L "$config_target" ]; then
echo -e " ${YELLOW}AGENTS.md${NC} → 将被替换为软连接到 ${config_src}"
else
echo -e " ${GREEN}AGENTS.md${NC} → 将创建软连接到 ${config_src}"
fi
echo -e " ${DIM}目标路径: $config_target${NC}"
elif [ "$TOOL" = "claude" ]; then
if [ "$LEVEL" = "project" ]; then
config_target="$INSTALL_BASE/CLAUDE.md"
else
config_target="$CONFIG_ROOT/CLAUDE.md"
fi
if [ -e "$config_target" ] || [ -L "$config_target" ]; then
echo -e " ${YELLOW}CLAUDE.md${NC} (将被替换)"
else
echo -e " ${GREEN}CLAUDE.md${NC} (将创建)"
fi
else
if [ "$LEVEL" = "project" ]; then
config_target="$INSTALL_BASE/AGENTS.md"
else
config_target="$CONFIG_ROOT/AGENTS.md"
fi
if [ -e "$config_target" ] || [ -L "$config_target" ]; then
echo -e " ${YELLOW}AGENTS.md${NC} (将被替换)"
else
echo -e " ${GREEN}AGENTS.md${NC} (将创建)"
fi
fi
echo ""
echo -e "${BOLD}${YELLOW}注意:仅替换上述白名单内的内容,不影响其他已存在的 skills/agents${NC}"
echo ""
echo -e "${BOLD}是否继续安装? [y/N]${NC}"
read -r response
case "$response" in
[yY][eE][sS]|[yY])
ok "用户确认,开始安装..."
;;
*)
err "用户取消安装"
exit 0
;;
esac
echo ""
step "[1/4] Setting up CANNBot directory..."
mkdir -p "$CANNBOT_DIR"
step1_summary=""
step1_warns=""
if [ "$TOOL" = "opencode" ]; then
mkdir -p "$CANNBOT_DIR/skills"
for skill_dir in "$SHARED_SKILL_ROOT"/*/; do
[ -d "$skill_dir" ] || continue
name=$(basename "$skill_dir")
echo "$INCLUDED_SKILLS" | grep -qw "$name" || continue
target="$CANNBOT_DIR/skills/$name"
[ -e "$target" ] || [ -L "$target" ] && rm -rf "$target"
done
skill_count=0
for skill_dir in "$SHARED_SKILL_ROOT"/*/; do
[ -d "$skill_dir" ] || continue
name=$(basename "$skill_dir")
echo "$INCLUDED_SKILLS" | grep -qw "$name" || continue
[ -n "$EXCLUDED_SKILL" ] && [ "$name" = "$EXCLUDED_SKILL" ] && continue
ln -sfn "$(realpath "$skill_dir")" "$CANNBOT_DIR/skills/$name"
skill_count=$((skill_count + 1))
done
step1_summary="skills(${skill_count}) "
mkdir -p "$CANNBOT_DIR/agents"
for agent_entry in "$LOCAL_AGENT_ROOT"/*; do
[ -e "$agent_entry" ] || continue
name=$(basename "$agent_entry")
base_name="${name%.md}"
[[ "$base_name" != $INCLUDED_AGENT_PATTERN ]] && continue
target="$CANNBOT_DIR/agents/$name"
[ -e "$target" ] || [ -L "$target" ] && rm -rf "$target"
done
agent_count=0
for agent_entry in "$LOCAL_AGENT_ROOT"/*; do
[ -e "$agent_entry" ] || continue
name=$(basename "$agent_entry")
base_name="${name%.md}"
[[ "$base_name" != $INCLUDED_AGENT_PATTERN ]] && continue
ln -sfn "$(realpath "$agent_entry")" "$CANNBOT_DIR/agents/$name"
agent_count=$((agent_count + 1))
done
step1_summary="${step1_summary}agents(${agent_count})"
ok "Linked: $step1_summary"
else
mkdir -p "$CONFIG_ROOT/skills" "$CONFIG_ROOT/agents"
ok "Prepared: skills/, agents/, rules/"
fi
[ -n "$step1_warns" ] && echo -e "$step1_warns"
echo ""
step "[2/4] Installing configuration..."
config_src="$PLUGIN_ROOT/AGENTS.md"
if [ "$TOOL" = "opencode" ]; then
if [ "$LEVEL" = "project" ]; then
config_target="$INSTALL_BASE/AGENTS.md"
else
config_target="$CONFIG_ROOT/AGENTS.md"
fi
if [ "$LEVEL" = "project" ] && [ "$PLUGIN_ROOT" = "$INSTALL_BASE" ]; then
ok "AGENTS.md already in project directory"
elif [ "$LEVEL" = "global" ] || { [ "$LEVEL" = "project" ] && [ "$INSTALL_BASE" != "$SCRIPT_DIR" ]; }; then
[ -e "$config_target" ] || [ -L "$config_target" ] && rm -f "$config_target"
PLUGIN_ROOT_ABS="$(realpath "$PLUGIN_ROOT")"
ESCAPED_ROOT="$(echo "$PLUGIN_ROOT_ABS" | sed 's/#/\\#/g')"
sed \
-e "s#bash workflows/scripts/#bash ${ESCAPED_ROOT}/workflows/scripts/#g" \
-e "s#](workflows/#](${ESCAPED_ROOT}/workflows/#g" \
-e "s#\`workflows/#\`${ESCAPED_ROOT}/workflows/#g" \
-e "s#asc-devkit/docs/#${ESCAPED_ROOT}/asc-devkit/docs/#g" \
-e "s#asc-devkit/examples/#${ESCAPED_ROOT}/asc-devkit/examples/#g" \
"$config_src" > "$config_target"
if [ "$LEVEL" = "global" ]; then
ok "AGENTS.md (absolute paths for global mode)"
else
ok "AGENTS.md (absolute paths for project mode)"
fi
else
ln -sf "$config_src" "$config_target"
ok "AGENTS.md"
fi
elif [ "$TOOL" = "claude" ]; then
if [ "$LEVEL" = "project" ]; then
config_target="$INSTALL_BASE/CLAUDE.md"
else
config_target="$CONFIG_ROOT/CLAUDE.md"
fi
if [ "$config_src" = "$config_target" ]; then
info "$(basename "$config_target") already at target location"
elif [ "$LEVEL" = "global" ] || { [ "$LEVEL" = "project" ] && [ "$INSTALL_BASE" != "$SCRIPT_DIR" ]; }; then
[ -e "$config_target" ] || [ -L "$config_target" ] && rm -f "$config_target"
PLUGIN_ROOT_ABS="$(realpath "$PLUGIN_ROOT")"
ESCAPED_ROOT="$(echo "$PLUGIN_ROOT_ABS" | sed 's/#/\\#/g')"
sed \
-e "s#bash workflows/scripts/#bash ${ESCAPED_ROOT}/workflows/scripts/#g" \
-e "s#](workflows/#](${ESCAPED_ROOT}/workflows/#g" \
-e "s#\`workflows/#\`${ESCAPED_ROOT}/workflows/#g" \
-e "s#asc-devkit/docs/#${ESCAPED_ROOT}/asc-devkit/docs/#g" \
-e "s#asc-devkit/examples/#${ESCAPED_ROOT}/asc-devkit/examples/#g" \
"$config_src" > "$config_target"
if [ "$LEVEL" = "global" ]; then
ok "CLAUDE.md (absolute paths for global mode)"
else
ok "CLAUDE.md (absolute paths for project mode)"
fi
else
[ -e "$config_target" ] || [ -L "$config_target" ] && rm -f "$config_target"
ln -sf "$config_src" "$config_target"
ok "CLAUDE.md"
fi
else
if [ "$LEVEL" = "project" ]; then
config_target="$INSTALL_BASE/AGENTS.md"
else
config_target="$CONFIG_ROOT/AGENTS.md"
fi
if [ "$config_src" = "$config_target" ]; then
info "$(basename "$config_target") already at target location"
elif [ "$LEVEL" = "global" ] || { [ "$LEVEL" = "project" ] && [ "$INSTALL_BASE" != "$SCRIPT_DIR" ]; }; then
[ -e "$config_target" ] || [ -L "$config_target" ] && rm -f "$config_target"
PLUGIN_ROOT_ABS="$(realpath "$PLUGIN_ROOT")"
ESCAPED_ROOT="$(echo "$PLUGIN_ROOT_ABS" | sed 's/#/\\#/g')"
sed \
-e "s#bash workflows/scripts/#bash ${ESCAPED_ROOT}/workflows/scripts/#g" \
-e "s#](workflows/#](${ESCAPED_ROOT}/workflows/#g" \
-e "s#\`workflows/#\`${ESCAPED_ROOT}/workflows/#g" \
-e "s#asc-devkit/docs/#${ESCAPED_ROOT}/asc-devkit/docs/#g" \
-e "s#asc-devkit/examples/#${ESCAPED_ROOT}/asc-devkit/examples/#g" \
"$config_src" > "$config_target"
if [ "$LEVEL" = "global" ]; then
ok "AGENTS.md (absolute paths for global mode)"
else
ok "AGENTS.md (absolute paths for project mode)"
fi
else
[ -e "$config_target" ] || [ -L "$config_target" ] && rm -f "$config_target"
ln -sf "$config_src" "$config_target"
ok "AGENTS.md"
fi
fi
echo ""
step "[3/4] Configuring tool discovery..."
if [ "$TOOL" = "opencode" ]; then
ok "Auto-scan: skills/, agents/"
else
DISCOVERY="$CONFIG_ROOT/skills"
for skill_dir in "$SHARED_SKILL_ROOT"/*/; do
[ -d "$skill_dir" ] || continue
name=$(basename "$skill_dir")
echo "$INCLUDED_SKILLS" | grep -qw "$name" || continue
target="$DISCOVERY/$name"
[ -e "$target" ] || [ -L "$target" ] && rm -rf "$target"
done
link_count=0
for skill_dir in "$SHARED_SKILL_ROOT"/*/; do
[ -d "$skill_dir" ] || continue
name=$(basename "$skill_dir")
echo "$INCLUDED_SKILLS" | grep -qw "$name" || continue
[ -n "$EXCLUDED_SKILL" ] && [ "$name" = "$EXCLUDED_SKILL" ] && continue
target="$DISCOVERY/$name"
ln -sfn "$(realpath "$skill_dir")" "$target"
link_count=$((link_count + 1))
done
for link in "$DISCOVERY"/*/; do
link="${link%/}"
[ -L "$link" ] && [ ! -e "$link" ] && rm "$link"
done
ok "Skills: $link_count discovery symlinks"
AGENT_DISCOVERY="$CONFIG_ROOT/agents"
for agent_entry in "$LOCAL_AGENT_ROOT"/*; do
[ -e "$agent_entry" ] || continue
name=$(basename "$agent_entry")
base="${name%.md}"
[[ "$base" != $INCLUDED_AGENT_PATTERN ]] && continue
target="$AGENT_DISCOVERY/$name"
[ -e "$target" ] || [ -L "$target" ] && rm -rf "$target"
done
agent_link_count=0
for agent_entry in "$LOCAL_AGENT_ROOT"/*; do
[ -e "$agent_entry" ] || continue
name=$(basename "$agent_entry")
base="${name%.md}"
[[ "$base" != $INCLUDED_AGENT_PATTERN ]] && continue
target="$AGENT_DISCOVERY/$name"
ln -sfn "$(realpath "$agent_entry")" "$target"
agent_link_count=$((agent_link_count + 1))
done
for link in "$AGENT_DISCOVERY"/*; do
[ -L "$link" ] && [ ! -e "$link" ] && rm "$link"
done
ok "Agents: $agent_link_count discovery symlinks"
fi
echo ""
step "[4/4] Running health check..."
health_ok=true
health_errors=""
for sub in skills agents; do
target="$CANNBOT_DIR/$sub"
if [ -d "$target" ]; then
count=$(ls -d "$target"/* 2>/dev/null | wc -l)
[ "$count" -eq 0 ] && { health_errors="${health_errors}\n ${YELLOW}⚠${NC} $sub/ is empty"; }
else
health_errors="${health_errors}\n ${RED}✗${NC} $sub/ missing"
health_ok=false
fi
done
if [ "$TOOL" = "opencode" ]; then
if [ "$LEVEL" = "project" ]; then
[ -f "$INSTALL_BASE/AGENTS.md" ] || { health_errors="${health_errors}\n ${RED}✗${NC} AGENTS.md missing in project directory"; health_ok=false; }
else
[ -f "$CONFIG_ROOT/AGENTS.md" ] || { health_errors="${health_errors}\n ${RED}✗${NC} AGENTS.md missing"; health_ok=false; }
fi
elif [ "$TOOL" = "claude" ]; then
if [ "$LEVEL" = "project" ]; then
[ -f "$INSTALL_BASE/CLAUDE.md" ] || { health_errors="${health_errors}\n ${RED}✗${NC} CLAUDE.md missing in project directory"; health_ok=false; }
else
[ -f "$CONFIG_ROOT/CLAUDE.md" ] || { health_errors="${health_errors}\n ${RED}✗${NC} CLAUDE.md missing"; health_ok=false; }
fi
else
if [ "$LEVEL" = "project" ]; then
[ -f "$INSTALL_BASE/AGENTS.md" ] || { health_errors="${health_errors}\n ${RED}✗${NC} AGENTS.md missing in project directory"; health_ok=false; }
else
[ -f "$CONFIG_ROOT/AGENTS.md" ] || { health_errors="${health_errors}\n ${RED}✗${NC} AGENTS.md missing"; health_ok=false; }
fi
fi
MANIFEST="$CONFIG_ROOT/cannbot-manifest.json"
SKILLS_JSON="[]"
if [ -d "$CANNBOT_DIR/skills" ]; then
SKILLS_JSON=$(ls -d "$CANNBOT_DIR/skills"/*/ 2>/dev/null | while read d; do
basename "$d"
done | python3 -c "import sys,json; print(json.dumps([l.strip() for l in sys.stdin if l.strip()]))" 2>/dev/null || echo "[]")
fi
AGENTS_JSON="[]"
if [ -d "$CANNBOT_DIR/agents" ]; then
AGENTS_JSON=$(ls -d "$CANNBOT_DIR/agents"/* 2>/dev/null | while read d; do
basename "$d"
done | python3 -c "import sys,json; print(json.dumps([l.strip() for l in sys.stdin if l.strip()]))" 2>/dev/null || echo "[]")
fi
cat > "$MANIFEST" << MANIFEST_EOF
{
"brand": "CANNBot",
"version": "$VERSION",
"team": "$(basename "$SCRIPT_DIR")",
"level": "$LEVEL",
"tool": "$TOOL",
"installed_skills": $SKILLS_JSON,
"installed_agents": $AGENTS_JSON,
"brand_dir": "$CONFIG_ROOT",
"install_time": "$(date -u +%Y-%m-%dT%H:%M:%SZ)"
}
MANIFEST_EOF
[ -f "$MANIFEST" ] || { health_errors="${health_errors}\n ${RED}✗${NC} Manifest generation failed"; health_ok=false; }
if [ "$health_ok" = true ] && [ -z "$health_errors" ]; then
ok "All checks passed"
else
echo -e "$health_errors"
[ "$health_ok" = true ] && warn "Some warnings, see above" || err "Some checks failed, see above"
fi
echo ""
echo -e " ${GREEN}${BOLD}✓ CANNBot installed successfully!${NC}"
echo ""
echo -e " ${BOLD}Quick Start:${NC}"
if [ "$TOOL" = "opencode" ]; then
echo -e " ${CYAN}1.${NC} 启动 CLI: ${GREEN}opencode${NC}"
echo -e " ${CYAN}2.${NC} 告诉 CANNBot: ${GREEN}${BOLD}检视算子文件:moe_init_routing/op_kernel/moe_init_routing.h${NC}"
elif [ "$TOOL" = "trae" ]; then
echo -e " ${CYAN}1.${NC} 通过 CLI/IDE 启动${NC}"
echo -e " ${CYAN}2.${NC} 告诉 CANNBot: ${GREEN}${BOLD}检视算子文件:moe_init_routing/op_kernel/moe_init_routing.h${NC}"
elif [ "$TOOL" = "cursor" ]; then
echo -e " ${CYAN}1.${NC} 通过 Cursor IDE 启动${NC}"
echo -e " ${CYAN}2.${NC} 告诉 CANNBot: ${GREEN}${BOLD}检视算子文件:moe_init_routing/op_kernel/moe_init_routing.h${NC}"
else
echo -e " ${CYAN}1.${NC} 启动 CLI: ${GREEN}claude${NC}"
echo -e " ${CYAN}2.${NC} 告诉 CANNBot: ${GREEN}${BOLD}检视算子文件:moe_init_routing/op_kernel/moe_init_routing.h${NC}"
fi
echo ""