Skill: alex-shen1121/feishu-bot-manager-cn (version 1.1.0)

--- name: feishu-bot-manager description: 管理 OpenClaw 中的飞书机器人账户与路由绑定。用于新增飞书机器人账号、把机器人账户级或群聊级绑定到指定 Agent，或在创建新机器人时顺带创建一个全新的独立 Agent 工作区。用户提到“绑定新飞书机器人”“新增飞书机器人”“把机器人绑到某个 Agent”“给某个群绑定 Agent”时使用。 --- # feishu-bot-manager 飞书多账户机器人配置管理 skill。 ## 优先路径 当用户说“绑定一个新的飞书机器人”时，先引导用户去网页创建机器人： - https://open.feishu.cn/page/openclaw?form=multiAgent 网页会给出 App ID 和 App Secret。拿到这两个值之后，再继续绑定流程。 示例回复： ```text 新机器人先去这里创建：https://open.feishu.cn/page/openclaw?form=multiAgent 拿到 App ID 和 Secret 后发我，我再帮你继续绑定。 *是否要绑定到现有 agent，也可以一起告诉我。* ``` 只有在用户明确说“我不想用网页”或“网页打不开”时，才走纯手动流程。 ## 两种绑定方式 ### 账户级绑定 该飞书账户的所有消息 → 指定 Agent 适合一个机器人专门服务一个 Agent。 生成的 binding 示例： ```json { "agentId": "recruiter", "match": { "channel": "feishu", "accountId": "bot-sales" } } ``` ### 群聊级绑定 特定群聊的消息 → 指定 Agent 适合把某个群单独分配给某个 Agent。 生成的 binding 示例： ```json { "agentId": "recruiter", "match": { "channel": "feishu", "peer": { "kind": "group", "id": "oc_xxx" } } } ``` 注意：**群聊级绑定优先级高于账户级绑定**。 ## 收集信息顺序 拿到 App ID / App Secret 后，按这个顺序收集： 1. App ID 和 App Secret 2. **先问：绑定到现有 Agent，还是创建新的 Agent？** - 如果是现有 Agent：直接问要绑定到哪个 Agent - 如果是新 Agent：问新 Agent 的名称、用途、期望的 agentId（可给默认值） 3. 路由方式：账户级 / 群聊级 4. 群聊 ID（仅群聊级需要） 5. 机器人名称（可选） 6. 给出预览，用户确认后执行 7. **重启 Gateway 前再次确认** 确认时的回复里，最下面加一行小字： ```text *是否要绑定到现有 agent？* ``` ## 创建新 Agent 时的额外要求 如果用户选择“创建新的 Agent”，除了写入 OpenClaw 配置，还必须初始化对应工作区文件，并把治理规则写进合适的文件。 创建新 Agent 时，读取并遵守： - `references/new-agent-governance.md` 重点包括： - `AGENTS.md`：任务响应规范、复杂任务优先子代理、修改后先验证、skill-vetter 强制审查、问题升级策略、定时任务与稳定性规则 - `SOUL.md`：风格、边界感、群聊克制发言、长任务先告知再执行 - `MEMORY.md`：两层记忆规则、长期信息提炼、必须写文件而不是只靠会话记忆 - `USER.md`：用户偏好、禁忌、长期习惯 - `HEARTBEAT.md`：仅放轻量、幂等、低副作用周期任务 - `TOOLS.md`：环境专属信息 - `.learnings/`：初始化 `LEARNINGS.md`、`ERRORS.md`、`FEATURE_REQUESTS.md` ## 执行流程 1. 检查并备份现有配置 2. 如果需要，创建新的 Agent 工作区与基础文件 3. 添加新账户到 `channels.feishu.accounts` 4. 根据选择的路由模式添加 binding 5. 设置 `session.dmScope` 为 `per-account-channel-peer` 6. 告诉用户配置已改好，**重启 Gateway 前先确认** 7. 重启完成后，提醒用户去新机器人的私聊发送 `/feishu auth` ## 绑定完成后的固定提醒 每次新机器人创建/绑定完成后，都必须提醒用户： ```text 请去新机器人的私聊窗口发送 /feishu auth 进行授权，否则机器人无法正常使用。 ``` ## 命令行调用 ```bash # 账户级绑定 - 该机器人所有消息都由指定 Agent 处理 openclaw skills run feishu-bot-manager -- \ --app-id cli_xxx \ --app-secret yyy \ --account-id bot-sales \ --agent-id recruiter \ --routing-mode account # 群聊级绑定 - 特定群聊的消息由指定 Agent 处理 openclaw skills run feishu-bot-manager -- \ --app-id cli_xxx \ --app-secret yyy \ --account-id bot-sales \ --agent-id recruiter \ --chat-id oc_xxx \ --routing-mode group ``` ## 参数说明 | 参数 | 必填 | 说明 | |------|------|------| | --app-id | ✅ | 飞书 App ID (cli_xxx) | | --app-secret | ✅ | 飞书 App Secret | | --account-id | ❌ | 账户标识，默认自动生成 | | --bot-name | ❌ | 机器人名称，默认 `Feishu Bot` | | --dm-policy | ❌ | DM 策略: open / pairing / allowlist，默认 open | | --agent-id | ❌ | 要绑定的 Agent ID | | --chat-id | ❌ | 群聊 ID (oc_xxx)，群聊绑定时需要 | | --routing-mode | ❌ | 路由模式: account / group，默认 account | ## 注意事项 - 保留现有配置，不覆盖已有主账号配置 - 修改前自动备份 `openclaw.json` - 绑定新机器人后，重启 Gateway 前必须再次确认 - 完成后必须提醒用户去机器人私聊发送 `/feishu auth` - 如配置有误，可用备份文件手动恢复

