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にのみインストール。1つも検知されない場合は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モードを活用:1回のnpx呼び出しで複数の-aターゲットを指定し、最初にインストールが成功したディレクトリがcanonicalとなり、残りはシンボリックリンクを作成。1回修復すれば3環境すべてに同期反映。
if ! npx -y skills add "$SKILL_SRC" -g -y "${AGENT_FLAGS[@]}"; then
認証情報はXDG平文ファイル+環境変数優先で管理:スクリプトはまず環境変数を参照し、次に~/.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で3つのagentパスを正規化し、同一の実体ディレクトリに対するスキャンを1回に制限して重複報告を回避。
canonical() { python3 -c "import os,sys; print(os.path.realpath(sys.argv[1]))" "$1" 2>/dev/null || echo "$1" }
ISSUE-001の検出はブール値ではなく「3状態ステートマシン」:未修復(1行目が---でない)、Strategy A適用済み(MODULE.mdにリネーム)、Strategy B適用済み(frontmatter補完)を識別し、両方が存在する衝突状態も検出。
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
修復処理はスクリプト内に内包せず、ドキュメントに記載されたシェルコマンドとしてユーザーの明示的同意を得てから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ワーカー)、クライアント側でグループ化とソートを実施。
with concurrent.futures.ThreadPoolExecutor(max_workers=args.workers) as pool:
100件のサイレント切り捨てをレスポンス特徴から判定:ヒット数がHARD_HIT_CAP (100) に達し、かつレスポンスにis_endもnext_cursorも含まれない場合に切り捨てと判定し、出力に⚠️アラートを明記。
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の3項目。設定ファイルがない場合は「ニュートラルなデフォルト」(全KBファンアウト、件数順ソート、ブーストなし)で動作。
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外部依存関係
| Kind | Dependency / Endpoint |
|---|---|
| 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推奨統制措置と判定根拠
- scripts/: ローカルスクリプトまたはコマンドの実行: bash scripts/install_ima_skill.sh:curlで公式zipをダウンロード → unzipで/tmp/ima-copiloに解凍
- 网络端点: 外部ネットワークアクセスの宣言: https://app-dl.ima.qq.com/skills/ima-skills-<version>.zip(curlで公式配布パッケージをダウンロード。検証は
- 本地工作目录: ファイル読み書きとアーティファクト出力: /tmp/ima-copilot-staging/<ts>-<pid>/(ダウンロードしたzipと解凍内容。インストーラーのcleanup()は
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…