chanpinhsd/agent/install.sh
lidf da6a360cfe fix: install.sh 合并 skill.json(不覆盖内置 skills)
- skill.json 不再直接 cp 覆盖(会丢失 CoPaw 内置 skills)
- 改用 Python 合并注入:保留内置 + 追加自定义
- 补全 6 个自定义 skills 注册(5 TOC + voc_research)
2026-04-07 01:36:24 +08:00

186 lines
7.1 KiB
Bash
Executable File
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/usr/bin/env bash
# 黑手党提案 Agent — 一键安装/更新脚本
# 支持两种调用方式:
# 1. git clone 后bash agent/install.sh
# 2. curl 下载后bash /tmp/chanpinhsd-main/agent/install.sh
set -euo pipefail
GREEN='\033[0;32m'
YELLOW='\033[0;33m'
RED='\033[0;31m'
NC='\033[0m'
info() { printf "${GREEN}[mafia]${NC} %s\n" "$*"; }
warn() { printf "${YELLOW}[mafia]${NC} %s\n" "$*"; }
error() { printf "${RED}[mafia]${NC} %s\n" "$*" >&2; exit 1; }
COPAW_HOME="${COPAW_HOME:-$HOME/.copaw}"
AGENT_ID="mafia-expert"
WORKSPACE_DIR="$COPAW_HOME/workspaces/$AGENT_ID"
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
# ── 检测操作系统 ──────────────────────────────────────────────────────
OS="$(uname -s)"
case "$OS" in
Darwin) info "检测到 macOS" ;;
Linux) info "检测到 Linux" ;;
MINGW*|MSYS*|CYGWIN*) warn "检测到 Windows (Git Bash/MSYS),部分功能可能受限" ;;
*) error "不支持的操作系统: $OS" ;;
esac
# ── 检查 CoPaw 是否已安装 ──────────────────────────────────────────────
if [ ! -f "$COPAW_HOME/config.json" ]; then
if command -v copaw &>/dev/null || [ -f "$COPAW_HOME/bin/copaw" ]; then
info "CoPaw 已安装但未初始化,正在初始化..."
export PATH="$COPAW_HOME/bin:$PATH"
copaw init --defaults --accept-security
else
error "CoPaw 未安装。请先安装 CoPaw 桌面客户端https://copaw.agentscope.io"
fi
else
info "CoPaw 已就绪"
fi
# ── 创建工作区并复制文件 ───────────────────────────────────────────────
info "配置 $AGENT_ID 工作区..."
mkdir -p "$WORKSPACE_DIR/active_skills"
mkdir -p "$WORKSPACE_DIR/cases"
mkdir -p "$WORKSPACE_DIR/iteration_reports"
mkdir -p "$WORKSPACE_DIR/memory"
# 核心配置skill.json 单独合并,不覆盖)
for f in AGENTS.md SOUL.md PROFILE.md HEARTBEAT.md agent.json; do
if [ -f "$SCRIPT_DIR/$f" ]; then
cp "$SCRIPT_DIR/$f" "$WORKSPACE_DIR/$f"
fi
done
# MEMORY.md 只在首次创建(不覆盖用户积累的记忆)
if [ ! -f "$WORKSPACE_DIR/MEMORY.md" ]; then
cp "$SCRIPT_DIR/MEMORY.md" "$WORKSPACE_DIR/MEMORY.md" 2>/dev/null || echo "# 黑手党提案专家长期记忆" > "$WORKSPACE_DIR/MEMORY.md"
fi
# Skills每次全量覆盖保证最新
if [ -d "$SCRIPT_DIR/skills" ]; then
for skill_dir in "$SCRIPT_DIR/skills"/*/; do
skill_name="$(basename "$skill_dir")"
# installer skill 不复制到 mafia-expert它属于 default agent
if [ "$skill_name" = "mafia_agent_installer" ]; then
continue
fi
mkdir -p "$WORKSPACE_DIR/active_skills/$skill_name"
cp "$skill_dir"* "$WORKSPACE_DIR/active_skills/$skill_name/" 2>/dev/null || true
done
fi
info "文件复制完成"
# ── 合并 skill.json注入自定义 skills保留内置 skills──────────────
info "注册自定义 Skills..."
python3 -c "
import json, os, time
ws_skill = os.path.expanduser('$WORKSPACE_DIR/skill.json')
repo_skill = '$SCRIPT_DIR/skill.json'
# 读取工作区已有的 manifest含内置 skills
if os.path.exists(ws_skill):
with open(ws_skill) as f:
manifest = json.load(f)
else:
manifest = {'schema_version': 'workspace-skill-manifest.v1', 'version': 0, 'skills': {}}
# 读取仓库的自定义 skills 定义
if os.path.exists(repo_skill):
with open(repo_skill) as f:
repo = json.load(f)
for name, skill_cfg in repo.get('skills', {}).items():
manifest['skills'][name] = skill_cfg
print(f' + {name}')
# 同时扫描 active_skills 目录,确保所有 SKILL.md 都被注册
skills_dir = os.path.expanduser('$WORKSPACE_DIR/active_skills')
if os.path.isdir(skills_dir):
for d in os.listdir(skills_dir):
if d.startswith('.'):
continue
skill_md = os.path.join(skills_dir, d, 'SKILL.md')
if os.path.exists(skill_md) and d not in manifest['skills']:
manifest['skills'][d] = {
'enabled': True,
'channels': ['all'],
'source': 'customized',
'metadata': {
'name': d,
'description': '',
'version_text': '1.0.0',
'source': 'customized',
'protected': False,
'requirements': {'require_bins': [], 'require_envs': []},
},
'requirements': {'require_bins': [], 'require_envs': []},
}
print(f' + {d} (from dir)')
manifest['version'] = int(time.time() * 1000)
with open(ws_skill, 'w') as f:
json.dump(manifest, f, indent=2, ensure_ascii=False)
print(' skills 注册完成')
"
# ── 注册到 config.json ─────────────────────────────────────────────────
info "注册 Agent..."
python3 -c "
import json, os
config_path = os.path.expanduser('$COPAW_HOME/config.json')
with open(config_path, 'r') as f:
cfg = json.load(f)
agent_id = '$AGENT_ID'
ws_dir = '$WORKSPACE_DIR'
changed = False
if agent_id not in cfg['agents']['profiles']:
cfg['agents']['profiles'][agent_id] = {
'id': agent_id,
'workspace_dir': ws_dir,
'enabled': True
}
changed = True
if agent_id not in cfg['agents']['agent_order']:
cfg['agents']['agent_order'].append(agent_id)
changed = True
if changed:
with open(config_path, 'w') as f:
json.dump(cfg, f, indent=2, ensure_ascii=False)
print(' ✅ 注册成功')
else:
print(' ✅ 已注册,配置已更新')
"
# ── 记录来源路径(便于后续更新)─────────────────────────────────────────
REPO_DIR="$(cd "$SCRIPT_DIR/.." && pwd)"
echo "$REPO_DIR" > "$WORKSPACE_DIR/.repo_path"
# ── 清理临时文件(如果是 curl 下载的)──────────────────────────────────
if [[ "$SCRIPT_DIR" == /tmp/* ]]; then
info "清理临时文件..."
rm -rf "$(cd "$SCRIPT_DIR/.." && pwd)"
fi
# ── 完成 ───────────────────────────────────────────────────────────────
echo ""
info "════════════════════════════════════════════════"
info " ✅ 黑手党提案专家 安装/更新完成!"
info "════════════════════════════════════════════════"
echo ""
info "下一步:"
info " 1. 打开 CoPaw 客户端"
info " 2. 刷新页面Cmd+R / F5"
info " 3. 左上角切换到「黑手党提案专家」"
info " 4. 发送:我想为 XX 品牌做一个黑手党提案"
echo ""