path: index.js
content: #!/usr/bin/env node
/**
 * feishu-bot-manager
 * 飞书多账户机器人配置管理 Skill
 * 
 * 支持的路由绑定方案：
 * 1. 账户级绑定 - 该飞书账户的所有消息路由到指定 Agent
 * 2. 群聊级绑定 - 特定群聊的消息路由到指定 Agent
 */

const fs = require('fs');
const path = require('path');
const { execSync } = require('child_process');

// 配置路径
const CONFIG_PATH = path.join(process.env.HOME, '.openclaw', 'openclaw.json');
const BACKUP_DIR = path.join(process.env.HOME, '.openclaw', 'backups');

// 颜色输出
const colors = {
  reset: '\x1b[0m',
  green: '\x1b[32m',
  yellow: '\x1b[33m',
  red: '\x1b[31m',
  cyan: '\x1b[36m',
  gray: '\x1b[90m',
  bold: '\x1b[1m'
};

const log = {
  info: (msg) => console.log(`${colors.cyan}ℹ${colors.reset} ${msg}`),
  success: (msg) => console.log(`${colors.green}✓${colors.reset} ${msg}`),
  warning: (msg) => console.log(`${colors.yellow}⚠${colors.reset} ${msg}`),
  error: (msg) => console.log(`${colors.red}✗${colors.reset} ${msg}`),
  step: (num, total, msg) => console.log(`\n${colors.cyan}[${num}/${total}]${colors.reset} ${msg}`),
  preview: (msg) => console.log(`${colors.gray}${msg}${colors.reset}`),
  bold: (msg) => console.log(`${colors.bold}${msg}${colors.reset}`)
};

// 读取配置
function loadConfig() {
  try {
    const content = fs.readFileSync(CONFIG_PATH, 'utf8');
    return JSON.parse(content);
  } catch (err) {
    log.error(`读取配置失败: ${err.message}`);
    process.exit(1);
  }
}

// 保存配置
function saveConfig(config) {
  try {
    fs.writeFileSync(CONFIG_PATH, JSON.stringify(config, null, 2), 'utf8');
    return true;
  } catch (err) {
    log.error(`保存配置失败: ${err.message}`);
    return false;
  }
}

// 创建备份
function createBackup() {
  try {
    if (!fs.existsSync(BACKUP_DIR)) {
      fs.mkdirSync(BACKUP_DIR, { recursive: true });
    }
    const timestamp = new Date().toISOString().replace(/[:.]/g, '-');
    const backupPath = path.join(BACKUP_DIR, `openclaw.json.${timestamp}`);
    fs.copyFileSync(CONFIG_PATH, backupPath);
    return backupPath;
  } catch (err) {
    log.error(`创建备份失败: ${err.message}`);
    return null;
  }
}

