{"id":"b46acff8-5c05-49a1-8e4a-f5bdf043d97c","entityType":"agent","slug":"clawhub-iampennyli-ima-skills","name":"ima skills","canonicalUrl":"https://www.xpersona.co/agent/clawhub-iampennyli-ima-skills","canonicalPath":"/agent/clawhub-iampennyli-ima-skills","generatedAt":"2026-10-09T21:09:11.071Z","source":"CLAWHUB","claimStatus":"UNCLAIMED","verificationTier":"NONE","summary":{"evidence":{"source":"CLAWHUB","verified":false,"confidence":"medium","updatedAt":"2026-10-09T01:50:36.800Z","emptyReason":null},"description":"统一的 IMA OpenAPI 技能，支持笔记管理和知识库操作。 当用户提到知识库、资料库、笔记、备忘录、记事，或者想要上传文件、添加网页到知识库、 搜索知识库内容、搜索/浏览/创建/编辑笔记时，使用此 skill。 即使用户没有明确说\"知识库\"或\"笔记\"，只要意图涉及文件上传到知识库、网页收藏、 知识搜索、个人...","descriptionLabel":"Source description","evidenceSummary":"Capability contract not published. No trust telemetry is available yet. 16.1K downloads reported by the source. Last updated 10/9/2026.","installCommand":"clawhub skill install s17b8zpkvjjj39qt4e1wx3r8a583gg9t:ima-skills","sourceUrl":"https://clawhub.ai/iampennyli/ima-skills","homepage":"https://clawhub.ai/iampennyli/skills/ima-skills","primaryLinks":[{"label":"View on ClawHub","url":"https://clawhub.ai/iampennyli/ima-skills","kind":"source"},{"label":"Homepage","url":"https://clawhub.ai/iampennyli/skills/ima-skills","kind":"homepage"}],"safetyScore":84,"overallRank":62,"popularityScore":84,"trustScore":null,"claimedByName":null,"isOwner":false,"seoDescription":"ima skills technical dossier on Xpersona with agent coverage, OPENCLEW support, and live trust metadata."},"coverage":{"evidence":{"source":"public-profile","verified":false,"confidence":"medium","updatedAt":"2026-10-09T01:50:36.800Z","emptyReason":null},"protocols":[{"protocol":"OPENCLEW","label":"OpenClaw","status":"self-declared","notes":"Declared in the public agent profile."}],"capabilities":[],"verifiedCount":0,"selfDeclaredCount":1,"capabilityMatrix":{"rows":[{"key":"OPENCLEW","type":"protocol","support":"unknown","confidenceSource":"profile","notes":"Listed on profile"}],"flattenedTokens":"protocol:OPENCLEW|unknown|profile"}},"adoption":{"evidence":{"source":"CLAWHUB","verified":false,"confidence":"medium","updatedAt":"2026-10-09T01:50:36.800Z","emptyReason":null},"stars":null,"forks":null,"downloads":16103,"packageName":null,"latestVersion":"1.1.7","tractionLabel":"16.1K downloads"},"release":{"evidence":{"source":"CLAWHUB","verified":false,"confidence":"medium","updatedAt":"2026-10-09T01:50:36.800Z","emptyReason":null},"lastUpdatedAt":"2026-10-09T01:50:36.800Z","lastCrawledAt":"2026-10-09T01:50:36.800Z","lastIndexedAt":null,"nextCrawlAt":"2026-10-10T01:50:36.800Z","lastVerifiedAt":null,"highlights":[{"version":"1.1.7","createdAt":"2026-04-24T10:05:59.209Z","changelog":"ima-skill 1.1.7 changelog - Initial release providing a unified IMA OpenAPI skill supporting note management and knowledge-base operations. - Automates intent routing between notes and knowledge-base modules based on user requests. - Enforces strict rules for credential usage, file uploads, encoding validation, and module decision logic. - Guides users through credential setup before allowing API operations. - Adds detailed error handling for process and backend errors. - Includes structured instructions and decision tables for handling ambiguous or cross-module user scenarios.","fileCount":11,"zipByteSize":39376},{"version":"1.1.2","createdAt":"2026-03-24T02:03:12.140Z","changelog":"**ima-skills v1.1.2 changelog** Skill upgraded to support both notes and knowledge-base with enhanced modularity and credential security. - Modularized into `notes` and `knowledge-base` subskills; unified under `ima-skill`. - Detailed credential setup: now supports both environment variables and config files. - Added clear module routing/decision table for intent disambiguation. - Strict UTF-8 encoding requirements for notes-writing operations; critical handling for PowerShell 5.1 encoding issues. - Enhanced security notice: credentials are only sent to ima.qq.com and never logged or sent elsewhere. - Added extensive module docs in `knowledge-base/` and `notes/`, with code samples for preflight, uploads, and more.","fileCount":8,"zipByteSize":32588},{"version":"1.0.4","createdAt":"2026-03-19T11:24:13.218Z","changelog":"ima-note 1.0.4 - 初始发布，支持 IMA 个人笔记服务 API。 - 实现搜索、浏览、查看、创建、和追加用户个人笔记的能力。 - 补充多种调用接口参数说明与使用工作流，以及分级权限和响应字段说明。 - 新增详细 UTF-8 编码兼容和跨平台转码操作指引。 - 明確接口错误码和常见问题处理建议。","fileCount":3,"zipByteSize":8550},{"version":"1.0.3","createdAt":"2026-03-18T11:53:14.463Z","changelog":"- 新增 skill：ima-note，提供 IMA 个人笔记服务 API，支持用户创建、搜索、浏览和编辑个人笔记。 - 详细文档说明各 API 用法，包括参数要求与常见工作流（如查找/新建/追加笔记）。 - 增补编码与平台兼容性注意事项，提供多种环境下 UTF-8 转码方法。 - 明确群聊隐私行为：仅可展示笔记标题和摘要，不得泄露笔记正文内容。 - 增加错误码及常见问题处理建议。","fileCount":3,"zipByteSize":8550},{"version":"1.0.2","createdAt":"2026-03-18T02:40:59.971Z","changelog":"- 增强兼容性：新增详细说明，要求所有写入内容需确保为 UTF-8 编码，提供多语言环境（Python、Node.js、Unix、PowerShell）下转码和内容清洗方法。 - PowerShell 技巧：特别补充 PowerShell 5.1 发送 UTF-8 JSON 的操作指引，避免编码导致的调用异常。 - 文档完善：强调标题、正文等字符串均需 UTF-8 编码，防止乱码及 API 报错。","fileCount":3,"zipByteSize":8551},{"version":"1.0.1","createdAt":"2026-03-16T13:15:37.409Z","changelog":"上线了 ima 笔记 skill，支持对笔记的读取、写入、检索等操作。","fileCount":3,"zipByteSize":7279},{"version":"1.0.0","createdAt":"2026-03-16T12:55:38.363Z","changelog":"上线了 ima 笔记 skill，支持对笔记的读取、写入、检索等操作。","fileCount":3,"zipByteSize":7364}]},"execution":{"evidence":{"source":"CLAWHUB","verified":false,"confidence":"low","updatedAt":null,"emptyReason":"No published capability contract is available yet."},"installCommand":"clawhub skill install s17b8zpkvjjj39qt4e1wx3r8a583gg9t:ima-skills","setupComplexity":"low","setupSteps":["Install using `clawhub skill install s17b8zpkvjjj39qt4e1wx3r8a583gg9t:ima-skills` in an isolated environment before connecting it to live workloads.","No published capability contract is available yet, so validate auth and request/response behavior manually.","Review the upstream CLAWHUB listing at https://clawhub.ai/iampennyli/ima-skills before using production credentials."],"contract":{"contractStatus":"missing","authModes":[],"requires":[],"forbidden":[],"supportsMcp":false,"supportsA2a":false,"supportsStreaming":false,"inputSchemaRef":null,"outputSchemaRef":null,"dataRegion":null,"contractUpdatedAt":null,"sourceUpdatedAt":null,"freshnessSeconds":null},"invocationGuide":{"preferredApi":{"snapshotUrl":"https://www.xpersona.co/api/v1/agents/clawhub-iampennyli-ima-skills/snapshot","contractUrl":"https://www.xpersona.co/api/v1/agents/clawhub-iampennyli-ima-skills/contract","trustUrl":"https://www.xpersona.co/api/v1/agents/clawhub-iampennyli-ima-skills/trust"},"curlExamples":["curl -s \"https://www.xpersona.co/api/v1/agents/clawhub-iampennyli-ima-skills/snapshot\"","curl -s \"https://www.xpersona.co/api/v1/agents/clawhub-iampennyli-ima-skills/contract\"","curl -s \"https://www.xpersona.co/api/v1/agents/clawhub-iampennyli-ima-skills/trust\""],"jsonRequestTemplate":{"query":"summarize this repo","constraints":{"maxLatencyMs":2000,"protocolPreference":["OPENCLEW"]}},"jsonResponseTemplate":{"ok":true,"result":{"summary":"...","confidence":0.9},"meta":{"source":"CLAWHUB","generatedAt":"2026-10-09T21:09:11.068Z"}},"retryPolicy":{"maxAttempts":3,"backoffMs":[500,1500,3500],"retryableConditions":["HTTP_429","HTTP_503","NETWORK_TIMEOUT"]}},"endpoints":{"dossierUrl":"https://www.xpersona.co/api/v1/agents/clawhub-iampennyli-ima-skills/dossier","snapshotUrl":"https://www.xpersona.co/api/v1/agents/clawhub-iampennyli-ima-skills/snapshot","contractUrl":"https://www.xpersona.co/api/v1/agents/clawhub-iampennyli-ima-skills/contract","trustUrl":"https://www.xpersona.co/api/v1/agents/clawhub-iampennyli-ima-skills/trust"}},"reliability":{"evidence":{"source":"runtime-metrics","verified":false,"confidence":"low","updatedAt":null,"emptyReason":"No trust, reliability, or runtime telemetry is available."},"trust":{"status":"unavailable","handshakeStatus":"UNKNOWN","verificationFreshnessHours":null,"reputationScore":null,"p95LatencyMs":null,"successRate30d":null,"fallbackRate":null,"attempts30d":null,"trustUpdatedAt":null,"trustConfidence":"unknown","sourceUpdatedAt":null,"freshnessSeconds":null},"decisionGuardrails":{"doNotUseIf":["Contract metadata is missing or unavailable for deterministic execution."],"safeUseWhen":[],"riskFlags":["missing_or_unavailable_contract","trust_data_unavailable","schema_references_missing"],"operationalConfidence":"low"},"executionMetrics":{"observedLatencyMsP50":null,"observedLatencyMsP95":null,"estimatedCostUsd":null,"uptime30d":null,"rateLimitRpm":null,"rateLimitBurst":null,"lastVerifiedAt":null,"verificationSource":null},"runtimeMetrics":{"successRate":null,"avgLatencyMs":null,"avgCostUsd":null,"hallucinationRate":null,"retryRate":null,"disputeRate":null,"p50Latency":null,"p95Latency":null,"lastUpdated":null}},"benchmarks":{"evidence":{"source":"no-benchmark-data","verified":false,"confidence":"low","updatedAt":null,"emptyReason":"No benchmark suites or observed failure patterns are available."},"suites":[],"failurePatterns":[]},"artifacts":{"evidence":{"source":"CLAWHUB","verified":false,"confidence":"medium","updatedAt":"2026-10-09T01:50:36.800Z","emptyReason":null},"readme":"Skill: ima skills\n\nOwner: iampennyli\n\nSummary: 统一的 IMA OpenAPI 技能，支持笔记管理和知识库操作。 当用户提到知识库、资料库、笔记、备忘录、记事，或者想要上传文件、添加网页到知识库、 搜索知识库内容、搜索/浏览/创建/编辑笔记时，使用此 skill。 即使用户没有明确说\"知识库\"或\"笔记\"，只要意图涉及文件上传到知识库、网页收藏、 知识搜索、个人...\n\nTags: latest:1.1.7\n\nVersion history:\n\nv1.1.7 | 2026-04-24T10:05:59.209Z | user\n\nima-skill 1.1.7 changelog\n\n- Initial release providing a unified IMA OpenAPI skill supporting note management and knowledge-base operations.\n- Automates intent routing between notes and knowledge-base modules based on user requests.\n- Enforces strict rules for credential usage, file uploads, encoding validation, and module decision logic.\n- Guides users through credential setup before allowing API operations.\n- Adds detailed error handling for process and backend errors.\n- Includes structured instructions and decision tables for handling ambiguous or cross-module user scenarios.\n\nv1.1.2 | 2026-03-24T02:03:12.140Z | user\n\n**ima-skills v1.1.2 changelog**\n\nSkill upgraded to support both notes and knowledge-base with enhanced modularity and credential security.\n\n- Modularized into `notes` and `knowledge-base` subskills; unified under `ima-skill`.\n- Detailed credential setup: now supports both environment variables and config files.\n- Added clear module routing/decision table for intent disambiguation.\n- Strict UTF-8 encoding requirements for notes-writing operations; critical handling for PowerShell 5.1 encoding issues.\n- Enhanced security notice: credentials are only sent to ima.qq.com and never logged or sent elsewhere.\n- Added extensive module docs in `knowledge-base/` and `notes/`, with code samples for preflight, uploads, and more.\n\nv1.0.4 | 2026-03-19T11:24:13.218Z | user\n\nima-note 1.0.4\n\n- 初始发布，支持 IMA 个人笔记服务 API。\n- 实现搜索、浏览、查看、创建、和追加用户个人笔记的能力。\n- 补充多种调用接口参数说明与使用工作流，以及分级权限和响应字段说明。\n- 新增详细 UTF-8 编码兼容和跨平台转码操作指引。\n- 明確接口错误码和常见问题处理建议。\n\nv1.0.3 | 2026-03-18T11:53:14.463Z | user\n\n- 新增 skill：ima-note，提供 IMA 个人笔记服务 API，支持用户创建、搜索、浏览和编辑个人笔记。\n- 详细文档说明各 API 用法，包括参数要求与常见工作流（如查找/新建/追加笔记）。\n- 增补编码与平台兼容性注意事项，提供多种环境下 UTF-8 转码方法。\n- 明确群聊隐私行为：仅可展示笔记标题和摘要，不得泄露笔记正文内容。\n- 增加错误码及常见问题处理建议。\n\nv1.0.2 | 2026-03-18T02:40:59.971Z | user\n\n- 增强兼容性：新增详细说明，要求所有写入内容需确保为 UTF-8 编码，提供多语言环境（Python、Node.js、Unix、PowerShell）下转码和内容清洗方法。\n- PowerShell 技巧：特别补充 PowerShell 5.1 发送 UTF-8 JSON 的操作指引，避免编码导致的调用异常。\n- 文档完善：强调标题、正文等字符串均需 UTF-8 编码，防止乱码及 API 报错。\n\nv1.0.1 | 2026-03-16T13:15:37.409Z | user\n\n上线了 ima 笔记 skill，支持对笔记的读取、写入、检索等操作。\n\nv1.0.0 | 2026-03-16T12:55:38.363Z | user\n\n上线了 ima 笔记 skill，支持对笔记的读取、写入、检索等操作。\n\nArchive index:\n\nArchive v1.1.7: 11 files, 39376 bytes\n\nFiles: ima_api.cjs (6390b), knowledge-base/references/api.md (27034b), knowledge-base/scripts/cos-upload.cjs (5251b), knowledge-base/scripts/preflight-check.cjs (12074b), knowledge-base/SKILL.md (18095b), meta.json (236b), notes/references/api.md (16154b), notes/SKILL.md (10762b), skill-card.md (2587b), SKILL.md (15980b), _meta.json (129b)\n\nFile v1.1.7:knowledge-base/SKILL.md\n\n# Knowledge Base (知识库)\n\nAPI base path: `openapi/wiki/v1` — 完整数据结构和接口参数详见 `references/api.md`。\n\n## 接口决策表\n\n| 用户意图                                      | 调用接口                                                               | 关键参数                                                                                           |\n| --------------------------------------------- | ---------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------- |\n| 上传文件到知识库                              | `check_repeated_names` → `create_media` → COS Upload → `add_knowledge` | `media_type`（按扩展名），`knowledge_base_id`，`file_name`，`file_size`                            |\n| 上传文件到知识库的某个文件夹                  | 先定位文件夹 → 同上（`folder_id` 传入目标文件夹 ID）                   | 见「文件夹操作」章节                                                                               |\n| 添加网页/微信文章到知识库                     | `import_urls`                                                          | `urls`（1-10 个），`knowledge_base_id`，可选 `folder_id`（省略则根目录）                           |\n| 添加笔记到知识库                              | `add_knowledge`                                                        | `media_type=11`，`note_info.content_id=<note_id>`，`knowledge_base_id`                             |\n| 添加 URL（文件型）到知识库                    | `check_repeated_names` → 下载文件 → 走\"上传文件\"流程                   | URL 指向 PDF/Word/PPT 等文件时，按文件方式处理                                                     |\n| 检查文件名是否重复                            | `check_repeated_names`                                                 | `params[].name`，`params[].media_type`，`knowledge_base_id`，`folder_id`                           |\n| 获取知识库信息                                | `get_knowledge_base`                                                   | `ids`（1-20 个，不重复）                                                                           |\n| 浏览知识库内容列表 / 浏览文件夹               | `get_knowledge_list`                                                   | `knowledge_base_id`，`cursor`，`limit`(1~50)，可选 `folder_id`                                     |\n| 在知识库中搜索（含文件和文件夹）              | `search_knowledge`                                                     | `query`，`knowledge_base_id`，`cursor`                                                             |\n| 按关键词查找知识库（用户知道名字但不知道 ID） | `search_knowledge_base`                                                | `query`，`cursor`，`limit`(1~20)                                                                   |\n| 查看/了解自己有哪些知识库                     | `search_knowledge_base`（`query` 传空字符串）                          | `query: \"\"`，`cursor`，`limit`(1~20)                                                               |\n| 添加内容但**未指定**目标知识库                | `get_addable_knowledge_base_list` → 展示列表让用户选择                 | `cursor`，`limit`(1~50)                                                                            |\n| 查看原文、分析原文、导出原文                  | `get_media_info`                                                       | `media_id`；导出/下载时在 URL 后追加 `response-content-type` + `response-content-disposition` 参数 |\n\n### `search_knowledge_base` vs `get_addable_knowledge_base_list`\n\n| 场景                                             | 使用接口                                       | 原因                               |\n| ------------------------------------------------ | ---------------------------------------------- | ---------------------------------- |\n| 用户说了知识库名称（如\"添加到产品文档库\"）       | `search_knowledge_base`                        | 按名称搜索，找到 ID 后继续操作     |\n| 用户想浏览/了解某个知识库                        | `search_knowledge_base` → `get_knowledge_base` | 先搜到 ID，再获取详情              |\n| 用户想查看自己有哪些知识库（无具体关键词）       | `search_knowledge_base`（`query: \"\"`）         | 空 query 返回用户的所有知识库列表  |\n| 用户要添加内容但**没说添加到哪个知识库**         | `get_addable_knowledge_base_list`              | 列出有权限添加的知识库，让用户选择 |\n| 用户说\"添加到知识库\"但上下文中无法确定哪个知识库 | `get_addable_knowledge_base_list`              | 同上，不要猜测，让用户选择         |\n\n**绝不要**在用户已明确指定知识库名称时调用 `get_addable_knowledge_base_list`。\n\n---\n\n## 写入类工作流\n\n### ⛔ 文件上传安全门（仅适用于文件上传 → `add_knowledge` 流程）\n\n以下 4 条规则**仅**在上传文件到知识库时适用。搜索、浏览、获取信息等读取操作不受影响。\n\n```\nGATE 1 [TYPE CHECK]\n  Run preflight-check.cjs FIRST. pass=false → reject immediately.\n  NEVER ask \"do you still want to try?\" for unsupported types.\n  Video files, Bilibili/YouTube URLs, file:// URLs → tell user to use IMA desktop client.\n\nGATE 2 [NAMING]\n  add_knowledge title MUST equal file_name (with extension).\n  NEVER rename, shorten, translate, or modify the original filename.\n  Example: file is \"音频.mp3\" → title=\"音频.mp3\", file_name=\"音频.mp3\"\n\nGATE 3 [DUPLICATES]\n  Call check_repeated_names BEFORE create_media for ALL file uploads.\n  is_repeated=true → ask user: keep both (append timestamp) or cancel.\n  \"Replace\" is NOT supported.\n  Timestamp format: {name}_YYYYMMDDHHmmss.{ext}\n\nGATE 4 [UPLOAD EXIT]\n  cos-upload.cjs non-zero exit → STOP immediately.\n  Do NOT call add_knowledge. Report error to user.\n```\n\n### 上传文件到知识库\n\n完整流程：前置检查 → 重名检查 → 创建媒体 → COS 上传 → COS 验证 → 添加知识。\n\n```bash\n# ── Step 1: preflight-check.cjs ← ⛔ GATE 1 ──\n# 有扩展名时自动推断；无扩展名时需传 --content-type\nPREFLIGHT=$(node .claude/skills/ima-skill/knowledge-base/scripts/preflight-check.cjs \\\n  --file \"/path/to/report.pdf\")\necho \"$PREFLIGHT\"\n# pass=false → 终止，将 reason 展示给用户。NEVER ask \"want to try?\"\n\n# ── Step 2: Extract fields ──\nFILE_NAME=$(echo \"$PREFLIGHT\" | node -e \"const d=JSON.parse(require('fs').readFileSync(0,'utf8'));process.stdout.write(d.file_name)\")\nFILE_EXT=$(echo \"$PREFLIGHT\" | node -e \"const d=JSON.parse(require('fs').readFileSync(0,'utf8'));process.stdout.write(d.file_ext)\")\nFILE_SIZE=$(echo \"$PREFLIGHT\" | node -e \"const d=JSON.parse(require('fs').readFileSync(0,'utf8'));process.stdout.write(String(d.file_size))\")\nMEDIA_TYPE=$(echo \"$PREFLIGHT\" | node -e \"const d=JSON.parse(require('fs').readFileSync(0,'utf8'));process.stdout.write(String(d.media_type))\")\nCONTENT_TYPE=$(echo \"$PREFLIGHT\" | node -e \"const d=JSON.parse(require('fs').readFileSync(0,'utf8'));process.stdout.write(d.content_type)\")\n\n# ── Step 3: check_repeated_names ← ⛔ GATE 3 ──\n# MANDATORY for ALL file uploads (media_type 1/3/4/5/7/9/13/14/15).\n# is_repeated=true → ask user: keep both (append _YYYYMMDDHHmmss) or cancel.\nima_api \"openapi/wiki/v1/check_repeated_names\" \"{\n  \\\"params\\\": [{\\\"name\\\": \\\"$FILE_NAME\\\", \\\"media_type\\\": $MEDIA_TYPE}],\n  \\\"knowledge_base_id\\\": \\\"<kb_id>\\\"\n}\"\n# folder_id is optional — omit for root, include for subfolder\n\n# ── Step 4: create_media ──\nCREATE_MEDIA_RESP=$(ima_api \"openapi/wiki/v1/create_media\" \"{\n  \\\"file_name\\\": \\\"$FILE_NAME\\\",\n  \\\"file_size\\\": $FILE_SIZE,\n  \\\"content_type\\\": \\\"$CONTENT_TYPE\\\",\n  \\\"knowledge_base_id\\\": \\\"<kb_id>\\\",\n  \\\"file_ext\\\": \\\"$FILE_EXT\\\"\n}\")\n# Extract media_id, url, and cos_credential fields. code≠0 → terminate.\n# COS_URL is the file's accessible URL — used for verification in Step 6.\n\n# ── Step 5: cos-upload.cjs ← ⛔ GATE 5 (non-zero = STOP) ──\n# ⚠️ Large files may exceed default 120s timeout — set --timeout explicitly.\nnode .claude/skills/ima-skill/knowledge-base/scripts/cos-upload.cjs \\\n  --file \"/path/to/report.pdf\" \\\n  --secret-id \"<cos_credential.secret_id>\" \\\n  --secret-key \"<cos_credential.secret_key>\" \\\n  --token \"<cos_credential.token>\" \\\n  --bucket \"<cos_credential.bucket_name>\" \\\n  --region \"<cos_credential.region>\" \\\n  --cos-key \"<cos_credential.cos_key>\" \\\n  --content-type \"$CONTENT_TYPE\" \\\n  --start-time \"<cos_credential.start_time>\" \\\n  --expired-time \"<cos_credential.expired_time>\" \\\n  --timeout 300000\n# ⛔ Non-zero exit → STOP HERE. Do NOT proceed to step 7.\n\n# ── Step 6: add_knowledge ← ⛔ GATE 2 (title = file_name) ──\n# ONLY execute if Step 5 succeeded (exit code 0).\n# add_knowledge will verify the file was uploaded — no separate verify step needed.\nima_api \"openapi/wiki/v1/add_knowledge\" \"{\n  \\\"media_type\\\": $MEDIA_TYPE,\n  \\\"media_id\\\": \\\"<media_id>\\\",\n  \\\"title\\\": \\\"$FILE_NAME\\\",\n  \\\"knowledge_base_id\\\": \\\"<kb_id>\\\",\n  \\\"file_info\\\": {\n    \\\"cos_key\\\": \\\"<cos_credential.cos_key>\\\",\n    \\\"file_size\\\": $FILE_SIZE,\n    \\\"file_name\\\": \\\"$FILE_NAME\\\"\n  }\n}\"\n```\n\n#### 批量上传时的重复处理\n\n可一次性检查所有文件名（最多 2000 个）：\n\n```bash\n# ⛔ GATE 3 — batch check\nima_api \"openapi/wiki/v1/check_repeated_names\" '{\n  \"params\": [\n    {\"name\": \"report.pdf\", \"media_type\": 1},\n    {\"name\": \"slides.pptx\", \"media_type\": 4},\n    {\"name\": \"data.xlsx\", \"media_type\": 5}\n  ],\n  \"knowledge_base_id\": \"<kb_id>\",\n  \"folder_id\": \"<folder_id>\"\n}'\n# 根目录时省略 folder_id。\n# is_repeated=true → \"以下文件已存在同名：report.pdf。是否保留两者？（不支持替换）\"\n# 保留两者 → append _YYYYMMDDHHmmss；取消 → remove from upload list\n```\n\n### 添加网页/微信文章到知识库\n\n```bash\n# 无需 GATE 3-5（非文件上传）\n# 添加到根目录（不传 folder_id）\nima_api \"openapi/wiki/v1/import_urls\" '{\n  \"knowledge_base_id\": \"<kb_id>\",\n  \"urls\": [\n    \"https://example.com/article\",\n    \"https://mp.weixin.qq.com/s/xxxxx\"\n  ]\n}'\n\n# 添加到指定文件夹\nima_api \"openapi/wiki/v1/import_urls\" '{\n  \"knowledge_base_id\": \"<kb_id>\",\n  \"folder_id\": \"<folder_id>\",\n  \"urls\": [\"https://example.com/article\"]\n}'\n# 返回 results 映射：{ \"<url>\": { url, ret_code, media_id } }\n```\n\n### 添加笔记到知识库\n\n```bash\nima_api \"openapi/wiki/v1/add_knowledge\" '{\n  \"media_type\": 11,\n  \"note_info\": { \"content_id\": \"<note_id>\" },\n  \"title\": \"笔记标题\",\n  \"knowledge_base_id\": \"<kb_id>\"\n}'\n```\n\n### 添加 URL 到知识库（自动检测文件型 URL）\n\nURL 可能指向网页或可下载文件。检测逻辑 → see `references/api.md §URL Type Detection`。\n\n**文件型 URL 处理流程**：\n\n```bash\n# 1. 探测 URL 类型\nCONTENT_TYPE=$(curl -sI -L \"<url>\" | grep -i \"^content-type:\" | tail -1 | awk '{print $2}' | tr -d '\\r')\n\n# 2. 下载到临时目录\nTEMP_DIR=$(mktemp -d)\ncurl -sL -o \"$TEMP_DIR/paper.pdf\" \"<url>\"\n\n# 3. preflight-check.cjs ← ⛔ GATE 1\nPREFLIGHT=$(node .claude/skills/ima-skill/knowledge-base/scripts/preflight-check.cjs \\\n  --file \"$TEMP_DIR/paper.pdf\" --content-type \"$CONTENT_TYPE\")\n# pass=false → terminate\n\n# 4. Follow \"上传文件到知识库\" workflow (Steps 3-7 with all gates)\n\n# 5. Clean up\nrm -rf \"$TEMP_DIR\"\n```\n\n**文件名推断**（优先级）：Content-Disposition header → URL path → last URL segment + Content-Type extension\n\n---\n\n---\n\n## 文件夹操作\n\n知识库内容以文件夹层级组织。`folder_id` 始终以 `folder_` 前缀开头。\n\n**核心规则**：\n\n- 操作根目录时 **省略 `folder_id` 字段**，不要传该参数\n- **不要将 `knowledge_base_id` 作为 `folder_id` 传入**\n- `get_knowledge_list` 返回的 `current_path`（`FolderInfo[]`）= 面包屑\n\n### 定位文件夹（用户只给了名称）\n\n```bash\n# 方法 1：搜索（推荐）\nima_api \"openapi/wiki/v1/search_knowledge\" '{\n  \"query\": \"文件夹名称\",\n  \"knowledge_base_id\": \"<kb_id>\",\n  \"cursor\": \"\"\n}'\n# 从 info_list 找匹配文件夹，取 media_id 作为 folder_id\n\n# 方法 2：逐级浏览\nima_api \"openapi/wiki/v1/get_knowledge_list\" '{\n  \"knowledge_base_id\": \"<kb_id>\",\n  \"cursor\": \"\",\n  \"limit\": 50\n}'\n```\n\n---\n\n## 查询类工作流（无安全门限制）\n\n### 获取知识库信息\n\n```bash\nima_api \"openapi/wiki/v1/get_knowledge_base\" '{\"ids\": [\"<kb_id>\"]}'\n```\n\n### 浏览知识库内容\n\n```bash\n# 根目录\nima_api \"openapi/wiki/v1/get_knowledge_list\" '{\"knowledge_base_id\": \"<kb_id>\", \"cursor\": \"\", \"limit\": 20}'\n\n# 指定文件夹\nima_api \"openapi/wiki/v1/get_knowledge_list\" '{\"knowledge_base_id\": \"<kb_id>\", \"folder_id\": \"<folder_id>\", \"cursor\": \"\", \"limit\": 20}'\n# 翻页：用 next_cursor，is_end=true 时停止\n```\n\n### 搜索知识库内容 / 搜索知识库列表\n\n```bash\nima_api \"openapi/wiki/v1/search_knowledge\" '{\"query\": \"关键词\", \"knowledge_base_id\": \"<kb_id>\", \"cursor\": \"\"}'\n\n# 搜索知识库列表（按名称）\nima_api \"openapi/wiki/v1/search_knowledge_base\" '{\"query\": \"关键词\", \"cursor\": \"\", \"limit\": 20}'\n\n# 查看所有知识库\nima_api \"openapi/wiki/v1/search_knowledge_base\" '{\"query\": \"\", \"cursor\": \"\", \"limit\": 20}'\n```\n\n### 获取可添加的知识库列表\n\n**仅当用户未指定目标知识库时使用**。\n\n```bash\nima_api \"openapi/wiki/v1/get_addable_knowledge_base_list\" '{\"cursor\": \"\", \"limit\": 20}'\n```\n\n### 获取媒体原文内容\n\n```bash\nRESPONSE=$(ima_api \"openapi/wiki/v1/get_media_info\" '{\"media_id\": \"<media_id>\"}')\n```\n\n**处理分支**：\n\n| 条件                                                    | 处理                                                              |\n| ------------------------------------------------------- | ----------------------------------------------------------------- |\n| `media_type=11` 且 `notebook_ext_info.notebook_id` 存在 | 将 `notebook_id` 作为 `note_id` 调用 notes 模块 `get_doc_content` |\n| `url_info.url` 非空                                     | 用 `url` + `headers`（如有）请求原文                              |\n| `url_info` 为空，或请求失败，或 `code≠0`                | 提示用户「请使用ima客户端查看原文」                               |\n\n**强制下载并指定文件名**：当需要将 `url_info.url` 返回的链接作为下载链接（而非在线预览）时，可在 URL 后追加以下查询参数：\n\n```\nresponse-content-type=application/octet-stream&response-content-disposition=attachment;filename=\"<desired_filename>\"\n```\n\n示例：用户要求\"导出\"或\"下载\"某个知识库文件时，将 `get_media_info` 返回的 `url` 拼接上述参数，即可让浏览器/客户端以指定文件名下载，而非在线打开。\n\n---\n\n## 分页\n\n所有列表/搜索接口使用**游标分页**：首次 `cursor: \"\"`，检查 `is_end`，用 `next_cursor` 翻页，`is_end=true` 停止。\n\n## 响应处理\n\n统一结构 `{ \"code\": 0, \"msg\": \"...\", \"data\": { ... } }`。`code=0` 成功；`code≠0` 直接展示 `msg` 给用户。\n\n## 用户体验\n\n- **隐藏内部 ID**：面向用户展示中**永远不要暴露** `knowledge_base_id`、`media_id`、`folder_id`。使用知识库名称、文件标题、文件夹名称。\n- **精简进度**：不要逐步暴露内部操作（\"正在创建媒体…正在上传 COS…\"）。只报告：\n  - 上传文件：`\"正在上传 report.pdf…\"` → `\"已添加到知识库「产品文档库」✓\"`\n  - 添加网页：`\"正在添加…\"` → `\"已添加到「产品文档库」✓\"`\n  - 失败时展示 `msg`\n- **批量操作**：汇总结果，如 `\"3 个文件已添加到「产品文档库」，1 个失败（data.xlsx: 文件大小超限）\"`\n- **格式化展示**：\n\n  **知识库列表**（`search_knowledge_base` / `get_addable_knowledge_base_list`）：\n\n  > 搜索知识库后，用返回的 ID 列表调用 `get_knowledge_base` 获取描述信息，一并展示。\n\n  ```\n  📚 搜索结果（共 3 个知识库）：\n  1. **产品文档库** — 存放产品相关的所有文档资料\n  2. **技术方案库** — 各项目技术方案汇总\n  3. **竞品分析库**\n  ```\n\n  **知识库内容列表**（`get_knowledge_list`）：\n\n  ```\n  📂 知识库「产品文档库」内容：\n  📁 设计文档/          (3 个文件, 1 个子文件夹)\n  📁 会议纪要/          (12 个文件)\n  📄 产品需求文档.pdf\n  📄 技术方案.docx\n  📄 数据分析.xlsx\n  --- 第 1 页，还有更多内容 ---\n  ```\n\n  **搜索结果**（`search_knowledge`）：\n\n  ```\n  🔍 在知识库「产品文档库」中搜索「排期」的结果：\n\n  1. 📄 Q1排期表.xlsx (文件夹: 项目管理/)\n     > ...包含**排期**计划的详细信息...\n  2. 📄 开发排期讨论.pdf (文件夹: 会议纪要/)\n  3. 📁 排期模板/ (文件夹: 根目录)\n  ```\n\n  **知识库详情**（`get_knowledge_base`）：\n\n  ```\n  📚 产品文档库\n  📝 描述：存放产品相关的所有文档资料\n  💡 推荐问题：\n     - 最新的产品需求是什么？\n     - 技术方案有哪些？\n  ```\n\n## 注意事项\n\n- `get_knowledge_base` 接受 1-20 个 ID；单个 ID 也需包装为数组\n- **文件夹是知识条目的一种**：返回结果中同时包含文件和文件夹\n- 文件扩展名必须正确提取，用于 `media_type` 检测和 `file_ext` 字段（无点号，如 `pdf`）\n- COS 上传时 `--content-type` 应传入文件的实际 MIME 类型，非 `application/octet-stream`\n- 当用户提供 URL 添加到知识库时，必须先检测是否文件型 URL → see `references/api.md §URL Type Detection`\n- MediaType 枚举和文件大小限制 → see `references/api.md §MediaType` and `§文件大小限制`\n\nFile v1.1.7:notes/SKILL.md\n\n# Notes (笔记)\n\n> ⛔ Before ANY write (`import_doc`/`append_doc`): validate ALL string fields (`content`, `title`) are legal UTF-8.\n> Non-UTF-8 content causes irreversible garbled text in IMA. See root SKILL.md § MANDATORY RULES for platform-specific validation methods.\n\nAPI base path: `openapi/note/v1`\n\n通过 IMA OpenAPI 管理用户个人笔记，支持读取（搜索、列表、获取内容）和写入（新建、追加）。\n\n完整的数据结构和接口参数详见 `references/api.md`。\n\n> **隐私规则：** 笔记内容属于用户隐私，在群聊场景中只展示标题和摘要，禁止展示笔记正文。\n\n## 接口决策表\n\n| 用户意图                                                                          | 调用接口          | 关键参数                                                                  |\n| --------------------------------------------------------------------------------- | ----------------- | ------------------------------------------------------------------------- |\n| 搜索/查找笔记                                                                     | `search_note`     | `query_info`（QueryInfo 对象）                                            |\n| 查看笔记本列表 / 列出笔记本                                                       | `list_notebook`   | `cursor`(必填，首页传`\"0\"`) + `limit`(必填)                               |\n| 列出笔记/获取多篇笔记信息                                                         | `list_note`       | `folder_id`(选填,空为全部) + `sort_type` + `cursor`(首次传`\"\"`) + `limit` |\n| 读取笔记正文                                                                      | `get_doc_content` | `note_id` + `target_content_format`(必填，推荐`0`纯文本)                  |\n| 新建一篇笔记（用户明确说\"新建/创建笔记\"时走此接口）                               | `import_doc`      | `content` + `content_format`(必填，固定`1`) + 可选 `folder_id`            |\n| 往已有笔记追加内容（⚠️ **敏感操作**：用户必须明确指定目标笔记，否则先确认再操作） | `append_doc`      | `note_id` + `content` + `content_format`(必填，固定`1`)                   |\n\n## ⚠️ 新建 vs. 追加 — 行为规则\n\n**新建笔记（`import_doc`）** 和 **追加内容到已有笔记（`append_doc`）** 是两个完全不同的操作，务必正确区分：\n\n### 明确走新建的信号词\n\n用户说以下任一表述时，**直接调用 `import_doc` 创建新笔记**：\n\n- \"**新建**笔记\"、\"**创建**笔记\"、\"**写一篇**笔记\"\n- \"**新建**一篇笔记记录这些内容\"\n\n### 明确走追加的信号词\n\n用户说以下任一表述时，**调用 `append_doc` 追加到已有笔记**（但仍需确认目标笔记，见下方规则）：\n\n- \"把这段话**追加到**《XX》笔记里\"\n- \"在那篇笔记**末尾加上**这段内容\"\n\n### 模糊场景 — 必须先询问用户\n\n以下表述**既可能是新建、也可能是追加**，agent **不得自行假设**，必须先向用户确认：\n\n- \"帮我记一下\"、\"记录一下\"、\"保存为笔记\"、\"存成笔记\"\n- \"把这段内容记到笔记里\"\n- \"添加到笔记里\"\n- 任何其他未明确表达\"新建\"或\"追加\"意图的表述\n\n询问示例：\n\n> \"您是想**创建一篇新笔记**，还是**追加到某篇已有笔记**？\"\n\n### 追加到已有笔记是敏感操作\n\n`append_doc` 会**不可撤销地修改**用户的现有笔记，因此必须谨慎处理：\n\n1. **用户明确指定了目标笔记** — 可以直接追加。例如：\n\n   - \"把这段话追加到《会议纪要》笔记里\"\n   - \"在那篇笔记末尾加上这段内容\"（上下文中已有明确的笔记对象）\n\n2. **用户没有明确指定目标笔记** — **必须先向用户确认**，不要自行猜测。例如：\n   - 用户说\"添加到笔记里\" → 询问：\"您想追加到哪篇已有笔记？请提供笔记标题或让我帮您搜索。\"\n   - 用户说\"把这个加到之前那篇笔记\" → 如果上下文中有多篇笔记或不确定是哪篇 → 列出候选笔记让用户选择\n\n> **原则**：不确定时，先问。宁可多问一句，也不要误改用户的已有笔记或自作主张创建新笔记。\n\n### 🖼️ 本地图片不支持\n\n`import_doc` 和 `append_doc` 的 `content` 字段仅支持Markdown，**不支持本地图片**。\n\n写入笔记内容前，必须检查并处理图片引用：\n\n1. **过滤本地图片** — 如果用户提供的内容中包含本地图片路径（如 `![](file:///...)`, `![](/Users/...)`, `![](C:\\...)` 等），**移除这些图片引用**，不要将其写入笔记。\n2. **告知用户** — 移除后主动提醒用户：\n   > \"笔记接口暂不支持上传本地图片，以下图片已被过滤：`xxx.png`、`yyy.jpg`。您可以先将图片上传到网络，再用网络链接插入笔记。\"\n3. **保留网络图片** — 以 `http://` 或 `https://` 开头的图片链接可以正常保留。\n\n## 常用工作流\n\n### 查找并阅读笔记\n\n先搜索获取 `note_id`，再用 `get_doc_content` 读取正文：\n\n```bash\n# 1. 按标题搜索\nima_api \"openapi/note/v1/search_note\" '{\"search_type\": 0, \"query_info\": {\"title\": \"会议纪要\"}, \"start\": 0, \"end\": 20}'\n# 从返回的 search_note_infos[].note_book_info.note_id 中取目标笔记 ID\n\n# 2. 读取正文（纯文本格式，Markdown 格式目前不支持）\nima_api \"openapi/note/v1/get_doc_content\" '{\"note_id\": \"目标note_id\", \"target_content_format\": 0}'\n```\n\n### 列出自己有哪些笔记\n\n直接使用`list_note`，拉取全部笔记列表，直到符合用户要求（如：用户要求全部笔记，则到 `is_end=true` 时停止；用户要求近30天的笔记，则根据`modify_time`与当前时间判断停止）\n\n```bash\n# 1. 拉取全部笔记的列表（首页 cursor 传 \"\"）\nima_api \"openapi/note/v1/list_note\" '{\"folder_id\":\"\", \"sort_type\":0, \"cursor\": \"\", \"limit\": 20}'\n# 获取全部笔记中前20篇笔记的信息\n\n```\n\n### 浏览笔记本里的笔记\n\n先拉笔记本列表获取 `folder_id`，再拉该笔记本下的笔记：\n\n```bash\n# 1. 列出笔记本（首页 cursor 传 \"0\"）\nima_api \"openapi/note/v1/list_notebook\" '{\"cursor\": \"0\", \"limit\": 20}'\n\n# 2. 拉取指定笔记本的笔记（首页 cursor 传 \"\"）\nima_api \"openapi/note/v1/list_note\" '{\"folder_id\": \"目标folder_id\", \"cursor\": \"\", \"limit\": 20}'\n```\n\n### 新建笔记\n\n```bash\n# 新建到默认位置\nima_api \"openapi/note/v1/import_doc\" '{\"content_format\": 1, \"content\": \"# 标题\\n\\n正文内容\"}'\n\n# 新建到指定笔记本\nima_api \"openapi/note/v1/import_doc\" '{\"content_format\": 1, \"content\": \"# 标题\\n\\n正文内容\", \"folder_id\": \"笔记本ID\"}'\n# 返回 note_id，后续可用于 append_doc\n```\n\n### 追加内容到已有笔记\n\n```bash\nima_api \"openapi/note/v1/append_doc\" '{\"note_id\": \"笔记ID\", \"content_format\": 1, \"content\": \"\\n## 补充内容\\n\\n追加的文本\"}'\n```\n\n### 按正文搜索\n\n```bash\nima_api \"openapi/note/v1/search_note\" '{\"search_type\": 1, \"query_info\": {\"content\": \"项目排期\"}, \"start\": 0, \"end\": 20}'\n```\n\n## 核心响应字段\n\n**搜索结果**（`SearchNoteInfo`）：笔记信息路径为 `search_note_infos` 包含 `NoteBookInfo`，关键字段：`note_id`、`title`、`summary`、`create_time`、`modify_time`、`note_ext_info.folder_id`、`note_ext_info.folder_name`。额外包含 `highlightInfo`（高亮匹配，key 为 `doc_title`，value 含 `<em>高亮词</em>`）。\n\n**笔记列表条目**（`NoteBookInfo`）：关键字段：`note_id`、`title`、`summary`、`create_time`、`modify_time`、`cover_image`、`note_ext_info`（含 `folder_id`、`folder_name`）。\n\n**笔记本条目**（`NoteFolderInfo`）：关键字段：`folder_id`、`name`、`note_number`、`create_time`、`modify_time`、`parent_folder_id`、`folder_type`（`0`=用户自建，`1`=全部笔记，`2`=未分类）。\n\n**写入结果**（`import_doc`/`append_doc`）：返回 `note_id`（新建或目标笔记的唯一 ID）。\n\n完整字段定义见 `references/api.md`。\n\n## 分页\n\n- **游标分页 — 笔记本列表**（`list_notebook`）：首次 `cursor: \"0\"`，后续用 `next_cursor`，`is_end=true` 时停止。\n- **游标分页 — 笔记列表**（`list_note`）：首次 `cursor: \"\"`，`is_end=true` 时停止。\n- **偏移量分页**（`search_note`）：首次 `start: 0, end: 20`，翻页时递增，`is_end=true` 时停止。\n\n## 枚举值\n\n- **`content_format`：** `0`=纯文本，`1`=Markdown，`2`=JSON。写入（`import_doc`/`append_doc`）目前仅支持 `1`（Markdown）。读取（`get_doc_content`）推荐 `0`（纯文本），Markdown 格式不支持。\n- **`search_type`：** `0`=标题检索（默认），`1`=正文检索\n- **`sort_type`：** `0`=更新时间（默认），`1`=创建时间，`2`=标题，`3`=大小（仅 `search_note_book` 使用）\n- **`folder_type`：** `0`=用户自建，`1`=全部笔记（根目录），`2`=未分类\n\n## 注意事项\n\n- `folder_id` 不可为 `\"0\"`，根目录 ID 格式为 `user_list_{userid}`（从 `folder_type=1` 的笔记本条目获取）\n- 笔记内容有大小上限，超过时返回 `100009`，可拆分为多次 `append_doc` 写入\n- 写入内容不支持本地图片，写入前必须过滤本地图片路径并告知用户（详见\"🖼️ 本地图片不支持\"规则）\n- 展示笔记列表时只展示标题、摘要和修改时间，不要主动展示正文\n- 时间字段是 Unix 毫秒时间戳，展示时转为可读格式\n- 返回数据为嵌套结构：搜索结果取 `SearchNoteInfo[].note_book_info.note_id`，笔记本列表取 `NoteFolderInfo[].folder_id`，笔记列表取 `NoteBookInfo[].note_id`，注意按层级解析\n\n## 错误处理\n\n| 错误码 | 含义                   | 建议处理                     |\n| ------ | ---------------------- | ---------------------------- |\n| 100001 | 参数错误               | 检查请求参数格式和必填字段   |\n| 100002 | 无效 ID                | 检查凭证配置                 |\n| 100003 | 服务器内部错误         | 等待后重试                   |\n| 100004 | size 不合法 / 空间不够 | 检查参数范围                 |\n| 100005 | 无权限                 | 确认操作的是用户自己的笔记   |\n| 100006 | 笔记已删除             | 告知用户该笔记不存在         |\n| 100008 | 版本冲突               | 重新获取内容后再操作         |\n| 100009 | 超过大小限制           | 拆分为多次 `append_doc` 写入 |\n| 310001 | 笔记本不存在           | 检查 `folder_id` 是否正确    |\n| 20002  | apiKey超过最大限频     |\n| 20004  | apikey 鉴权失败        | 检查凭证配置是否正确         |\n\nFile v1.1.7:SKILL.md\n\n---\nname: ima-skill\ndescription: |\n  统一的 IMA OpenAPI 技能，支持笔记管理和知识库操作。\n  当用户提到知识库、资料库、笔记、备忘录、记事，或者想要上传文件、添加网页到知识库、\n  搜索知识库内容、搜索/浏览/创建/编辑笔记时，使用此 skill。\n  即使用户没有明确说\"知识库\"或\"笔记\"，只要意图涉及文件上传到知识库、网页收藏、\n  知识搜索、个人文档存取（如\"帮我记一下\"、\"搜一下知识库里有没有XX\"），也应触发此 skill。\nhomepage: https://ima.qq.com\nmetadata:\n  openclaw:\n    emoji: 🔧\n    requires:\n      env:\n        - IMA_OPENAPI_CLIENTID\n        - IMA_OPENAPI_APIKEY\n    primaryEnv: IMA_OPENAPI_CLIENTID\n  security:\n    credentials_usage: |\n      This skill requires user-provisioned IMA OpenAPI credentials (Client ID and API Key)\n      to authenticate with the official IMA API at https://ima.qq.com.\n      Credentials are ONLY sent to the official IMA API endpoint (ima.qq.com) as HTTP headers.\n      The file-upload flow also sends requests to COS endpoints (*.myqcloud.com) using\n      short-lived, scoped temporary credentials returned by the IMA API (create_media);\n      the user's Client ID / API Key are never sent to COS.\n      No credentials are logged, stored in files, or transmitted to any other destination.\n    allowed_domains:\n      - ima.qq.com\n      - '*.myqcloud.com'\n---\n\n# ima-skill\n\nUnified IMA OpenAPI skill. Currently supports: **notes**, **knowledge-base**.\n\n## ⛔ MANDATORY RULES — read before ANY operation\n\n1. **UTF-8 encoding (notes writes only):** Before calling `import_doc` or `append_doc`, ALL string fields (`content`, `title`) MUST be validated as legal UTF-8. Non-UTF-8 content causes irreversible garbled text. See [Detailed Rules](#detailed-utf-8-encoding-rules) for platform-specific methods.\n2. **File upload naming:** `title` MUST equal `file_name` (with extension). Never rename, shorten, translate, or modify the original filename.\n3. **Unsupported file types:** Reject immediately with a clear message. Do NOT ask user \"do you still want to try?\" Video files, Bilibili/YouTube URLs, and `file://` URLs are not supported — tell user to use IMA desktop client.\n4. **File upload integrity:** Keep file content as-is during upload. No encoding conversion for binary files (PDF, images, Excel, etc.).\n5. **PowerShell 5.1 (all modules):** If running in PowerShell, detect version before first API call. PS 5.1 silently converts request Body to GBK — must use UTF-8 byte array mode. See [Detailed Rules](#powershell-51-environment-detection).\n\n## 模块决策表\n\n| 用户意图                                                                                   | 模块           | 读取                      |\n| ------------------------------------------------------------------------------------------ | -------------- | ------------------------- |\n| 搜索笔记、浏览笔记本、获取笔记内容、创建笔记、追加内容                                     | notes          | `notes/SKILL.md`          |\n| 上传文件、添加网页链接、搜索知识库、浏览知识库内容、获取知识库信息、获取可添加的知识库列表 | knowledge-base | `knowledge-base/SKILL.md` |\n| 查看原文、分析原文、导出原文（需要 media_id）                                              | knowledge-base | `knowledge-base/SKILL.md` |\n\n### ⚠️ 易混淆场景\n\n| 用户说的                                                 | 实际意图                 | 正确路由                                                    |\n| -------------------------------------------------------- | ------------------------ | ----------------------------------------------------------- |\n| \"把这段内容添加到知识库XX里的笔记YY\"                     | 往已有**笔记**追加内容   | **notes** — 先搜索笔记获取 `note_id`，再用 `append_doc`     |\n| \"把这个写到XX笔记里\"、\"记到XX笔记\"                       | 往已有**笔记**追加内容   | **notes** — `append_doc`                                    |\n| \"把这篇笔记添加到知识库\"                                 | 将笔记关联到**知识库**   | **knowledge-base** — `add_knowledge` with `media_type=11`   |\n| \"上传文件到知识库\"                                       | 上传**文件**到知识库     | **knowledge-base** — `create_media` → COS → `add_knowledge` |\n| \"新建一篇笔记记录这些内容\"                               | **创建**新笔记           | **notes** — `import_doc`                                    |\n| \"帮我记一下\"、\"记录一下\"、\"保存为笔记\"（未指定已有笔记） | 意图不明确，**需要确认** | **notes** — 先询问用户是创建新笔记还是追加到哪篇已有笔记    |\n| \"添加到笔记里\"（未指定具体哪篇）                         | 意图不明确，**需要确认** | **notes** — 先询问用户是创建新笔记还是追加到哪篇已有笔记    |\n\n### ⚠️ 跨模块任务 — 必须读取两个子模块\n\n某些意图跨越 notes 和 knowledge-base 两个模块。**不要只读取一个子模块就开始执行**，必须先读取两个模块的 SKILL.md 再按顺序操作。\n\n| 用户说的                             | 实际流程                                      | 读取顺序                                               |\n| ------------------------------------ | --------------------------------------------- | ------------------------------------------------------ |\n| \"把知识库里的XX内容记到笔记\"         | KB 搜索/读取 → Notes 创建/追加                | 先读 `knowledge-base/SKILL.md` → 再读 `notes/SKILL.md` |\n| \"查看原文\"（知识库中的笔记类型媒体） | KB `get_media_info` → Notes `get_doc_content` | 先读 `knowledge-base/SKILL.md` → 再读 `notes/SKILL.md` |\n| \"把这篇笔记添加到知识库\"             | Notes 搜索获取 note_id → KB `add_knowledge`   | 先读 `notes/SKILL.md` → 再读 `knowledge-base/SKILL.md` |\n\n**规则**：如果用户意图同时涉及「笔记」和「知识库」，或者 API 响应揭示需要另一个模块（如 `media_type=11` 表示笔记类型），必须读取两个子模块再继续。\n\n**核心判断规则**：\n\n- 目标是**笔记的内容**（读、写、追加）→ notes 模块\n- 目标是**知识库的条目**（上传文件、添加链接、关联笔记到知识库）→ knowledge-base 模块\n- 目标是**获取知识库条目的原始内容**（查看原文、分析原文、导出原文）→ knowledge-base 模块（若原文是笔记，会跨模块到 notes `get_doc_content`）\n- 用户提到\"知识库\"只是在**描述笔记的位置**（如\"知识库里的那篇笔记\"），真正操作对象仍是笔记 → notes 模块\n\n## Credential Check\n\n!`test -f ~/.config/ima/client_id && test -f ~/.config/ima/api_key && echo \"✅ Credentials configured\" || echo \"⚠️ NO CREDENTIALS — setup required before any API call\"`\n\n**If ⚠️ NO CREDENTIALS:** Guide the user through setup BEFORE attempting any API call:\n\n1. 打开 https://ima.qq.com/agent-interface 获取 **Client ID** 和 **API Key**\n2. 存储凭证（二选一）：\n\n**方式 A — 配置文件（推荐）：**\n\n```bash\nmkdir -p ~/.config/ima\necho \"your_client_id\" > ~/.config/ima/client_id\necho \"your_api_key\" > ~/.config/ima/api_key\n```\n\n**方式 B — 环境变量：**\n\n```bash\nexport IMA_OPENAPI_CLIENTID=\"your_client_id\"\nexport IMA_OPENAPI_APIKEY=\"your_api_key\"\n```\n\nAgent 会按优先级依次尝试：环境变量 → 配置文件。缺少凭证时，`node ima_api.cjs ...` 会以程序错误退出（`code: -100`），并在 stderr 输出对应 `msg`。\n\n> **Security note:** Credentials are only sent as HTTP headers to `ima.qq.com` and never to any other domain, file, or log.\n> **Runtime dependencies:** Check `meta.json` → `required_binaries`\n\n## API 调用模板\n\n所有请求统一为 **HTTP POST + JSON Body**，仅发往官方 Base URL `https://ima.qq.com`。\n\n`ima_api` 已抽离到脚本：`./ima_api.cjs`\n\n```bash\n# Example usage (cross-platform, pass credentials via options JSON)\nSKILL_DIR=\"$(cd \"$(dirname \"${BASH_SOURCE[0]:-$0}\")\" && pwd)\"\nOPTS=$(printf '{\"clientId\":\"%s\",\"apiKey\":\"%s\"}' \"$IMA_OPENAPI_CLIENTID\" \"$IMA_OPENAPI_APIKEY\")\n\n# stdout 返回正常响应；stderr 返回结构化错误 {\"code\":-100|-200,\"msg\":\"...\"}\nif ! resp=$(node \"$SKILL_DIR/ima_api.cjs\" \"openapi/list_docs\" '{\"limit\":10}' \"$OPTS\" 2>/tmp/ima_err); then\n  err_json=$(cat /tmp/ima_err)\n  err_code=$(echo \"$err_json\" | jq -r '.code // empty' 2>/dev/null)\n  err_msg=$(echo \"$err_json\" | jq -r '.msg // empty' 2>/dev/null)\n\n  if [ \"$err_code\" = \"-200\" ]; then\n    # 有新版本，原请求未发送；stdout 中带有更新上下文 JSON（含 instruction）\n    echo \"[update] $err_msg\" >&2\n  else\n    # -100 或其他程序错误：msg 已包含可直接展示给用户的说明\n    echo \"[error] $err_msg\" >&2\n  fi\n  exit 1\nfi\n\necho \"$resp\"\n```\n\n> **错误处理有两层，必须都检查：**\n>\n> **第一层 — 脚本执行错误**（进程非 0 退出，错误在 **stderr**）：\n>\n> - `-100`：程序错误（缺少凭证、参数非法、网络错误等），`msg` 可直接展示给用户\n> - `-200`：skill 需要更新，原请求未发送，stdout 中有更新上下文 JSON\n>\n> **第二层 — 后端业务错误**（进程正常退出，响应在 **stdout**）：\n>\n> - stdout 返回 JSON `{\"code\": 0, \"msg\": \"...\", \"data\": {...}}`\n> - `code=0` 表示成功，从 `data` 提取业务字段\n> - `code≠0` 表示后端业务错误（如参数不合法、权限不足、资源不存在等），**直接将 `msg` 展示给用户**\n> - 常见后端错误码见各子模块的「错误处理」章节\n\n## SKILL Update\n\n`ima_api` 已内置更新检查：默认**每天首次 API 调用自动检查一次**，同一天内不会重复检查。\n\n- `latest_version`：最新版本号，格式为 `MAJOR.MINOR.PATCH`\n- `release_desc`：最新版本发布说明\n- `instruction`：更新指引（prompt 文本）\n\n### 错误返回与后续处理\n\n> 出错时进程以非 0 退出，并在 **stderr** 输出结构化 JSON：`{\"code\":-100|-200,\"msg\":\"具体错误描述\"}`。\n\n- `-200`（skill 需要更新）\n  - 含义：检测到可用更新，原请求**未发送**\n  - 后续处理：从 `ima_api.cjs` 的 stdout 读取更新上下文 JSON，根据其中 `instruction`（prompt）引导用户完成更新，然后重试原请求\n- `-100`（程序错误，兜底）\n  - 含义：其他所有错误（缺少凭证、参数非法、缺少 apiPath、网络错误等）\n  - 后续处理：直接读取 `msg` 向用户展示；`msg` 已指出具体原因与修复建议\n\n> 更新检查调用本身失败时，会**直接跳过本次检查并继续原请求**，不会抛错。\n\n如需主动触发（忽略\"每天一次\"限制），可在调用前设置：\n\n```bash\nexport IMA_FORCE_UPDATE_CHECK=1\n```\n\n---\n\n## Detailed Rules Reference\n\n> The sections below contain full platform-specific examples for the mandatory rules above. Refer to these when you need implementation details.\n\n### Detailed UTF-8 Encoding Rules\n\n> **此规则为强制性要求，不可跳过。** 非法编码会导致内容在 IMA 中显示为乱码，且无法修复，必须重新写入。\n>\n> **适用范围：notes 模块**（`import_doc`、`append_doc` 等文本写入 API）。\n>\n> **不适用于 knowledge-base 模块的文件上传**：上传文件时必须保持文件原始内容，不得转码。文件以二进制方式上传，服务端自行处理。\n\n**每次调用 notes 写入类 API（`import_doc`/`append_doc`）之前，必须对 `content`、`title` 等所有字符串字段执行 UTF-8 编码校验/转换。** 无论内容来源如何——用户直接输入、从文件读取、WebFetch 抓取、剪贴板粘贴、外部 API 返回——都不能假设已经是合法 UTF-8，必须显式确认。\n\n#### 强制检查清单（notes 模块写入前）\n\n在构造 notes 写入请求的 body **之前**，完成以下步骤：\n\n1. **来自文件的内容**：先检测文件编码，转为 UTF-8 后再读入变量（注意：这是指读取文件内容作为笔记正文写入，不是上传文件到知识库）\n2. **来自 WebFetch / HTTP 请求的内容**：响应可能为 GBK/Latin-1 等，必须转码\n3. **来自用户输入或变量拼接的内容**：清洗非法 UTF-8 字节（`\\xff\\xfe` 等）\n4. **标题字段同理**：`title` 也必须为合法 UTF-8\n\n#### 各环境转码方法\n\n**Python（推荐，几乎所有环境都有）：**\n\n```bash\n# 读取文件，自动检测编码并转为 UTF-8\ncontent=$(python3 -c \"\nimport sys\ndata = open('tmpfile', 'rb').read()\nfor enc in ['utf-8', 'gbk', 'gb2312', 'big5', 'latin-1']:\n    try:\n        sys.stdout.write(data.decode(enc))\n        break\n    except (UnicodeDecodeError, LookupError):\n        continue\n\" 2>/dev/null)\n\n# 如果内容已在变量中，清洗非法 UTF-8 字节\ncontent=$(printf '%s' \"$content\" | python3 -c \"import sys; sys.stdout.write(sys.stdin.buffer.read().decode('utf-8','ignore'))\")\n```\n\n**Node.js：**\n\n```bash\ncontent=$(node -e \"const fs=require('fs');const buf=fs.readFileSync('tmpfile');process.stdout.write(buf.toString('utf8'))\")\n# 已知编码（如 GBK）：\ncontent=$(node -e \"const fs=require('fs');process.stdout.write(new TextDecoder('gbk').decode(fs.readFileSync('tmpfile')))\")\n```\n\n**Unix (macOS/Linux)：**\n\n```bash\ncontent=$(iconv -f \"$(file -b --mime-encoding tmpfile)\" -t UTF-8 tmpfile 2>/dev/null || cat tmpfile)\n```\n\n**Windows PowerShell：**\n\n```powershell\n# 读取非 UTF-8 文件并转码\n$content = [System.IO.File]::ReadAllText('tmpfile', [System.Text.Encoding]::Default)\n[System.IO.File]::WriteAllText('tmpfile.utf8', $content, [System.Text.Encoding]::UTF8)\n```\n\n### PowerShell 5.1 Environment Detection\n\n> **此问题影响所有 API 调用（notes、knowledge-base 等）**\n>\n> **此问题极其隐蔽：PowerShell 5.1 下 `Invoke-RestMethod` 会静默将请求 Body 从 UTF-8 转为系统 ANSI 编码（中文 Windows 为 GBK），即使设置了 `Content-Type: charset=utf-8` 也无效。结果是请求看起来发送成功，但服务端收到的内容已经是乱码，且无任何错误提示。**\n\n**当 agent 运行在 PowerShell 环境时，必须在首次 API 调用前检测版本：**\n\n```powershell\n# 检测 PowerShell 版本 — 在任何 API 调用之前执行（notes 和 knowledge-base 都需要）\nif ($PSVersionTable.PSVersion.Major -le 5) {\n    Write-Host \"⚠️ 检测到 PowerShell 5.1，将使用 UTF-8 字节数组模式发送请求\"\n    $useUtf8Bytes = $true\n} else {\n    Write-Host \"✅ PowerShell 7+，默认 UTF-8，无需额外处理\"\n    $useUtf8Bytes = $false\n}\n```\n\n**PowerShell 5.1 下必须使用以下方式发送请求**（用 `ConvertTo-Json` 构建 JSON 以避免手动拼接的转义风险，再显式转为 UTF-8 字节数组）：\n\n```powershell\n# PowerShell 5.1 安全请求模板（适用于所有模块的所有 API 调用）\n$body = @{ title = \"标题\"; content = $content; content_format = 1 } | ConvertTo-Json -Depth 10\nif ($useUtf8Bytes) {\n    # CRITICAL: 必须转为字节数组，否则中文/非ASCII内容会变成乱码\n    $utf8Bytes = [System.Text.Encoding]::UTF8.GetBytes($body)\n    Invoke-RestMethod -Uri $url -Method Post -Body $utf8Bytes -ContentType \"application/json; charset=utf-8\" -Headers $headers\n} else {\n    # PowerShell 7+ 可直接传字符串\n    Invoke-RestMethod -Uri $url -Method Post -Body $body -ContentType \"application/json; charset=utf-8\" -Headers $headers\n}\n```\n\n> **总结：** 在 PowerShell 5.1 环境中，**所有** API 调用（无论 notes 还是 knowledge-base）都必须将 Body 显式转为 UTF-8 字节数组。不检测版本直接发请求 = 中文内容必乱码。这是 PowerShell 5.1 的已知设计缺陷，不是 bug 可以被修复。\n\nFile v1.1.7:_meta.json\n\n{\n  \"ownerId\": \"kn7fpa7e88ngzptwrczstadp5h831pc9\",\n  \"slug\": \"ima-skills\",\n  \"version\": \"1.1.7\",\n  \"publishedAt\": 1777025159209\n}\n\nFile v1.1.7:knowledge-base/references/api.md\n\n# IMA知识库 API\n\n## ⚠️ 必读约束\n\n### 🌐 服务信息\n\n- **Base URL **：`https://ima.qq.com`\n- **Base Path**：`/openapi/wiki/v1`\n- **协议**：HTTP POST，JSON body\n- **完整示例**：`POST https://ima.qq.com/openapi/wiki/v1/get_knowledge_base`\n\n### 🔒 认证\n\n所有请求必须携带 Header：\n\n| Header                 | 说明               |\n| ---------------------- | ------------------ |\n| `ima-openapi-clientid` | Client ID          |\n| `ima-openapi-apikey`   | API Key            |\n| `Content-Type`         | `application/json` |\n\n---\n\n## 快速决策\n\n| 用户意图                             | 接口                                                                   |\n| ------------------------------------ | ---------------------------------------------------------------------- |\n| 「上传文件到知识库」                 | `check_repeated_names` → `create_media` → COS Upload → `add_knowledge` |\n| 「上传文件到指定文件夹」             | 先定位文件夹 → 同上（传入 `folder_id`）                                |\n| 「添加网页/微信文章到知识库」        | `import_urls`                                                          |\n| 「获取知识库信息」                   | `get_knowledge_base`                                                   |\n| 「浏览知识库内容 / 浏览文件夹」      | `get_knowledge_list`（可传 `folder_id` 进入子文件夹）                  |\n| 「在知识库中搜索」                   | `search_knowledge`                                                     |\n| 「搜索知识库列表」                   | `search_knowledge_base`                                                |\n| 「获取可添加的知识库列表」           | `get_addable_knowledge_base_list`                                      |\n| 「检查文件名是否重复」               | `check_repeated_names`                                                 |\n| 「查看原文」「分析原文」「导出原文」 | `get_media_info`                                                       |\n\n---\n\n## 数据结构\n\n### KnowledgeBaseInfo（知识库信息）\n\n| 字段                    | 类型     | 说明          |\n| ----------------------- | -------- | ------------- |\n| `id`                    | string   | 知识库唯一 ID |\n| `name`                  | string   | 知识库名称    |\n| `cover_url`             | string   | 封面图 URL    |\n| `description`           | string   | 描述          |\n| `recommended_questions` | string[] | 推荐问题列表  |\n\n### KnowledgeInfo（知识条目）\n\n| 字段               | 类型   | 说明          |\n| ------------------ | ------ | ------------- |\n| `media_id`         | string | 媒体 ID       |\n| `title`            | string | 标题          |\n| `parent_folder_id` | string | 所属文件夹 ID |\n\n### FolderInfo（文件夹条目）\n\n| 字段               | 类型   | 说明        |\n| ------------------ | ------ | ----------- |\n| `folder_id`        | string | 文件夹 ID   |\n| `name`             | string | 文件夹名称  |\n| `file_number`      | int64  | 文件数      |\n| `folder_number`    | int64  | 子文件夹数  |\n| `parent_folder_id` | string | 父文件夹 ID |\n| `is_top`           | bool   | 是否置顶    |\n\n### AddableKnowledgeBaseInfo（可添加的知识库信息）\n\n| 字段   | 类型   | 说明       |\n| ------ | ------ | ---------- |\n| `id`   | string | 知识库 ID  |\n| `name` | string | 知识库名称 |\n\n### SearchedKnowledgeBaseInfo（搜索到的知识库信息）\n\n| 字段        | 类型   | 说明       |\n| ----------- | ------ | ---------- |\n| `id`        | string | 知识库 ID  |\n| `name`      | string | 知识库名称 |\n| `cover_url` | string | 封面图 URL |\n\n### SearchedKnowledgeInfo（搜索到的知识条目）\n\n| 字段                | 类型   | 说明                       |\n| ------------------- | ------ | -------------------------- |\n| `media_id`          | string | 媒体 ID                    |\n| `title`             | string | 标题                       |\n| `parent_folder_id`  | string | 所属文件夹 ID              |\n| `highlight_content` | string | 高亮内容（内容匹配时返回） |\n\n### ContentInfo（内容信息）\n\n| 字段         | 类型   | 说明                    |\n| ------------ | ------ | ----------------------- |\n| `content_id` | string | 内容 ID（网页时为 URL） |\n\n### ImportURLData（URL 导入结果）\n\n| 字段       | 类型   | 说明                    |\n| ---------- | ------ | ----------------------- |\n| `url`      | string | 导入的 URL              |\n| `ret_code` | int32  | 0=成功，非 0=失败       |\n| `media_id` | string | 导入成功后返回的媒体 ID |\n\n### URLInfo（访问链接信息）\n\n| 字段      | 类型                  | 说明                                                      |\n| --------- | --------------------- | --------------------------------------------------------- |\n| `url`     | string                | 访问链接                                                  |\n| `headers` | map\\<string, string\\> | 访问链接所需 header，非空时需在请求 url 时同时传入 header |\n\n### NotebookExtInfo（笔记扩展信息）\n\n| 字段          | 类型   | 说明    |\n| ------------- | ------ | ------- |\n| `notebook_id` | string | 笔记 ID |\n\n### FileInfo（文件信息）\n\n`add_knowledge` 文件上传时使用：\n\n| 字段               | 类型   | 说明                       |\n| ------------------ | ------ | -------------------------- |\n| `cos_key`          | string | COS 对象 Key               |\n| `file_size`        | uint64 | 文件大小（字节）           |\n| `last_modify_time` | int64  | 最后修改时间（秒级时间戳） |\n| `password`         | string | 文件密码（如有）           |\n| `file_name`        | string | 文件名称                   |\n\n### Credential（COS 上传凭证）\n\n`create_media` 返回，用于上传文件到腾讯云 COS：\n\n| 字段            | 类型   | 说明                       |\n| --------------- | ------ | -------------------------- |\n| `token`         | string | 临时 TOKEN                 |\n| `secret_id`     | string | 临时 Secret ID             |\n| `secret_key`    | string | 临时 Secret Key            |\n| `start_time`    | int64  | 凭证开始时间（秒级时间戳） |\n| `expired_time`  | int64  | 凭证过期时间（秒级时间戳） |\n| `appid`         | string | COS AppID                  |\n| `bucket_name`   | string | COS 桶名称                 |\n| `region`        | string | COS 桶所在区域             |\n| `custom_domain` | string | 自定义域名                 |\n| `cos_key`       | string | COS 对象 Key               |\n\n### MediaType（媒体类型枚举）\n\n| 值  | 名称           | content_type / 说明                                                                                           |\n| --- | -------------- | ------------------------------------------------------------------------------------------------------------- |\n| 1   | PDF            | `application/pdf`                                                                                             |\n| 2   | 网页           | N/A（直接 AddKnowledge，`web_info.content_id=<url>`）                                                         |\n| 3   | Word           | `application/msword` / `application/vnd.openxmlformats-officedocument.wordprocessingml.document`              |\n| 4   | PPT            | `application/vnd.ms-powerpoint` / `application/vnd.openxmlformats-officedocument.presentationml.presentation` |\n| 5   | Excel          | `application/vnd.ms-excel` / `application/vnd.openxmlformats-officedocument.spreadsheetml.sheet` / `text/csv` |\n| 6   | 微信公众号文章 | N/A（直接 AddKnowledge，`web_info.content_id=<url>`，URL 匹配 `mp.weixin.qq.com/s`）                          |\n| 7   | MarkDown       | `text/markdown` / `text/x-markdown` / `application/md` / `application/markdown`                               |\n| 9   | 图片           | `image/png`, `image/jpeg`, `image/webp`                                                                       |\n| 11  | 笔记           | N/A（直接 AddKnowledge，`note_info.content_id=<doc_id>`）                                                     |\n| 12  | AI会话         | N/A（直接 AddKnowledge，`session_info.content_id=<session_id>`）                                              |\n| 13  | TXT            | `text/plain`                                                                                                  |\n| 14  | Xmind          | `application/x-xmind` / `application/vnd.xmind.workbook` / `application/zip`                                  |\n| 15  | 录音           | `audio/mpeg`(mp3), `audio/x-m4a`(m4a), `audio/wav`(wav), `audio/aac`(aac)                                     |\n| 16  | 视频解析       | **不支持通过 skill 添加**。Bilibili/YouTube/本地HTML等仅支持在 ima 桌面端内添加进知识库                       |\n\n---\n\n## 接口详情\n\n### 1. 创建媒体\n\nPOST /openapi/wiki/v1/create_media\n\n**触发场景**：上传文件到知识库的第一步，获取 COS 上传凭证。\n\n#### 请求参数\n\n| 字段                | 类型   | 必填 | 说明                           |\n| ------------------- | ------ | ---- | ------------------------------ |\n| `file_name`         | string | 是   | 文件名称（最长 1024 字符）     |\n| `file_size`         | uint64 | 是   | 文件大小（字节）               |\n| `content_type`      | string | 是   | MIME 类型                      |\n| `knowledge_base_id` | string | 是   | 知识库 ID                      |\n| `file_ext`          | string | 是   | 文件后缀名（无点号，如 `pdf`） |\n\n#### 返回字段\n\n| 字段             | 类型       | 说明         |\n| ---------------- | ---------- | ------------ |\n| `media_id`       | string     | 媒体 ID      |\n| `cos_credential` | Credential | COS 上传凭证 |\n\n---\n\n### 2. 添加知识\n\nPOST /openapi/wiki/v1/add_knowledge\n\n**触发场景**：上传文件到知识库的最后一步，或直接添加网页 URL。\n\n#### 请求参数\n\n| 字段                  | 类型        | 必填     | 说明                                    |\n| --------------------- | ----------- | -------- | --------------------------------------- |\n| `media_type`          | int32       | 是       | 媒体类型                                |\n| `media_id`            | string      | 否       | 文件上传时必填，CreateMedia 返回的 ID   |\n| `title`               | string      | 是       | 标题                                    |\n| `knowledge_base_id`   | string      | 是       | 知识库 ID                               |\n| `folder_id`           | string      | 否       | 文件夹 ID（省略则添加到根目录）         |\n| `note_info`           | ContentInfo | 否       | 笔记内容信息                            |\n| `web_info`            | ContentInfo | 否       | 网页内容信息（media_type=2 时必填）     |\n| `web_info.content_id` | string      | 条件必填 | 网页 URL（media_type=2 时必填）         |\n| `session_info`        | ContentInfo | 否       | 会话内容信息                            |\n| `file_info`           | FileInfo    | 否       | 文件信息（文件上传时必填，见 FileInfo） |\n\n#### 返回字段\n\n| 字段       | 类型   | 说明    |\n| ---------- | ------ | ------- |\n| `media_id` | string | 媒体 ID |\n\n---\n\n### 3. 获取知识库信息\n\nPOST /openapi/wiki/v1/get_knowledge_base\n\n#### 请求参数\n\n| 字段  | 类型     | 必填 | 说明                              |\n| ----- | -------- | ---- | --------------------------------- |\n| `ids` | string[] | 是   | 知识库 ID 列表（1-20 个，不重复） |\n\n#### 返回字段\n\n| 字段    | 类型                             | 说明           |\n| ------- | -------------------------------- | -------------- |\n| `infos` | map\\<string, KnowledgeBaseInfo\\> | 知识库信息映射 |\n\n---\n\n### 4. 浏览知识库内容\n\nPOST /openapi/wiki/v1/get_knowledge_list\n\n#### 请求参数\n\n| 字段                | 类型   | 必填 | 说明                          |\n| ------------------- | ------ | ---- | ----------------------------- |\n| `cursor`            | string | 是   | 游标，首次传空字符串          |\n| `limit`             | uint64 | 是   | 数量限制（1-50）              |\n| `knowledge_base_id` | string | 是   | 知识库 ID                     |\n| `folder_id`         | string | 否   | 文件夹 ID（省略则列出根目录） |\n\n#### 返回字段\n\n| 字段             | 类型            | 说明             |\n| ---------------- | --------------- | ---------------- |\n| `knowledge_list` | KnowledgeInfo[] | 知识条目列表     |\n| `is_end`         | bool            | 是否到达列表末尾 |\n| `next_cursor`    | string          | 下页游标         |\n| `current_path`   | FolderInfo[]    | 当前路径         |\n\n---\n\n### 5. 搜索知识库内容\n\nPOST /openapi/wiki/v1/search_knowledge\n\n#### 请求参数\n\n| 字段                | 类型   | 必填 | 说明                 |\n| ------------------- | ------ | ---- | -------------------- |\n| `query`             | string | 是   | 搜索关键词           |\n| `cursor`            | string | 是   | 游标，首次传空字符串 |\n| `knowledge_base_id` | string | 是   | 知识库 ID            |\n\n#### 返回字段\n\n| 字段          | 类型                    | 说明                                                                     |\n| ------------- | ----------------------- | ------------------------------------------------------------------------ |\n| `info_list`   | SearchedKnowledgeInfo[] | 搜索结果（`media_id`, `title`, `parent_folder_id`, `highlight_content`） |\n| `is_end`      | bool                    | 是否到达列表末尾                                                         |\n| `next_cursor` | string                  | 下页游标                                                                 |\n\n---\n\n### 6. 搜索知识库列表\n\nPOST /openapi/wiki/v1/search_knowledge_base\n\n#### 请求参数\n\n| 字段     | 类型   | 必填 | 说明                 |\n| -------- | ------ | ---- | -------------------- |\n| `query`  | string | 是   | 搜索关键词           |\n| `cursor` | string | 是   | 游标，首次传空字符串 |\n| `limit`  | uint64 | 是   | 数量限制（1-20）     |\n\n#### 返回字段\n\n| 字段          | 类型                        | 说明                                  |\n| ------------- | --------------------------- | ------------------------------------- |\n| `info_list`   | SearchedKnowledgeBaseInfo[] | 搜索结果（`id`, `name`, `cover_url`） |\n| `is_end`      | bool                        | 是否到达列表末尾                      |\n| `next_cursor` | string                      | 下页游标                              |\n\n---\n\n### 7. 获取可添加的知识库列表\n\nPOST /openapi/wiki/v1/get_addable_knowledge_base_list\n\n**触发场景**：用户想上传文件或添加内容到知识库，但不确定可以添加到哪些知识库时，列出当前用户有权限添加内容的知识库。\n\n#### 请求参数\n\n| 字段     | 类型   | 必填 | 说明                 |\n| -------- | ------ | ---- | -------------------- |\n| `cursor` | string | 是   | 游标，首次传空字符串 |\n| `limit`  | uint64 | 是   | 数量限制（1-50）     |\n\n#### 返回字段\n\n| 字段                          | 类型                       | 说明                   |\n| ----------------------------- | -------------------------- | ---------------------- |\n| `addable_knowledge_base_list` | AddableKnowledgeBaseInfo[] | 可添加内容的知识库列表 |\n| `next_cursor`                 | string                     | 下页游标               |\n| `is_end`                      | bool                       | 是否到达列表末尾       |\n\n---\n\n### 8. 检查文件名重复\n\nPOST /openapi/wiki/v1/check_repeated_names\n\n**触发场景**：上传文件到知识库前，检查目标知识库（及文件夹）中是否已存在同名文件。仅用于文件类型（media_type 1/3/4/5/7/9/13/14），不用于网页（2/6）、笔记（11）等。\n\n#### 请求参数\n\n| 字段                | 类型                      | 必填 | 说明                          |\n| ------------------- | ------------------------- | ---- | ----------------------------- |\n| `params`            | CheckRepeatedNamesParam[] | 是   | 待检查的文件列表（1-2000 个） |\n| `knowledge_base_id` | string                    | 是   | 知识库 ID                     |\n| `folder_id`         | string                    | 否   | 文件夹 ID（省略则检查根目录） |\n\n**CheckRepeatedNamesParam：**\n\n| 字段         | 类型   | 说明                          |\n| ------------ | ------ | ----------------------------- |\n| `name`       | string | 文件名称                      |\n| `media_type` | int32  | 媒体类型（见 MediaType 枚举） |\n\n#### 返回字段\n\n| 字段      | 类型                       | 说明     |\n| --------- | -------------------------- | -------- |\n| `results` | CheckRepeatedNamesResult[] | 检查结果 |\n\n**CheckRepeatedNamesResult：**\n\n| 字段          | 类型   | 说明                      |\n| ------------- | ------ | ------------------------- |\n| `name`        | string | 文件名称                  |\n| `is_repeated` | bool   | `true` 表示同名文件已存在 |\n\n---\n\n### 9. 导入 URL\n\nPOST /openapi/wiki/v1/import_urls\n\n**触发场景**：添加网页或微信公众号文章到知识库。替代 `add_knowledge` 的 `media_type=2/6` 用法，支持批量导入，服务端自动识别 URL 类型。\n\n#### 请求参数\n\n| 字段                | 类型     | 必填 | 说明                                |\n| ------------------- | -------- | ---- | ----------------------------------- |\n| `knowledge_base_id` | string   | 是   | 知识库 ID                           |\n| `folder_id`         | string   | 是   | 文件夹 ID                           |\n| `urls`              | string[] | 是   | URL 列表（1-10 个，每个非空字符串） |\n\n#### 返回字段\n\n| 字段      | 类型                         | 说明                                      |\n| --------- | ---------------------------- | ----------------------------------------- |\n| `results` | map\\<string, ImportURLData\\> | URL→结果映射（含 `ret_code`、`media_id`） |\n\n---\n\n### 10. 获取媒体信息\n\nPOST /openapi/wiki/v1/get_media_info\n\n**触发场景**：用户想查看原文、分析原文、导出原文时，通过 `media_id` 获取媒体的访问信息。\n\n#### 请求参数\n\n| 字段       | 类型   | 必填 | 说明                |\n| ---------- | ------ | ---- | ------------------- |\n| `media_id` | string | 是   | 媒体 ID（不可为空） |\n\n#### 响应示例\n\n**成功 — URL 类型媒体：**\n\n```json\n{\n  \"code\": 0,\n  \"msg\": \"success\",\n  \"data\": {\n    \"media_type\": 1,\n    \"url_info\": {\n      \"url\": \"https://example.com/file.pdf\",\n      \"headers\": {\n        \"Authorization\": \"Bearer xxx\"\n      }\n    }\n  }\n}\n```\n\n**成功 — 笔记类型媒体（media_type=11）：**\n\n```json\n{\n  \"code\": 0,\n  \"msg\": \"success\",\n  \"data\": {\n    \"media_type\": 11,\n    \"notebook_ext_info\": {\n      \"notebook_id\": \"abc123\"\n    }\n  }\n}\n```\n\n**成功 — 不可访问（无 url_info）：**\n\n```json\n{\n  \"code\": 0,\n  \"msg\": \"success\",\n  \"data\": {\n    \"media_type\": 1\n  }\n}\n```\n\n**失败：**\n\n```json\n{\n  \"code\": 110001,\n  \"msg\": \"参数非法\",\n  \"data\": {}\n}\n```\n\n#### 返回字段（`data` 内）\n\n| 字段                | 类型            | 说明                                                                                              |\n| ------------------- | --------------- | ------------------------------------------------------------------------------------------------- |\n| `media_type`        | int32           | 媒体类型（见 MediaType 枚举）                                                                     |\n| `url_info`          | URLInfo         | 访问链接信息，非笔记类型时填写（见 [URLInfo](#urlinfo访问链接信息)）                              |\n| `notebook_ext_info` | NotebookExtInfo | 笔记扩展信息，`media_type=11`（笔记）时填写（见 [NotebookExtInfo](#notebookextinfo笔记扩展信息)） |\n\n#### 响应分支说明\n\n| 场景                                   | 响应特征                                                             | 处理方式                                                                     |\n| -------------------------------------- | -------------------------------------------------------------------- | ---------------------------------------------------------------------------- |\n| 媒体可通过 URL 访问                    | `code=0`，`data.url_info` 存在，`url` 非空                           | 使用 `url` 和 `headers`（如有）请求原文内容                                  |\n| 媒体是笔记类型                         | `code=0`，`data.media_type=11`，`notebook_ext_info.notebook_id` 存在 | 将 `notebook_id` 作为 `note_id` 调用 notes 模块的 `get_doc_content` 获取内容 |\n| 媒体不可访问（无 URL 或 URL 请求失败） | `code=0`，`data.url_info` 为空，或请求 `url` 返回非 200 状态         | 提示用户「请使用ima客户端查看原文」                                          |\n| API 调用失败                           | `code≠0`                                                             | 将 `msg` 展示给用户                                                          |\n\n---\n\n## 文件夹说明\n\n知识库内容以文件夹层级结构组织。文件夹是一种特殊的知识条目：\n\n- `get_knowledge_list` 返回结果中同时包含 **文件**（`KnowledgeInfo`）和 **文件夹**（`FolderInfo`），通过 `current_path` 字段可获取当前路径的面包屑信息\n- `search_knowledge` 搜索结果中也会包含匹配的文件夹\n- 所有支持 `folder_id` 参数的接口（`add_knowledge`、`import_urls`、`get_knowledge_list`、`check_repeated_names`），省略 `folder_id` 则操作根目录。**根目录的 folder_id 等于 knowledge_base_id**，当接口要求 `folder_id` 必填时（如 `import_urls`），传 `knowledge_base_id` 的值即可表示根目录\n- **定位文件夹**：当用户只提供文件夹名称时，使用 `search_knowledge` 按名称搜索，或用 `get_knowledge_list` 逐级浏览，从返回结果中找到目标文件夹的 ID\n\n---\n\n## Preflight Check\n\n使用 `scripts/preflight-check.cjs` 脚本自动完成类型检测和大小校验。脚本按以下优先级解析：\n\n1. **`--content-type` 已提供且可识别** → content-type 优先，直接使用\n2. **`--content-type` 不可识别** → 回退到扩展名\n3. **未提供 `--content-type`** → 使用扩展名\n4. **两者都无法识别** → 拒绝处理\n\n```bash\n# 有扩展名（自动推断）\nnode .claude/skills/ima-skill/knowledge-base/scripts/preflight-check.cjs --file report.pdf\n\n# 无扩展名或扩展名不可识别（需传入 content-type）\nnode .claude/skills/ima-skill/knowledge-base/scripts/preflight-check.cjs --file downloaded_file --content-type application/pdf\n```\n\n---\n\n## URL Type Detection\n\n添加 URL 到知识库时，需根据 URL 模式和 Content-Type 判断类型。\n\n**1. Content-Type 为 `text/html` 时，按 URL 模式区分：**\n\n| URL 模式                                            | media_type | 类型           | 处理方式                                                  |\n| --------------------------------------------------- | ---------- | -------------- | --------------------------------------------------------- |\n| 匹配 `mp.weixin.qq.com/s/` 或 `mp.weixin.qq.com/s?` | 6          | 微信公众号文章 | 使用 `import_urls`                                        |\n| 以 `https://www.bilibili.com/video/` 开头           | ❌ 16      | 视频网页       | **不支持**，告知用户「仅支持在 ima 桌面端内添加进知识库」 |\n| 以 `https://www.youtube.com/watch` 开头             | ❌ 16      | 视频网页       | **不支持**，告知用户「仅支持在 ima 桌面端内添加进知识库」 |\n| 以 `file://` 开头                                   | ❌         | 本地 HTML      | **不支持**，告知用户「仅支持在 ima 桌面端内添加进知识库」 |\n| 其他 `text/html` 页面                               | 2          | 普通网页       | 使用 `import_urls`                                        |\n\n**2. Content-Type 为文件类型时**：按 MediaType 枚举表处理。\n\n**3. 其他**：告知用户该类型不被支持。\n\n**已知文件型 URL 模式**：\n\n- `arxiv.org/pdf/*` → PDF\n- `*.pdf`、`*.docx`、`*.pptx`、`*.xlsx` 结尾 → 对应文件类型\n- GitHub raw 文件链接 → 按扩展名判断\n\n**文件名推断优先级**：Content-Disposition header → URL path → last URL segment + Content-Type extension\n\n---\n\n## 文件大小限制\n\n上传前必须校验文件大小，超限文件应在上传前拦截：\n\n| 文件类型                    | media_type  | 最大大小 |\n| --------------------------- | ----------- | -------- |\n| Excel、TXT、Xmind、Markdown | 5/13/14/7   | 10 MB    |\n| 图片                        | 9           | 30 MB    |\n| PDF、Word、PPT、音频及其他  | 1/3/4/15 等 | 200 MB   |\n\n网页（2/6）、笔记（11）等非文件类型无大小限制。音频文件额外限制：最长 2 小时。\n\n---\n\n## 响应格式\n\n所有 API 返回统一结构：\n\n```json\n{\n  \"code\": 0,\n  \"msg\": \"成功\",\n  \"data\": { ... }\n}\n```\n\n- `code=0`：成功，从 `data` 提取业务字段\n- `code≠0`：失败，**直接将 `msg` 展示给用户**，无需自行翻译错误码\n\n---\n\n## 游标翻页使用规范\n\n1. **首次请求**：`cursor` 传空字符串 `\"\"`\n2. 检查返回的 `is_end`：`false` 表示还有更多数据\n3. 将返回的 `next_cursor` 作为下次请求的 `cursor`\n4. `is_end = true` 时停止翻页\n\n---\n\n## 错误码\n\n| 错误码 | 说明         | 建议处理                 |\n| ------ | ------------ | ------------------------ |\n| 0      | 成功         | —                        |\n| 110001 | 参数非法     | 检查请求参数（详见 msg） |\n| 110002 | 配置非法     | 检查服务配置             |\n| 110010 | 下游网络错误 | 可重试                   |\n| 110011 | 下游逻辑错误 | 不可重试，详见 msg       |\n| 110012 | 接口无效     | 检查接口路径             |\n| 110013 | 客户端取消   | 检查请求是否超时         |\n| 110020 | 安全打击     | 检查内容是否违规         |\n| 110021 | 请求频控     | 降低请求频率后重试       |\n| 110030 | 无权限       | 确认操作权限             |\n\nFile v1.1.7:notes/references/api.md\n\n# IMA笔记 API\n\n## ⚠️ 必读约束\n\n### 🔒 认证\n\n所有请求必须携带 Header：\n\n```\nima-openapi-clientid: {IMA_OPENAPI_CLIENTID}\nima-openapi-apikey: {IMA_OPENAPI_APIKEY}\nContent-Type: application/json\n```\n\n### 🔒 安全规则\n\n- 笔记属于用户隐私，**不要在群聊中主动展示笔记内容**。\n- 仅响应授权用户的笔记操作请求。\n\n---\n\n## 快速决策\n\n| 用户意图                                                   | 接口别名                           |\n| ---------------------------------------------------------- | ---------------------------------- |\n| 「搜索笔记」「找包含XX的笔记」                             | `/openapi/note/v1/search_note`     |\n| 「查看笔记本列表」「列出笔记本」「有哪些笔记本」           | `/openapi/note/v1/list_notebook`   |\n| 「列出笔记」「查看XX笔记本里的笔记」                       | `/openapi/note/v1/list_note`       |\n| 「从markdown新建笔记」「导入笔记」「创建笔记」「生成笔记」 | `/openapi/note/v1/import_doc`      |\n| 「追加内容到笔记」「在笔记末尾添加」                       | `/openapi/note/v1/append_doc`      |\n| 「获取笔记纯文本」「读取笔记内容」                         | `/openapi/note/v1/get_doc_content` |\n\n---\n\n## 数据结构\n\n### 公共结构体\n\n---\n\n#### NoteBookInfo（笔记信息）\n\n| 字段            | 类型        | 说明                                                 |\n| --------------- | ----------- | ---------------------------------------------------- |\n| `note_id`       | string      | 笔记唯一 ID                                          |\n| `title`         | string      | 标题                                                 |\n| `summary`       | string      | 简介                                                 |\n| `create_time`   | int64       | 创建时间（Unix 毫秒）                                |\n| `modify_time`   | int64       | 修改时间（Unix 毫秒）                                |\n| `cover_image`   | string      | 封面缩略图 URL                                       |\n| `note_ext_info` | NoteExtinfo | 扩展字段，见 [NoteExtinfo](#noteextinfo笔记扩展字段) |\n\n---\n\n#### NoteExtinfo（笔记扩展字段）\n\n| 字段          | 类型   | 说明           |\n| ------------- | ------ | -------------- |\n| `folder_id`   | string | 所属笔记本 ID  |\n| `folder_name` | string | 所属笔记本名称 |\n\n---\n\n#### NoteFolderInfo（笔记本信息）\n\n| 字段               | 类型       | 说明                                                                                   |\n| ------------------ | ---------- | -------------------------------------------------------------------------------------- |\n| `folder_id`        | string     | 笔记本唯一 ID                                                                          |\n| `name`             | string     | 笔记本名称                                                                             |\n| `create_time`      | int64      | 创建时间（Unix 毫秒）                                                                  |\n| `modify_time`      | int64      | 修改时间（Unix 毫秒）                                                                  |\n| `note_number`      | int64      | 笔记本内笔记数量                                                                       |\n| `parent_folder_id` | string     | 上级笔记本 ID（支持嵌套）                                                              |\n| `folder_type`      | FolderType | 类型：`0`=USER_CREATE（用户自建），`1`=TOTAL（全部笔记），`2`=UN_CATEGORIZED（未分类） |\n\n---\n\n#### QueryInfo（搜索条件）\n\n| 字段      | 类型   | 说明           |\n| --------- | ------ | -------------- |\n| `title`   | string | 标题搜索关键词 |\n| `content` | string | 正文搜索关键词 |\n\n---\n\n#### SearchNoteInfo（搜索结果条目）\n\n| 字段             | 类型                  | 说明                                                             |\n| ---------------- | --------------------- | ---------------------------------------------------------------- |\n| `note_book_info` | NoteBookInfo          | 笔记信息，见 [NoteBookInfo](#notebookinfo笔记信息)               |\n| `highlightInfo`  | map\\<string, string\\> | 高亮匹配，key: `doc_title`，value: 包含 `<em>高亮词</em>` 的文本 |\n\n---\n\n### 请求/响应结构体\n\n---\n\n#### SearchNoteReq\n\n| 字段          | 类型       | 必填   | 说明                                                                  |\n| ------------- | ---------- | ------ | --------------------------------------------------------------------- |\n| `search_type` | SearchType | 否     | 检索方式，`0`=DOC_TITLE(默认)，`1`=DOC_CONTENT                        |\n| `sort_type`   | SortType   | 否     | 排序方式，`0`=MODIFY_TIME(默认)，`1`=CREATE_TIME，`2`=TITLE，`3`=SIZE |\n| `query_info`  | QueryInfo  | 否     | 搜索条件，见 [QueryInfo](#queryinfo搜索条件)                          |\n| `start`       | int64      | **是** | 翻页起始编号                                                          |\n| `end`         | int64      | **是** | 翻页终止编号，与 start 相差不超过 20                                  |\n\n#### SearchNoteRsp\n\n| 字段                | 类型             | 说明                                                           |\n| ------------------- | ---------------- | -------------------------------------------------------------- |\n| `search_note_infos` | SearchNoteInfo[] | 搜索结果列表，见 [SearchNoteInfo](#searchnoteinfo搜索结果条目) |\n| `is_end`            | bool             | 是否为最后一批数据                                             |\n| `total_hit_num`     | int64            | 检索命中结果总数                                               |\n\n---\n\n#### ListNoteReq\n\n| 字段        | 类型     | 必填   | 校验规则       | 说明                                                         |\n| ----------- | -------- | ------ | -------------- | ------------------------------------------------------------ |\n| `folder_id` | string   | 否     | tsecstr        | 笔记本 ID，为空则拉取全部笔记，根目录为 `user_list_{userid}` |\n| `sort_type` | SortType | 否     | —              | 排序方式，`0`=MODIFY_TIME(默认)                              |\n| `cursor`    | string   | **是** | tsecstr        | 游标，首次传空字符串 `\"\"`                                    |\n| `limit`     | uint64   | **是** | 0 < limit ≤ 20 | 每页数量                                                     |\n\n#### ListNoteRsp\n\n| 字段             | 类型           | 说明                                               |\n| ---------------- | -------------- | -------------------------------------------------- |\n| `note_book_list` | NoteBookInfo[] | 笔记列表，见 [NoteBookInfo](#notebookinfo笔记信息) |\n| `is_end`         | bool           | 是否为最后一批数据                                 |\n\n---\n\n#### GetNoteContentReq\n\n| 字段                    | 类型          | 必填   | 校验规则 | 说明                                                |\n| ----------------------- | ------------- | ------ | -------- | --------------------------------------------------- |\n| `note_id`               | string        | **是** | tsecstr  | 笔记唯一 ID，需要是本人的笔记                       |\n| `target_content_format` | ContentFormat | **是** | —        | `0`=PLAINTEXT(推荐)，`1`=MARKDOWN(不支持)，`2`=JSON |\n\n#### GetNoteContentRsp\n\n| 字段      | 类型   | 说明                                              |\n| --------- | ------ | ------------------------------------------------- |\n| `content` | string | 笔记文本内容（按 target_content_format 格式返回） |\n\n---\n\n#### ImportNoteReq\n\n| 字段             | 类型          | 必填   | 校验规则 | 说明                                        |\n| ---------------- | ------------- | ------ | -------- | ------------------------------------------- |\n| `content_format` | ContentFormat | **是** | —        | 固定为 `1`（MARKDOWN），目前仅支持 Markdown |\n| `content`        | string        | **是** | —        | Markdown 格式正文内容，不要传空值           |\n| `folder_id`      | string        | 否     | —        | 关联的笔记本 ID                             |\n| `folder_name`    | string        | 否     | —        | 关联的笔记本名称                            |\n\n#### ImportNoteRsp\n\n| 字段      | 类型   | 说明            |\n| --------- | ------ | --------------- |\n| `note_id` | string | 新笔记的唯一 ID |\n\n---\n\n#### AppendNoteReq\n\n| 字段             | 类型          | 必填   | 校验规则 | 说明                                    |\n| ---------------- | ------------- | ------ | -------- | --------------------------------------- |\n| `note_id`        | string        | **是** | tsecstr  | 目标笔记的唯一 ID，需要是本人的笔记     |\n| `content_format` | ContentFormat | **是** | —        | 固定为 `1`（MARKDOWN），仅支持 Markdown |\n| `content`        | string        | **是** | —        | 要追加的 Markdown 文本内容              |\n\n#### AppendNoteRsp\n\n| 字段      | 类型   | 说明              |\n| --------- | ------ | ----------------- |\n| `note_id` | string | 目标笔记的唯一 ID |\n\n---\n\n#### ListNoteFolderReq\n\n| 字段      | 类型   | 必填   | 校验规则       | 说明                                             |\n| --------- | ------ | ------ | -------------- | ------------------------------------------------ |\n| `cursor`  | string | **是** | tsecstr        | 游标，第一页传 `\"0\"`，后续传返回的 `next_cursor` |\n| `limit`   | uint64 | **是** | 0 < limit ≤ 20 | 每页数量                                         |\n| `version` | string | 否     | tsecstr        | 版本号，用后台返回的值，用于增量更新检查         |\n\n#### ListNoteFolderRsp\n\n| 字段                | 类型             | 说明                                                       |\n| ------------------- | ---------------- | ---------------------------------------------------------- |\n| `note_folder_infos` | NoteFolderInfo[] | 笔记本列表，见 [NoteFolderInfo](#notefolderinfo笔记本信息) |\n| `next_cursor`       | string           | 下次请求的起始游标                                         |\n| `is_end`            | bool             | 是否为最后一批数据                                         |\n| `next_version`      | string           | 版本号（可用于下次请求的 version 参数）                    |\n| `need_update`       | bool             | 对比 version 是否需要更新                                  |\n\n---\n\n## 接口详情\n\n> 每个接口的请求/响应结构体的完整字段定义见上方 [请求/响应结构体](#请求响应结构体) 部分。\n\n---\n\n### 1. SearchNote — 搜索笔记\n\nPOST /openapi/note/v1/search_note\n\n**触发场景**：用户说「搜索」「找笔记」「查找包含XX的内容」\n\n- **请求**：[SearchNoteReq](#searchnotereq)\n- **响应**：[SearchNoteRsp](#searchnotersp)\n\n---\n\n### 2. ListNote — 获取笔记列表\n\nPOST /openapi/note/v1/list_note\n\n**触发场景**：用户说「查看XX笔记本的笔记」「最近的笔记」「列出笔记」\n\n- **请求**：[ListNoteReq](#listnotereq)\n- **响应**：[ListNoteRsp](#listnotersp)\n\n---\n\n### 3. GetNoteContent — 获取笔记内容\n\nPOST /openapi/note/v1/get_doc_content\n\n**触发场景**：用户说「读取笔记内容」「获取这篇笔记的纯文本」\n\n> ⚠️ 需要用户是笔记作者\n\n- **请求**：[GetNoteContentReq](#getnotecontentreq)\n- **响应**：[GetNoteContentRsp](#getnotecontentrsp)\n\n---\n\n### 4. ImportNote — 新建笔记\n\nPOST /openapi/note/v1/import_doc\n\n**触发场景**：用户说「新建笔记」「导入笔记」「把这段内容保存为笔记」\n\n- **请求**：[ImportNoteReq](#importnotereq)\n- **响应**：[ImportNoteRsp](#importnotersp)\n\n---\n\n### 5. AppendNote — 追加内容到笔记\n\nPOST /openapi/note/v1/append_doc\n\n**触发场景**：用户说「在这篇笔记末尾追加内容」「把XX添加到笔记里」\n\n> ⚠️ 需要用户是笔记作者\n\n- **请求**：[AppendNoteReq](#appendnotereq)\n- **响应**：[AppendNoteRsp](#appendnotersp)\n\n---\n\n### 6. ListNoteFolder — 笔记本列表\n\nPOST /openapi/note/v1/list_notebook\n\n**触发场景**：用户说「列出笔记本」「有哪些分类」「查看笔记本目录」\n\n- **请求**：[ListNoteFolderReq](#listnotefolderreq)\n- **响应**：[ListNoteFolderRsp](#listnotefolderrsp)\n\n---\n\n## 枚举值\n\n### `ContentFormat`（文本类型）\n\n| 值  | 名称      | 说明          |\n| --- | --------- | ------------- |\n| `0` | PLAINTEXT | 纯文本        |\n| `1` | MARKDOWN  | Markdown 格式 |\n| `2` | JSON      | JSON 格式     |\n\n### `SearchType`（检索方式）\n\n| 值  | 名称        | 说明             |\n| --- | ----------- | ---------------- |\n| `0` | DOC_TITLE   | 标题检索（默认） |\n| `1` | DOC_CONTENT | 正文检索         |\n\n### `SortType`（排序方式）\n\n| 值  | 名称        | 说明             |\n| --- | ----------- | ---------------- |\n| `0` | MODIFY_TIME | 更新时间（默认） |\n| `1` | CREATE_TIME | 创建时间         |\n| `2` | TITLE       | 标题             |\n| `3` | SIZE        | 大小             |\n\n### `FolderType`（笔记本类型）\n\n| 值  | 名称           | 说明               |\n| --- | -------------- | ------------------ |\n| `0` | USER_CREATE    | 用户自建           |\n| `1` | TOTAL          | 全部笔记（根目录） |\n| `2` | UN_CATEGORIZED | 未分类             |\n\n---\n\n## 游标翻页使用规范\n\n### 笔记本列表（ListNoteFolder）\n\n1. 首次请求：`cursor` 传 `\"0\"`\n2. 检查返回的 `is_end`：`false` 表示还有更多数据\n3. 将返回的 `next_cursor` 作为下次请求的 `cursor`\n4. `is_end = true` 时停止翻页\n\n### 笔记列表（ListNote）\n\n1. 首次请求：`cursor` 传空字符串 `\"\"`\n2. `is_end = true` 时停止翻页\n\n### 搜索（SearchNote）\n\n1. 首次请求：`start: 0, end: 20`\n2. 翻页时递增 start/end\n3. `is_end = true` 时停止\n\n---\n\n## 错误码（ErrorCode 枚举）\n\n| 错误码 | 名称                   | 说明                     |\n| ------ | ---------------------- | ------------------------ |\n| 0      | OK                     | 成功                     |\n| 210001 | PARAM_ERROR            | 参数错误                 |\n| 210002 | REQ_WITH_INVALID_UID   | 携带无效的 UID           |\n| 210003 | SERVICE_ERROR          | 服务器内部错误           |\n| 210004 | SPACE_NOT_ENOUGH       | 用户空间不够             |\n| 210005 | NOTE_NOT_OWNER         | 不是笔记的作者           |\n| 210006 | NOTE_IS_DELETE         | 笔记已被删除             |\n| 210007 | COS_CRED_ERROR         | 获取 COS 上传凭证出错    |\n| 210008 | VERSION_CONFLICT       | 版本冲突                 |\n| 210009 | CONTENT_SIZE_OVERLOAD  | 单篇笔记超过最大限制     |\n| 210010 | EXIST_GUIDE            | 新手引导笔记添加重复     |\n| 210011 | SHARE_DOC_NOPERM       | 共享知识库的笔记无权访问 |\n| 210012 | USER_IS_DELETE         | 用户已注销               |\n| 210030 | notebook_NAME_EXIST    | 笔记本名称重复           |\n| 210031 | notebook_NUM_LIMIT     | 笔记本数量达到上限       |\n| 210032 | BATCH_EXEC_FAIL        | 批量操作部分失败         |\n| 210033 | BATCH_EXEC_ALL_FAIL    | 批量操作全部失败         |\n| 210034 | PRIVATE_NOTE_NOT_OWNER | 笔记私有且不是作者       |\n| 210035 | FOLDER_NOT_EXIST       | 笔记本不存在             |\n| 210036 | ADD_KNOWLEDGE_FAIL     | 笔记添加知识库失败       |\n| 20002  | —                      | apiKey 超过最大限频      |\n| 20004  | —                      | apiKey 鉴权失败          |\n\nFile v1.1.7:skill-card.md\n\n## Description:\n\nIMA Skills helps agents manage IMA notes and knowledge bases through IMA OpenAPI, including note search, note creation, knowledge-base search, file upload, URL import, and source-content retrieval.\n\nThis skill is ready for commercial/non-commercial use.\n\n## Publisher:\n\n[iampennyli](https://clawhub.ai/user/iampennyli)\n\n### License/Terms of Use:\n\nMIT-0\n\n## Use Case:\n\nExternal users and developers use this skill to let an agent search, browse, create, and append IMA notes, and to add, browse, search, or retrieve content from IMA knowledge bases. The skill is intended for users who provide their own IMA OpenAPI Client ID and API Key.\n\n### Deployment Geography for Use:\n\nGlobal\n\n## Known Risks and Mitigations:\n\nRisk: The security review flags credential and update-handling risks for a skill that uses user-provided IMA OpenAPI credentials.\n\nMitigation: Constrain network access to ima.qq.com and *.myqcloud.com, keep credentials in a secret manager or protected files, and avoid custom base URLs.\n\nRisk: Update instructions returned by the service may be untrusted text.\n\nMitigation: Require explicit user review and confirmation before following any service-returned update instruction.\n\nRisk: Write operations can create or append notes and upload files to a knowledge base.\n\nMitigation: Confirm ambiguous note targets, validate UTF-8 text before note writes, run upload preflight checks, and stop if COS upload fails.\n\n## Reference(s):\n\n- [ClawHub skill page](https://clawhub.ai/iampennyli/skills/ima-skills)\n- [IMA](https://ima.qq.com)\n- [IMA OpenAPI credential setup](https://ima.qq.com/agent-interface)\n- [IMA knowledge-base API reference](knowledge-base/references/api.md)\n- [IMA notes API reference](notes/references/api.md)\n- [Tencent Cloud COS request signature reference](https://cloud.tencent.com/document/product/436/7778)\n\n## Skill Output:\n\n**Output Type(s):** [text, markdown, shell commands, configuration, guidance, JSON]\n\n**Output Format:** [Markdown guidance with inline shell commands and JSON request or response examples]\n\n**Output Parameters:** [1D]\n\n**Other Properties Related to Output:** [Requires Node.js 18 or later and user-provided IMA OpenAPI credentials for live API operations.]\n\n## Skill Version(s):\n\n1.1.7 (source: server release evidence and artifact meta.json)\n\n## Ethical Considerations:\n\nUsers should evaluate whether this skill is appropriate for their environment, review any generated or modified files before relying on them, and apply their organization's safety, security, and compliance requirements before deployment.\n\nFile v1.1.7:meta.json\n\n{\n  \"version\": \"1.1.7\",\n  \"required_binaries\": [\n    {\n      \"name\": \"node\",\n      \"min_version\": \"18.0.0\",\n      \"reason\": \"Runs .cjs scripts (preflight-check.cjs, cos-upload.cjs) and inline node -e calls for JSON parsing\"\n    }\n  ]\n}\n\nArchive v1.1.2: 8 files, 32588 bytes\n\nFiles: knowledge-base/references/api.md (20587b), knowledge-base/scripts/cos-upload.cjs (4700b), knowledge-base/scripts/preflight-check.cjs (8767b), knowledge-base/SKILL.md (28714b), notes/references/api.md (14797b), notes/SKILL.md (10641b), SKILL.md (12207b), _meta.json (129b)\n\nFile v1.1.2:knowledge-base/SKILL.md\n\n# Knowledge Base (知识库)\n\n> Prerequisites: see root `../SKILL.md` for setup, credentials, and `ima_api()` helper.\n\nAPI base path: `openapi/wiki/v1`\n\n通过 IMA Wiki OpenAPI 管理用户知识库，支持上传文件、添加网页链接、搜索知识库内容、浏览知识库列表和获取知识库详情。\n\n完整的数据结构和接口参数详见 `references/api.md`。\n\n## 接口决策表\n\n| 用户意图                                      | 调用接口                                                               | 关键参数                                                                 |\n| --------------------------------------------- | ---------------------------------------------------------------------- | ------------------------------------------------------------------------ |\n| 上传文件到知识库                              | `check_repeated_names` → `create_media` → COS Upload → `add_knowledge` | `media_type`（按扩展名），`knowledge_base_id`，`file_name`，`file_size`  |\n| 上传文件到知识库的某个文件夹                  | 先定位文件夹 → 同上（`folder_id` 传入目标文件夹 ID）                   | 见「文件夹操作」章节                                                     |\n| 添加网页/微信文章到知识库                     | `import_urls`                                                          | `urls`（1-10 个），`knowledge_base_id`，可选 `folder_id`（省略则根目录） |\n| 添加笔记到知识库                              | `add_knowledge`                                                        | `media_type=11`，`note_info.content_id=<doc_id>`，`knowledge_base_id`    |\n| 添加 URL（文件型）到知识库                    | `check_repeated_names` → 下载文件 → 走\"上传文件\"流程                   | URL 指向 PDF/Word/PPT 等文件时，按文件方式处理                           |\n| 检查文件名是否重复                            | `check_repeated_names`                                                 | `params[].name`，`params[].media_type`，`knowledge_base_id`，`folder_id` |\n| 获取知识库信息                                | `get_knowledge_base`                                                   | `ids`（1-20 个，不重复）                                                 |\n| 浏览知识库内容列表 / 浏览文件夹               | `get_knowledge_list`                                                   | `knowledge_base_id`，`cursor`，`limit`(1~50)，可选 `folder_id`           |\n| 在知识库中搜索（含文件和文件夹）              | `search_knowledge`                                                     | `query`，`knowledge_base_id`，`cursor`                                   |\n| 按关键词查找知识库（用户知道名字但不知道 ID） | `search_knowledge_base`                                                | `query`，`cursor`，`limit`(1~50)                                         |\n| 查看/了解自己有哪些知识库                     | `search_knowledge_base`（`query` 传空字符串）                          | `query: \"\"`，`cursor`，`limit`(1~50)                                     |\n| 添加内容但**未指定**目标知识库                | `get_addable_knowledge_base_list` → 展示列表让用户选择                 | `cursor`，`limit`(1~50)                                                  |\n\n### `search_knowledge_base` vs `get_addable_knowledge_base_list` 选择指南\n\n这两个接口容易混淆，选择规则：\n\n| 场景                                             | 使用接口                                       | 原因                               |\n| ------------------------------------------------ | ---------------------------------------------- | ---------------------------------- |\n| 用户说了知识库名称（如\"添加到产品文档库\"）       | `search_knowledge_base`                        | 按名称搜索，找到 ID 后继续操作     |\n| 用户想浏览/了解某个知识库                        | `search_knowledge_base` → `get_knowledge_base` | 先搜到 ID，再获取详情              |\n| 用户想查看自己有哪些知识库（无具体关键词）       | `search_knowledge_base`（`query: \"\"`）         | 空 query 返回用户的所有知识库列表  |\n| 用户要添加内容但**没说添加到哪个知识库**         | `get_addable_knowledge_base_list`              | 列出有权限添加的知识库，让用户选择 |\n| 用户说\"添加到知识库\"但上下文中无法确定哪个知识库 | `get_addable_knowledge_base_list`              | 同上，不要猜测，让用户选择         |\n\n**绝不要**在用户已明确指定知识库名称时调用 `get_addable_knowledge_base_list`，直接用 `search_knowledge_base` 按名称搜索即可。\n\n## 文件类型检测\n\n使用 `scripts/preflight-check.cjs` 脚本自动完成类型检测和大小校验。脚本按以下优先级解析：\n\n1. **`--content-type` 已提供且可识别** → content-type 优先，直接使用\n2. **`--content-type` 不可识别** → 回退到扩展名\n3. **未提供 `--content-type`** → 使用扩展名\n4. **两者都无法识别** → 拒绝处理\n\n```bash\n# 有扩展名（自动推断）\nnode .claude/skills/ima-skill/knowledge-base/scripts/preflight-check.cjs --file report.pdf\n\n# 无扩展名或扩展名不可识别（需传入 content-type，如从 HTTP HEAD 获取）\nnode .claude/skills/ima-skill/knowledge-base/scripts/preflight-check.cjs --file downloaded_file --content-type application/pdf\n```\n\n扩展名与类型的对应关系：\n\n| 扩展名              | media_type | content_type                                                                 |\n| ------------------- | ---------- | ---------------------------------------------------------------------------- |\n| `.pdf`              | 1          | `application/pdf`                                                            |\n| `.doc`              | 3          | `application/msword`                                                         |\n| `.docx`             | 3          | `application/vnd.openxmlformats-officedocument.wordprocessingml.document`    |\n| `.ppt`              | 4          | `application/vnd.ms-powerpoint`                                              |\n| `.pptx`             | 4          | `application/vnd.openxmlformats-officedocument.presentationml.presentation`  |\n| `.xls`              | 5          | `application/vnd.ms-excel`                                                   |\n| `.xlsx`             | 5          | `application/vnd.openxmlformats-officedocument.spreadsheetml.sheet`          |\n| `.csv`              | 5          | `text/csv`                                                                   |\n| `.md` / `.markdown` | 7          | `text/markdown`                                                              |\n| `.png`              | 9          | `image/png`                                                                  |\n| `.jpg` / `.jpeg`    | 9          | `image/jpeg`                                                                 |\n| `.webp`             | 9          | `image/webp`                                                                 |\n| `.txt`              | 13         | `text/plain`                                                                 |\n| `.xmind`            | 14         | `application/x-xmind` / `application/vnd.xmind.workbook` / `application/zip` |\n| `.mp3`              | 15         | `audio/mpeg`                                                                 |\n| `.m4a`              | 15         | `audio/x-m4a`                                                                |\n| `.wav`              | 15         | `audio/wav`                                                                  |\n| `.aac`              | 15         | `audio/aac`                                                                  |\n\n未识别的扩展名或无扩展名：**直接告知用户该文件类型不被支持，立即终止操作**。不要猜测或默认为某个类型，**不要询问用户是否仍要上传**。\n\n> **不支持的类型**：视频文件（`.mp4`、`.avi`、`.mov` 等）、Bilibili（`bilibili.com/video/`）和 YouTube（`youtube.com/watch`）链接、本地 HTML 文件（`file://`）**无法**通过 skill 添加到知识库。直接告知用户「该文件类型不支持，仅支持在 ima 桌面端内添加进知识库」，**不要提供上传选项或询问是否继续**。\n\n## URL 类型检测\n\n添加 URL 到知识库时，需要根据 URL 模式和 Content-Type 判断类型。检测按以下优先级进行：\n\n**1. Content-Type 为 `text/html` 时，按 URL 模式区分：**\n\n| URL 模式                                            | media_type | 类型           | 处理方式                                                  |\n| --------------------------------------------------- | ---------- | -------------- | --------------------------------------------------------- |\n| 匹配 `mp.weixin.qq.com/s/` 或 `mp.weixin.qq.com/s?` | 6          | 微信公众号文章 | 使用 `import_urls`                                        |\n| 以 `https://www.bilibili.com/video/` 开头           | ❌ 16      | 视频网页       | **不支持**，告知用户「仅支持在 ima 桌面端内添加进知识库」 |\n| 以 `https://www.youtube.com/watch` 开头             | ❌ 16      | 视频网页       | **不支持**，告知用户「仅支持在 ima 桌面端内添加进知识库」 |\n| 以 `file://` 开头                                   | ❌         | 本地 HTML      | **不支持**，告知用户「仅支持在 ima 桌面端内添加进知识库」 |\n| 其他 `text/html` 页面                               | 2          | 普通网页       | 使用 `import_urls`                                        |\n\n**2. Content-Type 为文件类型时：** 按文件类型检测表处理（PDF、Word、Excel 等）。\n\n**3. 其他：** 告知用户该类型不被支持。\n\n## 添加前置检查（Pre-flight Check）\n\n在执行任何添加知识到知识库的操作前（`add_knowledge`、`import_urls`、上传文件流程），**必须按以下顺序逐项检查**，任一项不通过则**立即终止并告知用户，不要询问是否仍要尝试上传**：\n\n### 1. 类型支持检查\n\n| 检查项             | 条件                                                                      | 不通过时的处理                                |\n| ------------------ | ------------------------------------------------------------------------- | --------------------------------------------- |\n| 文件扩展名是否支持 | 扩展名不在「文件类型检测」表中                                            | 告知用户该文件类型不被支持                    |\n| 视频文件           | `.mp4`、`.avi`、`.mov` 等视频扩展名                                       | 告知用户「仅支持在 ima 桌面端内添加进知识库」 |\n| 视频网页 URL       | `https://www.bilibili.com/video/` 或 `https://www.youtube.com/watch` 开头 | 告知用户「仅支持在 ima 桌面端内添加进知识库」 |\n| 本地 HTML 文件     | `file://` 协议                                                            | 告知用户「仅支持在 ima 桌面端内添加进知识库」 |\n\n### 2. 文件大小检查\n\n上传前必须校验文件大小，超限文件应**在上传前拦截**，不要发起请求：\n\n| 文件类型                    | media_type  | 最大大小 |\n| --------------------------- | ----------- | -------- |\n| Excel、TXT、Xmind、Markdown | 5/13/14/7   | 10 MB    |\n| 图片                        | 9           | 30 MB    |\n| PDF、Word、PPT、音频及其他  | 1/3/4/15 等 | 200 MB   |\n\n### 3. 音频时长检查\n\n音频文件（media_type=15）额外限制：**最长 2 小时**。超过时告知用户。\n\n### 4. 文件名重复检查\n\n仅适用于文件类型（media_type 1/3/4/5/7/9/13/14/15），不适用于网页（2/6）、笔记（11）等：\n\n- 调用 `check_repeated_names` 检查\n- `is_repeated=true`：询问用户是否保留两者（追加时间戳）或取消\n- 不支持\"替换\"操作\n\n> **检查顺序很重要**：先做类型和大小检查（本地即可判断），通过后再调用远程接口检查重名。避免对不支持或超限的文件发起不必要的网络请求。\n\n## 常用工作流\n\n### 上传文件到知识库\n\n完成「添加前置检查」后，执行以下步骤：创建媒体 → 上传 COS → 添加知识。\n\n> 前置检查（类型检测、大小校验、重名检查）见「添加前置检查」章节。\n\n```bash\n# 1. 前置检查 — 类型、大小一步完成\n#    有扩展名时：自动从扩展名推断 media_type 和 content_type\n#    无扩展名时：需通过 --content-type 传入（如从 HTTP HEAD 获取）\nPREFLIGHT=$(node .claude/skills/ima-skill/knowledge-base/scripts/preflight-check.cjs \\\n  --file \"/path/to/report.pdf\")\necho \"$PREFLIGHT\"\n# pass=false 时直接终止，将 reason 展示给用户\n\n# 2. 从 preflight 结果提取字段（用于后续 API 调用）\nFILE_NAME=$(echo \"$PREFLIGHT\" | node -e \"const d=JSON.parse(require('fs').readFileSync(0,'utf8'));process.stdout.write(d.file_name)\")\nFILE_EXT=$(echo \"$PREFLIGHT\" | node -e \"const d=JSON.parse(require('fs').readFileSync(0,'utf8'));process.stdout.write(d.file_ext)\")\nFILE_SIZE=$(echo \"$PREFLIGHT\" | node -e \"const d=JSON.parse(require('fs').readFileSync(0,'utf8'));process.stdout.write(String(d.file_size))\")\nMEDIA_TYPE=$(echo \"$PREFLIGHT\" | node -e \"const d=JSON.parse(require('fs').readFileSync(0,'utf8'));process.stdout.write(String(d.media_type))\")\nCONTENT_TYPE=$(echo \"$PREFLIGHT\" | node -e \"const d=JSON.parse(require('fs').readFileSync(0,'utf8'));process.stdout.write(d.content_type)\")\n\n# 3. 重名检查（仅文件类型，见「添加前置检查」第 4 步）\n\n# 4. create_media — 获取 media_id 和 COS 上传凭证\nima_api \"openapi/wiki/v1/create_media\" \"{\n  \\\"file_name\\\": \\\"$FILE_NAME\\\",\n  \\\"file_size\\\": $FILE_SIZE,\n  \\\"content_type\\\": \\\"$CONTENT_TYPE\\\",\n  \\\"knowledge_base_id\\\": \\\"<kb_id>\\\",\n  \\\"file_ext\\\": \\\"$FILE_EXT\\\"\n}\"\n# 从返回值提取 media_id 和 cos_credential 各字段\n\n# 5. 上传文件到 COS\nnode .claude/skills/ima-skill/knowledge-base/scripts/cos-upload.cjs \\\n  --file \"/path/to/report.pdf\" \\\n  --secret-id \"<cos_credential.secret_id>\" \\\n  --secret-key \"<cos_credential.secret_key>\" \\\n  --token \"<cos_credential.token>\" \\\n  --bucket \"<cos_credential.bucket_name>\" \\\n  --region \"<cos_credential.region>\" \\\n  --cos-key \"<cos_credential.cos_key>\" \\\n  --content-type \"$CONTENT_TYPE\" \\\n  --start-time \"<cos_credential.start_time>\" \\\n  --expired-time \"<cos_credential.expired_time>\"\n\n# 6. add_knowledge — 将已上传的文件关联到知识库\nima_api \"openapi/wiki/v1/add_knowledge\" \"{\n  \\\"media_type\\\": $MEDIA_TYPE,\n  \\\"media_id\\\": \\\"<media_id>\\\",\n  \\\"title\\\": \\\"$FILE_NAME\\\",\n  \\\"knowledge_base_id\\\": \\\"<kb_id>\\\",\n  \\\"file_info\\\": {\n    \\\"cos_key\\\": \\\"<cos_credential.cos_key>\\\",\n    \\\"file_size\\\": $FILE_SIZE,\n    \\\"file_name\\\": \\\"$FILE_NAME\\\"\n  }\n}\"\n```\n\n#### 批量上传时的重复处理\n\n当上传多个文件时，可一次性检查所有文件名（最多 2000 个）：\n\n```bash\n# 批量检查\nima_api \"openapi/wiki/v1/check_repeated_names\" '{\n  \"params\": [\n    {\"name\": \"report.pdf\", \"media_type\": 1},\n    {\"name\": \"slides.pptx\", \"media_type\": 4},\n    {\"name\": \"data.xlsx\", \"media_type\": 5}\n  ],\n  \"knowledge_base_id\": \"<kb_id>\",\n  \"folder_id\": \"<folder_id>\"\n}'\n# 注意：如果是根目录，省略 folder_id 字段\n# 遍历 results，对 is_repeated=true 的文件询问用户：\n# - \"以下文件在知识库中已存在同名文件：report.pdf、data.xlsx。是否保留两者？（不支持替换）\"\n# - 用户选择\"保留两者\"的文件：追加时间戳后继续上传\n# - 用户选择\"取消\"的文件：从上传列表中移除\n```\n\n**时间戳命名规则**：在文件名（不含扩展名）末尾追加 `_YYYYMMDDHHmmss`，例如 `report_20260317153000.pdf`。\n\n### 添加网页/微信文章到知识库\n\n使用 `import_urls` 批量导入网页和微信公众号文章（1-10 个 URL），服务端自动识别类型：\n\n```bash\n# 添加到根目录（不传 folder_id）\nima_api \"openapi/wiki/v1/import_urls\" '{\n  \"knowledge_base_id\": \"<kb_id>\",\n  \"urls\": [\n    \"https://example.com/article\",\n    \"https://mp.weixin.qq.com/s/xxxxx\"\n  ]\n}'\n\n# 添加到指定文件夹（传 folder_id，以 folder_ 开头）\nima_api \"openapi/wiki/v1/import_urls\" '{\n  \"knowledge_base_id\": \"<kb_id>\",\n  \"folder_id\": \"<folder_id>\",\n  \"urls\": [\n    \"https://example.com/article\"\n  ]\n}'\n# 返回 results 映射：{ \"<url>\": { url, ret_code, media_id } }\n# ret_code=0 表示成功，非 0 查看 errmsg\n```\n\n### 添加笔记到知识库\n\n将已有笔记（通过 `doc_id` 引用）直接关联到知识库，无需下载内容：\n\n```bash\nima_api \"openapi/wiki/v1/add_knowledge\" '{\n  \"media_type\": 11,\n  \"note_info\": { \"content_id\": \"<doc_id>\" },\n  \"title\": \"笔记标题\",\n  \"knowledge_base_id\": \"<kb_id>\"\n}'\n```\n\n### 添加 URL 到知识库（自动检测文件型 URL）\n\n当用户提供 URL 时，需先判断该 URL 指向的是网页还是可下载文件（PDF、Word、PPT 等）。\n\n**判断规则**（按优先级）：\n\n1. **URL 路径包含文件扩展名**：如 `https://arxiv.org/pdf/2603.12268` 以 `/pdf/` 开头，或 `https://example.com/report.pdf` 以 `.pdf` 结尾 → 文件型\n2. **发送 HEAD 请求检查 Content-Type**：`curl -sI -L <url>` 查看响应头\n   - `application/pdf` → PDF 文件\n   - `application/msword` 或 `application/vnd.openxmlformats-*` → Word/PPT/Excel 文件\n   - `text/html` → 网页\n3. **已知文件型 URL 模式**：\n   - `arxiv.org/pdf/*` → PDF\n   - `*.pdf`、`*.docx`、`*.pptx`、`*.xlsx` 结尾 → 对应文件类型\n   - GitHub raw 文件链接 → 按扩展名判断\n\n**文件型 URL 处理流程**：\n\n```bash\n# 1. 探测 URL 类型\nCONTENT_TYPE=$(curl -sI -L \"https://arxiv.org/pdf/2603.12268\" | grep -i \"^content-type:\" | tail -1 | awk '{print $2}' | tr -d '\\r')\n# 结果如 application/pdf → 文件型\n\n# 2. 下载文件到临时目录\nTEMP_DIR=$(mktemp -d)\n# 根据 Content-Type 或 URL 推断文件名和扩展名\ncurl -sL -o \"$TEMP_DIR/paper.pdf\" \"https://arxiv.org/pdf/2603.12268\"\n\n# 3. 前置检查（传入 content-type 作为备用，文件名有扩展名时会优先用扩展名）\nPREFLIGHT=$(node .claude/skills/ima-skill/knowledge-base/scripts/preflight-check.cjs \\\n  --file \"$TEMP_DIR/paper.pdf\" --content-type \"$CONTENT_TYPE\")\necho \"$PREFLIGHT\"\n# pass=false 时直接终止\n\n# 4. 按\"上传文件到知识库\"流程处理：create_media → COS Upload → add_knowledge\n# （参见上方\"上传文件到知识库\"工作流）\n\n# 5. 清理临时文件\nrm -rf \"$TEMP_DIR\"\n```\n\n**文件名推断**：\n\n- 优先从 `Content-Disposition` 响应头提取文件名\n- 其次从 URL 路径中提取（如 `/pdf/2603.12268` → `2603.12268.pdf`）\n- 最后使用 URL 的最后一段路径 + 根据 Content-Type 补充扩展名\n\n### 文件夹操作\n\n知识库内容以文件夹结构组织。**文件夹本身也是一种知识条目**，在 `get_knowledge_list` 和 `search_knowledge` 的返回结果中会同时包含文件和文件夹。\n\n#### 核心概念\n\n- `folder_id`：文件夹的唯一标识，**始终以 `folder_` 前缀开头**（如 `folder_abc123`），在 `add_knowledge`、`import_urls`、`get_knowledge_list`、`check_repeated_names` 等接口中用于指定目标文件夹\n- **操作根目录时，不要传 `folder_id` 参数**（直接省略该字段），不要将 `knowledge_base_id` 作为 `folder_id` 传入\n- `get_knowledge_list` 返回的 `current_path`（`FolderInfo[]`）表示当前浏览位置的完整路径（面包屑）\n\n#### 定位文件夹（用户提到文件夹名时）\n\n当用户说「添加到 XX 文件夹」但只给了文件夹名称时，需要先找到 `folder_id`：\n\n```bash\n# 方法 1：搜索知识库内容（推荐，可直接按名称搜索文件夹）\nima_api \"openapi/wiki/v1/search_knowledge\" '{\n  \"query\": \"文件夹名称\",\n  \"knowledge_base_id\": \"<kb_id>\",\n  \"cursor\": \"\"\n}'\n# 从返回的 info_list 中找到匹配的文件夹条目，取其 media_id 作为 folder_id\n\n# 方法 2：浏览根目录列表逐级查找\nima_api \"openapi/wiki/v1/get_knowledge_list\" '{\n  \"knowledge_base_id\": \"<kb_id>\",\n  \"cursor\": \"\",\n  \"limit\": 50\n}'\n# 从返回的 knowledge_list 中找到目标文件夹，取其 media_id 作为 folder_id\n# 如果文件夹在子目录中，需要用返回的 folder_id 逐级深入\n```\n\n#### 添加内容到指定文件夹\n\n所有写入接口（`add_knowledge`、`import_urls`、`check_repeated_names`）都支持 `folder_id` 参数：\n\n```bash\n# 上传文件到指定文件夹\nima_api \"openapi/wiki/v1/add_knowledge\" '{\n  \"media_type\": 1,\n  \"media_id\": \"<media_id>\",\n  \"title\": \"report.pdf\",\n  \"knowledge_base_id\": \"<kb_id>\",\n  \"folder_id\": \"<folder_id>\",\n  \"file_info\": { \"cos_key\": \"...\", \"file_size\": 12345, \"file_name\": \"report.pdf\" }\n}'\n\n# 导入网页到指定文件夹\nima_api \"openapi/wiki/v1/import_urls\" '{\n  \"knowledge_base_id\": \"<kb_id>\",\n  \"folder_id\": \"<folder_id>\",\n  \"urls\": [\"https://example.com/article\"]\n}'\n\n# 添加到根目录时，直接省略 folder_id\nima_api \"openapi/wiki/v1/add_knowledge\" '{\n  \"media_type\": 1,\n  \"media_id\": \"<media_id>\",\n  \"title\": \"report.pdf\",\n  \"knowledge_base_id\": \"<kb_id>\",\n  \"file_info\": { \"cos_key\": \"...\", \"file_size\": 12345, \"file_name\": \"report.pdf\" }\n}'\n```\n\n### 获取知识库信息\n\n```bash\nima_api \"openapi/wiki/v1/get_knowledge_base\" '{\"ids\": [\"<kb_id>\"]}'\n# 返回 infos 映射：{ \"<kb_id>\": { id, name, cover_url, description, recommended_questions } }\n```\n\n### 浏览知识库内容\n\n```bash\n# 浏览根目录\nima_api \"openapi/wiki/v1/get_knowledge_list\" '{\"knowledge_base_id\": \"<kb_id>\", \"cursor\": \"\", \"limit\": 20}'\n\n# 浏览指定文件夹\nima_api \"openapi/wiki/v1/get_knowledge_list\" '{\"knowledge_base_id\": \"<kb_id>\", \"folder_id\": \"<folder_id>\", \"cursor\": \"\", \"limit\": 20}'\n# 翻页：用 next_cursor，is_end=true 时停止\n```\n\n### 在知识库中搜索\n\n```bash\nima_api \"openapi/wiki/v1/search_knowledge\" '{\"query\": \"搜索关键词\", \"knowledge_base_id\": \"<kb_id>\", \"cursor\": \"\"}'\n```\n\n### 搜索知识库列表\n\n```bash\n# 按关键词搜索\nima_api \"openapi/wiki/v1/search_knowledge_base\" '{\"query\": \"搜索关键词\", \"cursor\": \"\", \"limit\": 20}'\n\n# 查看所有知识库（空 query）\nima_api \"openapi/wiki/v1/search_knowledge_base\" '{\"query\": \"\", \"cursor\": \"\", \"limit\": 20}'\n```\n\n### 获取可添加的知识库列表\n\n**仅当用户要添加内容但未指定目标知识库时使用**。如果用户已给出知识库名称，应使用 `search_knowledge_base` 按名称搜索，而非此接口。\n\n```bash\n# 首次请求\nima_api \"openapi/wiki/v1/get_addable_knowledge_base_list\" '{\"cursor\": \"\", \"limit\": 20}'\n# 翻页：用 next_cursor，is_end=true 时停止\n```\n\n## 核心响应字段\n\n知识条目（`KnowledgeInfo`）关键字段：`media_id`（媒体ID）、`title`、`parent_folder_id`。\n\n搜索到的知识条目（`SearchedKnowledgeInfo`）关键字段：`media_id`、`title`、`parent_folder_id`、`highlight_content`（高亮内容，内容匹配时返回）。\n\n知识库信息（`KnowledgeBaseInfo`）关键字段：`id`、`name`、`cover_url`、`description`、`recommended_questions`。\n\n文件夹条目（`FolderInfo`）关键字段：`folder_id`、`name`、`file_number`、`folder_number`、`parent_folder_id`、`is_top`。\n\n完整字段定义见 `references/api.md`。\n\n## 分页\n\n所有列表和搜索接口使用**游标分页**：\n\n1. 首次请求：`cursor: \"\"`\n2. 检查返回的 `is_end`：`false` 表示还有更多数据\n3. 将返回的 `next_cursor` 作为下次请求的 `cursor`\n4. `is_end = true` 时停止翻页\n\n## 响应处理\n\n所有 API 返回统一结构 `{ \"retcode\": 0, \"errmsg\": \"...\", \"data\": { ... } }`：\n\n- `retcode=0`：成功，从 `data` 提取业务字段\n- `retcode≠0`：失败，**直接将 `errmsg` 展示给用户**即可，不需要自行翻译错误码\n\n## 用户体验\n\n- **隐藏内部 ID**：面向用户的展示中**永远不要暴露 `knowledge_base_id`、`media_id`、`folder_id` 等内部 ID**。始终使用知识库名称、文件标题、文件夹名称等用户可读信息。ID 仅用于后续 API 调用，不展示给用户。\n  - ✅ `\"已添加到知识库「产品文档库」✓\"`\n  - ❌ `\"已添加到知识库 abc123def456 ✓\"`\n  - 需要引用知识库时，先通过 `get_knowledge_base` 获取名称，再展示\n- **精简进度**：不要逐步暴露内部操作（如\"正在创建媒体…正在上传 COS…\"）。只报告用户关心的信息：\n  - 上传文件：`\"正在上传 report.pdf…\"` → `\"已添加到知识库「产品文档库」✓\"`\n  - 添加网页：`\"正在添加…\"` → `\"已添加到「产品文档库」✓\"`\n  - 失败时展示 `errmsg` 即可\n- **批量操作**：汇总结果，如 `\"3 个文件已添加到「产品文档库」，1 个失败（data.xlsx: 文件大小超限）\"`\n- **格式化展示**：读取类操作的结果应以结构化格式展示给用户，而非原始 JSON：\n\n  **知识库列表**（`search_knowledge_base` / `get_addable_knowledge_base_list`）：\n\n  > 搜索知识库后，用返回的 ID 列表调用 `get_knowledge_base` 获取描述信息，一并展示。\n\n  ```\n  📚 搜索结果（共 3 个知识库）：\n  1. **产品文档库** — 存放产品相关的所有文档资料\n  2. **技术方案库** — 各项目技术方案汇总\n  3. **竞品分析库**\n  ```\n\n  **知识库内容列表**（`get_knowledge_list`）：\n\n  ```\n  📂 知识库「产品文档库」内容：\n  📁 设计文档/          (3 个文件, 1 个子文件夹)\n  📁 会议纪要/          (12 个文件)\n  📄 产品需求文档.pdf\n  📄 技术方案.docx\n  📄 数据分析.xlsx\n  --- 第 1 页，还有更多内容 ---\n  ```\n\n  **搜索结果**（`search_knowledge`）：\n\n  > `search_knowledge` 返回的条目包含 `media_id`、`title`、`parent_folder_id`、`highlight_content`（内容匹配时返回高亮片段），\n\n  ```\n  🔍 在知识库「产品文档库」中搜索「排期」的结果：\n\n  1. 📄 Q1排期表.xlsx (文件夹: 项目管理/)\n     > ...包含**排期**计划的详细信息...\n  2. 📄 开发排期讨论.pdf (文件夹: 会议纪要/)\n  3. 📁 排期模板/ (文件夹: 根目录)\n  ```\n\n  **知识库详情**（`get_knowledge_base`）：\n\n  ```\n  📚 产品文档库\n  📝 描述：存放产品相关的所有文档资料\n  💡 推荐问题：\n     - 最新的产品需求是什么？\n     - 技术方案有哪些？\n  ```\n\n## 注意事项\n\n- `get_knowledge_base` 接受 1-20 个 ID；单个 ID 也需包装为数组\n- `get_knowledge_list` 的 `limit` 范围为 1~50\n- **文件夹是知识条目的一种**：`get_knowledge_list` 和 `search_knowledge` 的返回结果中同时包含文件和文件夹，需通过字段区分（文件夹有 `folder_id`/`name`/`file_number`/`folder_number`，文件有 `media_id`/`title`）\n- **用户提到文件夹时**：如果用户只给了文件夹名称（而非 ID），必须先通过 `search_knowledge` 或 `get_knowledge_list` 找到对应的 `folder_id`，再执行后续操作\n- `folder_id` 在 `add_knowledge`、`import_urls`、`get_knowledge_list`、`check_repeated_names` 中均为可选字段，**操作根目录时直接省略 `folder_id`，不要传该参数**。`folder_id` 的值始终以 `folder_` 前缀开头（如 `folder_abc123`），**不要将 `knowledge_base_id` 作为 `folder_id` 传入**\n- **文件上传时 `title` 必须等于 `file_name`**：调用 `add_knowledge` 添加文件时，`title` 字段**必须使用文件的原始完整文件名（含扩展名）**，不要自行拟定标题。`file_name` 和 `title` 传同一个值。**禁止缩短、翻译、重命名或省略任何部分**。例如文件名为 `音频.mp3`，则 `file_name` 和 `title` 都必须传 `音频.mp3`\n- 文件扩展名必须正确提取，用于 `media_type` 检测和 `file_ext` 字段（无点号，如 `pdf`）\n- COS 上传脚本失败（非零退出码）时，不要继续调用 `add_knowledge`\n- COS 上传时 `--content-type` 应传入文件的实际 MIME 类型（如 `application/pdf`），而非通用的 `application/octet-stream`\n- 当用户提供 URL 添加到知识库时，必须先检测 URL 是否指向文件（通过 URL 路径扩展名 + HEAD 请求 Content-Type），文件型 URL 需下载后走上传流程；网页/微信文章型 URL 使用 `import_urls`\n\nFile v1.1.2:notes/SKILL.md\n\n# Notes (笔记)\n\n> Prerequisites: see root `../SKILL.md` for setup, credentials, and `ima_api()` helper.\n\nAPI base path: `openapi/note/v1`\n\n通过 IMA OpenAPI 管理用户个人笔记，支持读取（搜索、列表、获取内容）和写入（新建、追加）。\n\n完整的数据结构和接口参数详见 `references/api.md`。\n\n> **隐私规则：** 笔记内容属于用户隐私，在群聊场景中只展示标题和摘要，禁止展示笔记正文。\n\n## 接口决策表\n\n| 用户意图                                                                                                  | 调用接口                     | 关键参数                                                                      |\n| --------------------------------------------------------------------------------------------------------- | ---------------------------- | ----------------------------------------------------------------------------- |\n| 搜索/查找笔记                                                                                             | `search_note_book`           | `query_info`（QueryInfo 对象）                                                |\n| 查看笔记本列表                                                                                            | `list_note_folder_by_cursor` | `cursor`(必填，首页传`\"0\"`) + `limit`(必填)                                   |\n| 浏览某笔记本里的笔记,当用户表述\"最新\"、\"最近\"之类的通用限定，没有指明笔记本时，都应该直接在全部笔记里去拉 | `list_note_by_folder_id`     | `folder_id`(选填,空为全部笔记本) + `cursor`(必填，首次传`\"\"`) + `limit`(必填) |\n| 读取笔记正文                                                                                              | `get_doc_content`            | `doc_id` + `target_content_format`(必填，推荐`0`纯文本)                       |\n| 新建一篇笔记（用户明确说\"新建/创建笔记\"时走此接口）                                                       | `import_doc`                 | `content` + `content_format`(必填，固定`1`) + 可选 `folder_id`                |\n| 往已有笔记追加内容（⚠️ **敏感操作**：用户必须明确指定目标笔记，否则先确认再操作）                          | `append_doc`                 | `doc_id` + `content` + `content_format`(必填，固定`1`)                        |\n\n## ⚠️ 新建 vs. 追加 — 行为规则\n\n**新建笔记（`import_doc`）** 和 **追加内容到已有笔记（`append_doc`）** 是两个完全不同的操作，务必正确区分：\n\n### 明确走新建的信号词\n\n用户说以下任一表述时，**直接调用 `import_doc` 创建新笔记**：\n\n- \"**新建**笔记\"、\"**创建**笔记\"、\"**写一篇**笔记\"\n- \"**新建**一篇笔记记录这些内容\"\n\n### 明确走追加的信号词\n\n用户说以下任一表述时，**调用 `append_doc` 追加到已有笔记**（但仍需确认目标笔记，见下方规则）：\n\n- \"把这段话**追加到**《XX》笔记里\"\n- \"在那篇笔记**末尾加上**这段内容\"\n\n### 模糊场景 — 必须先询问用户\n\n以下表述**既可能是新建、也可能是追加**，agent **不得自行假设**，必须先向用户确认：\n\n- \"帮我记一下\"、\"记录一下\"、\"保存为笔记\"、\"存成笔记\"\n- \"把这段内容记到笔记里\"\n- \"添加到笔记里\"\n- 任何其他未明确表达\"新建\"或\"追加\"意图的表述\n\n询问示例：\n> \"您是想**创建一篇新笔记**，还是**追加到某篇已有笔记**？\"\n\n### 追加到已有笔记是敏感操作\n\n`append_doc` 会**不可撤销地修改**用户的现有笔记，因此必须谨慎处理：\n\n1. **用户明确指定了目标笔记** — 可以直接追加。例如：\n   - \"把这段话追加到《会议纪要》笔记里\"\n   - \"在那篇笔记末尾加上这段内容\"（上下文中已有明确的笔记对象）\n\n2. **用户没有明确指定目标笔记** — **必须先向用户确认**，不要自行猜测。例如：\n   - 用户说\"添加到笔记里\" → 询问：\"您想追加到哪篇已有笔记？请提供笔记标题或让我帮您搜索。\"\n   - 用户说\"把这个加到之前那篇笔记\" → 如果上下文中有多篇笔记或不确定是哪篇 → 列出候选笔记让用户选择\n\n> **原则**：不确定时，先问。宁可多问一句，也不要误改用户的已有笔记或自作主张创建新笔记。\n\n### 🖼️ 本地图片不支持\n\n`import_doc` 和 `append_doc` 的 `content` 字段仅支持纯文本/Markdown，**不支持本地图片**。\n\n写入笔记内容前，必须检查并处理图片引用：\n\n1. **过滤本地图片** — 如果用户提供的内容中包含本地图片路径（如 `![](file:///...)`, `![](/Users/...)`, `![](C:\\...)` 等），**移除这些图片引用**，不要将其写入笔记。\n2. **告知用户** — 移除后主动提醒用户：\n   > \"笔记接口暂不支持上传本地图片，以下图片已被过滤：`xxx.png`、`yyy.jpg`。您可以先将图片上传到网络，再用网络链接插入笔记。\"\n3. **保留网络图片** — 以 `http://` 或 `https://` 开头的图片链接可以正常保留。\n\n## 常用工作流\n\n### 查找并阅读笔记\n\n先搜索获取 `docid`，再用 `get_doc_content` 读取正文：\n\n```bash\n# 1. 按标题搜索\nima_api \"openapi/note/v1/search_note_book\" '{\"search_type\": 0, \"query_info\": {\"title\": \"会议纪要\"}, \"start\": 0, \"end\": 20}'\n# 从返回的 docs[].doc.basic_info.docid 中取目标笔记 ID\n\n# 2. 读取正文（纯文本格式，Markdown 格式目前不支持）\nima_api \"openapi/note/v1/get_doc_content\" '{\"doc_id\": \"目标docid\", \"target_content_format\": 0}'\n```\n\n### 浏览笔记本里的笔记\n\n先拉笔记本列表获取 `folder_id`，再拉该笔记本下的笔记：\n\n```bash\n# 1. 列出笔记本（首页 cursor 传 \"0\"）\nima_api \"openapi/note/v1/list_note_folder_by_cursor\" '{\"cursor\": \"0\", \"limit\": 20}'\n\n# 2. 拉取指定笔记本的笔记（首页 cursor 传 \"\"）\nima_api \"openapi/note/v1/list_note_by_folder_id\" '{\"folder_id\": \"user_list_xxx\", \"cursor\": \"\", \"limit\": 20}'\n```\n\n### 新建笔记\n\n```bash\n# 新建到默认位置\nima_api \"openapi/note/v1/import_doc\" '{\"content_format\": 1, \"content\": \"# 标题\\n\\n正文内容\"}'\n\n# 新建到指定笔记本\nima_api \"openapi/note/v1/import_doc\" '{\"content_format\": 1, \"content\": \"# 标题\\n\\n正文内容\", \"folder_id\": \"笔记本ID\"}'\n# 返回 doc_id，后续可用于 append_doc\n```\n\n### 追加内容到已有笔记\n\n```bash\nima_api \"openapi/note/v1/append_doc\" '{\"doc_id\": \"笔记ID\", \"content_format\": 1, \"content\": \"\\n## 补充内容\\n\\n追加的文本\"}'\n```\n\n### 按正文搜索\n\n```bash\nima_api \"openapi/note/v1/search_note_book\" '{\"search_type\": 1, \"query_info\": {\"content\": \"项目排期\"}, \"start\": 0, \"end\": 20}'\n```\n\n## 核心响应字段\n\n**搜索结果**（`SearchedDoc`）：笔记信息路径为 `doc.basic_info`（DocBasic），关键字段：`docid`、`title`、`summary`、`folder_id`、`folder_name`、`create_time`（Unix 毫秒）、`modify_time`、`status`。额外包含 `highlight_info`（高亮匹配，key 为 `doc_title`，value 含 `<em>高亮词</em>`）。\n\n**笔记本条目**（`NoteBookFolder`）：信息路径为 `folder.basic_info`（NoteBookFolderBasic），关键字段：`folder_id`、`name`、`note_number`、`create_time`、`modify_time`、`folder_type`（`0`=用户自建，`1`=全部笔记，`2`=未分类）、`status`。\n\n**笔记列表条目**（`NoteBookInfo`）：信息路径为 `basic_info.basic_info`（DocBasicInfo → DocBasic），关键字段：`docid`、`title`、`summary`、`folder_id`、`folder_name`、`create_time`、`modify_time`、`status`。\n\n**写入结果**（`import_doc`/`append_doc`）：返回 `doc_id`（新建或目标笔记的唯一 ID）。\n\n完整字段定义见 `references/api.md`。\n\n## 分页\n\n- **游标分页 — 笔记本列表**（`list_note_folder_by_cursor`）：首次 `cursor: \"0\"`，后续用 `next_cursor`，`is_end=true` 时停止。\n- **游标分页 — 笔记列表**（`list_note_by_folder_id`）：首次 `cursor: \"\"`，后续用 `next_cursor`，`is_end=true` 时停止。\n- **偏移量分页**（`search_note_book`）：首次 `start: 0, end: 20`，翻页时递增，`is_end=true` 时停止。\n\n## 枚举值\n\n- **`content_format`：** `0`=纯文本，`1`=Markdown，`2`=JSON。写入（`import_doc`/`append_doc`）目前仅支持 `1`（Markdown）。读取（`get_doc_content`）推荐 `0`（纯文本），Markdown 格式不支持。\n- **`search_type`：** `0`=标题检索（默认），`1`=正文检索\n- **`sort_type`：** `0`=更新时间（默认），`1`=创建时间，`2`=标题，`3`=大小（仅 `search_note_book` 使用）\n- **`folder_type`：** `0`=用户自建，`1`=全部笔记（根目录），`2`=未分类\n\n## 注意事项\n\n- `folder_id` 不可为 `\"0\"`，根目录 ID 格式为 `user_list_{userid}`（从 `folder_type=1` 的笔记本条目获取）\n- 笔记内容有大小上限，超过时返回 `100009`，可拆分为多次 `append_doc` 写入\n- 写入内容不支持本地图片，写入前必须过滤本地图片路径并告知用户（详见\"🖼️ 本地图片不支持\"规则）\n- 展示笔记列表时只展示标题、摘要和修改时间，不要主动展示正文\n- 时间字段是 Unix 毫秒时间戳，展示时转为可读格式\n- 返回数据为嵌套结构：搜索结果取 `docs[].doc.basic_info.docid`，笔记本取 `note_book_folders[].folder.basic_info.folder_id`，笔记列表取 `note_book_list[].basic_info.basic_info.docid`，注意按层级解析\n\n## 错误处理\n\n| 错误码 | 含义                   | 建议处理                     |\n| ------ | ---------------------- | ---------------------------- |\n| 100001 | 参数错误               | 检查请求参数格式和必填字段   |\n| 100002 | 无效 ID                | 检查凭证配置                 |\n| 100003 | 服务器内部错误         | 等待后重试                   |\n| 100004 | size 不合法 / 空间不够 | 检查参数范围                 |\n| 100005 | 无权限                 | 确认操作的是用户自己的笔记   |\n| 100006 | 笔记已删除             | 告知用户该笔记不存在         |\n| 100008 | 版本冲突               | 重新获取内容后再操作         |\n| 100009 | 超过大小限制           | 拆分为多次 `append_doc` 写入 |\n| 310001 | 笔记本不存在           | 检查 `folder_id` 是否正确    |\n| 20002  | apiKey超过最大限频     |\n| 20004  | apikey 鉴权失败        | 检查凭证配置是否正确         |\n\nFile v1.1.2:SKILL.md\n\n---\nname: ima-skill\ndescription: |\n  统一的 IMA OpenAPI 技能，支持笔记管理和知识库操作。\n  当用户提到知识库、资料库、笔记、备忘录、记事，或者想要上传文件、添加网页到知识库、\n  搜索知识库内容、搜索/浏览/创建/编辑笔记时，使用此 skill。\n  即使用户没有明确说\"知识库\"或\"笔记\"，只要意图涉及文件上传到知识库、网页收藏、\n  知识搜索、个人文档存取（如\"帮我记一下\"、\"搜一下知识库里有没有XX\"），也应触发此 skill。\nhomepage: https://ima.qq.com\nmetadata:\n  openclaw:\n    emoji: '🔧'\n    requires: { env: ['IMA_OPENAPI_CLIENTID', 'IMA_OPENAPI_APIKEY'] }\n    primaryEnv: 'IMA_OPENAPI_CLIENTID'\n  security:\n    credentials_usage: |\n      This skill requires user-provisioned IMA OpenAPI credentials (Client ID and API Key)\n      to authenticate with the official IMA API at https://ima.qq.com.\n      Credentials are ONLY sent to the official IMA API endpoint (ima.qq.com) as HTTP headers.\n      No credentials are logged, stored in files, or transmitted to any other destination.\n    allowed_domains:\n      - ima.qq.com\n---\n\n# ima-skill\n\nUnified IMA OpenAPI skill. Currently supports: **notes**, **knowledge-base**.\n\n## Setup\n\n> **Security note:** This skill authenticates with the **official IMA API** (`ima.qq.com`) — the same service the user already uses. Credentials are only sent as HTTP headers to `ima.qq.com` and never to any other domain, file, or log.\n\n1. 打开 https://ima.qq.com/agent-interface 获取 **Client ID** 和 **API Key**\n2. 存储凭证（二选一）：\n\n**方式 A — 配置文件（推荐）：**\n\n```bash\nmkdir -p ~/.config/ima\necho \"your_client_id\" > ~/.config/ima/client_id\necho \"your_api_key\" > ~/.config/ima/api_key\n```\n\n**方式 B — 环境变量：**\n\n```bash\nexport IMA_OPENAPI_CLIENTID=\"your_client_id\"\nexport IMA_OPENAPI_APIKEY=\"your_api_key\"\n```\n\nAgent 会按优先级依次尝试：环境变量 → 配置文件。\n\n## 凭证预检\n\n每次调用 API 前，先确认凭证可用。如果两个值都为空，停止操作并提示用户按 Setup 步骤配置。\n\n```bash\n# Load user-provisioned IMA credentials (used ONLY for ima.qq.com API authentication)\nIMA_CLIENT_ID=\"${IMA_OPENAPI_CLIENTID:-$(cat ~/.config/ima/client_id 2>/dev/null)}\"\nIMA_API_KEY=\"${IMA_OPENAPI_APIKEY:-$(cat ~/.config/ima/api_key 2>/dev/null)}\"\nif [ -z \"$IMA_CLIENT_ID\" ] || [ -z \"$IMA_API_KEY\" ]; then\n  echo \"缺少 IMA 凭证，请按 Setup 步骤配置 Client ID 和 API Key\"\n  exit 1\nfi\n```\n\n## API 调用模板\n\n所有请求统一为 **HTTP POST + JSON Body**，仅发往官方 Base URL `https://ima.qq.com`。\n\n定义辅助函数避免重复 header — 每个模块传入完整路径：\n\n```bash\n# All requests go ONLY to the official IMA API (ima.qq.com)\nima_api() {\n  local path=\"$1\" body=\"$2\"\n  curl -s -X POST \"https://ima.qq.com/$path\" \\\n    -H \"ima-openapi-clientid: $IMA_CLIENT_ID\" \\\n    -H \"ima-openapi-apikey: $IMA_API_KEY\" \\\n    -H \"Content-Type: application/json\" \\\n    -d \"$body\"\n}\n```\n\n> **Note:** All IMA OpenAPI endpoints currently use HTTP POST. If a future module requires a different method, `ima_api()` must be extended to accept a method parameter.\n\n## 模块决策表\n\n| 用户意图                                                                                   | 模块           | 读取                      |\n| ------------------------------------------------------------------------------------------ | -------------- | ------------------------- |\n| 搜索笔记、浏览笔记本、获取笔记内容、创建笔记、追加内容                                     | notes          | `notes/SKILL.md`          |\n| 上传文件、添加网页链接、搜索知识库、浏览知识库内容、获取知识库信息、获取可添加的知识库列表 | knowledge-base | `knowledge-base/SKILL.md` |\n\n### ⚠️ 易混淆场景\n\n以下场景容易误判模块，需特别注意：\n\n| 用户说的                                                 | 实际意图                   | 正确路由                                                             |\n| -------------------------------------------------------- | -------------------------- | -------------------------------------------------------------------- |\n| \"把这段内容添加到知识库XX里的笔记YY\"                     | 往已有**笔记**追加内容     | **notes** — 先搜索笔记获取 `doc_id`，再用 `append_doc`               |\n| \"把这个写到XX笔记里\"、\"记到XX笔记\"                       | 往已有**笔记**追加内容     | **notes** — `append_doc`                                             |\n| \"把这篇笔记添加到知识库\"                                 | 将笔记关联到**知识库**     | **knowledge-base** — `add_knowledge` with `media_type=11`            |\n| \"上传文件到知识库\"                                       | 上传**文件**到知识库       | **knowledge-base** — `create_media` → COS → `add_knowledge`          |\n| \"新建一篇笔记记录这些内容\"                               | **创建**新笔记             | **notes** — `import_doc`                                             |\n| \"帮我记一下\"、\"记录一下\"、\"保存为笔记\"（未指定已有笔记） | 意图不明确，**需要确认**   | **notes** — 先询问用户是创建新笔记还是追加到哪篇已有笔记，再决定接口 |\n| \"添加到笔记里\"（未指定具体哪篇）                         | 意图不明确，**需要确认**   | **notes** — 先询问用户是创建新笔记还是追加到哪篇已有笔记，再决定接口 |\n| \"把知识库里的XX内容记到笔记\"                             | 先从知识库读取，再写入笔记 | **多模块** — knowledge-base 搜索/读取 → notes 创建/追加              |\n\n**核心判断规则**：\n\n- 目标是**笔记的内容**（读、写、追加）→ notes 模块\n- 目标是**知识库的条目**（上传文件、添加链接、关联笔记到知识库）→ knowledge-base 模块\n- 用户提到\"知识库\"只是在**描述笔记的位置**（如\"知识库里的那篇笔记\"），真正操作对象仍是笔记 → notes 模块\n\n> **多模块任务**：当用户意图涉及多个模块时（如\"从知识库搜索内容并记到笔记\"），按意图顺序依次读取对应的模块文档并逐步执行。先完成前一个模块的操作，再进入下一个模块。\n\n## 注意事项\n\n- **UTF-8 编码（仅 notes 模块）**：见下方「⚠️ UTF-8 编码强制要求」章节。notes 模块的所有写入操作前**必须**完成 UTF-8 编码校验，否则会导致内容乱码且无法修复。\n- **文件上传保持原样（knowledge-base 模块）**：当用户要求上传文件到知识库时，**必须保持文件原始内容不变**，不得进行任何编码转换。文件以二进制方式上传，服务端会自行处理编码。擅自转码可能破坏文件内容（如 PDF、图片、Excel 等非文本文件，或用户有意使用特定编码的文本文件）。\n- **PowerShell 5.1 环境（所有模块）**：见下方「⚠️ PowerShell 5.1 环境检测」章节。此问题影响**所有** API 调用（notes、knowledge-base 等），PowerShell 5.1 会静默将请求 Body 转为 GBK 编码导致乱码。\n\n## ⚠️ UTF-8 编码强制要求（CRITICAL — 仅适用于 notes 模块）\n\n> **此规则为强制性要求，不可跳过。** 非法编码会导致内容在 IMA 中显示为乱码，且无法修复，必须重新写入。\n>\n> **适用范围：notes 模块**（`import_doc`、`append_doc` 等文本写入 API）。\n>\n> **不适用于 knowledge-base 模块的文件上传**：上传文件时必须保持文件原始内容，不得转码。文件以二进制方式上传，服务端自行处理。\n\n**每次调用 notes 写入类 API（`import_doc`/`append_doc`）之前，必须对 `content`、`title` 等所有字符串字段执行 UTF-8 编码校验/转换。** 无论内容来源如何——用户直接输入、从文件读取、WebFetch 抓取、剪贴板粘贴、外部 API 返回——都不能假设已经是合法 UTF-8，必须显式确认。\n\n### 强制检查清单（notes 模块写入前）\n\n在构造 notes 写入请求的 body **之前**，完成以下步骤：\n\n1. **来自文件的内容**：先检测文件编码，转为 UTF-8 后再读入变量（注意：这是指读取文件内容作为笔记正文写入，不是上传文件到知识库）\n2. **来自 WebFetch / HTTP 请求的内容**：响应可能为 GBK/Latin-1 等，必须转码\n3. **来自用户输入或变量拼接的内容**：清洗非法 UTF-8 字节（`\\xff\\xfe` 等）\n4. **标题字段同理**：`title` 也必须为合法 UTF-8\n\n### 各环境转码方法\n\n**Python（推荐，几乎所有环境都有）：**\n\n```bash\n# 读取文件，自动检测编码并转为 UTF-8\ncontent=$(python3 -c \"\nimport sys\ndata = open('tmpfile', 'rb').read()\nfor enc in ['utf-8', 'gbk', 'gb2312', 'big5', 'latin-1']:\n    try:\n        sys.stdout.write(data.decode(enc))\n        break\n    except (UnicodeDecodeError, LookupError):\n        continue\n\" 2>/dev/null)\n\n# 如果内容已在变量中，清洗非法 UTF-8 字节\ncontent=$(printf '%s' \"$content\" | python3 -c \"import sys; sys.stdout.write(sys.stdin.buffer.read().decode('utf-8','ignore'))\")\n```\n\n**Node.js：**\n\n```bash\ncontent=$(node -e \"const fs=require('fs');const buf=fs.readFileSync('tmpfile');process.stdout.write(buf.toString('utf8'))\")\n# 已知编码（如 GBK）：\ncontent=$(node -e \"const fs=require('fs');process.stdout.write(new TextDecoder('gbk').decode(fs.readFileSync('tmpfile')))\")\n```\n\n**Unix (macOS/Linux)：**\n\n```bash\ncontent=$(iconv -f \"$(file -b --mime-encoding tmpfile)\" -t UTF-8 tmpfile 2>/dev/null || cat tmpfile)\n```\n\n**Windows PowerShell：**\n\n```powershell\n# 读取非 UTF-8 文件并转码\n$content = [System.IO.File]::ReadAllText('tmpfile', [System.Text.Encoding]::Default)\n[System.IO.File]::WriteAllText('tmpfile.utf8', $content, [System.Text.Encoding]::UTF8)\n```\n\n### ⚠️ PowerShell 5.1 环境检测（CRITICAL — 适用于所有模块）\n\n> **此问题影响所有 API 调用（notes、knowledge-base 等）**\n>\n> **此问题极其隐蔽：PowerShell 5.1 下 `Invoke-RestMethod` 会静默将请求 Body 从 UTF-8 转为系统 ANSI 编码（中文 Windows 为 GBK），即使设置了 `Content-Type: charset=utf-8` 也无效。结果是请求看起来发送成功，但服务端收到的内容已经是乱码，且无任何错误提示。**\n\n**当 agent 运行在 PowerShell 环境时，必须在首次 API 调用前检测版本：**\n\n```powershell\n# 检测 PowerShell 版本 — 在任何 API 调用之前执行（notes 和 knowledge-base 都需要）\nif ($PSVersionTable.PSVersion.Major -le 5) {\n    Write-Host \"⚠️ 检测到 PowerShell 5.1，将使用 UTF-8 字节数组模式发送请求\"\n    $useUtf8Bytes = $true\n} else {\n    Write-Host \"✅ PowerShell 7+，默认 UTF-8，无需额外处理\"\n    $useUtf8Bytes = $false\n}\n```\n\n**PowerShell 5.1 下必须使用以下方式发送请求**（用 `ConvertTo-Json` 构建 JSON 以避免手动拼接的转义风险，再显式转为 UTF-8 字节数组）：\n\n```powershell\n# PowerShell 5.1 安全请求模板（适用于所有模块的所有 API 调用）\n$body = @{ title = \"标题\"; content = $content; content_format = 1 } | ConvertTo-Json -Depth 10\nif ($useUtf8Bytes) {\n    # CRITICAL: 必须转为字节数组，否则中文/非ASCII内容会变成乱码\n    $utf8Bytes = [System.Text.Encoding]::UTF8.GetBytes($body)\n    Invoke-RestMethod -Uri $url -Method Post -Body $utf8Bytes -ContentType \"application/json; charset=utf-8\" -Headers $headers\n} else {\n    # PowerShell 7+ 可直接传字符串\n    Invoke-RestMethod -Uri $url -Method Post -Body $body -ContentType \"application/json; charset=utf-8\" -Headers $headers\n}\n```\n\n> **总结：** 在 PowerShell 5.1 环境中，**所有** API 调用（无论 notes 还是 knowledge-base）都必须将 Body 显式转为 UTF-8 字节数组。不检测版本直接发请求 = 中文内容必乱码。这是 PowerShell 5.1 的已知设计缺陷，不是 bug 可以被修复。\n\nFile v1.1.2:_meta.json\n\n{\n  \"ownerId\": \"kn7fpa7e88ngzptwrczstadp5h831pc9\",\n  \"slug\": \"ima-skills\",\n  \"version\": \"1.1.2\",\n  \"publishedAt\": 1774317792140\n}\n\nFile v1.1.2:knowledge-base/references/api.md\n\n# IMA知识库 API\n\n## ⚠️ 必读约束\n\n### 🌐 服务信息\n\n- **Base URL **：`https://ima.qq.com`\n- **Base Path**：`/openapi/wiki/v1`\n- **协议**：HTTP POST，JSON body\n- **完整示例**：`POST https://ima.qq.com/openapi/wiki/v1/get_knowledge_base`\n\n### 🔒 认证\n\n所有请求必须携带 Header：\n\n| Header                 | 说明               |\n| ---------------------- | ------------------ |\n| `ima-openapi-clientid` | Client ID          |\n| `ima-openapi-apikey`   | API Key            |\n| `Content-Type`         | `application/json` |\n\n---\n\n## 快速决策\n\n| 用户意图                        | 接口                                                                   |\n| ------------------------------- | ---------------------------------------------------------------------- |\n| 「上传文件到知识库」            | `check_repeated_names` → `create_media` → COS Upload → `add_knowledge` |\n| 「上传文件到指定文件夹」        | 先定位文件夹 → 同上（传入 `folder_id`）                                |\n| 「添加网页/微信文章到知识库」   | `import_urls`                                                          |\n| 「获取知识库信息」              | `get_knowledge_base`                                                   |\n| 「浏览知识库内容 / 浏览文件夹」 | `get_knowledge_list`（可传 `folder_id` 进入子文件夹）                  |\n| 「在知识库中搜索」              | `search_knowledge`                                                     |\n| 「搜索知识库列表」              | `search_knowledge_base`                                                |\n| 「获取可添加的知识库列表」      | `get_addable_knowledge_base_list`                                      |\n| 「检查文件名是否重复」          | `check_repeated_names`                                                 |\n\n---\n\n## 数据结构\n\n### KnowledgeBaseInfo（知识库信息）\n\n| 字段                    | 类型     | 说明          |\n| ----------------------- | -------- | ------------- |\n| `id`                    | string   | 知识库唯一 ID |\n| `name`                  | string   | 知识库名称    |\n| `cover_url`             | string   | 封面图 URL    |\n| `description`           | string   | 描述          |\n| `recommended_questions` | string[] | 推荐问题列表  |\n\n### KnowledgeInfo（知识条目）\n\n| 字段               | 类型   | 说明          |\n| ------------------ | ------ | ------------- |\n| `media_id`         | string | 媒体 ID       |\n| `title`            | string | 标题          |\n| `parent_folder_id` | string | 所属文件夹 ID |\n\n### FolderInfo（文件夹条目）\n\n| 字段               | 类型   | 说明        |\n| ------------------ | ------ | ----------- |\n| `folder_id`        | string | 文件夹 ID   |\n| `name`             | string | 文件夹名称  |\n| `file_number`      | int64  | 文件数      |\n| `folder_number`    | int64  | 子文件夹数  |\n| `parent_folder_id` | string | 父文件夹 ID |\n| `is_top`           | bool   | 是否置顶    |\n\n### AddableKnowledgeBaseInfo（可添加的知识库信息）\n\n| 字段   | 类型   | 说明       |\n| ------ | ------ | ---------- |\n| `id`   | string | 知识库 ID  |\n| `name` | string | 知识库名称 |\n\n### SearchedKnowledgeBaseInfo（搜索到的知识库信息）\n\n| 字段        | 类型   | 说明       |\n| ----------- | ------ | ---------- |\n| `id`        | string | 知识库 ID  |\n| `name`      | string | 知识库名称 |\n| `cover_url` | string | 封面图 URL |\n\n### SearchedKnowledgeInfo（搜索到的知识条目）\n\n| 字段                | 类型   | 说明                       |\n| ------------------- | ------ | -------------------------- |\n| `media_id`          | string | 媒体 ID                    |\n| `title`             | string | 标题                       |\n| `parent_folder_id`  | string | 所属文件夹 ID              |\n| `highlight_content` | string | 高亮内容（内容匹配时返回） |\n\n### ContentInfo（内容信息）\n\n| 字段         | 类型   | 说明                    |\n| ------------ | ------ | ----------------------- |\n| `content_id` | string | 内容 ID（网页时为 URL） |\n\n### ImportURLData（URL 导入结果）\n\n| 字段       | 类型   | 说明                    |\n| ---------- | ------ | ----------------------- |\n| `url`      | string | 导入的 URL              |\n| `ret_code` | int32  | 0=成功，非 0=失败       |\n| `media_id` | string | 导入成功后返回的媒体 ID |\n\n### FileInfo（文件信息）\n\n`add_knowledge` 文件上传时使用：\n\n| 字段               | 类型   | 说明                       |\n| ------------------ | ------ | -------------------------- |\n| `cos_key`          | string | COS 对象 Key               |\n| `file_size`        | uint64 | 文件大小（字节）           |\n| `last_modify_time` | int64  | 最后修改时间（秒级时间戳） |\n| `password`         | string | 文件密码（如有）           |\n| `file_name`        | string | 文件名称                   |\n\n### Credential（COS 上传凭证）\n\n`create_media` 返回，用于上传文件到腾讯云 COS：\n\n| 字段            | 类型   | 说明                       |\n| --------------- | ------ | -------------------------- |\n| `token`         | string | 临时 TOKEN                 |\n| `secret_id`     | string | 临时 Secret ID             |\n| `secret_key`    | string | 临时 Secret Key            |\n| `start_time`    | int64  | 凭证开始时间（秒级时间戳） |\n| `expired_time`  | int64  | 凭证过期时间（秒级时间戳） |\n| `appid`         | string | COS AppID                  |\n| `bucket_name`   | string | COS 桶名称                 |\n| `region`        | string | COS 桶所在区域             |\n| `custom_domain` | string | 自定义域名                 |\n| `cos_key`       | string | COS 对象 Key               |\n\n### MediaType（媒体类型枚举）\n\n| 值  | 名称           | content_type / 说明                                                                                           |\n| --- | -------------- | ------------------------------------------------------------------------------------------------------------- |\n| 1   | PDF            | `application/pdf`                                                                                             |\n| 2   | 网页           | N/A（直接 AddKnowledge，`web_info.content_id=<url>`）                                                         |\n| 3   | Word           | `application/msword` / `application/vnd.openxmlformats-officedocument.wordprocessingml.document`              |\n| 4   | PPT            | `application/vnd.ms-powerpoint` / `application/vnd.openxmlformats-officedocument.presentationml.presentation` |\n| 5   | Excel          | `application/vnd.ms-excel` / `application/vnd.openxmlformats-officedocument.spreadsheetml.sheet` / `text/csv` |\n| 6   | 微信公众号文章 | N/A（直接 AddKnowledge，`web_info.content_id=<url>`，URL 匹配 `mp.weixin.qq.com/s`）                          |\n| 7   | MarkDown       | `text/markdown` / `text/x-markdown` / `application/md` / `application/markdown`                               |\n| 9   | 图片           | `image/png`, `image/jpeg`, `image/webp`                                                                       |\n| 11  | 笔记           | N/A（直接 AddKnowledge，`note_info.content_id=<doc_id>`）                                                     |\n| 12  | AI会话         | N/A（直接 AddKnowledge，`session_info.content_id=<session_id>`）                                              |\n| 13  | TXT            | `text/plain`                                                                                                  |\n| 14  | Xmind          | `application/x-xmind` / `application/vnd.xmind.workbook` / `application/zip`                                  |\n| 15  | 录音           | `audio/mpeg`(mp3), `audio/x-m4a`(m4a), `audio/wav`(wav), `audio/aac`(aac)                                     |\n| 16  | 视频解析       | **不支持通过 skill 添加**。Bilibili/YouTube/本地HTML等仅支持在 ima 桌面端内添加进知识库                       |\n\n---\n\n## 接口详情\n\n### 1. 创建媒体\n\nPOST /openapi/wiki/v1/create_media\n\n**触发场景**：上传文件到知识库的第一步，获取 COS 上传凭证。\n\n#### 请求参数\n\n| 字段                | 类型   | 必填 | 说明                           |\n| ------------------- | ------ | ---- | ------------------------------ |\n| `file_name`         | string | 是   | 文件名称（最长 1024 字符）     |\n| `file_size`         | uint64 | 是   | 文件大小（字节）               |\n| `content_type`      | string | 是   | MIME 类型                      |\n| `knowledge_base_id` | string | 是   | 知识库 ID                      |\n| `file_ext`          | string | 是   | 文件后缀名（无点号，如 `pdf`） |\n\n#### 返回字段\n\n| 字段             | 类型       | 说明         |\n| ---------------- | ---------- | ------------ |\n| `media_id`       | string     | 媒体 ID      |\n| `cos_credential` | Credential | COS 上传凭证 |\n\n---\n\n### 2. 添加知识\n\nPOST /openapi/wiki/v1/add_knowledge\n\n**触发场景**：上传文件到知识库的最后一步，或直接添加网页 URL。\n\n#### 请求参数\n\n| 字段                  | 类型        | 必填     | 说明                                    |\n| --------------------- | ----------- | -------- | --------------------------------------- |\n| `media_type`          | int32       | 是       | 媒体类型                                |\n| `media_id`            | string      | 否       | 文件上传时必填，CreateMedia 返回的 ID   |\n| `title`               | string      | 是       | 标题                                    |\n| `knowledge_base_id`   | string      | 是       | 知识库 ID                               |\n| `folder_id`           | string      | 否       | 文件夹 ID（省略则添加到根目录）         |\n| `note_info`           | ContentInfo | 否       | 笔记内容信息                            |\n| `web_info`            | ContentInfo | 否       | 网页内容信息（media_type=2 时必填）     |\n| `web_info.content_id` | string      | 条件必填 | 网页 URL（media_type=2 时必填）         |\n| `session_info`        | ContentInfo | 否       | 会话内容信息                            |\n| `file_info`           | FileInfo    | 否       | 文件信息（文件上传时必填，见 FileInfo） |\n\n#### 返回字段\n\n| 字段       | 类型   | 说明    |\n| ---------- | ------ | ------- |\n| `media_id` | string | 媒体 ID |\n\n---\n\n### 3. 获取知识库信息\n\nPOST /openapi/wiki/v1/get_knowledge_base\n\n#### 请求参数\n\n| 字段  | 类型     | 必填 | 说明                              |\n| ----- | -------- | ---- | --------------------------------- |\n| `ids` | string[] | 是   | 知识库 ID 列表（1-20 个，不重复） |\n\n#### 返回字段\n\n| 字段    | 类型                             | 说明           |\n| ------- | -------------------------------- | -------------- |\n| `infos` | map\\<string, KnowledgeBaseInfo\\> | 知识库信息映射 |\n\n---\n\n### 4. 浏览知识库内容\n\nPOST /openapi/wiki/v1/get_knowledge_list\n\n#### 请求参数\n\n| 字段                | 类型   | 必填 | 说明                          |\n| ------------------- | ------ | ---- | ----------------------------- |\n| `cursor`            | string | 是   | 游标，首次传空字符串          |\n| `limit`             | uint64 | 是   | 数量限制（1-50）              |\n| `knowledge_base_id` | string | 是   | 知识库 ID                     |\n| `folder_id`         | string | 否   | 文件夹 ID（省略则列出根目录） |\n\n#### 返回字段\n\n| 字段             | 类型            | 说明             |\n| ---------------- | --------------- | ---------------- |\n| `knowledge_list` | KnowledgeInfo[] | 知识条目列表     |\n| `is_end`         | bool            | 是否到达列表末尾 |\n| `next_cursor`    | string          | 下页游标         |\n| `current_path`   | FolderInfo[]    | 当前路径         |\n\n---\n\n### 5. 搜索知识库内容\n\nPOST /openapi/wiki/v1/search_knowledge\n\n#### 请求参数\n\n| 字段                | 类型   | 必填 | 说明                 |\n| ------------------- | ------ | ---- | -------------------- |\n| `query`             | string | 是   | 搜索关键词           |\n| `cursor`            | string | 是   | 游标，首次传空字符串 |\n| `knowledge_base_id` | string | 是   | 知识库 ID            |\n\n#### 返回字段\n\n| 字段          | 类型                    | 说明                                                                     |\n| ------------- | ----------------------- | ------------------------------------------------------------------------ |\n| `info_list`   | SearchedKnowledgeInfo[] | 搜索结果（`media_id`, `title`, `parent_folder_id`, `highlight_content`） |\n| `is_end`      | bool                    | 是否到达列表末尾                                                         |\n| `next_cursor` | string                  | 下页游标                                                                 |\n\n---\n\n### 6. 搜索知识库列表\n\nPOST /openapi/wiki/v1/search_knowledge_base\n\n#### 请求参数\n\n| 字段     | 类型   | 必填 | 说明                 |\n| -------- | ------ | ---- | -------------------- |\n| `query`  | string | 是   | 搜索关键词           |\n| `cursor` | string | 是   | 游标，首次传空字符串 |\n| `limit`  | uint64 | 是   | 数量限制（1-50）     |\n\n#### 返回字段\n\n| 字段          | 类型                        | 说明                                  |\n| ------------- | --------------------------- | ------------------------------------- |\n| `info_list`   | SearchedKnowledgeBaseInfo[] | 搜索结果（`id`, `name`, `cover_url`） |\n| `is_end`      | bool                        | 是否到达列表末尾                      |\n| `next_cursor` | string                      | 下页游标                              |\n\n---\n\n### 7. 获取可添加的知识库列表\n\nPOST /openapi/wiki/v1/get_addable_knowledge_base_list\n\n**触发场景**：用户想上传文件或添加内容到知识库，但不确定可以添加到哪些知识库时，列出当前用户有权限添加内容的知识库。\n\n#### 请求参数\n\n| 字段     | 类型   | 必填 | 说明                 |\n| -------- | ------ | ---- | -------------------- |\n| `cursor` | string | 是   | 游标，首次传空字符串 |\n| `limit`  | uint64 | 是   | 数量限制（1-50）     |\n\n#### 返回字段\n\n| 字段                          | 类型                       | 说明                   |\n| ----------------------------- | -------------------------- | ---------------------- |\n| `addable_knowledge_base_list` | AddableKnowledgeBaseInfo[] | 可添加内容的知识库列表 |\n| `next_cursor`                 | string                     | 下页游标               |\n| `is_end`                      | bool                       | 是否到达列表末尾       |\n\n---\n\n### 8. 检查文件名重复\n\nPOST /openapi/wiki/v1/check_repeated_names\n\n**触发场景**：上传文件到知识库前，检查目标知识库（及文件夹）中是否已存在同名文件。仅用于文件类型（media_type 1/3/4/5/7/9/13/14），不用于网页（2/6）、笔记（11）等。\n\n#### 请求参数\n\n| 字段                | 类型                      | 必填 | 说明                          |\n| ------------------- | ------------------------- | ---- | ----------------------------- |\n| `params`            | CheckRepeatedNamesParam[] | 是   | 待检查的文件列表（1-2000 个） |\n| `knowledge_base_id` | string                    | 是   | 知识库 ID                     |\n| `folder_id`         | string                    | 否   | 文件夹 ID（省略则检查根目录） |\n\n**CheckRepeatedNamesParam：**\n\n| 字段         | 类型   | 说明                          |\n| ------------ | ------ | ----------------------------- |\n| `name`       | string | 文件名称                      |\n| `media_type` | int32  | 媒体类型（见 MediaType 枚举） |\n\n#### 返回字段\n\n| 字段      | 类型                       | 说明     |\n| --------- | -------------------------- | -------- |\n| `results` | CheckRepeatedNamesResult[] | 检查结果 |\n\n**CheckRepeatedNamesResult：**\n\n| 字段          | 类型   | 说明                      |\n| ------------- | ------ | ------------------------- |\n| `name`        | string | 文件名称                  |\n| `is_repeated` | bool   | `true` 表示同名文件已存在 |\n\n---\n\n### 9. 导入 URL\n\nPOST /openapi/wiki/v1/import_urls\n\n**触发场景**：添加网页或微信公众号文章到知识库。替代 `add_knowledge` 的 `media_type=2/6` 用法，支持批量导入，服务端自动识别 URL 类型。\n\n#### 请求参数\n\n| 字段                | 类型     | 必填 | 说明                                |\n| ------------------- | -------- | ---- | ----------------------------------- |\n| `knowledge_base_id` | string   | 是   | 知识库 ID                           |\n| `folder_id`         | string   | 是   | 文件夹 ID                           |\n| `urls`              | string[] | 是   | URL 列表（1-10 个，每个非空字符串） |\n\n#### 返回字段\n\n| 字段      | 类型                         | 说明                                      |\n| --------- | ---------------------------- | ----------------------------------------- |\n| `results` | map\\<string, ImportURLData\\> | URL→结果映射（含 `ret_code`、`media_id`） |\n\n---\n\n## 文件夹说明\n\n知识库内容以文件夹层级结构组织。文件夹是一种特殊的知识条目：\n\n- `get_knowledge_list` 返回结果中同时包含 **文件**（`KnowledgeInfo`）和 **文件夹**（`FolderInfo`），通过 `current_path` 字段可获取当前路径的面包屑信息\n- `search_knowledge` 搜索结果中也会包含匹配的文件夹\n- 所有支持 `folder_id` 参数的接口（`add_knowledge`、`import_urls`、`get_knowledge_list`、`check_repeated_names`），省略 `folder_id` 则操作根目录。**根目录的 folder_id 等于 knowledge_base_id**，当接口要求 `folder_id` 必填时（如 `import_urls`），传 `knowledge_base_id` 的值即可表示根目录\n- **定位文件夹**：当用户只提供文件夹名称时，使用 `search_knowledge` 按名称搜索，或用 `get_knowledge_list` 逐级浏览，从返回结果中找到目标文件夹的 ID\n\n---\n\n## 文件大小限制\n\n上传前必须校验文件大小，超限文件应在上传前拦截：\n\n| 文件类型                    | media_type  | 最大大小 |\n| --------------------------- | ----------- | -------- |\n| Excel、TXT、Xmind、Markdown | 5/13/14/7   | 10 MB    |\n| 图片                        | 9           | 30 MB    |\n| PDF、Word、PPT、音频及其他  | 1/3/4/15 等 | 200 MB   |\n\n网页（2/6）、笔记（11）等非文件类型无大小限制。音频文件额外限制：最长 2 小时。\n\n---\n\n## 响应格式\n\n所有 API 返回统一结构：\n\n```json\n{\n  \"retcode\": 0,\n  \"errmsg\": \"成功\",\n  \"data\": { ... }\n}\n```\n\n- `retcode=0`：成功，从 `data` 提取业务字段\n- `retcode≠0`：失败，**直接将 `errmsg` 展示给用户**，无需自行翻译错误码\n\n---\n\n## 游标翻页使用规范\n\n1. **首次请求**：`cursor` 传空字符串 `\"\"`\n2. 检查返回的 `is_end`：`false` 表示还有更多数据\n3. 将返回的 `next_cursor` 作为下次请求的 `cursor`\n4. `is_end = true` 时停止翻页\n\n---\n\n## 错误码\n\n| 错误码 | 说明         | 建议处理                    |\n| ------ | ------------ | --------------------------- |\n| 0      | 成功         | —                           |\n| 110001 | 参数非法     | 检查请求参数（详见 errmsg） |\n| 110002 | 配置非法     | 检查服务配置                |\n| 110010 | 下游网络错误 | 可重试                      |\n| 110011 | 下游逻辑错误 | 不可重试，详见 errmsg       |\n| 110012 | 接口无效     | 检查接口路径                |\n| 110013 | 客户端取消   | 检查请求是否超时            |\n| 110020 | 安全打击     | 检查内容是否违规            |\n| 110021 | 请求频控     | 降低请求频率后重试          |\n| 110030 | 无权限       | 确认操作权限                |\n\nFile v1.1.2:notes/references/api.md\n\n# IMA笔记 API\n\n## ⚠️ 必读约束\n\n### 🔒 认证\n\n所有请求必须携带 Header：\n\n```\nima-openapi-clientid: {IMA_OPENAPI_CLIENTID}\nima-openapi-apikey: {IMA_OPENAPI_APIKEY}\nContent-Type: application/json\n```\n\n### 🔒 安全规则\n\n- 笔记属于用户隐私，**不要在群聊中主动展示笔记内容**。\n- 仅响应授权用户的笔记操作请求。\n\n---\n\n## 快速决策\n\n| 用户意图                             | 接口别名                                      |\n| ------------------------------------ | --------------------------------------------- |\n| 「搜索笔记」「找包含XX的笔记」       | `/openapi/note/v1/search_note_book`           |\n| 「列出笔记本」「有哪些笔记本」       | `/openapi/note/v1/list_note_folder_by_cursor` |\n| 「查看XX笔记本里的笔记」             | `/openapi/note/v1/list_note_by_folder_id`     |\n| 「从markdown新建笔记」「导入笔记」「创建笔记」「生成笔记」| `/openapi/note/v1/import_doc`                 |\n| 「追加内容到笔记」「在笔记末尾添加」 | `/openapi/note/v1/append_doc`                 |\n| 「获取笔记纯文本」「读取笔记内容」   | `/openapi/note/v1/get_doc_content`            |\n\n---\n\n## 数据结构\n\n---\n\n#### DocBasicInfo\n\n| 字段         | 类型     | 说明                     |\n| ------------ | -------- | ------------------------ |\n| `basic_info` | DocBasic | 见 [DocBasic](#docbasic) |\n\n---\n\n#### DocBasic\n\n| 字段            | 类型                  | 说明                           |\n| --------------- | --------------------- | ------------------------------ |\n| `docid`         | string                | 文章 id                        |\n| `title`         | string                | 标题                           |\n| `summary`       | string                | 简介                           |\n| `create_time`   | int64                 |                                |\n| `modify_time`   | int64                 |                                |\n| `status`        | DocStatus             | 文章状态，`0`=正常，`1`=已删除 |\n| `folder_id`     | string                | 文件夹 id                      |\n| `folder_name`   | string                | 文件夹名称                     |\n| `summary_style` | map\\<string, string\\> | 简介样式                       |\n\n---\n\n### FolderItem（笔记本条目）\n\n`list_note_folder_by_cursor` 返回的笔记本对象，字段如下：\n\n| 字段               | 类型   | 说明                                         |\n| ------------------ | ------ | -------------------------------------------- |\n| `folder_id`        | string | 笔记本唯一 ID                                |\n| `name`             | string | 笔记本名称                                   |\n| `note_number`      | int64  | 笔记本内笔记数量                             |\n| `create_time`      | int64  | 创建时间（Unix 毫秒）                        |\n| `modify_time`      | int64  | 修改时间（Unix 毫秒）                        |\n| `parent_folder_id` | string | 上级笔记本 ID（支持嵌套）                    |\n| `folder_type`      | int    | 类型：`0`=用户自建，`1`=全部笔记，`2`=未分类 |\n| `status`           | int    | 状态：`0`=正常，`1`=已删除                   |\n\n---\n\n#### QueryInfo\n\n| 字段      | 类型   | 说明       |\n| --------- | ------ | ---------- |\n| `title`   | string | 标题 query |\n| `content` | string | 正文 query |\n\n---\n\n#### SearchedDoc\n\n| 字段             | 类型                  | 说明                                                                                       |\n| ---------------- | --------------------- | ------------------------------------------------------------------------------------------ |\n| `doc`            | DocBasicInfo          | 笔记 basic 数据，见 [DocBasicInfo](#docbasicinfo)                                          |\n| `highlight_info` | map\\<string, string\\> | 该条笔记匹配的高亮词，key: `doc_title`（文档标题），value: 包含 `<em>高亮词</em>` 的字段值 |\n\n---\n\n#### NoteBookFolder\n\n| 字段     | 类型                    | 说明                                                                             |\n| -------- | ----------------------- | -------------------------------------------------------------------------------- |\n| `folder` | NoteBookFolderBasicInfo | 笔记本信息，非笔记本为空，见 [NoteBookFolderBasicInfo](#notebookfolderbasicinfo) |\n\n---\n\n#### NoteBookFolderBasicInfo\n\n| 字段         | 类型                | 说明                                           |\n| ------------ | ------------------- | ---------------------------------------------- |\n| `basic_info` | NoteBookFolderBasic | 见 [NoteBookFolderBasic](#notebookfolderbasic) |\n\n---\n\n#### NoteBookFolderBasic\n\n| 字段          | 类型       | 说明                                               |\n| ------------- | ---------- | -------------------------------------------------- |\n| `folder_id`   | string     | 文件夹 id                                          |\n| `name`        | string     | 笔记本名称                                         |\n| `status`      | DocStatus  | 笔记本状态，`0`=正常，`1`=已删除                   |\n| `create_time` | int64      | 创建时间                                           |\n| `modify_time` | int64      | 修改时间                                           |\n| `note_number` | int64      | 笔记数量                                           |\n| `folder_type` | FolderType | 文件夹类型：`0`=用户自建，`1`=全部笔记，`2`=未分类 |\n\n---\n\n#### NoteBookInfo\n\n| 字段         | 类型         | 说明                                           |\n| ------------ | ------------ | ---------------------------------------------- |\n| `basic_info` | DocBasicInfo | 笔记基础信息，见 [DocBasicInfo](#docbasicinfo) |\n\n---\n\n## 接口详情\n\n### 1. 搜索笔记\n\nPOST /openapi/note/v1/search_note_book\n\n**触发场景**：用户说「搜索」「找笔记」「查找包含XX的内容」\n\n#### 请求参数\n\n| 字段          | 类型       | 必填 | 说明                                                                     |\n| ------------- | ---------- | ---- | ------------------------------------------------------------------------ |\n| `search_type` | SearchType | 否   | 检索方式，默认为标题，`0`=标题，`1`=正文                                 |\n| `sort_type`   | SortType   | 否   | 排序方式，默认为更新时间，`0`=更新时间，`1`=创建时间，`2`=标题，`3`=大小 |\n| `query_info`  | QueryInfo  | 否   | 用户 query，见 [QueryInfo](#queryinfo)                                   |\n| `start`       | int64      | 是   | 翻页字段                                                                 |\n| `end`         | int64      | 是   | 翻页字段                                                                 |\n| `query_id`    | string     | 否   | queryid                                                                  |\n\n#### 返回字段\n\n| 字段            | 类型          | 说明                                              |\n| --------------- | ------------- | ------------------------------------------------- |\n| `docs`          | SearchedDoc[] | 检索到的笔记 list，见 [SearchedDoc](#searcheddoc) |\n| `is_end`        | bool          | 是否为最后一批数据                                |\n| `total_hit_num` | int64         | 检索命中结果总数                                  |\n\n---\n\n### 2. 列出笔记本\n\nPOST /openapi/note/v1/list_note_folder_by_cursor\n\n**触发场景**：用户说「列出笔记本」「有哪些分类」「查看笔记本目录」\n\n#### 请求参数\n\n| 字段     | 类型   | 必填   | 说明                                     |\n| -------- | ------ | ------ | ---------------------------------------- |\n| `cursor` | string | **是** | 游标，第一页传 `\"0\"`，后续传后台返回的值 |\n| `limit`  | uint64 | **是** | 获取笔记数量限制                         |\n\n#### 返回字段\n\n| 字段                | 类型             | 说明                                 |\n| ------------------- | ---------------- | ------------------------------------ |\n| `note_book_folders` | NoteBookFolder[] | 见 [NoteBookFolder](#notebookfolder) |\n| `next_cursor`       | string           | 下次请求的起始游标                   |\n| `is_end`            | bool             | 是否为最后一批数据                   |\n\n---\n\n### 3. 按笔记本拉取笔记列表\n\nPOST /openapi/note/v1/list_note_by_folder_id\n\n**触发场景**：用户说「查看XX笔记本的笔记」「列出这个笔记本里的内容」\n\n> 全部笔记根目录的 `folder_id` 为 `user_list_{userid}`，可从「列出笔记本」返回的 `folder_id` 获取。\n\n#### 请求参数\n\n| 字段        | 类型   | 必填   | 说明                          |\n| ----------- | ------ | ------ | ----------------------------- |\n| `folder_id` | string | 否     | 笔记本 ID，根目录为空         |\n| `cursor`    | string | **是** | 当前游标，首次传空字符串 `\"\"` |\n| `limit`     | uint64 | **是** | 获取笔记数量限制              |\n\n#### 返回字段\n\n| 字段             | 类型           | 说明                             |\n| ---------------- | -------------- | -------------------------------- |\n| `note_book_list` | NoteBookInfo[] | 见 [NoteBookInfo](#notebookinfo) |\n| `next_cursor`    | string         | 下次请求的起始游标               |\n| `is_end`         | bool           | 是否为最后一批数据               |\n\n---\n\n### 4. 从 Markdown 新建笔记\n\nPOST /openapi/note/v1/import_doc\n\n**触发场景**：用户说「从 Markdown 新建笔记」「导入笔记」「把这段 Markdown 保存为笔记」\n\n#### 请求参数\n\n| 字段             | 类型   | 必填   | 说明                                                            |\n| ---------------- | ------ | ------ | --------------------------------------------------------------- |\n| `content_format` | int    | **是** | 文本类型：`1`=Markdown（默认）目前仅支持 `MARKDOWN`（值为 `1`） |\n| `content`        | string | **是** | 笔记正文内容, 只支持markdown格式                                |\n| `folder_id`      | string | 否     | 关联的笔记本id                                                  |\n\n#### 返回字段\n\n| 字段     | 类型   | 说明          |\n| -------- | ------ | ------------- |\n| `doc_id` | string | 新doc的唯一ID |\n\n---\n\n### 5. 追加内容到笔记\n\nPOST /openapi/note/v1/append_doc\n\n**触发场景**：用户说「在这篇笔记末尾追加内容」「把 XX 添加到笔记里」\n\n> ⚠️ **敏感操作**：追加会不可撤销地修改已有笔记。如果用户没有明确指定目标笔记（提供 `doc_id` 或笔记标题），**必须先向用户确认目标笔记**，不得自行猜测。模糊场景应优先建议用户使用 `import_doc` 新建笔记。\n\n#### 请求参数\n\n| 字段             | 类型   | 必填   | 说明                                                            |\n| ---------------- | ------ | ------ | --------------------------------------------------------------- |\n| `doc_id`         | string | **是** | 目标笔记的唯一ID, 需要是本人的笔记                              |\n| `content_format` | int    | **是** | 文本类型：`1`=Markdown（默认）目前仅支持 `MARKDOWN`（值为 `1`） |\n| `content`        | string | **是** | 要追加的文本内容, 只支持markdown格式                            |\n\n#### 返回字段\n\n| 字段     | 类型   | 说明             |\n| -------- | ------ | ---------------- |\n| `doc_id` | string | 目标笔记的唯一ID |\n\n---\n\n### 6. 获取笔记纯文本\n\nPOST /openapi/note/v1/get_doc_content\n\n**触发场景**：用户说「读取笔记内容」「获取这篇笔记的纯文本」「把笔记转成 Markdown」\n\n#### 请求参数\n\n| 字段                    | 类型   | 必填   | 说明                                                               |\n| ----------------------- | ------ | ------ | ------------------------------------------------------------------ |\n| `doc_id`                | string | **是** | 目标笔记的唯一 ID, 需要是本人的笔记                                |\n| `target_content_format` | int    | **是** | 目标文本类型：`0`=纯文本（推荐），`1`=Markdown（不支持），`2`=JSON |\n\n#### 返回字段\n\n| 字段      | 类型   | 说明                                                  |\n| --------- | ------ | ----------------------------------------------------- |\n| `content` | string | 笔记的文本内容（按 `target_content_format` 格式返回） |\n\n---\n\n## 枚举值\n\n### `sort_type`（排序方式）\n\n| 值  | 说明             |\n| --- | ---------------- |\n| `0` | 更新时间（默认） |\n| `1` | 创建时间         |\n| `2` | 标题             |\n| `3` | 大小             |\n\n### `search_type`（检索方式）\n\n| 值  | 说明             |\n| --- | ---------------- |\n| `0` | 标题检索（默认） |\n| `1` | 正文检索         |\n\n### `content_format`（文本类型）\n\n| 值  | 说明                     |\n| --- | ------------------------ |\n| `0` | PLAINTEXT - 纯文本       |\n| `1` | MARKDOWN - Markdown 格式 |\n| `2` | JSON - JSON 格式         |\n\n### `FolderType`\n\n| 值  | 说明     |\n| --- | -------- |\n| `0` | 用户自建 |\n| `1` | 全部笔记 |\n| `2` | 未分类   |\n\n---\n\n## 游标翻页使用规范\n\n1. **首次请求**：`cursor` 传空字符串 `\"\"`\n2. 检查返回的 `is_end`：`false` 表示还有更多数据\n3. 将返回的 `next_cursor` 作为下次请求的 `cursor`\n4. `is_end = true` 时停止翻页\n\n---\n\n## 错误码\n\n| 错误码 | 说明                                         |\n| ------ | -------------------------------------------- |\n| 0      | 成功                                         |\n| 100001 | 参数错误                                     |\n| 100002 | 携带无效的 ID                                |\n| 100003 | 服务器内部错误                               |\n| 100004 | 拉取的 size 不合法（超出范围）/ 用户空间不够 |\n| 100005 | 不能获取私有笔记的访客信息 / 不是笔记的作者  |\n| 100006 | 笔记已被删除                                 |\n| 100008 | 版本冲突                                     |\n| 100009 | 单篇笔记超过最大限制                         |\n| 310001 | 笔记本不存在                                 |\n| 20002  | apiKey超过最大限频                           |\n| 20004  | apikey鉴权失败                               |\n\nArchive v1.0.4: 3 files, 8550 bytes\n\nFiles: references/api.md (10842b), SKILL.md (10785b), _meta.json (129b)\n\nFile v1.0.4:SKILL.md\n\n---\nname: ima-note\ndescription: |\n  IMA 个人笔记服务 API skill，用于管理用户的 IMA 笔记。支持搜索笔记、浏览笔记本、获取笔记内容、新建笔记和追加内容。\n  当用户提到笔记、备忘录、记事、知识库，或者想要查找、阅读、创建、编辑笔记内容时，使用此 skill。\n  即使用户没有明确说\"笔记\"，只要意图涉及个人文档的存取（如\"帮我记一下\"、\"我之前写过一个关于XX的东西\"、\"把这段内容保存下来\"），也应触发此 skill。\nhomepage: https://ima.qq.com\nmetadata:\n  {\n    \"openclaw\":\n      {\n        \"emoji\": \"📝\",\n        \"requires\": { \"env\": [\"IMA_OPENAPI_CLIENTID\", \"IMA_OPENAPI_APIKEY\"] },\n        \"primaryEnv\": \"IMA_OPENAPI_CLIENTID\"\n      },\n  }\n---\n\n# ima-note\n\n通过 IMA OpenAPI 管理用户个人笔记，支持读取（搜索、列表、获取内容）和写入（新建、追加）。\n\n完整的数据结构和接口参数详见 `references/api.md`。\n\n## Setup\n\n1. 请打开 https://ima.qq.com/agent-interface 获取 **Client ID** 和 **Api Key**\n2. 配置环境变量：\n\n```bash\nexport IMA_OPENAPI_CLIENTID=\"your_client_id\"\nexport IMA_OPENAPI_APIKEY=\"your_api_key\"\n```\n\n> 建议将上述 export 语句写入 `~/.zshrc` 或 `~/.bashrc`，避免每次重开终端失效。\n\n## 凭证预检\n\n每次调用 API 前，先确认凭证可用。如果环境变量未设置，停止操作并提示用户按 Setup 步骤配置。\n\n```bash\nif [ -z \"$IMA_OPENAPI_CLIENTID\" ] || [ -z \"$IMA_OPENAPI_APIKEY\" ]; then\n  echo \"缺少 IMA 凭证，请按 Setup 步骤配置环境变量 IMA_OPENAPI_CLIENTID 和 IMA_OPENAPI_APIKEY\"\n  exit 1\nfi\n```\n\n## API 调用模板\n\n所有请求统一为 **HTTP POST + JSON Body**，Base URL 为 `https://ima.qq.com/openapi/note/v1`。\n\n定义辅助函数避免重复 header：\n\n```bash\nima_api() {\n  local endpoint=\"$1\" body=\"$2\"\n  curl -s -X POST \"https://ima.qq.com/openapi/note/v1/$endpoint\" \\\n    -H \"ima-openapi-clientid: $IMA_OPENAPI_CLIENTID\" \\\n    -H \"ima-openapi-apikey: $IMA_OPENAPI_APIKEY\" \\\n    -H \"Content-Type: application/json\" \\\n    -d \"$body\"\n}\n```\n\n> **隐私规则：** 笔记内容属于用户隐私，在群聊场景中只展示标题和摘要，禁止展示笔记正文。\n\n## 接口决策表\n\n| 用户意图 | 调用接口 | 关键参数 |\n|---------|---------|---------|\n| 搜索/查找笔记 | `search_note_book` | `query_info`（QueryInfo 对象） |\n| 查看笔记本列表 | `list_note_folder_by_cursor` | `cursor`(必填，首页传`\"0\"`) + `limit`(必填) |\n| 浏览某笔记本里的笔记,当用户表述\"最新\"、\"最近\"之类的通用限定，没有指明笔记本时，都应该直接在全部笔记里去拉 | `list_note_by_folder_id` | `folder_id`(选填,空为全部笔记本) + `cursor`(必填，首次传`\"\"`) + `limit`(必填) |\n| 读取笔记正文 | `get_doc_content` | `doc_id` + `target_content_format`(必填，推荐`0`纯文本) |\n| 新建一篇笔记 | `import_doc` | `content` + `content_format`(必填，固定`1`) + 可选 `folder_id` |\n| 往已有笔记追加内容 | `append_doc` | `doc_id` + `content` + `content_format`(必填，固定`1`) |\n\n## 常用工作流\n\n### 查找并阅读笔记\n\n先搜索获取 `docid`，再用 `get_doc_content` 读取正文：\n\n```bash\n# 1. 按标题搜索\nima_api \"search_note_book\" '{\"search_type\": 0, \"query_info\": {\"title\": \"会议纪要\"}, \"start\": 0, \"end\": 20}'\n# 从返回的 docs[].doc.basic_info.docid 中取目标笔记 ID\n\n# 2. 读取正文（纯文本格式，Markdown 格式目前不支持）\nima_api \"get_doc_content\" '{\"doc_id\": \"目标docid\", \"target_content_format\": 0}'\n```\n\n### 浏览笔记本里的笔记\n\n先拉笔记本列表获取 `folder_id`，再拉该笔记本下的笔记：\n\n```bash\n# 1. 列出笔记本（首页 cursor 传 \"0\"）\nima_api \"list_note_folder_by_cursor\" '{\"cursor\": \"0\", \"limit\": 20}'\n\n# 2. 拉取指定笔记本的笔记（首页 cursor 传 \"\"）\nima_api \"list_note_by_folder_id\" '{\"folder_id\": \"user_list_xxx\", \"cursor\": \"\", \"limit\": 20}'\n```\n\n### 新建笔记\n\n```bash\n# 新建到默认位置\nima_api \"import_doc\" '{\"content_format\": 1, \"content\": \"# 标题\\n\\n正文内容\"}'\n\n# 新建到指定笔记本\nima_api \"import_doc\" '{\"content_format\": 1, \"content\": \"# 标题\\n\\n正文内容\", \"folder_id\": \"笔记本ID\"}'\n# 返回 doc_id，后续可用于 append_doc\n```\n\n### 追加内容到已有笔记\n\n```bash\nima_api \"append_doc\" '{\"doc_id\": \"笔记ID\", \"content_format\": 1, \"content\": \"\\n## 补充内容\\n\\n追加的文本\"}'\n```\n\n### 按正文搜索\n\n```bash\nima_api \"search_note_book\" '{\"search_type\": 1, \"query_info\": {\"content\": \"项目排期\"}, \"start\": 0, \"end\": 20}'\n```\n\n## 核心响应字段\n\n**搜索结果**（`SearchedDoc`）：笔记信息路径为 `doc.basic_info`（DocBasic），关键字段：`docid`、`title`、`summary`、`folder_id`、`folder_name`、`create_time`（Unix 毫秒）、`modify_time`、`status`。额外包含 `highlight_info`（高亮匹配，key 为 `doc_title`，value 含 `<em>高亮词</em>`）。\n\n**笔记本条目**（`NoteBookFolder`）：信息路径为 `folder.basic_info`（NoteBookFolderBasic），关键字段：`folder_id`、`name`、`note_number`、`create_time`、`modify_time`、`folder_type`（`0`=用户自建，`1`=全部笔记，`2`=未分类）、`status`。\n\n**笔记列表条目**（`NoteBookInfo`）：信息路径为 `basic_info.basic_info`（DocBasicInfo → DocBasic），关键字段：`docid`、`title`、`summary`、`folder_id`、`folder_name`、`create_time`、`modify_time`、`status`。\n\n**写入结果**（`import_doc`/`append_doc`）：返回 `doc_id`（新建或目标笔记的唯一 ID）。\n\n完整字段定义见 `references/api.md`。\n\n## 分页\n\n- **游标分页 — 笔记本列表**（`list_note_folder_by_cursor`）：首次 `cursor: \"0\"`，后续用 `next_cursor`，`is_end=true` 时停止。\n- **游标分页 — 笔记列表**（`list_note_by_folder_id`）：首次 `cursor: \"\"`，后续用 `next_cursor`，`is_end=true` 时停止。\n- **偏移量分页**（`search_note_book`）：首次 `start: 0, end: 20`，翻页时递增，`is_end=true` 时停止。\n\n## 枚举值\n\n- **`content_format`：** `0`=纯文本，`1`=Markdown，`2`=JSON。写入（`import_doc`/`append_doc`）目前仅支持 `1`（Markdown）。读取（`get_doc_content`）推荐 `0`（纯文本），Markdown 格式不支持。\n- **`search_type`：** `0`=标题检索（默认），`1`=正文检索\n- **`sort_type`：** `0`=更新时间（默认），`1`=创建时间，`2`=标题，`3`=大小（仅 `search_note_book` 使用）\n- **`folder_type`：** `0`=用户自建，`1`=全部笔记（根目录），`2`=未分类\n\n## 注意事项\n\n- `folder_id` 不可为 `\"0\"`，根目录 ID 格式为 `user_list_{userid}`（从 `folder_type=1` 的笔记本条目获取）\n- 笔记内容有大小上限，超过时返回 `100009`，可拆分为多次 `append_doc` 写入\n- 展示笔记列表时只展示标题、摘要和修改时间，不要主动展示正文\n- 时间字段是 Unix 毫秒时间戳，展示时转为可读格式\n- 返回数据为嵌套结构：搜索结果取 `docs[].doc.basic_info.docid`，笔记本取 `note_book_folders[].folder.basic_info.folder_id`，笔记列表取 `note_book_list[].basic_info.basic_info.docid`，注意按层级解析\n- **UTF-8 编码**：内容写入前必须确保为 UTF-8 编码。当内容来自临时文件、WebFetch 或外部来源时，按运行环境选择合适的方式转码：\n\n  **Python（推荐，几乎所有环境都有）：**\n  ```bash\n  # 读取文件，自动检测编码并转为 UTF-8\n  content=$(python3 -c \"\n  import sys\n  data = open('tmpfile', 'rb').read()\n  for enc in ['utf-8', 'gbk', 'gb2312', 'big5', 'latin-1']:\n      try:\n          sys.stdout.write(data.decode(enc))\n          break\n      excep\n\nArchive v1.0.3: 3 files, 8550 bytes\n\nFiles: references/api.md (10842b), SKILL.md (10785b), _meta.json (129b)\n\nArchive v1.0.2: 3 files, 8551 bytes\n\nFiles: references/api.md (10842b), SKILL.md (10785b), _meta.json (129b)\n\nArchive v1.0.1: 3 files, 7279 bytes\n\nFiles: references/api.md (10717b), SKILL.md (8065b), _meta.json (129b)\n\nArchive v1.0.0: 3 files, 7364 bytes\n\nFiles: references/api.md (10717b), SKILL.md (8261b), _meta.json (129b)","readmeExcerpt":"Skill: ima skills Owner: iampennyli Summary: 统一的 IMA OpenAPI 技能，支持笔记管理和知识库操作。 当用户提到知识库、资料库、笔记、备忘录、记事，或者想要上传文件、添加网页到知识库、 搜索知识库内容、搜索/浏览/创建/编辑笔记时，使用此 skill。 即使用户没有明确说\"知识库\"或\"笔记\"，只要意图涉及文件上传到知识库、网页收藏、 知识搜索、个人... Tags: latest:1.1.7 Version history: v1.1.7 | 2026-04-24T10:05:59.209Z | user ima-skill 1.1.7 changelog - Initial release providing a unified IMA OpenAPI skill supporting note management and knowledge-base operation","codeSnippets":[],"executableExamples":[{"language":"text","snippet":"GATE 1 [TYPE CHECK]\n  Run preflight-check.cjs FIRST. pass=false → reject immediately.\n  NEVER ask \"do you still want to try?\" for unsupported types.\n  Video files, Bilibili/YouTube URLs, file:// URLs → tell user to use IMA desktop client.\n\nGATE 2 [NAMING]\n  add_knowledge title MUST equal file_name (with extension).\n  NEVER rename, shorten, translate, or modify the original filename.\n  Example: file is \"音频.mp3\" → title=\"音频.mp3\", file_name=\"音频.mp3\"\n\nGATE 3 [DUPLICATES]\n  Call check_repeated_names BEFORE create_media for ALL file uploads.\n  is_repeated=true → ask user: keep both (append timestamp) or cancel.\n  \"Replace\" is NOT supported.\n  Timestamp format: {name}_YYYYMMDDHHmmss.{ext}\n\nGATE 4 [UPLOAD EXIT]\n  cos-upload.cjs non-zero exit → STOP immediately.\n  Do NOT call add_knowledge. Report error to user."},{"language":"bash","snippet":"# ── Step 1: preflight-check.cjs ← ⛔ GATE 1 ──\n# 有扩展名时自动推断；无扩展名时需传 --content-type\nPREFLIGHT=$(node .claude/skills/ima-skill/knowledge-base/scripts/preflight-check.cjs \\\n  --file \"/path/to/report.pdf\")\necho \"$PREFLIGHT\"\n# pass=false → 终止，将 reason 展示给用户。NEVER ask \"want to try?\"\n\n# ── Step 2: Extract fields ──\nFILE_NAME=$(echo \"$PREFLIGHT\" | node -e \"const d=JSON.parse(require('fs').readFileSync(0,'utf8'));process.stdout.write(d.file_name)\")\nFILE_EXT=$(echo \"$PREFLIGHT\" | node -e \"const d=JSON.parse(require('fs').readFileSync(0,'utf8'));process.stdout.write(d.file_ext)\")\nFILE_SIZE=$(echo \"$PREFLIGHT\" | node -e \"const d=JSON.parse(require('fs').readFileSync(0,'utf8'));process.stdout.write(String(d.file_size))\")\nMEDIA_TYPE=$(echo \"$PREFLIGHT\" | node -e \"const d=JSON.parse(require('fs').readFileSync(0,'utf8'));process.stdout.write(String(d.media_type))\")\nCONTENT_TYPE=$(echo \"$PREFLIGHT\" | node -e \"const d=JSON.parse(require('fs').readFileSync(0,'utf8'));process.stdout.write(d.content_type)\")\n\n# ── Step 3: check_repeated_names ← ⛔ GATE 3 ──\n# MANDATORY for ALL file uploads (media_type 1/3/4/5/7/9/13/14/15).\n# is_repeated=true → ask user: keep both (append _YYYYMMDDHHmmss) or cancel.\nima_api \"openapi/wiki/v1/check_repeated_names\" \"{\n  \\\"params\\\": [{\\\"name\\\": \\\"$FILE_NAME\\\", \\\"media_type\\\": $MEDIA_TYPE}],\n  \\\"knowledge_base_id\\\": \\\"<kb_id>\\\"\n}\"\n# folder_id is optional — omit for root, include for subfolder\n\n# ── Step 4: create_media ──\nCREATE_MEDIA_RESP=$(ima_api \"openapi/wiki/v1/create_media\" \"{\n  \\\"file_name\\\": \\\"$FILE_NAME\\\",\n  \\\"file_size\\\": $FILE_SIZE,\n  \\\"content_type\\\": \\\"$CONTENT_TYPE\\\",\n  \\\"knowledge_base_id\\\": \\\"<kb_id>\\\",\n  \\\"file_ext\\\": \\\"$FILE_EXT\\\"\n}\")\n# Extract media_id, url, and cos_credential fields. code≠0 → terminate.\n# COS_URL is the file's accessible URL — used for verification in Step 6.\n\n# ── Step 5: cos-upload.cjs ← ⛔ GATE 5 (non-zero = STOP) ──\n# ⚠️ Large files may exceed default 120s timeout — set --timeout explicitly.\nnode .claude/skills/ima-skill/"},{"language":"bash","snippet":"# ⛔ GATE 3 — batch check\nima_api \"openapi/wiki/v1/check_repeated_names\" '{\n  \"params\": [\n    {\"name\": \"report.pdf\", \"media_type\": 1},\n    {\"name\": \"slides.pptx\", \"media_type\": 4},\n    {\"name\": \"data.xlsx\", \"media_type\": 5}\n  ],\n  \"knowledge_base_id\": \"<kb_id>\",\n  \"folder_id\": \"<folder_id>\"\n}'\n# 根目录时省略 folder_id。\n# is_repeated=true → \"以下文件已存在同名：report.pdf。是否保留两者？（不支持替换）\"\n# 保留两者 → append _YYYYMMDDHHmmss；取消 → remove from upload list"},{"language":"bash","snippet":"# 无需 GATE 3-5（非文件上传）\n# 添加到根目录（不传 folder_id）\nima_api \"openapi/wiki/v1/import_urls\" '{\n  \"knowledge_base_id\": \"<kb_id>\",\n  \"urls\": [\n    \"https://example.com/article\",\n    \"https://mp.weixin.qq.com/s/xxxxx\"\n  ]\n}'\n\n# 添加到指定文件夹\nima_api \"openapi/wiki/v1/import_urls\" '{\n  \"knowledge_base_id\": \"<kb_id>\",\n  \"folder_id\": \"<folder_id>\",\n  \"urls\": [\"https://example.com/article\"]\n}'\n# 返回 results 映射：{ \"<url>\": { url, ret_code, media_id } }"},{"language":"bash","snippet":"ima_api \"openapi/wiki/v1/add_knowledge\" '{\n  \"media_type\": 11,\n  \"note_info\": { \"content_id\": \"<note_id>\" },\n  \"title\": \"笔记标题\",\n  \"knowledge_base_id\": \"<kb_id>\"\n}'"},{"language":"bash","snippet":"curl -sL -o \"$TEMP_DIR/paper.pdf\" \"<url>\""}],"parameters":null,"dependencies":[],"permissions":[],"extractedFiles":[{"path":"knowledge-base/SKILL.md","content":"# Knowledge Base (知识库)\n\nAPI base path: `openapi/wiki/v1` — 完整数据结构和接口参数详见 `references/api.md`。\n\n## 接口决策表\n\n| 用户意图                                      | 调用接口                                                               | 关键参数                                                                                           |\n| --------------------------------------------- | ---------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------- |\n| 上传文件到知识库                              | `check_repeated_names` → `create_media` → COS Upload → `add_knowledge` | `media_type`（按扩展名），`knowledge_base_id`，`file_name`，`file_size`                            |\n| 上传文件到知识库的某个文件夹                  | 先定位文件夹 → 同上（`folder_id` 传入目标文件夹 ID）                   | 见「文件夹操作」章节                                                                               |\n| 添加网页/微信文章到知识库                     | `import_urls`                                                          | `urls`（1-10 个），`knowledge_base_id`，可选 `folder_id`（省略则根目录）                           |\n| 添加笔记到知识库                              | `add_knowledge`                                                        | `media_type=11`，`note_info.content_id=<note_id>`，`knowledge_base_id`                             |\n| 添加 URL（文件型）到知识库                    | `check_repeated_names` → 下载文件 → 走\"上传文件\"流程                   | URL 指向 PDF/Word/PPT 等文件时，按文件方式处理                                                     |\n| 检查文件名是否重复                            | `check_repeated_names`                                                 | `params[].name`，`params[].media_type`，`knowledge_base_id`，`folder_id`                           |\n| 获取知识库信息                                | `get_knowledge_base`                                                   | `ids`（1-20 个，不重复）                                                                           |\n| 浏览知识库内容列表 / 浏览文件夹               | `get_knowledge_list`                                                   | `knowledge_base_id`，`cursor`，`limit`(1~50)，可选 `folder_id`                                     |\n| 在知识库中搜索（含文件和文件夹）              | `search_knowledge`                                                     | `query`，`knowledge_base_id`，`cursor`                                                             |\n| 按关键词查找知识库（用户知道名字但不知道 ID） | `search_knowledge_base`                                                | `query`，`cursor`，`limit`(1~20)                                                                   |\n| 查看/了解自己有哪些知识库                     | `search_knowledge_base`（`query` 传空字符串）                          | `query: \"\"`，`cursor`，`limit`(1~20)                                                               |\n| 添加内容但**未指定**目标知识库                | `get_addable_knowledge_base_list` → 展示列表让用户选择                 | `cursor`，`limit`(1~50)                                                                            |\n| 查看原文、分析原文、导出原文                "},{"path":"notes/SKILL.md","content":"# Notes (笔记)\n\n> ⛔ Before ANY write (`import_doc`/`append_doc`): validate ALL string fields (`content`, `title`) are legal UTF-8.\n> Non-UTF-8 content causes irreversible garbled text in IMA. See root SKILL.md § MANDATORY RULES for platform-specific validation methods.\n\nAPI base path: `openapi/note/v1`\n\n通过 IMA OpenAPI 管理用户个人笔记，支持读取（搜索、列表、获取内容）和写入（新建、追加）。\n\n完整的数据结构和接口参数详见 `references/api.md`。\n\n> **隐私规则：** 笔记内容属于用户隐私，在群聊场景中只展示标题和摘要，禁止展示笔记正文。\n\n## 接口决策表\n\n| 用户意图                                                                          | 调用接口          | 关键参数                                                                  |\n| --------------------------------------------------------------------------------- | ----------------- | ------------------------------------------------------------------------- |\n| 搜索/查找笔记                                                                     | `search_note`     | `query_info`（QueryInfo 对象）                                            |\n| 查看笔记本列表 / 列出笔记本                                                       | `list_notebook`   | `cursor`(必填，首页传`\"0\"`) + `limit`(必填)                               |\n| 列出笔记/获取多篇笔记信息                                                         | `list_note`       | `folder_id`(选填,空为全部) + `sort_type` + `cursor`(首次传`\"\"`) + `limit` |\n| 读取笔记正文                                                                      | `get_doc_content` | `note_id` + `target_content_format`(必填，推荐`0`纯文本)                  |\n| 新建一篇笔记（用户明确说\"新建/创建笔记\"时走此接口）                               | `import_doc`      | `content` + `content_format`(必填，固定`1`) + 可选 `folder_id`            |\n| 往已有笔记追加内容（⚠️ **敏感操作**：用户必须明确指定目标笔记，否则先确认再操作） | `append_doc`      | `note_id` + `content` + `content_format`(必填，固定`1`)                   |\n\n## ⚠️ 新建 vs. 追加 — 行为规则\n\n**新建笔记（`import_doc`）** 和 **追加内容到已有笔记（`append_doc`）** 是两个完全不同的操作，务必正确区分：\n\n### 明确走新建的信号词\n\n用户说以下任一表述时，**直接调用 `import_doc` 创建新笔记**：\n\n- \"**新建**笔记\"、\"**创建**笔记\"、\"**写一篇**笔记\"\n- \"**新建**一篇笔记记录这些内容\"\n\n### 明确走追加的信号词\n\n用户说以下任一表述时，**调用 `append_doc` 追加到已有笔记**（但仍需确认目标笔记，见下方规则）：\n\n- \"把这段话**追加到**《XX》笔记里\"\n- \"在那篇笔记**末尾加上**这段内容\"\n\n### 模糊场景 — 必须先询问用户\n\n以下表述**既可能是新建、也可能是追加**，agent **不得自行假设**，必须先向用户确认：\n\n- \"帮我记一下\"、\"记录一下\"、\"保存为笔记\"、\"存成笔记\"\n- \"把这段内容记到笔记里\"\n- \"添加到笔记里\"\n- 任何其他未明确表达\"新建\"或\"追加\"意图的表述\n\n询问示例：\n\n> \"您是想**创建一篇新笔记**，还是**追加到某篇已有笔记**？\"\n\n### 追加到已有笔记是敏感操作\n\n`append_doc` 会**不可撤销地修改**用户的现有笔记，因此必须谨慎处理：\n\n1. **用户明确指定了目标笔记** — 可以直接追加。例如：\n\n   - \"把这段话追加到《会议纪要》笔记里\"\n   - \"在那篇笔记末尾加上这段内容\"（上下文中已有明确的笔记对象）\n\n2. **用户没有明确指定目标笔记** — **必须先向用户确认**，不要自行猜测。例如：\n   - 用户说\"添加到笔记里\" → 询问：\"您想追加到哪篇已有笔记？请提供笔记标题或让我帮您搜索。\"\n   - 用户说\"把这个加到之前那篇笔记\" → 如果上下文中有多篇笔记或不确定是哪篇 → 列出候选笔记让用户选择\n\n> **原则**：不确定时，先问。宁可多问一句，也不要误改用户的已有笔记或自作主张创建新笔记。\n\n### 🖼️ 本地图片不支持\n\n`import_doc` 和 `append_doc` 的 `content` 字段仅支持Markdown，**不支持本地图片**。\n\n写入笔记内容前，必须检查并处理图片引用：\n\n1. **过滤本地图片** — 如果用户提供的内容中包含本地图片路径（如 `![](file:///...)`, `![](/Users/...)`, `![](C:\\...)` 等），**移除这些图片引用**，不要将其写入笔记。\n2. **告知用户** — 移除后主动提醒用户：\n   > \"笔记接口暂不支持上传本地图片，以下图片已被过滤：`xxx.png`、`yyy.jpg`。您可以先将图片上传到网络，再用网络链接插入笔记。\"\n3. **保留网络图片** — 以 `http://`"},{"path":"SKILL.md","content":"---\nname: ima-skill\ndescription: |\n  统一的 IMA OpenAPI 技能，支持笔记管理和知识库操作。\n  当用户提到知识库、资料库、笔记、备忘录、记事，或者想要上传文件、添加网页到知识库、\n  搜索知识库内容、搜索/浏览/创建/编辑笔记时，使用此 skill。\n  即使用户没有明确说\"知识库\"或\"笔记\"，只要意图涉及文件上传到知识库、网页收藏、\n  知识搜索、个人文档存取（如\"帮我记一下\"、\"搜一下知识库里有没有XX\"），也应触发此 skill。\nhomepage: https://ima.qq.com\nmetadata:\n  openclaw:\n    emoji: 🔧\n    requires:\n      env:\n        - IMA_OPENAPI_CLIENTID\n        - IMA_OPENAPI_APIKEY\n    primaryEnv: IMA_OPENAPI_CLIENTID\n  security:\n    credentials_usage: |\n      This skill requires user-provisioned IMA OpenAPI credentials (Client ID and API Key)\n      to authenticate with the official IMA API at https://ima.qq.com.\n      Credentials are ONLY sent to the official IMA API endpoint (ima.qq.com) as HTTP headers.\n      The file-upload flow also sends requests to COS endpoints (*.myqcloud.com) using\n      short-lived, scoped temporary credentials returned by the IMA API (create_media);\n      the user's Client ID / API Key are never sent to COS.\n      No credentials are logged, stored in files, or transmitted to any other destination.\n    allowed_domains:\n      - ima.qq.com\n      - '*.myqcloud.com'\n---\n\n# ima-skill\n\nUnified IMA OpenAPI skill. Currently supports: **notes**, **knowledge-base**.\n\n## ⛔ MANDATORY RULES — read before ANY operation\n\n1. **UTF-8 encoding (notes writes only):** Before calling `import_doc` or `append_doc`, ALL string fields (`content`, `title`) MUST be validated as legal UTF-8. Non-UTF-8 content causes irreversible garbled text. See [Detailed Rules](#detailed-utf-8-encoding-rules) for platform-specific methods.\n2. **File upload naming:** `title` MUST equal `file_name` (with extension). Never rename, shorten, translate, or modify the original filename.\n3. **Unsupported file types:** Reject immediately with a clear message. Do NOT ask user \"do you still want to try?\" Video files, Bilibili/YouTube URLs, and `file://` URLs are not supported — tell user to use IMA desktop client.\n4. **File upload integrity:** Keep file content as-is during upload. No encoding conversion for binary files (PDF, images, Excel, etc.).\n5. **PowerShell 5.1 (all modules):** If running in PowerShell, detect version before first API call. PS 5.1 silently converts request Body to GBK — must use UTF-8 byte array mode. See [Detailed Rules](#powershell-51-environment-detection).\n\n## 模块决策表\n\n| 用户意图                                                                                   | 模块           | 读取                      |\n| ------------------------------------------------------------------------------------------ | -------------- | ------------------------- |\n| 搜索笔记、浏览笔记本、获取笔记内容、创建笔记、追加内容                                     | notes          | `notes/SKILL.md`          |\n| 上传文件、添加网页链接、搜索知识库、浏览知识库内容、获取知识库信息、获取可添加的知识库列表 | knowledge-base | `knowledge-base/SKILL.md` |\n| 查看原文、分析原文、导出原文（需要 media_id）                                              | knowledge-base | `knowledge-base/SKILL.md` |\n\n### ⚠️ 易混淆场景\n\n| 用户说的                                                 | 实际意图  "},{"path":"_meta.json","content":"{\n  \"ownerId\": \"kn7fpa7e88ngzptwrczstadp5h831pc9\",\n  \"slug\": \"ima-skills\",\n  \"version\": \"1.1.7\",\n  \"publishedAt\": 1777025159209\n}"},{"path":"knowledge-base/references/api.md","content":"# IMA知识库 API\n\n## ⚠️ 必读约束\n\n### 🌐 服务信息\n\n- **Base URL **：`https://ima.qq.com`\n- **Base Path**：`/openapi/wiki/v1`\n- **协议**：HTTP POST，JSON body\n- **完整示例**：`POST https://ima.qq.com/openapi/wiki/v1/get_knowledge_base`\n\n### 🔒 认证\n\n所有请求必须携带 Header：\n\n| Header                 | 说明               |\n| ---------------------- | ------------------ |\n| `ima-openapi-clientid` | Client ID          |\n| `ima-openapi-apikey`   | API Key            |\n| `Content-Type`         | `application/json` |\n\n---\n\n## 快速决策\n\n| 用户意图                             | 接口                                                                   |\n| ------------------------------------ | ---------------------------------------------------------------------- |\n| 「上传文件到知识库」                 | `check_repeated_names` → `create_media` → COS Upload → `add_knowledge` |\n| 「上传文件到指定文件夹」             | 先定位文件夹 → 同上（传入 `folder_id`）                                |\n| 「添加网页/微信文章到知识库」        | `import_urls`                                                          |\n| 「获取知识库信息」                   | `get_knowledge_base`                                                   |\n| 「浏览知识库内容 / 浏览文件夹」      | `get_knowledge_list`（可传 `folder_id` 进入子文件夹）                  |\n| 「在知识库中搜索」                   | `search_knowledge`                                                     |\n| 「搜索知识库列表」                   | `search_knowledge_base`                                                |\n| 「获取可添加的知识库列表」           | `get_addable_knowledge_base_list`                                      |\n| 「检查文件名是否重复」               | `check_repeated_names`                                                 |\n| 「查看原文」「分析原文」「导出原文」 | `get_media_info`                                                       |\n\n---\n\n## 数据结构\n\n### KnowledgeBaseInfo（知识库信息）\n\n| 字段                    | 类型     | 说明          |\n| ----------------------- | -------- | ------------- |\n| `id`                    | string   | 知识库唯一 ID |\n| `name`                  | string   | 知识库名称    |\n| `cover_url`             | string   | 封面图 URL    |\n| `description`           | string   | 描述          |\n| `recommended_questions` | string[] | 推荐问题列表  |\n\n### KnowledgeInfo（知识条目）\n\n| 字段               | 类型   | 说明          |\n| ------------------ | ------ | ------------- |\n| `media_id`         | string | 媒体 ID       |\n| `title`            | string | 标题          |\n| `parent_folder_id` | string | 所属文件夹 ID |\n\n### FolderInfo（文件夹条目）\n\n| 字段               | 类型   | 说明        |\n| ------------------ | ------ | ----------- |\n| `folder_id`        | string | 文件夹 ID   |\n| `name`             | string | 文件夹名称  |\n| `file_number`      | int64  | 文件数      |\n| `folder_number`    | int64  | 子文件夹数  |\n| `parent_folder_id` | string | 父文件夹 ID |\n| `is_top`           | bool   | 是否置顶    |\n\n### AddableKnowledgeBaseInfo（可添加的知识库信息）\n\n| 字段   | 类型   | 说明       |\n| ------ | ------ | ---------- |\n| `id`   | string | 知识库 ID  |\n| `name` | string | 知识库名称 |\n\n### SearchedKnowledgeBaseInfo（搜索到的知识库信息）\n\n| 字段        | 类型   | 说明       |\n| ----------- | ------ | --------"}],"languages":[],"docsSourceLabel":"CLAWHUB","editorialOverview":null,"editorialQuality":{"score":100,"threshold":65,"status":"thin","wordCount":1238,"uniquenessScore":44,"reasons":["uniqueness-below-45"]}},"media":{"evidence":{"source":"no-media","verified":false,"confidence":"low","updatedAt":"2026-10-09T01:50:36.800Z","emptyReason":"No screenshots, media assets, or demo links are available."},"primaryImageUrl":null,"mediaAssetCount":0,"assets":[],"demoUrl":null},"ownerResources":{"evidence":{"source":"unclaimed","verified":false,"confidence":"low","updatedAt":"2026-10-09T01:50:36.800Z","emptyReason":"This page has not been claimed by the agent owner."},"hasCustomPage":false,"customPageUpdatedAt":null,"customLinks":[],"structuredLinks":{"docsUrl":null,"demoUrl":null,"supportUrl":null,"pricingUrl":null,"statusUrl":null},"customPage":null},"relatedAgents":{"evidence":{"source":"protocol-neighbors","verified":false,"confidence":"medium","updatedAt":"2026-10-09T21:09:11.071Z","emptyReason":null},"items":[{"id":"8ebccd8e-3863-4187-8355-c3f14e1f9edf","entityType":"agent","canonicalPath":"/agent/iofficeai-aionui","slug":"iofficeai-aionui","name":"AionUi","description":"Free, local, open-source 24/7 Cowork app and OpenClaw for Gemini CLI, Claude Code, Codex, OpenCode, Qwen Code, Goose CLI, Auggie, and more | 🌟 Star if you like it!","url":"https://github.com/iOfficeAI/AionUi","homepage":"https://www.aionui.com","source":"GITHUB_REPOS","protocols":["MCP","OPENCLAW"],"capabilities":[],"safetyScore":100,"overallRank":70,"updatedAt":"2026-10-09T19:11:12.944Z","createdAt":"2026-02-25T03:38:16.584Z","downloads":null},{"id":"b917f68a-ebff-438e-84f8-3f4b2494c0bc","entityType":"agent","canonicalPath":"/agent/activepieces-activepieces","slug":"activepieces-activepieces","name":"activepieces","description":"AI Agents & MCPs & AI Workflow Automation • (~400 MCP servers for AI agents) • AI Automation / AI Agent with MCPs • AI Workflows & AI Agents • MCPs for AI Agents","url":"https://github.com/activepieces/activepieces","homepage":"https://www.activepieces.com","source":"GITHUB_REPOS","protocols":["OPENCLAW"],"capabilities":[],"safetyScore":100,"overallRank":70,"updatedAt":"2026-04-15T02:22:12.426Z","createdAt":"2026-02-25T03:38:12.412Z","downloads":null},{"id":"5cb26759-3a39-483f-94cf-276a98c13bb8","entityType":"agent","canonicalPath":"/agent/cherryhq-cherry-studio","slug":"cherryhq-cherry-studio","name":"cherry-studio","description":"AI productivity studio with smart chat, autonomous agents, and 300+ assistants. Unified access to frontier LLMs","url":"https://github.com/CherryHQ/cherry-studio","homepage":"https://cherry-ai.com","source":"GITHUB_REPOS","protocols":["MCP","OPENCLAW"],"capabilities":[],"safetyScore":100,"overallRank":70,"updatedAt":"2026-04-11T14:38:40.986Z","createdAt":"2026-02-25T03:38:19.379Z","downloads":null},{"id":"6f6582d0-5d76-4f0f-b81d-86520247950b","entityType":"agent","canonicalPath":"/agent/copilotkit-copilotkit","slug":"copilotkit-copilotkit","name":"CopilotKit","description":"The Frontend for Agents & Generative UI. React + Angular","url":"https://github.com/CopilotKit/CopilotKit","homepage":"https://docs.copilotkit.ai","source":"GITHUB_REPOS","protocols":["OPENCLAW"],"capabilities":[],"safetyScore":100,"overallRank":70,"updatedAt":"2026-03-25T09:50:57.846Z","createdAt":"2026-02-25T03:39:14.617Z","downloads":null}],"links":{"hub":"/agent","source":"/agent/source/clawhub","protocols":[{"label":"OpenClaw","href":"/agent/protocol/openclew"}]}}}