用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
直接命令不会经过审查 Prompt;运行前请先检查来源。
npx skills add https://github.com/Aquarius-mu/FeiShubot_Gp_Agent --skill feishu-file-ops命令会保持在同一行。复制前请横向滚动并检查完整内容。
想先保存到本地?可下载 SkillsMP 当前能够提供的文件。
基于 SOC 职业分类
正在显示 SKILL.md
| name | feishu-file-ops |
| version | 2.0.0 |
| description | 飞书Bot文件操作安全规范:白名单写入 ~/feishu_bot/cache/,禁止操作敏感路径和脚本文件,所有写入必须 flock+jq 原子替换。 |
| metadata | {"requires":{"bins":["jq","flock"]}} |
飞书 Bot 运行时的文件操作安全规范。写操作仅限 ~/feishu_bot/cache/ 三个 JSON 文件,其余路径一律只读。
| 路径 | 读 | 写 | 说明 |
|---|---|---|---|
~/feishu_bot/cache/tokens.json | ✅ | ✅ | Claude 维护 |
~/feishu_bot/cache/groups.json | ✅ | ✅ | Claude 维护 |
~/feishu_bot/cache/users.json | ✅ | ✅ | Claude 维护 |
~/feishu_bot/cache/*.lock | ✅ | ✅ | flock 锁文件(自动创建) |
~/feishu_bot/bot.log | ✅ | ❌ | 脚本写,Claude 只读 |
~/feishu_bot/skill_improve.log | ✅ | ❌ | 脚本写,Claude 只读 |
~/feishu_bot/name_cache | ✅ | ❌ | 脚本专属,只读 |
~/feishu_bot/group_cache | ✅ | ❌ | 脚本专属,只读 |
~/feishu_bot/sessions | ✅ | ❌ | 脚本专属,只读 |
~/feishu_bot/warmup_session | ✅ | ❌ | 脚本专属,只读 |
~/.claude/skills/*/SKILL.md | ✅ | ✅ | Skill 自我改进专用 |
~/.claude/lark_cli_rules.md | ✅ | ✅ | 规则文件,可更新 |
~/.ssh/ ~/.gnupg/ | ❌ | ❌ | 绝对禁止 |
~/.claude/(skills 外) | ✅ | ❌ | 只读 |
lark_sweet_bot.sh 等脚本 | ✅ | ❌ | 只读,禁止执行 |
rm / rmdir ❌ 不删除任何文件
chmod / chown ❌ 不修改权限
sudo / su ❌ 不提权
curl / wget ❌ 不自行下载
bash xxx.sh / ./xxx.sh ❌ 不执行任意脚本
> file(清空写) ❌ 不清空 sessions / name_cache / group_cache
整体覆盖 JSON ❌ 必须用 jq 合并,不能直接 echo '{...}' > file
4 步缺一不可:
flock -x 持有对应 .lock 文件jq 合并(不整体覆盖),保留已有字段.tmp 临时文件jq empty 验证合法后 mv 原子替换# 模板(以 groups.json 为例)
TARGET=~/feishu_bot/cache/groups.json
LOCK=~/feishu_bot/cache/groups.lock
(
flock -x 200
cur=$(cat "$TARGET" 2>/dev/null); [[ -z "$cur" ]] && cur="{}"
echo "$cur" \
| jq --arg id "oc_xxx" \
--arg name "群名" \
--arg ts "$(date -u +%Y-%m-%dT%H:%M:%SZ)" \
'.[$id] = ((.[$id] // {}) + {"name":$name,"updated_at":$ts})' \
> "${TARGET}.tmp" \
&& jq empty "${TARGET}.tmp" \
&& mv "${TARGET}.tmp" "$TARGET"
) 200>"$LOCK"
{
"spreadsheets": {
"<spreadsheet_token>": {"name": "表格名", "updated_at": "2026-04-22T10:00:00Z"}
},
"bitables": {
"<base_token>": {
"name": "多维表格名",
"updated_at": "2026-04-22T10:00:00Z",
"tables": {"<table_id>": "版本/页签名"}
}
},
"wikis": {
"<wiki_node_token>": {"name": "知识库节点名", "updated_at": "2026-04-22T10:00:00Z"}
}
}
{
"oc_xxx": {
"name": "群名",
"member_count": 42,
"updated_at": "2026-04-22T10:00:00Z"
}
}
{
"ou_xxx": {
"name": "张三",
"en_name": "Zhang San",
"email": "zhangsan@company.com",
"department": "游戏策划部",
"updated_at": "2026-04-22T10:00:00Z"
}
}
| 文件 | TTL | 原因 |
|---|---|---|
tokens.json | 永久(人工清除) | token 不过期,除非文档被删 |
groups.json | 30 天 | 群名偶尔改变 |
users.json | 7 天 | 人员信息变化不频繁 |
TTL 校验:
is_fresh() {
local updated_at="$1" ttl_days="$2"
[[ -z "$updated_at" ]] && return 1
local ts; ts=$(date -d "$updated_at" +%s 2>/dev/null) || return 1
(( $(date +%s) - ts < ttl_days * 86400 ))
}
# 使用示例
entry=$(jq -r --arg id "$chat_id" '.[$id] // empty' ~/feishu_bot/cache/groups.json)
if [[ -n "$entry" ]] && is_fresh "$(echo "$entry" | jq -r '.updated_at')" 30; then
echo "$entry" | jq -r '.name' # 缓存命中
else
# 缓存未命中,调 lark-cli 查询后写入
:
fi
# 读 users.json 中某个用户
jq -r --arg id "ou_xxx" '.[$id] // empty' ~/feishu_bot/cache/users.json
# 查所有已缓存的群
jq 'keys[]' ~/feishu_bot/cache/groups.json
# 查所有已解析的 bitable
jq '.bitables | to_entries[] | {token:.key, name:.value.name}' ~/feishu_bot/cache/tokens.json
# 查 name_cache(只读,脚本维护)
grep "^ou_xxx=" ~/feishu_bot/name_cache | cut -d= -f2
Claude 可以更新 ~/.claude/skills/*/SKILL.md 和 ~/.claude/lark_cli_rules.md,流程:
lark_sweet_bot.sh 或任何 .sh 脚本