// 显示路由方案说明
function showRoutingOptions() {
  console.log(`
${colors.bold}📋 路由绑定方案${colors.reset}

${colors.bold}方案 1：账户级绑定${colors.reset}
  该飞书账户的所有消息 → 指定 Agent
  适用：一个机器人专门服务一个 Agent
  
${colors.bold}方案 2：群聊级绑定${colors.reset}
  特定群聊的消息 → 指定 Agent
  适用：把 Agent 绑定到特定群聊

${colors.yellow}提示：群聊级绑定优先级更高，会覆盖账户级绑定！${colors.reset}
`);
}

// 快速模式
async function quickMode(options) {
  console.log(`\n${colors.cyan}🤖 飞书机器人配置助手${colors.reset}\n`);
  
  const { 
    appid, 
    appsecret, 
    accountid,
    botname,
    agentid, 
    chatid,
    routingmode
  } = options;
  
  if (!appid || !appsecret) {
    log.error('需要提供 --app-id 和 --app-secret');
    process.exit(1);
  }
  
  const config = loadConfig();
  const accountId = accountid || `bot-${Date.now()}`;
  
  // 创建备份
  const backupPath = createBackup();
  log.success(`配置已备份: ${path.basename(backupPath)}`);
  
  // 确保 channels.feishu.accounts 存在
  if (!config.channels) config.channels = {};
  if (!config.channels.feishu) config.channels.feishu = { enabled: true };
  if (!config.channels.feishu.accounts) config.channels.feishu.accounts = {};
  
  // 添加账户
  config.channels.feishu.accounts[accountId] = {
    appId: appid,
    appSecret: appsecret,
    botName: botname || 'Feishu Bot',
    dmPolicy: options.dmpolicy || 'open',
    allowFrom: ['*'],
    enabled: true
  };
  
  // 添加绑定
  if (!config.bindings) config.bindings = [];
  
  const mode = routingmode || 'account';
  
  if (mode === 'account' && agentid) {
    // 账户级绑定：该账户所有消息路由到指定 Agent
    config.bindings.push({
      agentId: agentid,
      match: {
        channel: 'feishu',
        accountId: accountId
      }
    });
    log.success(`已添加账户级绑定: ${agentid} ← ${accountId}`);
  } else if (mode === 'group' && agentid && chatid) {
    // 群聊级绑定：特定群聊消息路由到指定 Agent
    config.bindings.push({
      agentId: agentid,
      match: {
        channel: 'feishu',
        peer: { kind: 'group', id: chatid }
      }
    });
    log.success(`已添加群聊级绑定: ${agentid} ← ${chatid}`);
  }
  
  saveConfig(config);
  log.success('配置已更新');
  
  // 设置会话绑定颗粒度
  log.info('设置会话绑定颗粒度...');
  try {
    execSync('openclaw config set session.dmScope "per-account-channel-peer"', { stdio: 'pipe' });
    log.success('会话绑定颗粒度已设置');
  } catch (err) {
    log.warning('设置 dmScope 失败，请手动执行:');
    console.log('  openclaw config set session.dmScope "per-account-channel-peer"');
  }
  
  // 重启
  log.warning('正在重启 Gateway...');
  try {
    execSync('openclaw gateway restart', { stdio: 'inherit' });
    log.success('Gateway 重启完成');
  } catch (err) {
    log.error(`重启失败: ${err.message}`);
    log.info('请手动执行: openclaw gateway restart');
  }
  
  // 完成提示
  console.log('\n' + '─'.repeat(50));
  log.success('配置完成！');
  console.log('\n配置摘要:');
  console.log(`  账户 ID: ${accountId}`);
  console.log(`  路由模式: ${mode}`);
  if (agentid) console.log(`  Agent: ${agentid}`);
  if (chatid) console.log(`  群聊: ${chatid}`);
  console.log('\n如配置有误，可从备份恢复:');
  console.log(`  cp ${backupPath} ${CONFIG_PATH}`);
  console.log('─'.repeat(50) + '\n');
}

