1实现原理 · 为什么它能做到
它是「包装层」而非 fork:目录内不含上游 ima-skill 的任何内容,只提供安装/诊断/修复/检索编排,所以上游发新版时用户直接拿到新版,包装层不与之冲突。
- **Never vendor upstream files.** This skill directory does not contain any copy, fork, or excerpt of ima-skill's own content. When ima-skill ships a new release, users get the new release without any interference from this wrapper.
安装原理:从 IMA 官方分发域下载 zip → 落到 /tmp 暂存目录 → 解包后交给 vercel-labs/skills 的 npx CLI 分发,全部步骤幂等。
ZIP_URL="${BASE_URL}/ima-skills-${IMA_VERSION}.zip" ZIP_PATH="${STAGING_DIR}/ima-skills.zip" echo " Downloading ${ZIP_URL}" http_code=$(curl -sS -L --fail -o "$ZIP_PATH" -w "%{http_code}" "$ZIP_URL" || echo "000")
分发决策不靠程序化探测上游 zip 结构:优先取 <staging>/ima-skill/SKILL.md 这一约定布局,只有当布局变化时才递归找最浅的 SKILL.md,避免误取 notes/、knowledge-base/ 下的同名子模块文件。
SKILL_SRC="" if [ -f "$STAGING_DIR/ima-skill/SKILL.md" ]; then SKILL_SRC="$STAGING_DIR/ima-skill" else
目标 agent 靠目录存在性探测(~/.claude / ~/.agents / openclaw 命令),只对探测到的 agent 安装;一个都没探测到时兜底装到 claude-code。
AGENTS=() [ -d "$HOME/.claude" ] && AGENTS+=("claude-code") [ -d "$HOME/.agents" ] && AGENTS+=("codex") if [ -d "$HOME/.openclaw" ] || command -v openclaw >/dev/null 2>&1; then AGENTS+=("openclaw") fi
跨 agent 共享靠 vercel skills 的默认 symlink 模式:一次 npx 调用带多个 -a 目标,第一个成功安装的目录成为 canonical,其余软链过来;因此修复一次即三端同步。
if ! npx -y skills add "$SKILL_SRC" -g -y "${AGENT_FLAGS[@]}"; then
凭证管理是 XDG 明文文件 + 环境变量优先:脚本先读 env,再读 ~/.config/ima/{client_id,api_key},两者都缺就报错退出。
client_id = os.environ.get("IMA_OPENAPI_CLIENTID", "").strip() api_key = os.environ.get("IMA_OPENAPI_APIKEY", "").strip() config_dir = Path.home() / ".config" / "ima"
诊断脚本声称严格只读:逐项打 ✅/⚠️/❌ 行并统计,退出码 0=全过 / 1=有需人工处理项 / 2=诊断自身失败(网络或工具缺失)。
# This script is strictly read-only. It will never modify, create, or delete # any file outside its own stdout. Safe to run as many times as you want.
对 symlink 共享做去重:先用 python3 os.path.realpath 把三个 agent 路径规范化,同一底层目录只扫描一次,避免同一问题被报多次。
canonical() { python3 -c "import os,sys; print(os.path.realpath(sys.argv[1]))" "$1" 2>/dev/null || echo "$1" }
ISSUE-001 检测是「三态状态机」而非布尔判断:区分未修(首行不是 ---)、Strategy A 已改名 MODULE.md、Strategy B 已补 frontmatter,另有「SKILL.md 与 MODULE.md 同时存在」的冲突态。
if [ -f "$skill_md" ]; then local first_line first_line=$(head -n 1 "$skill_md" 2>/dev/null || echo "") if [ "$first_line" = "---" ]; then return 0 fi return 1 fi
修复动作不由脚本携带,而是写成文档里的 shell 命令、由 agent 在获得用户明确同意后运行:'we ship instructions, not patches'。
4. **Do not** add the fix commands into any shipped script — keep them in this file so the agent reads and executes them at runtime under user consent. This preserves the contract: we ship instructions, not patches.
扇出检索绕开 API 缺陷:IMA OpenAPI 无跨库端点,脚本先分页枚举全部 KB,再对每个 KB 并发调用 search_knowledge(默认 12 worker),最后在客户端分组排序。
with concurrent.futures.ThreadPoolExecutor(max_workers=args.workers) as pool:
100 条静默截断靠特征反推:命中数正好达到 HARD_HIT_CAP(100) 且响应里既无 is_end 也无 next_cursor,才判定该 KB 被截断并在输出里单列 ⚠️ 提示。
truncated = len(hits) >= HARD_HIT_CAP and not data.get("is_end") and not data.get("next_cursor")
个性化完全落在用户侧配置文件:~/.config/ima/copilot.json 的 priority_kbs / skip_kbs / fanout_strategy 三项;无配置文件即「中性默认」(全库扇出、按命中数排序、不提升)。
The personalization file is **per-user** and private. This skill ships only a template — see `config-template/copilot.json.example`. A user with no config file gets a neutral default: fan out all accessible KBs, sort groups by hit count, no boosting.
2核心能力
3外部依赖
| 类型 | 依赖 |
|---|---|
| cli | curl(下载官方 zip + 凭证 liveness 调用) |
| cli | unzip(解包官方发行 zip) |
| cli | npx(要求 Node.js 18+) |
| cli | python3(search_fanout.py 运行环境;diagnose.sh 用它做 realpath 规范化) |
| cli | sed / cp / mv / mktemp / head(修复命令链使用的系统工具,统一用 command 前缀绕过用户别名) |
| package | skills(vercel-labs/skills,npm 包名 skills;npx 按需现场拉取并执行) |
| network | 上游 ima-skill 官方发行包(zip) |
| api | IMA OpenAPI · search_knowledge_base(枚举 KB / 凭证 liveness) |
| api | IMA OpenAPI · search_knowledge(单库检索,扇出的基本调用) |
| network | 凭证发行页(用户手工创建 Client ID / API Key,非脚本请求) |
| network | 可达性探测/文档引用域(api_key_setup.md 建议用 curl 探 http 码) |
4风险提醒 风险提醒:橙色 · 评估后使用
- 凭证为明文文件且上游 API key 无设备绑定 — client_id/api_key 以 600 明文存在 ~/.config/ima/;api_key_setup.md 自述 'The IMA API currently does not scope credentials per-device — a leaked API key can be used from anywhere on the internet until it's rotated.',并提醒备份工具可能把凭证同步出本机。
- 安装链路无完整性校验 + 运行未 pin 的远程包 — 官方 zip 只校验 HTTP 200 与体积 >1000 字节(无 checksum/签名);`npx -y skills add` 每次现拉 npm 包 skills(实测 latest 1.5.26)。上游包或 npm 包被投毒,等同把未审计内容装成 agent 指令源。
- 修复动作直接改写上游安装目录,且 symlink 模式下影响三端 — Strategy A/B 会 mv/sed 改 ~/.claude/skills/ima-skill/**;在默认 symlink 共享下,一次改动瞬时传播到 Codex/OpenClaw。虽有备份与逐项用户同意,但仍要求用户看懂 ask 提示(agent 若解释不清就变成『盲目同意』)。
- 检索结果原文进入模型上下文(间接 prompt injection) — search_knowledge 返回的 title/highlight_content 被原样 print(仅截断 120 字符),知识库/公众号文章正文可夹带指令文本;脚本不做净化、不标来源信任级。
- 文档与实现存在三处表述出入 — 示例诊断输出格式、备份路径结构、零探测兜底安装 claude-code 三处与脚本实际行为不符(详见 verification.second_pass 的 discrepancy 项);照字面照抄文档示例会困惑。
5第二遍独立确认
- [ok] 外部依赖调用点存在性(curl / unzip / npx / node 版本 / python3 / sed) — install_ima_skill.sh 对 curl/unzip/npx 做 `command -v` 前置检查、对 node 校验 `-lt 18`、用 `unzip -q -o` 解包、用 `npx -y skills add "$SKILL_SRC" -g -y ...` 分发;diagnose.sh 用 python3 打 realpath;known_issues.md 用 `command sed -i.bak`。逐条在源码内命中,无凭空依赖。
- [ok] npx 运行时依赖的真实身份与版本策略 — 实测 GET https://registry.npmjs.org/skills/latest 返回 name=skills、version=1.5.26、repository=git+https://github.com/vercel-labs/skills.git、description='The open agent skills ecosystem',与脚本 `npx -y skills add` 及文档 [vercel-labs/skills] 指向一致;未 pin 版本,每次按需现拉。
- [discrepancy] SKILL.md 示例诊断输出 vs diagnose.sh 实际输出 — SKILL.md 示例写 `✅ upstream ima-skill installed (claude-code)`、`❌ upstream ima-skill NOT installed (openclaw)`;脚本实际打印 `✅ ima-skill installed (claude-code) at $CLAUDE_PATH`(带路径、无 upstream 前缀)与 `⚠️ ima-skill NOT installed (openclaw) — run install_ima_skill.sh`(warn 而非 fail,退出码经汇总后仍为 1)。示例仅示意,功能无差异,但照字面比对会对不上。
- [discrepancy] 备份路径描述 vs known_issues.md 实际命令 — SKILL.md 说修复会把原文件拷到 `/tmp/ima-copilot-backups/<timestamp>/<relative-path>`;实际命令是 `BACKUP="/tmp/ima-copilot-backups/$(date +%Y%m%d-%H%M%S)"` 后以扁平重命名保存(`$BACKUP/notes-SKILL.md`、`$BACKUP/knowledge-base-SKILL.md`),并不保留相对目录结构;回滚命令与之一致,功能成立但文档描述不准。
- [discrepancy] 『未探测到 agent 就跳过、不写用户未选择的路径』的表述 — SKILL.md 与 installation_flow.md 都强调未探测到的 agent 静默跳过;但脚本在『零 agent 探测到』时的实际兜底是 `echo " Defaulting to claude-code as the most common case."` 并继续安装到 claude-code。SKILL.md 的概述未点明这条例外(references 里写了),属概括与实现的轻微出入。
- [ok] diagnose.sh『严格只读』声明复核 — 全文复读:输出只用 echo/printf,读取只用 head -n 1、[ -f ] 探测、tr -d、curl 一次 POST 读响应、python3 打印 realpath;无 > 重定向、无 sed -i、无 chmod、无 rm、无 mkdir。修正结论:『never modify, create, or delete any file』成立。
- [ok] 凭证读取点与去向(是否外发第三方) — 只有 diagnose.sh 与 search_fanout.py 读 env/文件;请求头统一 ima-openapi-clientid / ima-openapi-apikey,目标域名仅 ima.qq.com。全目录 URL 扫描命中集合 = ima.qq.com(含 /openapi 与 /agent-interface)、app-dl.ima.qq.com、github.com/vercel-labs/skills(文档引用)+ npm registry(npx 隐式);无第三方回调、无埋点、无硬编码密钥常量。
- [unlocatable] 站外 API 行为断言的可验证性(100 截断 / 220030 无权限 / 无跨库端点) — 『恰好 100 条即静默截断且无 is_end/next_cursor』『订阅型 KB 返回 code 220030』『无跨库端点』均为 IMA OpenAPI 的站外行为断言,仓库内无测试/fixture 可证;只能确认实现与断言自洽(HARD_HIT_CAP = 100、PERMISSION_DENIED_MARKER = "220030"、truncated 判定式)。要坐实需真实凭证实测,本侦查不硬写。
6结论
9677c96e7b3f34a4…d5c4678cb5