CoPaw skills_manager.py 的 get_workspace_skills_dir() 查找的是 workspace_dir/skills/,不是 active_skills/。 修正 install.sh 和所有相关路径。
186 lines
7.1 KiB
Bash
Executable File
186 lines
7.1 KiB
Bash
Executable File
#!/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/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/skills/$skill_name"
|
||
cp "$skill_dir"* "$WORKSPACE_DIR/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/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 ""
|