// 处理命令行参数
function parseArgs() {
  const args = process.argv.slice(2);
  const options = {};
  
  for (let i = 0; i < args.length; i++) {
    const arg = args[i];
    if (arg.startsWith('--')) {
      const key = arg.slice(2).replace(/-/g, '');
      const value = args[i + 1] && !args[i + 1].startsWith('--') ? args[i + 1] : 'true';
      options[key] = value;
      if (value !== 'true') i++;
    }
  }
  
  return options;
}

// 主入口
const options = parseArgs();

if (options.help || options.h) {
  showRoutingOptions();
  console.log(`
${colors.bold}用法:${colors.reset}
  node index.js [选项]

${colors.bold}选项:${colors.reset}
  --app-id <id>          飞书 App ID (必填)
  --app-secret <secret>  飞书 App Secret (必填)
  --account-id <id>      账户标识 (可选, 默认自动生成)
  --bot-name <name>      机器人名称 (可选)
  --dm-policy <policy>   DM 策略: open/pairing/allowlist (默认: open)
  --agent-id <id>        要绑定的 Agent ID (可选)
  --chat-id <id>         群聊 ID oc_xxx (群聊绑定时需要)
  --routing-mode <mode>  路由模式: account/group (默认: account)
  --help, -h             显示帮助

${colors.bold}示例:${colors.reset}
  # 账户级绑定 - 该机器人所有消息都由指定 Agent 处理
  node index.js --app-id cli_xxx --app-secret yyy --agent-id recruiter --routing-mode account

  # 群聊级绑定 - 特定群聊的消息由指定 Agent 处理
  node index.js --app-id cli_xxx --app-secret yyy --agent-id recruiter --chat-id oc_xxx --routing-mode group
`);
  process.exit(0);
}

if (options.appid) {
  quickMode(options);
} else {
  log.error('请提供 --app-id 和 --app-secret，或使用 --help 查看帮助');
  process.exit(1);
}


path: lib/validator.js
content: /**
 * 配置验证工具
 */

// 验证 App ID 格式
function validateAppId(appId) {
  return /^cli_[a-zA-Z0-9]+$/.test(appId);
}

// 验证账户 ID 格式
function validateAccountId(id) {
  return /^[a-z0-9-]+$/.test(id);
}

// 验证群聊 ID 格式
function validateChatId(id) {
  return /^oc_[a-zA-Z0-9]+$/.test(id);
}

// 验证用户 ID 格式
function validateUserId(id) {
  return /^ou_[a-zA-Z0-9]+$/.test(id);
}

// 验证完整配置
function validateConfig(config) {
  const errors = [];
  
  if (!config.channels?.feishu) {
    errors.push('缺少 channels.feishu 配置');
    return errors;
  }
  
  const accounts = config.channels.feishu.accounts || {};
  
  for (const [key, acc] of Object.entries(accounts)) {
    if (!validateAccountId(key)) {
      errors.push(`账户 ID "${key}" 格式无效`);
    }
    if (!validateAppId(acc.appId)) {
      errors.push(`[${key}] App ID 格式无效: ${acc.appId}`);
    }
    if (!acc.appSecret) {
      errors.push(`[${key}] App Secret 不能为空`);
    }
  }
  
  // 验证 bindings
  const bindings = config.bindings || [];
  for (const binding of bindings) {
    if (!binding.agentId) {
      errors.push('存在缺少 agentId 的 binding');
    }
    if (!binding.match?.peer?.id) {
      errors.push('存在缺少 peer.id 的 binding');
    }
  }
  
  return errors;
}

module.exports = {
  validateAppId,
  validateAccountId,
  validateChatId,
  validateUserId,
  validateConfig
};


path: package.json
content: {
  "name": "feishu-bot-manager",
  "version": "1.1.0",
  "description": "飞书多账户机器人配置管理",
  "main": "index.js",
  "scripts": {
    "start": "node index.js"
  },
  "dependencies": {
    "readline": "^1.3.0"
  }
}


path: references/new-agent-governance.md
content: # 新 Agent 创建治理规则

当用户要求“创建新的 Agent 并绑定飞书机器人”时，除新增账号、绑定和工作区外，还必须把下面这套规则写进合适的文件。

## 1. 任务响应规范

### 写入 AGENTS.md
- 需要调用工具执行时，先简短回复用户“收到，正在处理 XXX”，再动手。
- 复杂任务（预计超过 1 分钟、步骤多、容易阻塞主对话）优先使用 `sessions_spawn` 启动子代理。
- 任务必须拆步骤；步骤要具体、可执行、可验证。
- 修改后必须先验证，再汇报成功。

### 写入 SOUL.md
- 长任务先告知再执行。
- 做事稳、反馈及时、避免让用户长时间无感知等待。

## 2. 记忆管理

### 写入 MEMORY.md
- 使用两层记忆：`memory/YYYY-MM-DD.md` 记录当天流水，`MEMORY.md` 只保留长期有效信息。
- 想长期保留的内容必须写文件，不能只靠会话记忆。
- 用户说“记住这个”、纠正你、形成新教训或重要决策时，要及时写入。
- 定期从近 7 天日志中提炼长期信息更新到 `MEMORY.md`，并清理过时内容。

## 3. Skill 安装与安全审查

### 写入 AGENTS.md
- 安装任何来自 ClawHub、GitHub 或其他来源的 Skill 前，必须先通过 `skill-vetter` 审查。
- 标准流程：`clawhub inspect` → 读取 `SKILL.md` → 读取相关脚本/源码 → 输出审查结论 → 仅在 `SAFE TO INSTALL` 时安装。
- 安装结果写入当日日志；重要规则提炼到 `MEMORY.md`。

## 4. 定时任务设计

### 写入 AGENTS.md
- 轻量巡检/保活/状态检查优先 Heartbeat。
- 需要精确时间触发、独立 session 执行的任务优先 Cron。
- Heartbeat 要满足：批量化、幂等、轻量、可追踪。
- Cron 要满足：必须有交付物、失败可见、定期验证仍存在。

### 写入 HEARTBEAT.md
- 只记录轻量、可重复、低副作用的周期任务。

## 5. 稳定性与运维

### 写入 AGENTS.md
- 检查服务时要看全链路，不只看主服务进程。
- 备份必须验证结果，不是“命令跑了”就算完成。
- 废弃工具、路径、命令后，要清理 cron、脚本、配置、文档、心跳、skill 说明中的残留引用。

## 6. 问题解决规范

### 写入 AGENTS.md
- 说“做不到”前，先至少尝试 5 种本质不同的方法，并记录每种失败原因。
- 失败升级策略：
  1. 正常分析并调整
  2. 换一条本质不同的路线
  3. 查文档/网页/源码
  4. 反转最相信的假设
  5. 系统排查环境、版本、权限、依赖、配置、拼写
- 改完必须验证：代码要跑、配置要确认生效、脚本要看输出、UI 要实际打开验证。

## 7. 群聊与外部边界

### 写入 SOUL.md 或 AGENTS.md
- 群聊中克制发言：被点名、被提问、能明显增值、需要纠错时再说。
- 对外动作默认先确认：发消息给第三方、删除外部数据、改生产配置、任何不可逆动作。

## 8. 文件分工

### 创建时保证这些文件存在
- `AGENTS.md`：工作范围、执行流程、任务响应规范、审查和验证规则
- `SOUL.md`：风格、语气、做事气质
- `USER.md`：用户画像、偏好、禁忌、长期习惯
- `MEMORY.md`：长期规则、长期偏好、可复用决策
- `HEARTBEAT.md`：轻量周期任务
- `TOOLS.md`：环境特有信息、设备、路径、别名等
- `.learnings/`：`LEARNINGS.md`、`ERRORS.md`、`FEATURE_REQUESTS.md`

## 9. 机器人绑定完成后的固定提醒

完成新机器人绑定后，必须提醒用户：

```text
请去新机器人的私聊窗口发送 /feishu auth 进行授权，否则机器人无法正常使用。
```

## 10. 推荐创建顺序

1. 先引导用户去网页创建机器人，获取 App ID / Secret
2. 收集：是绑定现有 Agent 还是创建新 Agent
3. 如果创建新 Agent：按本文件要求初始化工作区文件
4. 写入 Feishu account 和 binding
5. 重启 Gateway 前再次确认
6. 完成后提醒用户去机器人私聊发送 `/feishu auth`


Security scan verdicts — ClawScan: suspicious | static analysis: suspicious | VirusTotal: clean | SkillSpector: suspicious (HIGH)