{"id":"83ff198f-0e19-4f42-9a9e-c41bd21c481c","entityType":"agent","slug":"clawhub-wwqww1-ima-plus-skill","name":"ima.plus-skill-v1.0.12","canonicalUrl":"https://www.xpersona.co/agent/clawhub-wwqww1-ima-plus-skill","canonicalPath":"/agent/clawhub-wwqww1-ima-plus-skill","generatedAt":"2026-10-12T00:58:45.592Z","source":"CLAWHUB","claimStatus":"UNCLAIMED","verificationTier":"NONE","summary":{"evidence":{"source":"CLAWHUB","verified":false,"confidence":"medium","updatedAt":"2026-10-11T19:16:50.113Z","emptyReason":null},"description":"优化了上传视频转换成HTML的功能，有任何skill的问题或建议，请到QQ频道：pd86156007，IMA 知识库与笔记操作技能（版本 v1.0.12）：用 `--path` 自然语言定位知识库/文件夹/笔记本，支持文件上传、知识库/目录导出 zip、文件夹与条目管理、标签权限、网页入库、笔记增改与插图，以及把本地视频封装成单文件 HTML（页面内置「导出视频」，导出为 .bin 后缀、改名 .mp4 即播放）入库（需环境变量 IMA_OPENAPI_CLIENTID / IMA_OPENAPI_APIKEY）。","descriptionLabel":"Source description","evidenceSummary":"Capability contract not published. No trust telemetry is available yet. 1K downloads reported by the source. Last updated 10/11/2026.","installCommand":"clawhub skill install s176erj4f2bg52kae7gtvxnc0x89vf8h:ima-plus-skill","sourceUrl":"https://clawhub.ai/wwqww1/ima-plus-skill","homepage":"https://clawhub.ai/wwqww1/skills/ima-plus-skill","primaryLinks":[{"label":"View on ClawHub","url":"https://clawhub.ai/wwqww1/ima-plus-skill","kind":"source"},{"label":"Homepage","url":"https://clawhub.ai/wwqww1/skills/ima-plus-skill","kind":"homepage"}],"safetyScore":84,"overallRank":62,"popularityScore":60,"trustScore":null,"claimedByName":null,"isOwner":false,"seoDescription":"ima.plus-skill-v1.0.12 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-11T19:16:50.113Z","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-11T19:16:50.113Z","emptyReason":null},"stars":null,"forks":null,"downloads":1004,"likes":null,"task":null,"library":null,"packageName":null,"latestVersion":"1.0.12","tractionLabel":"1K downloads"},"release":{"evidence":{"source":"CLAWHUB","verified":false,"confidence":"medium","updatedAt":"2026-10-11T19:16:50.036Z","emptyReason":null},"lastUpdatedAt":"2026-10-11T19:16:50.113Z","lastCrawledAt":"2026-10-11T19:16:50.036Z","lastIndexedAt":null,"nextCrawlAt":"2026-10-12T19:16:50.036Z","lastVerifiedAt":null,"highlights":[{"version":"1.0.12","createdAt":"2026-10-11T02:20:07.976Z","changelog":"ima-plus-skill v1.0.12 - Updated video module: exported HTML pages now embed an “Export Video” button, which downloads the video as a `.bin` file (users can rename to `.mp4` for playback). - Exported HTML with video now uses `.bin` suffix instead of `.mp4` (fixes mobile browser restrictions). - Minor wording updates in documentation for new video export feature. - Removed sample file: skill-card.md.","fileCount":43,"zipByteSize":108401},{"version":"1.0.11","createdAt":"2026-10-05T17:11:39.001Z","changelog":"**新增本地视频批量封装与入库功能，并优化笔记插图等操作：** - 新增 video 模块：本地视频批量转为内嵌 HTML 文件并上传到知识库文件夹，命令行工具 `video/scripts/video_batch.py`。 - 新增笔记插图脚本 `notes/scripts/note-images.cjs`，便捷向已有笔记添加图片。 - 补充操作示例与规则说明，包括视频文件处理、HTML 文件大小限制、命令行用法等。 - 添加 API 调用与平台细则参考文档，删去旧版 skill-card.md。 - 安全机制说明更新，明确 COS 上传与凭证保护方案。","fileCount":43,"zipByteSize":108223},{"version":"1.0.8","createdAt":"2026-08-19T11:26:20.315Z","changelog":"ima-plus-skill v1.0.8 - Added notes/scripts/notes_create.cjs and notes/scripts/notes_append.cjs for creating and appending to notes. - Removed obsolete skill-card.md file. - Switched to environment variable-only credential and cache management: now requires IMA_OPENAPI_CLIENTID/IMA_OPENAPI_APIKEY for all operations, and mandates IMA_RESOLVE_CACHE for path resolution cache (enforced outside ima.copilot environment). - Introduced a hierarchical, persistent path resolution cache with auto-healing and mandatory configuration. - Updated documentation and quickstart to reflect new caching and credential requirements.","fileCount":35,"zipByteSize":98828},{"version":"1.0.7","createdAt":"2026-08-17T11:18:18.950Z","changelog":"ima-plus-skill 1.0.7 - 新增「自然语言路径」自动解析：所有操作均支持通过名称/路径（--path）自动解析知识库/文件夹/笔记本，无需 kb_id。 - 强制禁用手动传 kb_id，所有 API 脚本必须走 --path 参数（除非用户显式要求 ID）。 - 笔记本支持路径自动解析（notes/scripts/resolve_notebook.cjs）。 - SKILL.md 规则与文档全面升级，突出路径优先规则与凭证多层加载顺序。 - 移除 skill-card.md，精简文档。 - 支持 config.json / ~/.config/ima / 环境变量多层凭证加载，增强兼容性。","fileCount":33,"zipByteSize":97316},{"version":"1.0.6","createdAt":"2026-08-08T06:41:30.354Z","changelog":"ima-plus-skill 1.0.6 - Added comprehensive troubleshooting guide at references/troubleshooting.md, covering error codes, known issues, and solutions. - Removed config.json and skill-card.md from the skill directory; configuration guidance is now fully documented in SKILL.md. - SKILL.md updated with a direct link and instructions to consult the new troubleshooting resource when encountering errors.","fileCount":31,"zipByteSize":90010},{"version":"1.0.5","createdAt":"2026-08-01T10:29:18.389Z","changelog":"ima-plus-skill 1.0.5 - Removed the file: skill-card.md - Documentation updated to version 1.0.5, with minor clarifications and improved credential notes in SKILL.md. - No functional or code changes to modules; all user-facing features remain unchanged.","fileCount":31,"zipByteSize":96477},{"version":"1.0.4","createdAt":"2026-08-01T07:52:08.713Z","changelog":"- Version updated to 1.0.4. - Added meta.json file for improved metadata management. - Removed skill-card.md file. - Updated documentation to reflect new version (V1.0.4).","fileCount":31,"zipByteSize":94417},{"version":"1.0.0","createdAt":"2026-07-27T05:40:28.353Z","changelog":"ima.plus-skill v1.0.0 - Initial release providing unified IMA.plus note management and knowledge base operations. - Supports uploading/exporting files, exporting knowledge bases as zip, creating folders, moving/renaming/setting to top for knowledge entries. - Enables creation and modification of knowledge bases, tag management, permission management, public discovery, adding web pages, and searching/browsing/creating/editing notes. - Enforces strict UTF-8 validation for note content, strict file handling, and clear module routing for different user intents. - Includes comprehensive best-practice guidelines and troubleshooting notes based on real-world API testing.","fileCount":30,"zipByteSize":94931}]},"execution":{"evidence":{"source":"CLAWHUB","verified":false,"confidence":"low","updatedAt":null,"emptyReason":"No published capability contract is available yet."},"installCommand":"clawhub skill install s176erj4f2bg52kae7gtvxnc0x89vf8h:ima-plus-skill","setupComplexity":"low","setupSteps":["Install using `clawhub skill install s176erj4f2bg52kae7gtvxnc0x89vf8h:ima-plus-skill` 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/wwqww1/ima-plus-skill 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-wwqww1-ima-plus-skill/snapshot","contractUrl":"https://www.xpersona.co/api/v1/agents/clawhub-wwqww1-ima-plus-skill/contract","trustUrl":"https://www.xpersona.co/api/v1/agents/clawhub-wwqww1-ima-plus-skill/trust"},"curlExamples":["curl -s \"https://www.xpersona.co/api/v1/agents/clawhub-wwqww1-ima-plus-skill/snapshot\"","curl -s \"https://www.xpersona.co/api/v1/agents/clawhub-wwqww1-ima-plus-skill/contract\"","curl -s \"https://www.xpersona.co/api/v1/agents/clawhub-wwqww1-ima-plus-skill/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-12T00:58:45.585Z"}},"retryPolicy":{"maxAttempts":3,"backoffMs":[500,1500,3500],"retryableConditions":["HTTP_429","HTTP_503","NETWORK_TIMEOUT"]}},"endpoints":{"dossierUrl":"https://www.xpersona.co/api/v1/agents/clawhub-wwqww1-ima-plus-skill/dossier","snapshotUrl":"https://www.xpersona.co/api/v1/agents/clawhub-wwqww1-ima-plus-skill/snapshot","contractUrl":"https://www.xpersona.co/api/v1/agents/clawhub-wwqww1-ima-plus-skill/contract","trustUrl":"https://www.xpersona.co/api/v1/agents/clawhub-wwqww1-ima-plus-skill/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-11T19:16:50.113Z","emptyReason":null},"readme":"Skill: ima.plus-skill-v1.0.12\n\nOwner: wwqww1\n\nSummary: 优化了上传视频转换成HTML的功能，有任何skill的问题或建议，请到QQ频道：pd86156007，IMA 知识库与笔记操作技能（版本 v1.0.12）：用 `--path` 自然语言定位知识库/文件夹/笔记本，支持文件上传、知识库/目录导出 zip、文件夹与条目管理、标签权限、网页入库、笔记增改与插图，以及把本地视频封装成单文件 HTML（页面内置「导出视频」，导出为 .bin 后缀、改名 .mp4 即播放）入库（需环境变量 IMA_OPENAPI_CLIENTID / IMA_OPENAPI_APIKEY）。\n\nTags: latest:1.0.12\n\nVersion history:\n\nv1.0.12 | 2026-10-11T02:20:07.976Z | user\n\nima-plus-skill v1.0.12\n\n- Updated video module: exported HTML pages now embed an “Export Video” button, which downloads the video as a `.bin` file (users can rename to `.mp4` for playback).\n- Exported HTML with video now uses `.bin` suffix instead of `.mp4` (fixes mobile browser restrictions).\n- Minor wording updates in documentation for new video export feature.\n- Removed sample file: skill-card.md.\n\nv1.0.11 | 2026-10-05T17:11:39.001Z | user\n\n**新增本地视频批量封装与入库功能，并优化笔记插图等操作：**\n\n- 新增 video 模块：本地视频批量转为内嵌 HTML 文件并上传到知识库文件夹，命令行工具 `video/scripts/video_batch.py`。\n- 新增笔记插图脚本 `notes/scripts/note-images.cjs`，便捷向已有笔记添加图片。\n- 补充操作示例与规则说明，包括视频文件处理、HTML 文件大小限制、命令行用法等。\n- 添加 API 调用与平台细则参考文档，删去旧版 skill-card.md。\n- 安全机制说明更新，明确 COS 上传与凭证保护方案。\n\nv1.0.8 | 2026-08-19T11:26:20.315Z | user\n\nima-plus-skill v1.0.8\n\n- Added notes/scripts/notes_create.cjs and notes/scripts/notes_append.cjs for creating and appending to notes.\n- Removed obsolete skill-card.md file.\n- Switched to environment variable-only credential and cache management: now requires IMA_OPENAPI_CLIENTID/IMA_OPENAPI_APIKEY for all operations, and mandates IMA_RESOLVE_CACHE for path resolution cache (enforced outside ima.copilot environment).\n- Introduced a hierarchical, persistent path resolution cache with auto-healing and mandatory configuration.\n- Updated documentation and quickstart to reflect new caching and credential requirements.\n\nv1.0.7 | 2026-08-17T11:18:18.950Z | user\n\nima-plus-skill 1.0.7\n\n- 新增「自然语言路径」自动解析：所有操作均支持通过名称/路径（--path）自动解析知识库/文件夹/笔记本，无需 kb_id。\n- 强制禁用手动传 kb_id，所有 API 脚本必须走 --path 参数（除非用户显式要求 ID）。\n- 笔记本支持路径自动解析（notes/scripts/resolve_notebook.cjs）。\n- SKILL.md 规则与文档全面升级，突出路径优先规则与凭证多层加载顺序。\n- 移除 skill-card.md，精简文档。\n- 支持 config.json / ~/.config/ima / 环境变量多层凭证加载，增强兼容性。\n\nv1.0.6 | 2026-08-08T06:41:30.354Z | user\n\nima-plus-skill 1.0.6\n\n- Added comprehensive troubleshooting guide at references/troubleshooting.md, covering error codes, known issues, and solutions.\n- Removed config.json and skill-card.md from the skill directory; configuration guidance is now fully documented in SKILL.md.\n- SKILL.md updated with a direct link and instructions to consult the new troubleshooting resource when encountering errors.\n\nv1.0.5 | 2026-08-01T10:29:18.389Z | user\n\nima-plus-skill 1.0.5\n\n- Removed the file: skill-card.md\n- Documentation updated to version 1.0.5, with minor clarifications and improved credential notes in SKILL.md.\n- No functional or code changes to modules; all user-facing features remain unchanged.\n\nv1.0.4 | 2026-08-01T07:52:08.713Z | user\n\n- Version updated to 1.0.4.\n- Added meta.json file for improved metadata management.\n- Removed skill-card.md file.\n- Updated documentation to reflect new version (V1.0.4).\n\nv1.0.0 | 2026-07-27T05:40:28.353Z | auto\n\nima.plus-skill v1.0.0\n\n- Initial release providing unified IMA.plus note management and knowledge base operations.\n- Supports uploading/exporting files, exporting knowledge bases as zip, creating folders, moving/renaming/setting to top for knowledge entries.\n- Enables creation and modification of knowledge bases, tag management, permission management, public discovery, adding web pages, and searching/browsing/creating/editing notes.\n- Enforces strict UTF-8 validation for note content, strict file handling, and clear module routing for different user intents.\n- Includes comprehensive best-practice guidelines and troubleshooting notes based on real-world API testing.\n\nArchive index:\n\nArchive v1.0.12: 43 files, 108401 bytes\n\nFiles: _lib.cjs (1647b), ima_api.cjs (5240b), knowledge-base/references/api.md (18844b), knowledge-base/scripts/cos-upload.cjs (6317b), knowledge-base/scripts/create_folder.cjs (2090b), knowledge-base/scripts/create_knowledge_base.cjs (1728b), knowledge-base/scripts/export_kb_zip.cjs (16197b), knowledge-base/scripts/export_media.cjs (2449b), knowledge-base/scripts/join_knowledge.cjs (1518b), knowledge-base/scripts/list_all_files.cjs (4883b), knowledge-base/scripts/move_knowledge.cjs (4096b), knowledge-base/scripts/preflight-check.cjs (13884b), knowledge-base/scripts/rename_knowledge.cjs (1628b), knowledge-base/scripts/search_knowledge_base_in_square.cjs (1549b), knowledge-base/scripts/set_knowledge_top.cjs (1650b), knowledge-base/scripts/tag_add.cjs (1569b), knowledge-base/scripts/tag_delete.cjs (1293b), knowledge-base/scripts/tag_list.cjs (1429b), knowledge-base/scripts/tag_remove.cjs (1398b), knowledge-base/scripts/tag_rename.cjs (1598b), knowledge-base/scripts/update_knowledge_access_status.cjs (2207b), knowledge-base/scripts/update_knowledge_base_basic_info.cjs (2262b), knowledge-base/scripts/update_knowledge_base_permission.cjs (2167b), knowledge-base/scripts/upload_to_kb.cjs (6807b), knowledge-base/SKILL.md (12370b), meta.json (439b), notes/references/api.md (10878b), notes/scripts/note-images.cjs (10376b), notes/scripts/notes_append.cjs (2929b), notes/scripts/notes_create.cjs (3551b), notes/scripts/resolve_notebook.cjs (2043b), notes/SKILL.md (19669b), references/api-call-templates.md (4118b), references/platform-notes.md (5045b), references/troubleshooting.md (11725b), resolve_path.cjs (18610b), skill-card.md (2109b), SKILL.md (19304b), video/assets/video-template.html (1614b), video/scripts/video_batch.py (7424b), video/scripts/video_to_html.py (4438b), video/SKILL.md (4732b), _meta.json (134b)\n\nFile v1.0.12:knowledge-base/SKILL.md\n\n---\nname: IMA 知识库模块\ndescription: IMA 知识库操作模块。负责上传文件、添加网页/微信文章到知识库、搜索与浏览知识库内容、获取知识库信息。\nallowed-tools: Bash,Read\nmetadata: {\"openclaw\":{\"emoji\":\"📚\",\"requires\":{\"bins\":[\"node\"]}}}\n---\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` 传入） | 见「脚本速查」upload_to_kb |\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| 检查文件名重复 | `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| 按名称找知识库 | `search_knowledge_base` | `query`，`cursor`，`limit`(1~20) |\n| 查看自己有哪些知识库 | `search_knowledge_base` | `query: \"\"` |\n| 添加内容但未指定库 | `get_addable_knowledge_base_list` | `cursor`，`limit`(1~50) |\n| 查看/导出原文 | `get_media_info` | `media_id`；下载时 URL 后追加 `response-content-type=application/octet-stream&response-content-disposition=attachment;filename=\"<名>\"` |\n| 创建文件夹 | `create_folder` | `knowledge_base_id`，`name`，可选 `folder_id`（父夹） |\n| 重命名文件/文件夹 | `rename_knowledge` | `knowledge_base_id`，`media_id`，`name` |\n| 移动文件（**不支持文件夹**） | `move_knowledge` | `src_knowledge_base_id`，`dst_knowledge_base_id`，`infos:[{media_id}]`，可选 `dst_folder_id` |\n| 获取下载链接 | `export_media_for_ima_sandbox` | `media_id`；返回 `url`+`headers`，下载需带 `headers` |\n| 创建知识库 | `create_knowledge_base` | `name`(必填)，`type`(1001/1002/1004)，可选 `description`/`cover-url`/`recommended-questions` |\n| 修改库基本信息 | `update_knowledge_base_basic_info` | `id`，自动推导 `update_fields`（1名 2封面 3简介 4推荐问题） |\n| 置顶/取消置顶 | `set_knowledge_top` | `knowledge_base_id`，`media_id`，`is_top`(布尔) |\n| 打/移除标签 | `tag_add` / `tag_remove` | `knowledge_base_id`，`item_id`(=media_id)，`tag_name` |\n| 列/搜标签 | `tag_list` | `knowledge_base_id`，可选 `keyword`/`cursor`，`limit` |\n| 重命名/删除标签 | `tag_rename` / `tag_delete` | 重命名新名存在自动合并；删除不可逆 |\n| 修改库权限 | `update_knowledge_base_permission` | `id`，自动推导 `update_fields`（1导出状态 2加入类型） |\n| 加入知识库 | `join_knowledge` | `knowledge_base_id`，`name`（**真实加入，有副作用**） |\n| 批量更新访问状态 | `update_knowledge_access_status` | `knowledge_base_id`，`infos:[{media_id}]`(≤10)，`access_status`(1/2/3) |\n| 广场发现 | `search_knowledge_base_in_square` | `question`(必填，**不是** query)，`cursor`(首次空)，`limit` |\n\n**`search_knowledge_base` vs `get_addable_knowledge_base_list`**：用户说了库名 → 前者按名搜；用户没说加到哪个库 → 后者列出可选库让用户选。**绝不要**在用户已明确库名时调 `get_addable_knowledge_base_list`。\n\n---\n\n## ⛔ 文件上传安全门（仅文件上传 → `add_knowledge` 流程）\n\n```\nGATE 1 [TYPE]   preflight-check.cjs 先行，pass=false 直接拒绝。视频/B站/YouTube/file:// → 引导用户用 IMA 客户端。绝不问\"还要试吗\"\nGATE 2 [NAME]   add_knowledge 的 title 必须等于 file_name（含扩展名），绝不改名/缩写/翻译\nGATE 3 [DUP]    所有文件上传前先 check_repeated_names；is_repeated=true → 问用户保留两者(追加 _YYYYMMDDHHmmss)或取消；不支持替换\nGATE 4 [EXIT]   cos-upload.cjs 非零退出 → 立即停止，不调 add_knowledge\n```\n\n## 上传文件到知识库\n\n**首选一键脚本** `upload_to_kb.cjs`（封装 GATE 1-4 全部五步，自动重名处理与 JSON 解析，失败即停）：\n\n```bash\nnode knowledge-base/scripts/upload_to_kb.cjs --file a.pdf --path \"我的知识库/项目/文档\"\nnode knowledge-base/scripts/upload_to_kb.cjs --file a.pdf --path \"我的知识库\"          # 根目录\nnode knowledge-base/scripts/upload_to_kb.cjs --file a.pdf --cancel-if-dup             # 重名时取消\n```\n\n目标库**必须显式指定**（`--path` 首选 / `--kb-name` 兼容 / `--folder` 指定文件夹），脚本不自动选库。批量重名检查见 `api.md`（最多 2000 个文件名）。\n\n### 添加网页 / 微信文章 / 笔记\n\n```bash\n# 网页/微信（无 GATE，非文件）\nima_api \"openapi/wiki/v1/import_urls\" '{\"knowledge_base_id\": \"<库ID>\", \"urls\": [\"https://...\"], \"folder_id\": \"<可选>\"}'\n# 返回 results 映射 {url: {url, ret_code, media_id}}\n\n# 笔记 → 知识库\nima_api \"openapi/wiki/v1/add_knowledge\" '{\"media_type\": 11, \"note_info\": {\"content_id\": \"<note_id>\"}, \"title\": \"笔记标题\", \"knowledge_base_id\": \"<库ID>\"}'\n\n# URL 指向可下载文件时：先探测 content-type → 下载 → preflight-check → 走上传流程（详见 api.md §URL Type Detection）\n```\n\n---\n\n## 🌐 自然语言目录解析（统一入口，优先使用）\n\n**所有需要知识库/文件夹的操作，用自然语言路径，禁止让用户提供 kb_id。**\n\n```bash\nnode resolve_path.cjs --path \"我的知识库/项目/文档\"   # → { kb_id, kb_name, folder_id, folder_name }\nnode resolve_path.cjs --path \"我的知识库\"             # folder_id 空 = 根目录\nnode resolve_path.cjs --path \"项目/文档\"              # 唯一库可省略库名\n```\n\n**使用规则**：\n1. 用户给了路径/名称 → **直接 `resolve_path.cjs --path`**，不要手动 search + list 逐步找 ID\n2. 解析结果分层缓存（防重名串库、无 TTL、失效自愈），重复解析同一路径 0 次 API\n3. 所有封装脚本支持 `--path \"库名/文件夹...\"` 直接传\n4. 用户没给位置 → 用 `--kb-name` 或让用户选择\n5. **面向用户永远只展示名称**，禁止暴露 kb_id / folder_id / media_id\n6. ⛔ **禁止擅自使用 `--kb <id>`**：即使解析拿到 ID 也不得主动用，一律 `--path`；仅用户明确要求指定 ID 时可用\n\n## 脚本速查\n\n> 所有脚本支持 `--path \"库名/文件夹...\"`（自动解析），兼容 `--kb-name`。详见各脚本头部 Usage 注释。\n\n```bash\n# 文件夹：创建（可多级）/ 浏览 / 重命名 / 置顶（仅文件夹，media_type=99）\nnode knowledge-base/scripts/create_folder.cjs --path \"库/父夹\" --name \"新夹\"\nnode knowledge-base/scripts/list_all_files.cjs --path \"库/夹\" [--json] [--with-url]\nnode knowledge-base/scripts/rename_knowledge.cjs --path \"库\" --media-id <id> --name \"新名\"\nnode knowledge-base/scripts/set_knowledge_top.cjs --path \"库\" --media-id <folder_id> --is-top true   # ⚠️ 仅文件夹，文件报 220001\n\n# 移动（仅文件，≤10 个） / 导出媒体\nnode knowledge-base/scripts/move_knowledge.cjs --src-path \"库A\" --dst-path \"库B/目标夹\" --media-id id1,id2\nnode knowledge-base/scripts/export_media.cjs --media-id <id> [--download --out /path/save]\n\n# 标签（文件夹不支持打标签；rename 重名自动合并、delete 不可逆，调用前确认）\nnode knowledge-base/scripts/tag_add.cjs --path \"库\" --media-id <id> --tag-name \"重要\"\nnode knowledge-base/scripts/tag_remove.cjs --path \"库\" --media-id <id> --tag-name \"重要\"\nnode knowledge-base/scripts/tag_list.cjs --path \"库\" [--keyword 关键词]\nnode knowledge-base/scripts/tag_rename.cjs --path \"库\" --old-tag-name 旧 --new-tag-name 新\nnode knowledge-base/scripts/tag_delete.cjs --path \"库\" --tag-name 待删\n\n# 知识库管理（普通成员写操作会 220030，需创建者/协作成员/管理员）\nnode knowledge-base/scripts/create_knowledge_base.cjs --name \"库名\" --type 1001        # 1001个人 1002共享 1004订阅\nnode knowledge-base/scripts/update_knowledge_base_basic_info.cjs --path \"库\" --name 新名 [--description 简介]\nnode knowledge-base/scripts/update_knowledge_base_permission.cjs --path \"库\" --visible-export-status 3 [--join-type 1]  # ⚠️ 影响全库成员，调用前确认\nnode knowledge-base/scripts/update_knowledge_access_status.cjs --path \"库\" --media-id id1,id2 --access-status 3\n\n# 广场发现 / 加入（join 真实加入公开库，调用前确认用户确实要加）\nnode knowledge-base/scripts/search_knowledge_base_in_square.cjs --question \"关键词\"\nnode knowledge-base/scripts/join_knowledge.cjs --path \"知识库名称\" --name \"知识库名称\"\n```\n\n## 打包导出为 zip（整库 / 文件夹 / 多文件）\n\n```bash\n# ① 整个库 / ② 某个文件夹（递归）/ ③ 指定多文件（--media-ids）\nnode knowledge-base/scripts/export_kb_zip.cjs --path \"我的知识库\" --out /path/out.zip\nnode knowledge-base/scripts/export_kb_zip.cjs --path \"我的知识库/项目\" --out /path/out.zip\nnode knowledge-base/scripts/export_kb_zip.cjs --path \"我的知识库\" --media-ids id1,id2 --out /path/out.zip\n\n# 打包前先看调用量：--count（JSON）/ --estimate / --dry-run（列出将导出的文件）\nnode knowledge-base/scripts/export_kb_zip.cjs --path \"我的知识库\" --count\n```\n\n- 导出需 API key **开通导出权限**（凭证见主 SKILL.md「Credential Check」；agent-interface 普通 key 会 220030）\n- 超 50 次/分钟自动限速；单文件失败跳过不中断，全部失败不生成 zip\n- ⚠️ 订阅库（普通成员）不可下载，引导用户到 IMA 客户端\n- 完整 SOP 见 `references/troubleshooting.md`「批量导出打包 SOP」\n\n---\n\n## 查询类工作流\n\n```bash\n# 库信息 / 浏览 / 搜索 / 可添加库列表\nima_api \"openapi/wiki/v1/get_knowledge_base\" '{\"ids\": [\"<库ID>\"]}'\nima_api \"openapi/wiki/v1/get_knowledge_list\" '{\"knowledge_base_id\": \"<库ID>\", \"cursor\": \"\", \"limit\": 20}'\nima_api \"openapi/wiki/v1/search_knowledge\" '{\"query\": \"关键词\", \"knowledge_base_id\": \"<库ID>\", \"cursor\": \"\"}'\nima_api \"openapi/wiki/v1/get_addable_knowledge_base_list\" '{\"cursor\": \"\", \"limit\": 20}'\n\n# 原文内容（get_media_info）处理分支：\n#   media_type=11 且有 notebook_ext_info.notebook_id → 作为 note_id 走 notes 模块 get_doc_content\n#   url_info.url 非空 → 用 url+headers 请求原文\n#   否则 → 提示用户用 IMA 客户端查看原文\n```\n\n`list_all_files.cjs` 递归遍历全库输出目录树（限深 20、单目录 2500 条保护），`--json` 输出结构化数组，`--with-url` 逐个拿下载链接（订阅库多为空/220030）。\n\n## 分页 / 响应 / 用户体验\n\n- **分页**：所有列表/搜索接口游标分页，首次 `cursor: \"\"`，用 `next_cursor` 翻页，`is_end=true` 停止\n- **响应**：统一 `{ code, msg, data }`；`code=0` 成功，`code≠0` 直接展示 `msg`\n- **隐藏 ID**：面向用户永不暴露 `knowledge_base_id` / `media_id` / `folder_id`，只展示名称\n- **精简进度**：不暴露内部步骤，只报告结果（如「正在上传 report.pdf…」→「已添加到知识库「XX」✓」）；批量操作汇总成功/失败\n- **格式化展示**：库列表带描述（ID 列表调 `get_knowledge_base` 补描述）；内容列表带 📁/📄 前缀与文件数；搜索结果显示所在文件夹\n\n## 注意事项\n\n- 文件夹是知识条目（`media_type=99`），其 `media_id` 即 `folder_id`\n- 扩展名用于 `media_type` 检测与 `file_ext`（无点号，如 `pdf`）；COS `--content-type` 传实际 MIME\n- URL 入库先检测是否文件型 → `api.md §URL Type Detection`；MediaType 枚举/大小限制 → `api.md §MediaType`\n- **IMA OpenAPI 不支持删除任何实体**（文件/文件夹/库），需客户端手动清理\n- 错误码（220030 / 51 / 220001 等）先读 `references/troubleshooting.md`\n\nFile v1.0.12:notes/SKILL.md\n\n---\nname: IMA 笔记模块\ndescription: IMA 笔记管理模块。负责搜索、浏览、创建、编辑（追加）用户个人笔记。\nallowed-tools: Bash,Read\nmetadata: {\"openclaw\":{\"emoji\":\"📝\",\"requires\":{\"bins\":[\"node\"]}}}\n---\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| 往笔记插入含图片的内容（本地/远程图片）                                           | `note-images.cjs` | `--note-id` + `--file`/`--content`；图片 < 3MiB，仅 PNG/JPEG/WebP         |\n| 编辑笔记前获取块结构（update_note 前置）                                          | `export_note_blocks` | `note_id` |\n| 按 block 精细编辑笔记（改/删/插某段）                                             | `update_note`     | `note_id` + `user_request_id`(UUIDv4) + `updates[]`(block_id/action/new_content) |\n| 重命名笔记本                                                                       | `rename_notebook` | `folder_id` + `new_folder_name` |\n| 导出整篇笔记（Markdown/纯文本/JSON）                                            | `export_note`     | `note_id` + `target_content_format`(推荐`1`) |\n| 智能推送：不存在则新建、存在则追加                                              | `push_note`       | `content`(可选)+`note_id`(可选)+`content_cos_key`(可选) |\n| 重命名单篇笔记标题                                                               | `rename_note`     | `note_id` + `title` |\n| 批量移动笔记到其他笔记本                                                         | `move_notes`      | `note_ids[]` + `target_folder_id` |\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**含图片的 Markdown 一律用 `notes/scripts/note-images.cjs` 写入**：它把内容按原顺序分批——连续文本合并为一批、每张图片单独一批，逐批 `append_doc`。图片会被规范化为 data URL，**无需先上传到网络**。\n\n- **支持来源**：本地路径 / `file://` URI / `http(s)` 远程图片 / base64 data URL\n- **支持格式**：PNG / JPEG / WebP，单张原始文件必须 **< 3 MiB**（不得压缩、转码规避）\n- **原始预检**：大小 + MIME + 真实文件签名一致性，任一不符立即拒绝\n\n```bash\n# 写入到已有笔记（--file 与 --content 二选一；建议先 --dry-run 预演）\nnode notes/scripts/note-images.cjs --note-id \"<笔记ID>\" --file \"/path/to/content.md\" --dry-run\nnode notes/scripts/note-images.cjs --note-id \"<笔记ID>\" --file \"/path/to/content.md\"\n\n# 仅把本地图片转成临时 download_url（此模式不接受远程 URL）\nnode notes/scripts/note-images.cjs --url \"/path/to/img.png\"\n```\n\n⚠️ **它是「追加」接口，不负责新建**：\n\n- 新建含图片的笔记 → 先用 `notes_create.cjs` 建好笔记（拿到 `note_id`），再用 `note-images.cjs` 追加含图片的正文\n- 同一段文本不要两边都传，否则会重复写入\n- 任一批次失败立即停止，已成功批次不回滚\n\n**降级规则（不走脚本时）**：直接调 `import_doc` / `append_doc` 时 `content` 仅支持 Markdown，**本地图片引用会被过滤**，只保留 `http(s)` 网络图片——`notes_create.cjs` / `notes_append.cjs` 也保留此过滤行为并会提示。需要插入本地图片时，请改用 `note-images.cjs`。\n\n## 跨平台调用说明（Windows / Linux）\n\n单一 Node.js 实现，命令跨平台一致（需 Node 18+）；**优先用封装脚本**（`notes_create.cjs` / `notes_append.cjs` / `note-images.cjs` / `resolve_notebook.cjs`），其余接口走 `ima_api.cjs`。下文 `ima_api \"<path>\" '<json>'` 即：\n\n- **Linux / macOS**：`node \"$SKILL_DIR/ima_api.cjs\" \"$1\" \"$2\"`\n- **Windows PowerShell**：`& node \"$env:SKILL_DIR/ima_api.cjs\" '<path>' '<json>'`\n- **Windows cmd**：先 `chcp 65001 >nul`，再 `node \"%SKILL_DIR%\\ima_api.cjs\" \"<path>\" \"<json>\"`\n\n中文编码：Linux/macOS 默认 UTF-8；PowerShell 5.1 须用 UTF-8 字节数组模式（Body 会被静默转 GBK）。完整写法、`ima_api` 包装函数与两层错误处理 → 见父级 `SKILL.md` 与 `references/api-call-templates.md`。\n\n## 🌐 笔记本名解析（统一入口，优先使用）\n\n**所有需要笔记本（folder_id）的操作，优先用笔记本名称，不要让用户提供 folder_id。**\n\n统一解析器 `notes/scripts/resolve_notebook.cjs`：\n\n```bash\n# 按名称解析笔记本\nnode notes/scripts/resolve_notebook.cjs --path \"学习笔记\"\n# → { \"note_folder_id\": \"...\", \"note_folder_name\": \"学习笔记\" }\n\n# 列出所有笔记本\nnode notes/scripts/resolve_notebook.cjs --list\n```\n\n**使用规则**：\n\n1. 用户说了笔记本名称（如\"存到学习笔记里\"）→ 先调 `resolve_notebook.cjs --path <名称>` 拿到 `note_folder_id`，再用于 `list_note` / `import_doc` / `move_notes` 等接口\n2. 解析不到时列出当前笔记本让用户确认，禁止猜测\n3. **面向用户永远只展示笔记本名称**，禁止暴露 folder_id\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# 0. 按名称解析笔记本 folder_id\nnode notes/scripts/resolve_notebook.cjs --path \"学习笔记\"\n# → { \"note_folder_id\": \"...\", \"note_folder_name\": \"学习笔记\" }\n\n# 1. 拉取该笔记本的笔记（首页 cursor 传 \"\"）\nima_api \"openapi/note/v1/list_note\" '{\"folder_id\": \"<解析出的note_folder_id>\", \"cursor\": \"\", \"limit\": 20}'\n```\n\n仅当需要手动探索时：\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**首选脚本**（自动 UTF-8 校验；本地图片会被过滤，含图片请改用 `note-images.cjs`）：\n\n```bash\n# 新建到默认位置\nnode notes/scripts/notes_create.cjs --content \"# 标题\n\n正文内容\"\n\n# 新建到指定笔记本（--path 自动解析 folder_id，带缓存）\nnode notes/scripts/notes_create.cjs --content \"# 标题\n\n正文内容\" --path \"学习笔记\"\n\n# 从文件新建\nnode notes/scripts/notes_create.cjs --file /tmp/note.md --path \"学习笔记\"\n# 返回 note_id，后续可用于 append_doc\n```\n\n也可以直接调接口（灵活场景）：\n\n```bash\nima_api \"openapi/note/v1/import_doc\" '{\"content_format\": 1, \"content\": \"# 标题\\n\\n正文内容\", \"folder_id\": \"<解析出的note_folder_id>\"}'\n```\n\n### 追加内容到已有笔记\n\n**首选脚本**（⚠️ 敏感操作，AI 必须确认目标笔记明确后再调用）：\n\n```bash\nnode notes/scripts/notes_append.cjs --note-id <笔记ID> --content \"\n## 补充内容\n\n追加的文本\"\nnode notes/scripts/notes_append.cjs --note-id <笔记ID> --file /tmp/extra.md\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编辑已有笔记中的某一段/某一块，需要两步：先用 `export_note_blocks` 获取块结构，再用 `update_note` 按 `block_id` 修改。\n\n```bash\n# 1. 获取块结构\nima_api \"openapi/note/v1/export_note_blocks\" '{\"note_id\": \"笔记ID\"}'\n# 从返回的 data.blocks[] 中取目标 block_id 和 editable 字段\n\n# 2. 按 block 修改：action 1=EDIT替换 / 2=DELETE删除 / 3=APPEND在该块后插入\nima_api \"openapi/note/v1/update_note\" '{\"note_id\": \"笔记ID\", \"user_request_id\": \"本轮UUIDv4\", \"updates\": [{\"block_id\": \"目标block_id\", \"action\": 1, \"new_content\": \"新的Markdown内容\"}]}'\n```\n\n**`user_request_id` 复用规则**：同一用户消息内的多次 `update_note` 调用必须复用同一个 UUID v4；收到新的用户消息时重新生成。未传或为空会返回 `210001`。\n\n**注意事项**：\n- `editable=false` 的块（图片/录音/附件/链接卡片/AI 生成块）只能作为 APPEND 锚点，对其下发 EDIT/DELETE 会返回 `210039`\n- `block_id` 必须来自 `export_note_blocks`，不可凭空构造\n- 虚拟锚点 `_begin_`（最前插入）/ `_end_`（末尾追加）配合 `action=3` 使用\n- 列表整体（`id1..idN`）作为一个逻辑块：EDIT 替换整个列表，DELETE 删除整个列表\n\n### 笔记本管理\n\n| 用户意图 | 调用接口 | 关键参数 |\n| -------- | -------- | -------- |\n| 列出笔记本 | `list_notebook` | `cursor`(首页`\"0\"`)+`limit` |\n| 创建笔记本 | `add_notebook` | `folder_name` |\n| 重命名笔记本 | `rename_notebook` | `folder_id`+`new_folder_name` |\n\n```bash\n# 重命名笔记本\nima_api \"openapi/note/v1/rename_notebook\" '{\"folder_id\": \"笔记本ID\", \"new_folder_name\": \"新名称\"}'\n```\n\n### 导出笔记（export_note）\n\n导出整篇笔记为文件，支持 Markdown / 纯文本 / JSON 三种格式。\n\n```bash\nima_api \"openapi/note/v1/export_note\" '{\"note_id\": \"笔记ID\", \"target_content_format\": 1}'\n```\n\n- 返回 `data.content_url` 为带签名的 COS 下载链接（时效约 3 小时），需二次 `curl` 该链接获取实际内容\n- `target_content_format`：`0`=纯文本 `.txt`，`1`=Markdown `.md`（推荐），`2`=JSON（Slate 编辑器 AST）`.json`\n- 需要作者权限\n\n### 智能推送（push_note）\n\n不确定笔记是否已存在时使用：note_id 为空则新建，不为空则追加到该笔记。\n\n```bash\nima_api \"openapi/note/v1/push_note\" '{\"content\": \"标题：项目排期。正文内容...\"}'\n```\n\n- `note_id` 可选（为空新建，不为空追加）；`content` 与 `content_cos_key` 不能同时为空\n- 长内容可先 `ima_cos_util -f <文件>` 上传拿 cosKey，再传 `content_cos_key`\n- 返回 `data.note_id`\n\n### 重命名笔记（rename_note）\n\n```bash\nima_api \"openapi/note/v1/rename_note\" '{\"note_id\": \"笔记ID\", \"title\": \"新标题\"}'\n```\n\n- 需要作者权限，返回空消息体\n\n### 移动笔记（move_notes）\n\n```bash\nima_api \"openapi/note/v1/move_notes\" '{\"note_ids\": [\"笔记ID1\", \"笔记ID2\"], \"target_folder_id\": \"目标笔记本ID\"}'\n```\n\n- `note_ids` 最多 100 条，`target_folder_name` 可选\n- 返回 `data.result` map（key=note_id, value=true/false），可能部分成功，需逐条检查\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**笔记列表条目**（`list_note` 响应数组字段是 `data.note_book_list`）：`NoteBookInfo` 关键字段：`note_id`、`title`、`summary`、`create_time`、`modify_time`、`cover_image`、`note_ext_info`（含 `folder_id`、`folder_name`）。\n\n**读取正文**（`get_doc_content`）：正文在 `data.content`（纯文本/Markdown 由 `target_content_format` 决定）。\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- 直接调 `import_doc` / `append_doc` 不支持本地图片；需插入本地/远程图片时用 `notes/scripts/note-images.cjs`（详见上方「🖼️ 图片写入」章节）\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\n> 遇到笔记接口错误码（210039 / 100009 / 100005 等）或异常现象，先读 `references/troubleshooting.md` 对照定位；UTF-8 强制校验与跨模块规则见父级 SKILL.md。\n\nFile v1.0.12:SKILL.md\n\n---\nname: ima_plus-skill\ndescription: IMA 知识库与笔记操作技能（版本 v1.0.12）：用 `--path` 自然语言定位知识库/文件夹/笔记本，支持文件上传、知识库/目录导出 zip、文件夹与条目管理、标签权限、网页入库、笔记增改与插图，以及把本地视频封装成单文件 HTML（页面内置「导出视频」，导出为 .bin 后缀、改名 .mp4 即播放）入库（需环境变量 IMA_OPENAPI_CLIENTID / IMA_OPENAPI_APIKEY）。\nallowed-tools: Bash,Read\nmetadata:\n  openclaw:\n    emoji: \"🔧\"\n    requires:\n      bins:\n        - node\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 request base URL is hard-whitelisted to ima.qq.com: options.baseUrl / IMA_BASE_URL\n      overrides are rejected unless they resolve to ima.qq.com, so credentials can never be\n      forwarded to an arbitrary host.\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, and COS temporary credentials are\n      passed to the upload helper via environment variables (not argv).\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# ima_plus-skill\n\n> **版本：V1.0.12**\n>\n> **运行环境**：Node.js ≥ 18.0.0（所有 .cjs 脚本 + inline JSON 解析依赖）；视频模块另需 `python3` + `curl`（`ffprobe` 可选，取时长）\n\nUnified IMA OpenAPI skill. Currently supports: **notes**, **knowledge-base**, **video**（视频链接 → 内嵌 HTML → 入库）.\n\n## ⛔ MANDATORY RULES — read before ANY operation\n\n0. **自然语言路径优先（所有模块通用，强制）：** 用户给出知识库/文件夹/笔记本的名称或路径（如\"我的知识库/项目/文档\"、\"存到学习笔记\"）时，**一律用解析器自动转 ID，禁止让用户提供 kb_id / folder_id**。知识库用根目录 `resolve_path.cjs --path`，笔记本用 `notes/scripts/resolve_notebook.cjs --path`。面向用户永远只展示名称，禁止暴露任何 ID。\n   - ⛔ **禁止擅自使用 `--kb <kb_id>`**：即使解析过程中拿到了 kb_id，**也不得主动用它调用脚本**——所有脚本调用一律走 `--path \"知识库名/文件夹...\"`（内部自动解析）。`--kb` 仅在**用户明确要求使用某个具体 ID** 时才允许出现。违反此规则视为流程错误。\n   - 兼容参数 `--kb-name`（按名称匹配）可以正常使用，但 `--path` 是首选。\n\n### 🔧 路径解析缓存机制（V1.0.8+，无需手动管理）\n\n解析器会把「知识库名 → kb_id、文件夹路径 → folder_id」**分层树状持久化**到缓存文件，\n按「知识库 → 子文件夹 → 孙文件夹」嵌套，同名文件夹在不同库/不同父目录各占节点，不会串库。\n\n**缓存位置（强制检查，安装 skill 时必须确定）：**\n1. 环境变量 `IMA_RESOLVE_CACHE` 显式指定（所有环境，优先级最高）\n2. ima.copilot 环境未设置时默认 `/sandbox/workspace/.ima_cache/resolve_cache.json`（workspace 持久、平台不重置）\n3. **其他 agent / 自建环境未设置 `IMA_RESOLVE_CACHE` → 直接报错不可用**（与凭证同等强制）。\n   安装时须先设置：`export IMA_RESOLVE_CACHE=/path/to/resolve_cache.json`（可写入 ~/.bashrc 或 ~/.zshrc）\n\n- **无过期时间**：缓存长期有效；重复解析同一路径 **0 次 API 调用**（部分命中只补查缺失层级）。\n- **失效自愈**：所有消费脚本已包 `withPathRetry`——若操作因「目标不存在」（如库/夹被删或改名，`220001/invalid/不存在` 类）失败，自动失效该路径缓存 → 全 API 重新解析 → 重试一次；**重查任一层失败即报「目录位置不存在」，整个操作直接中止，不猜测后续层级**。权限（220030）/限流（200001）类错误不触发自愈。\n- **手动清缓存**（一般不需要）：删除缓存文件即可，下次解析自动重建。知识库/文件夹被删除后首次操作会自愈恢复。\n- 笔记本解析（`--notes` / `resolve_notebook.cjs`）同样缓存（`notebooks` 节）。\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 `references/platform-notes.md` 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?\" **视频文件（mp4/avi/mov/mkv…）不能作为文件直接上传**——必须走视频模块转成「内嵌单文件 HTML」再上传（见 § 📹 视频模块，细则读 `video/SKILL.md`）；Bilibili / YouTube URL 与 `file://` URL 仍不支持，引导用户改用 IMA 客户端。\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 `references/platform-notes.md`.\n6. **副作用操作必须显式确认（不得自行执行）：** `join_knowledge`（真实加入公开库）、`tag_delete` / `tag_rename`（不可逆；新名已存在时自动合并）、`update_knowledge_base_permission`（影响全库成员）、`append_doc` 追加已有笔记（不可撤销修改）——调用前必须得到用户明确同意，不确定时先问。\n\n## 🚀 高频操作快查表（30 秒上手）\n\n| 用户意图 | 直接执行 |\n| --- | --- |\n| 上传文件到知识库 | `node knowledge-base/scripts/upload_to_kb.cjs --path \"库名/文件夹\" --file <路径>` |\n| 打包知识库/文件夹为 zip | `node knowledge-base/scripts/export_kb_zip.cjs --path \"库名/文件夹\" --out /path/out.zip` |\n| 列出知识库内容 | `node knowledge-base/scripts/list_all_files.cjs --path \"库名\"` |\n| 创建文件夹 | `node knowledge-base/scripts/create_folder.cjs --path \"库名/父夹\" --name \"新夹\"` |\n| 新建笔记 | `node notes/scripts/notes_create.cjs --content \"内容\" --path \"笔记本名\"` |\n| 追加笔记 | `node notes/scripts/notes_append.cjs --note-id <id> --content \"内容\"` |\n| 笔记插入图片 | `node notes/scripts/note-images.cjs --note-id <id> --file <md>` |\n| 本地视频批量封装为 HTML 并入库 | `python3 video/scripts/video_batch.py --dir <视频目录> --path \"<知识库>/<文件夹>\"` |\n\n> 路径一律用 `--path \"知识库名/文件夹...\"` 自然语言，禁止 kb_id。其余操作见各模块 SKILL.md 与脚本头部 Usage 注释。\n\n## 📹 视频模块（V1.0.10 新增；V1.0.12 起 HTML 导出为 .bin）\n\n把**本地视频文件**批量封装为「内嵌单文件 HTML」并上传到知识库文件夹。\n**只做封装与上传，不做下载**（视频文件不能直接上传知识库——服务端限制）。\n\n```bash\npython3 video/scripts/video_batch.py --dir <视频目录> --path \"<知识库>/<文件夹>\"\n```\n\n- HTML **超过 10MB 自动丢弃、不上传**；文件名不加序号，并清洗 `# ? & /` 等 URL 危险字符\n- 页面浅色极简（标题 + 视频），多端适配，兼容 iOS 12 Safari\n- **页面内置「导出视频」链接**：点击下载 `<标题>.bin`（blob + `application/octet-stream`）；手机浏览器按后缀拦 `.mp4`，故存为 `.bin`，页面提示改名为 `.mp4` 即可播放\n- **参数、行为约定、排障 → 见 `video/SKILL.md`**\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| 打包知识库 / 某个文件夹 / 多个文件为 zip 并发给用户                                         | knowledge-base | `knowledge-base/SKILL.md` |\n| 把本地视频批量转换成 HTML 并上传到知识库文件夹 | video | `video/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- 向笔记插入图片（本地/远程）必须由 notes 模块的 `note-images.cjs` 完成，**不得**调用 knowledge-base 的 `create_media` / `add_knowledge` / `get_media_info` 代替\n\n## ⚠️ 出错时查这里（按需读取）\n\n遇到后端错误码（`220030` / `51` / `210039` / `220001` 等）或任何异常现象，**先读 `references/troubleshooting.md`** 对照定位——那里汇总了全部实测沉淀的错误码对照表、权限边界、批量导出 SOP 与已知坑。正常执行时无需读取该文件。\n\n## ⚙️ 安装配置总览（必读）\n\n安装本 skill 只需配置 **两件事**（均为环境变量，强制设置，不设置无法使用）：\n\n| # | 配置项 | 环境变量 | 未设置时 |\n|---|--------|----------|----------|\n| 1 | 凭证 | `IMA_OPENAPI_CLIENTID` / `IMA_OPENAPI_APIKEY` | 报错不可用（`code=-100`） |\n| 2 | 缓存保存位置 | `IMA_RESOLVE_CACHE` | ima.copilot 默认 workspace 缓存；**其他环境报错不可用** |\n\n- ✅ **ima.copilot 环境：零配置直接可用**（平台已注入凭证 + 默认 `/sandbox/workspace/.ima_cache/` 缓存）\n- ⚠️ **其他 agent / 自建环境**：按下方「Credential Check」设置凭证、按「路径解析缓存机制」设置缓存位置，**两件都配好才能用**\n\n## Credential Check（凭证获取与配置）\n\n### 凭证从哪来（必读）\n\n凭证有 **两种来源，任选其一** 设置到环境变量即可：\n\n1. **ima app 内 copilot 会话环境变量中的凭证**（`IMA_OPENAPI_CLIENTID` / `IMA_OPENAPI_APIKEY`）\n   ——这套凭证**已开通导出权限**（`export_media` / `export_media_for_ima_sandbox` 可用），推荐。\n2. **https://ima.qq.com/agent-interface 申请的 API key**——普通功能（上传/建库/打标签/移动/搜索等）可用；\n   ⚠️ 但**导出类接口可能返回 `code=220030 无权限`**（导出权限未开通，非脚本缺陷），需要打包导出时请用来源 1 的凭证。\n\n> ⛔ **凭证强制从环境变量读取，单一来源，不设置技能无法使用**：\n> 不再支持 config.json / ~/.config/ima/ 等任何文件配置与自动降级。\n\n- ✅ **ima.copilot 环境**：平台已自动注入 `IMA_OPENAPI_CLIENTID` / `IMA_OPENAPI_APIKEY`，直接可用，无需任何配置。\n- ⚠️ **自建环境（自己的电脑 / 服务器）**：必须先主动设置环境变量（来源 1 或 2 任一），否则所有脚本报错退出（`code=-100`，提示未设置凭证）。\n\n### 自建环境设置方式\n\n**Linux / macOS**（写入 shell 配置文件，永久生效）：\n\n```bash\n# ~/.bashrc 或 ~/.zshrc 末尾追加（替换成你自己的凭证值）\nexport IMA_OPENAPI_CLIENTID=\"你的 clientId\"\nexport IMA_OPENAPI_APIKEY=\"你的 apiKey\"\nsource ~/.bashrc\n```\n\n**Windows**：系统设置 → 环境变量 → 新建 `IMA_OPENAPI_CLIENTID` / `IMA_OPENAPI_APIKEY`。\n\n### 一步获取凭证（完整指令）\n\n> 在 **ima app** 中打开 **copilot** 对话，原样发送以下指令：\n\n```\n请把环境变量里的 IMA 凭证发给我：IMA_OPENAPI_CLIENTID 和 IMA_OPENAPI_APIKEY 的值（我要配置 ima_plus-skill 技能的 clientId 和 apiKey）\n```\n\ncopilot 会从运行环境变量读取并返回 `clientId`（= `IMA_OPENAPI_CLIENTID`）与\n`apiKey`（= `IMA_OPENAPI_APIKEY`）。拿到后按上方方式 export 到自建环境。\n\n> ⚠️ **安全须知（V1.0.11）**：此操作会让凭证在对话中明文出现。请仅在**你自己的** ima 会话里执行，\n> 且只用于把凭证迁移到你的自建环境。**切勿**把该对话内容截图、转发或分享给他人/第三方 agent，\n> 也**不要**把凭证写入 skill 目录随 skill 一起分发。怀疑已泄露时，去\n> https://ima.qq.com/agent-interface 轮换凭证。\n\n### 验证\n\n```bash\nnode knowledge-base/scripts/export_kb_zip.cjs --path \"<你的个人库名>\" --dry-run\n```\n\n能列出文件清单即凭证有效。\n\n### 安全提醒\n\n- 该凭证绑定你的账号且已开通导出权限，**切勿外泄、切勿打包进公开分发的 zip**\n- 凭证只发送到 `ima.qq.com`，不写入任何日志、配置文件或外部文件\n- 凭证失效 / 导出报 220030 时，重新执行「一步获取凭证」更新环境变量即可\n\n### V1.0.11 安全加固（响应第三方安全审计）\n\n- **Base URL 白名单**：`ima_api.cjs` 拒绝一切非 `ima.qq.com` 的 base URL（`options.baseUrl` / `IMA_BASE_URL`），凭证不可能被转发到任意地址\n- **导出脱敏**：`export_media.cjs` 默认隐藏授权 header 取值（`--show-headers` 才显示），支持 `--quiet` 完全静默\n- **COS 凭证不再走 argv**：`upload_to_kb.cjs → cos-upload.cjs` 的临时凭证改经环境变量传递，不再出现在进程列表\n- **导出文件名净化**：`export_kb_zip.cjs` 对知识库条目标题做净化（去除 `/`、`..`、控制字符），防止路径遍历\n\n### 上下文瘦身（降低加载与运行时 token · 并入 v1.0.11）\n\n- **清单类输出紧凑化**：`list_all_files` 默认改紧凑格式（`路径\\t类型\\tmedia_id`），新增 `--summary`（只出统计）/ `--files-only` / `--json`(compact) / `--pretty`\n- **`export_kb_zip` 去重**：成功项不再打印两遍，`--verbose` 才输出明细\n- **文档下沉**：SKILL.md 的「API 调用模板」「UTF-8 / PowerShell 细节」移入 `references/api-call-templates.md`、`references/platform-notes.md`（按需读取）\n- **广场搜索 / 标签列表**输出改为紧凑 tab 分隔\n\n## 📎 按需参考（体积大，需要时再读）\n\n以下内容不属于高频路径，已拆为独立文件，**仅在需要时打开**，以降低常驻上下文：\n\n| 需要什么 | 文件 |\n| --- | --- |\n| API 调用模板 / 跨平台 shell 写法（bash · PowerShell · cmd） | `references/api-call-templates.md` |\n| UTF-8 编码规则、PowerShell 5.1 乱码处理（实现细节） | `references/platform-notes.md` |\n| 错误码对照 / 排障 / 批量导出 SOP | `references/troubleshooting.md` |\n\n\n## 核心心智：用 API 技能的 3 个原则\n\n| 原则 | 含义 | 反例 |\n|------|------|------|\n| **不猜** | 指代、ID、路径、枚举——拿不准就问/查 | 猜 media_type=11 是微信文章 |\n| **不省** | UTF-8 校验、双层 code 检查、双模块 SKILL.md | 跳过 encoding 直接写笔记 |\n| **不堆** | 结果分主题、ID 内部消化、摘要 + 下一步 | 50 行 ID 列表直接贴给用户 |\n\n> 最快的路径 = 凭证一次配置（问 copilot 拿环境变量凭证）+ Node 统一调用 + 浅读 SKILL.md + 模糊指令先问人。\n\nFile v1.0.12:video/SKILL.md\n\n# video 模块 —— 本地视频 → 内嵌 HTML（可导出） → 知识库\n\n> 独立模块，与 `knowledge-base` / `notes` 同级。\n> **只做封装与上传，不做下载**（视频从哪来不归本模块管）。\n\n## 为什么必须封装成 HTML\n\n知识库**不接受 mp4 / avi / mov 等视频文件**（服务端限制）。\n唯一可行方式：视频 base64 内嵌进单文件 HTML（≤10MB），页面用 **Blob URL** 播放\n（data: URI 在部分 WebView 会加载失败；Blob 方案实测 3MB+ 正常）。\n\n> 💡 **可反向导出**：页面「导出视频」把内嵌视频还原为文件保存。\n> ⚠️ **导出文件必须用 `.bin` 后缀（关键）**：手机浏览器（华为等）会按后缀拦截\"网页现场生成的 `.mp4`\"\n> （防网页偷放视频的安全策略），表现为**下载进度卡 0% / 下载失败**；而 `.bin` 等中性后缀畅通。\n> 因此导出存为 `<标题>.bin`，页面提示用户**下载后把后缀改成 `.mp4`** 即可播放。\n> 实现要点：下载用 `Blob([bytes],{type:'application/octet-stream'})`（**非 `video/mp4`**），且与播放用的 blob URL **分开创建**。\n\n> ⚠️ **条目名规则（最大的坑）**：条目名 = 文件名，不得含 `# ? & /` 等 URL 危险字符。\n> `#` 在 URL 中是锚点分隔符 → 打开条目时显示「无法打开网页」（与体积无关）。\n\n## 用法\n\n```bash\n# 批量：目录里的视频全部封装并上传\npython3 video/scripts/video_batch.py --dir <视频目录> --path \"<知识库>/<文件夹>\"\n\n# 只生成、不上传（本地检查）\npython3 video/scripts/video_batch.py --dir <视频目录> --path \"<知识库>/<文件夹>\" --skip-upload\n\n# 单个文件\npython3 video/scripts/video_to_html.py --mp4 a.mp4 --title \"标题\" --out-dir ./html\n```\n\n## video_batch.py 参数\n\n| 参数 | 必填 | 说明 |\n| --- | --- | --- |\n| `--dir` | ✅ | 视频所在目录（只读该层，不递归） |\n| `--path` | ✅ | 目标知识库路径，如 `\"库名/文件夹名\"` |\n| `--ext` | | 视频扩展名，默认 `mp4,m4v,mov,webm,avi,mkv` |\n| `--out-dir` | | HTML 输出目录，默认 `<dir>/kb_html` |\n| `--title-map` | | JSON `{\"文件名\":\"标题\"}`，自定义页面标题与文件名（文件名本身即标题时可省略） |\n| `--template` | | 替换 HTML 模板 |\n| `--skip-upload` | | 只生成不上传 |\n| `--allow-dup` | | 允许重名重复入库（默认跳过重名） |\n| `--force` | | 覆盖已生成的 HTML |\n| `--max` | | 只处理前 N 个（调试用） |\n\n## 行为约定\n\n| 项 | 规则 |\n| --- | --- |\n| 输入 | 只处理本地目录里的视频文件（`--dir` 下一层） |\n| 文件名 | 沿用视频文件名/标题，清洗 URL 危险字符；**不加序号、不加后缀** |\n| 体积 | HTML **≤10MB**；**超过 10MB 自动丢弃、不上传**，汇总里单独列出 |\n| 页面 | 极简：标题 + 视频 + 一行「时长 · 大小 · 导出视频」+ 一行改名提示；无按钮块、无标签、无原始链接 |\n| 导出 | 点「导出视频」下载 `<标题>.bin`（blob + `application/octet-stream`）；**禁用 `.mp4` 后缀**（手机浏览器拦），页面提示改名为 `.mp4` |\n| 样式 | 只保留最小 CSS（无渐变 / 阴影 / 安全区 / 冗余媒体查询），减少页面占用 |\n| 多端适配 | 手机全宽、电脑限高 78vh 居中；兼容 iOS 12 Safari（不用 clamp()/gap/dvh） |\n| 模板 | `video/assets/video-template.html`，占位符：`__TITLE__` `__FILENAME__` `__B64__` `__DUR__` `__SIZE__` |\n| 幂等 | HTML 已存在则跳过生成（`--force` 重建）；目标重名条目默认不重复入库 |\n\n## 排障\n\n| 现象 | 原因 / 处理 |\n| --- | --- |\n| 打开条目报「无法打开网页」 | 文件名含 `#` 等危险字符 → 重命名或换安全名重传 |\n| 上传报 `220010 添加知识失败` | HTML 超 10MB → 压缩视频或截短后重跑 |\n| 汇总出现「超 10MB 未上传」 | 预期行为，压缩后重跑该文件 |\n| 视频转圈 / 黑屏 | 预览环境不支持内嵌播放 → 确认模板走的是 Blob URL 而非 data: URI |\n| 「导出视频」卡 0% / 下载失败 | 下载名用了 `.mp4` 后缀（手机浏览器按后缀拦截）→ 改 `.bin`（v1.0.12）；`data:` URI 同样被拦 |\n| 想直接下载 `.mp4` | 手机浏览器不允许网页生成 `.mp4` 下载；改用桌面浏览器打开，或让 Agent 发 mp4 直链 |\n\n## 文件构成\n\n| 文件 | 作用 |\n| --- | --- |\n| `video/scripts/video_batch.py` | 批量编排：遍历目录 → 封装 → 上传 |\n| `video/scripts/video_to_html.py` | 单个视频 → 单文件 HTML（命名清洗、10MB 校验） |\n| `video/assets/video-template.html` | 极简模板（Blob 播放 + .bin 导出、多端适配） |\n\nFile v1.0.12:_meta.json\n\n{\n  \"ownerId\": \"kn7b5dm7qcadb0hdtk4pz07pwn89v0d0\",\n  \"slug\": \"ima-plus-skill\",\n  \"version\": \"1.0.12\",\n  \"publishedAt\": 1791685207976\n}\n\nFile v1.0.12:knowledge-base/references/api.md\n\n# IMA知识库 API\n\n## ⚠️ 必读约束\n\n> 认证 / 服务信息 / 响应格式见 SKILL.md：Base URL `https://ima.qq.com`、Base Path `/openapi/wiki/v1`、HTTP POST JSON body、Header `ima-openapi-clientid` / `ima-openapi-apikey` / `Content-Type`（`application/json`）、响应 `{code, msg, data}`（`code=0` 成功取 `data`，`code≠0` 把 `msg` 展示给用户）。完整示例 `POST https://ima.qq.com/openapi/wiki/v1/get_knowledge_base`。\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### 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等仅支持在 ima 桌面端内添加进知识库 |\n| 20 | HTML | `text/html`（.html 文件上传） |\n| 21 | EPUB | `application/epub+zip`（.epub 文件上传） |\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### 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### 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### 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### 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### 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### 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### 8. 检查文件名重复\n\nPOST /openapi/wiki/v1/check_repeated_names\n\n**触发场景**：上传文件到知识库前，检查目标知识库（及文件夹）中是否已存在同名文件。仅用于文件类型（media_type 1/3/4/5/7/9/13/14/20/21），不用于网页（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### 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### 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- `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## 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## 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| 文件类型 | media_type | 最大大小 |\n| --- | --- | --- |\n| Excel、TXT、Xmind、Markdown、HTML | 5/13/14/7/20 | 10 MB |\n| 图片 | 9 | 30 MB |\n| EPUB | 21 | 50 MB |\n| PDF、Word、PPT、音频及其他 | 1/3/4/15 等 | 200 MB |\n\n网页（2/6）、笔记（11）等非文件类型无大小限制。音频文件额外限制：最长 2 小时。\n\n## 游标翻页使用规范\n\n1. **首次请求**：`cursor` 传空字符串 `\"\"`\n2. 检查返回的 `is_end`：`false` 表示还有更多数据\n3. 将返回的 `next_cursor` 作为下次请求的 `cursor`\n4. `is_end = true` 时停止翻页\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.0.12:notes/references/api.md\n\n# IMA笔记 API\n\n## ⚠️ 必读约束\n\n> 认证 / 服务信息 / 响应格式：见 SKILL.md（Base URL `https://ima.qq.com`、Header `ima-openapi-clientid` / `ima-openapi-apikey`（环境变量 `IMA_OPENAPI_CLIENTID` / `IMA_OPENAPI_APIKEY`）、`Content-Type`（`application/json`）、响应 `{code, msg, data}`）。\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#### 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#### NoteExtinfo（笔记扩展字段）\n\n| 字段 | 类型 | 说明 |\n| --- | --- | --- |\n| `folder_id` | string | 所属笔记本 ID |\n| `folder_name` | string | 所属笔记本名称 |\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#### QueryInfo（搜索条件）\n\n| 字段 | 类型 | 说明 |\n| --- | --- | --- |\n| `title` | string | 标题搜索关键词 |\n| `content` | string | 正文搜索关键词 |\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#### 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#### 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#### 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#### 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#### 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#### ListNoteFolderReq\n\n| 字段 | 类型 | 必填 | 校验规则 | 说明 |\n| --- | --- | --- | --- | --- |\n| `cursor` | string | **是** | tsecstr | 游标，第一页传 `\"0\"`，后续传返回的 `next_cursor` |\n| `limit` | uint64 | **是** | 0 < limit ≤ 20 | 每页数量 |\n\n#### ListNoteFolderRsp\n\n| 字段 | 类型 | 说明 |\n| --- | --- | --- |\n| `note_folder_infos` | NoteFolderInfo[] | 笔记本列表，见 [NoteFolderInfo](#notefolderinfo笔记本信息) |\n| `next_cursor` | string | 下次请求的起始游标 |\n| `is_end` | bool | 是否为最后一批数据 |\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### 2. ListNote — 获取笔记列表\n\nPOST /openapi/note/v1/list_note\n\n**触发场景**：用户说「查看XX笔记本的笔记」「最近的笔记」「列出笔记」\n\n- **请求**：[ListNoteReq](#listnotereq)\n- **响应**：[ListNoteRsp](#listnotersp)\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### 4. ImportNote — 新建笔记\n\nPOST /openapi/note/v1/import_doc\n\n**触发场景**：用户说「新建笔记」「导入笔记」「把这段内容保存为笔记」\n\n- **请求**：[ImportNoteReq](#importnotereq)\n- **响应**：[ImportNoteRsp](#importnotersp)\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### 6. ListNoteFolder — 笔记本列表\n\nPOST /openapi/note/v1/list_notebook\n\n**触发场景**：用户说「列出笔记本」「有哪些分类」「查看笔记本目录」\n\n- **请求**：[ListNoteFolderReq](#listnotefolderreq)\n- **响应**：[ListNoteFolderRsp](#listnotefolderrsp)\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### 笔记本列表（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## 错误码（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.0.12:references/api-call-templates.md\n\n# API 调用模板（跨平台 shell 写法 · 按需查阅）\n\n> 由 SKILL.md 下沉，仅在**无脚本覆盖**的操作（笔记块编辑/移动/导出、自定义查询）时需要。\n> 常用操作见 SKILL.md「高频操作快查表」。\n\n\n> **先看「高频操作快查表」**：常用操作（上传/打包/标签/文件夹/笔记新建追加）已有封装脚本，直接调用脚本即可，无需手写 API。\n> 以下模板仅用于**无脚本覆盖的操作**（笔记块编辑/移动/导出、自定义查询等）。\n\n> **跨平台说明**：本 skill 的全部脚本（`.cjs`）为**单一 Node.js 实现**，Windows / Linux / macOS 命令本身完全一致；差异只在 shell 包装（捕获输出、检查退出码）与中文编码处理。**zip 打包为纯 Node 实现**（zlib + 手写 zip 结构），不依赖系统 `zip`/`tar` 命令，Windows 直接可用（含中文文件名 UTF-8）。下面分别给出两平台的规范写法。运行需 **Node 18+**（依赖全局 `fetch` 与 `node:` 前缀模块）。\n\n所有请求统一为 **HTTP POST + JSON Body**，仅发往官方 Base URL `https://ima.qq.com`。\n\n`ima_api` 已抽离到脚本：`./ima_api.cjs`\n\n```bash\n# ── Linux / macOS（bash / zsh）── 跨平台通用写法之一\n# SKILL_DIR = this skill's root directory\n# stdout = normal response JSON; stderr = structured error {\"code\":-100|-200,\"msg\":\"...\"}\nresp=$(node \"$SKILL_DIR/ima_api.cjs\" \"openapi/list_docs\" '{\"limit\":10}' 2>&1)\nif [ $? -ne 0 ]; then\n  # Extract error code & msg using Node (cross-platform, no jq needed)\n  err_info=$(node -e \"try{const e=JSON.parse(process.argv[1]);process.stdout.write(e.code+':'+e.msg)}catch(_){process.stdout.write('-100:unknown error')}\" \"$resp\")\n  err_code=\"${err_info%%:*}\"\n  err_msg=\"${err_info#*:}\"\n\n  if [ \"$err_code\" = \"-200\" ]; then\n    echo \"[update] $err_msg\" >&2\n  else\n    echo \"[error] $err_msg\" >&2\n  fi\n  exit 1\nfi\n\necho \"$resp\"\n```\n\n> **Windows 版（PowerShell 5.1 / 7+）：**\n>\n> ```powershell\n> # 用 & 调用避免别名/函数冲突；2>&1 合并错误流到 $resp\n> $resp = & node \"$env:SKILL_DIR/ima_api.cjs\" 'openapi/list_docs' '{\"limit\":10}' 2>&1\n> if ($LASTEXITCODE -ne 0) {\n>     $err = $resp | ConvertFrom-Json\n>     if ($err.code -eq -200) { Write-Host \"[update] $($err.msg)\" }\n>     else { Write-Host \"[error] $($err.msg)\" }\n>     exit 1\n> }\n> Write-Host $resp\n> ```\n>\n> ⚠️ **PowerShell 5.1 中文乱码必读**：PS 5.1 会静默把请求 Body 转成系统 ANSI（中文 Windows 为 GBK），导致服务端收到乱码。必须改用 UTF-8 字节数组模式发送，详见 `references/platform-notes.md`。PowerShell 7+ 默认 UTF-8，无需额外处理。\n>\n> **Windows 版（命令提示符 cmd）：**\n>\n> ```cmd\n> chcp 65001 >nul\n> node \"%SKILL_DIR%\\ima_api.cjs\" \"openapi/list_docs\" \"{\\\"limit\\\":10}\" 2>&1\n> @REM 成功：stdout 为响应 JSON；失败：进程非 0 退出，错误信息在 stderr\n> @REM 用 %ERRORLEVEL% 判断退出码；中文参数需先 chcp 65001 防止乱码\n> ```\n>\n> **cmd 提示**：`SET SKILL_DIR=...` 后，路径用 `%SKILL_DIR%` 引用；Windows 上 `\\` 与 `/` 均可作路径分隔符（Node 均接受）。若 `node` 不在 PATH，用完整路径（如 `\"C:\\Program Files\\nodejs\\node.exe\"`）；脚本内部已用 `process.execPath` 调用 node 子进程，通常无需手动处理。\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\nFile v1.0.12:references/platform-notes.md\n\n# 平台细节：UTF-8 编码 与 PowerShell 5.1（按需查阅）\n\n> 由 SKILL.md 下沉，为实现细节，仅在需要时阅读。\n\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.0.12:references/troubleshooting.md\n\n# Troubleshooting — 实测沉淀的错误码对照与避坑指南\n\n> **按需读取**：仅在 API 调用出错（`code≠0`、`-100`、`-200`、异常现象）时查阅本节对照定位。\n> 标注 `code=xxx` 为后端业务错误（stdout JSON 的 `code` 字段）；`退出码` 为脚本进程退出码。\n\n## 一、知识库接口坑对照\n\n| 接口 / 场景 | 试错现象 | 正确做法 |\n| --- | --- | --- |\n| `create_folder` | 手敲 `folder_name` → `code=51` 参数非法 | 字段名是 **`name`**（`--name` / 请求体 `name`） |\n| `search_knowledge_base_in_square`（广场发现） | 误用 `query` → `code=51` | 参数是 **`question`**（且必填非空），脚本用 `--question` |\n| `set_knowledge_top`（置顶） | ① 对单个**文件**置顶 → `code=220001 invalid media_id`；② `--media-id` 空时脚本误判成布尔 → `code=1 cannot unmarshal bool` | ① **仅支持文件夹**（`folder_...`，media_type=99）；② `is_top` 是布尔；③ `--media-id` 必须传真实 id |\n| `export_media` / `export_media_for_ima_sandbox` | `code=220030 无权限访问该接口` | **key 权限问题，非脚本缺陷**：导出接口需 API key 开通导出权限；个人在 agent-interface 申请的 key 默认未开通，需用 ima app 内 copilot 环境变量中的凭证（已开通）。凭证获取见主 SKILL.md「Credential Check」 |\n| `update_knowledge_base_permission` | 有**真实副作用**（影响该库所有成员） | 正式库改权限前**必须向用户确认** |\n| `join_knowledge` | 会**真实加入**公开库（副作用） | 调用前确认用户确实要加入；加入后需用户到 IMA 客户端退出 |\n| `get_media_info` 读取原文 | 订阅库（普通成员）返回 `code=220030 没有权限` | 仅**个人库（创建者）**能读文件/笔记原文；订阅库只能看列表，引导用户去客户端 |\n| `get_knowledge_list` 的 `folder_id` | 把 `knowledge_base_id` 当 `folder_id` 传入 → 返回根目录而非目标文件夹 | 根目录**省略** `folder_id`；子目录 ID 必须 `folder_xxxx` 开头；看到 `current_path` = 走对路径 |\n| `media_type` 枚举 | 曾误以为 `media_type=11` 是微信文章（其实是**笔记**），`6` 才是微信文章 | 速记：`1=PDF` `2=网页URL` `4=PPT` `5=Excel` `6=微信文章` `11=笔记` `16=网页视频` `20=HTML` `21=EPUB` `99=文件夹`；拿不准先搜样例 |\n| `search_*` 返回空 | `info_list:[]` 不一定是真没内容 | 换关键词 / 换接口（`get_knowledge_list` 翻文件夹）；别一次空就放弃 |\n| `check_repeated_names` 重名判定 | 刚上传完短时间内查同名可能 `is_repeated=false`（索引延迟） | 别仅凭一次查询认定无重名 |\n| `create_folder` 接口选择 | 早期误用 `add_knowledge`+`media_type=99` 建文件夹失败 | 正确接口是 `create_folder`（实测可成功，返回 `data.media_id` 即 `folder_id`） |\n| 删除类操作 | 试图删除文件/文件夹/知识库/标签 | **IMA OpenAPI 不支持任何实体删除**，测试留痕需用户到 IMA 客户端手动清理 |\n| `tag_delete` / `tag_rename` | 删除标签移除其与所有文件关联（**不可逆**）；`tag_rename` 新名已存在时自动合并两组标签 | 调用前确认 |\n| 写操作角色 | 普通成员调建库/改名/置顶/标签/权限 → `code=220030` | 需角色为创建者/协作成员/管理员 |\n| 批量导出 / 打包 | 订阅库不可下载；HTML(20) 个人库也 `220030`；大文件（如 103MB 无后缀音频）需按 media_type 补后缀；同名文件会覆盖 | 仅个人库（创建者）可导出；并发 ≤8，单文件失败跳过不中断；订阅库引导客户端。完整 SOP 见下文「六、批量导出打包 SOP」 |\n| `search_knowledge_base` 返回结构 | 按 `knowledge_base_list`/`id`/`name` 解析永远匹配不到 | 返回字段是 `info_list` / `kb_id` / `kb_name`；空 `query` 返回账号**全部**知识库（含订阅） |\n| 文件夹上传 | —— | 用 `--folder <folder_id>`，支持任意层级嵌套；文件夹的 `media_id` 即其 `folder_id`；`move_knowledge` 仅支持文件，**不支持移动文件夹** |\n| 订阅库权限墙 | 订阅库 134 条内容但 `get_media_info` 返回 `220030 没有权限通过skill获取订阅知识库的文件` | 个人库（创建者）全权限；订阅库（普通成员）只能看列表/元信息，引导用户去客户端，别反复重试 |\n| `kb_id` 是 Base64 URL 安全变体 | 含 `=`、`+`、`_`，shell 极易丢字符 | 写进变量 + 双引号包住（`\"$KB_ID\"`）；PowerShell 别用反引号包值（反引号是转义符）；传入前先 `echo` 核对一次 |\n| 写/查重类接口（`check_repeated_names` 等） | `code=222001 知识库已删除` | 目标知识库已在客户端被删除（索引残留：`get_knowledge_base` / `get_knowledge_list` 仍可能查到，但写操作全部拒绝）。换用现存库或重建；路径缓存会自动失效重查（`222001`/`已删除` 已纳入自愈判定） |\n\n## 二、笔记接口坑\n\n| 场景 | 试错现象 | 正确做法 |\n| --- | --- | --- |\n| 写入 UTF-8 编码 | PowerShell 5.1 下乱码内容写入笔记 → **永久乱码不可恢复** | 写 `import_doc`/`append_doc` 前**强制校验**所有字符串字段为合法 UTF-8（详见主 SKILL.md「Detailed UTF-8 Encoding Rules」） |\n| `update_note` 编辑块 | 对 `editable=false` 的块（图片/录音/附件/链接卡片/AI 生成块）下发 EDIT/DELETE → `code=210039` | 这类块只能作为 APPEND 锚点 |\n| 模糊指令 | 用户说「有什么经验吗」可能指「笔记里有没有相关经验记录」 | 先反问确认意图（搜已有笔记 vs 其他含义） |\n\n## 三、权限与凭证\n\n- **凭证获取**：两种来源任选其一——① ima app 的 copilot 对话索要环境变量 `IMA_OPENAPI_CLIENTID`/`IMA_OPENAPI_APIKEY` 的凭证（已开通导出，推荐）；② https://ima.qq.com/agent-interface 申请 key（普通功能可用，导出类接口可能 220030）。完整指令见主 SKILL.md「Credential Check」。\n- **凭证单一来源（V1.0.8+）**：强制从环境变量 `IMA_OPENAPI_CLIENTID`/`IMA_OPENAPI_APIKEY` 读取，**无任何文件配置与自动降级**（不再读 config.json / ~/.config/ima/）。ima.copilot 环境已自动注入；自建环境需主动 export 到 ~/.bashrc 或 ~/.zshrc。缺凭证 → 脚本退出码 `-100`。\n- **220030 三种常见情况**：① 导出接口 key 未开通权限；② 订阅库（普通成员）读原文；③ 普通成员执行写操作（建库/改名/置顶/标签/权限）。\n- **凭证安全**：凭证只发送到 `ima.qq.com`；**切勿打包进公开分发的 zip**；失效/报 220030 时重新走「一步获取凭证」更新。\n\n## 四、平台与环境\n\n- **PowerShell 5.1**：`Invoke-RestMethod` 静默将请求 Body 从 UTF-8 转系统 ANSI（中文 Windows 为 GBK）→ 必须用 UTF-8 字节数组模式（见主 SKILL.md「PowerShell 5.1 Environment Detection」）。PowerShell 7+ 默认 UTF-8。\n- **Windows cmd**：每条命令前先 `chcp 65001 >nul` 防中文参数乱码；`node` 不在 PATH 时用完整路径。\n- **cursor 分页**：首次 `cursor: \"\"`（空串），**不是** `null` 也不是 `\"0\"`（部分接口 `null` → `code:-100`；`\"0\"` 被当字符串跳过第一页）；用返回 `next_cursor` 翻页，`is_end=true` 停止。例外：`list_notebook` 首页传 `\"0\"`。`search_knowledge_base_in_square` 无 `is_end`，以 `next_cursor` 为空终止。\n- **Linux / macOS**：默认 UTF-8，直接跑。\n\n## 五、调用习惯\n\n- **模糊查询直接调 API，别过度读 SKILL.md**：「看看有啥」→ 立刻 `search_knowledge_base(query=\"\")`；「XX 库里有什么」→ `get_knowledge_list(knowledge_base_id=...)`。浅读即可，调用优先。\n- **模糊指令先反问**：指代歧义（「经验/技巧/记录/保存/添加」多重解释）→ **0.5 秒反问一句 > 翻 5-8 次 API**。未确认意图前不要调 API。\n- **内部 ID 不外露**：面向用户只展示知识库名称、文件标题、文件夹名；`kb_id`/`media_id`/`folder_id` 自己调用用。\n- **长结果做摘要 + 给下一步**：结果 > 10 条分主题归类，结尾引导「想深入哪条？」\n- **文件上传优先用一键脚本**：`upload_to_kb.cjs` 封装 5 步流程（preflight → 重名 → create_media → COS → add_knowledge），支持 `--path \"知识库名/文件夹\"`（首选，自动解析）/`--kb-name`/`--cancel-if-dup`，避免手工拼 JSON 出错。\n\n## 六、批量导出打包 SOP（2026-07-22 实测）\n\n1. `list_all_files.cjs --json --path \"我的知识库\"` 拿全量文件清单（路径 + media_id + media_type）。\n2. 对每个文件 `get_media_info` 拿 `url_info.url` + `headers`，URL 后拼 `response-content-type=application/octet-stream&response-content-disposition=attachment` 强制下载。\n3. 按 `path` 保持目录结构落盘；**同名文件会覆盖**（如「项目报告v1.0」出现在两个文件夹）→ 加 media_id 短后缀防重。\n4. 实测可下载：个人库 TXT(13)/Markdown(7)/MP3录音(15)/PDF 等；**HTML(20) 即使个人库也 220030**（类型受限）；订阅库任意类型 220030。\n5. 规模与健壮性：订阅库可能万级条目（如鸿蒙 14661 条）且无法下载；大文件（103MB 无后缀音频）按 media_type 补 `.mp3` 等后缀；批量下载并发 ≤8，单文件失败跳过不中断。\n6. 结论：「全部打包」API 层面只能覆盖个人库（创建者）；订阅库引导用户到 IMA 客户端手动导出或申请导出权限。\n\n## 七、实测结论（2026-07-21 全功能实测）\n- 在「测试知识库1」实测 **25 项 KB 功能 + 6 项 notes 功能**，仅 `export_media` 因后端权限未开通失败，其余全部通过。\n- 脚本为**单一跨平台 Node.js 实现**（纯 `node:` 内置模块、Node 18+）：Windows / Linux / macOS 命令本身完全一致，差异只在 shell 包装与中文编码；老 cmd（GBK）下 emoji 日志乱码但功能不受影响。\n- **IMA OpenAPI 不支持删除任何实体**：文件/文件夹/知识库/标签均不可删，测试留痕需用户到客户端手动清理。\n\n## 八、路径解析缓存（V1.0.8+）\n\n自然语言路径（`--path \"知识库名/文件夹/子夹\"`）的解析结果按「知识库 → 文件夹 → 子文件夹」**树状缓存**，避免重复查 API。\n\n- **缓存位置**：环境变量 `IMA_RESOLVE_CACHE` 指定（ima.copilot 默认 `/sandbox/workspace/.ima_cache/resolve_cache.json`，workspace 持久、平台不重置）；**非 ima.copilot 环境未设置 → 加载即报错**「未设置缓存位置环境变量 IMA_RESOLVE_CACHE」，与凭证同等强制。\n- **缓存内容**：只有「名字 → kb_id / folder_id」映射，**不含凭证**。\n- **失效自愈**：操作 API 报「目标不存在」（`220001` / invalid / 不存在 / 未找到 类）→ 自动失效该路径缓存 → 全 API 重查 → 重试一次；重查任一层找不到 → 报「在「X」下未找到「Y」」整体失败。权限（220030）/ 限流（200001）类错误**不触发**自愈。\n- **手动清缓存**：删除缓存文件即可，下次解析自动重建；知识库/文件夹被删除或改名后首次操作会走自愈恢复。\n- **常见坑**：\n  - 缓存文件损坏 / 格式不对 → 自动按空缓存重建，不影响使用\n  - 首次操作报「未找到」且路径确实存在 → 多为缓存键不匹配（省略库名/模糊名），会保守全清重查，属正常流程\n  - `ima_skill_create` 注册报 `is a directory` → skill 目录里有嵌套软链或同名子目录，先 `find <skill_dir> -type l` 检查并删除后重新注册\n\nFile v1.0.12:skill-card.md\n\n## Description:\n\nHelps agents manage IMA knowledge bases and notes, upload and export content, and package local videos as single-file HTML for import.\n\nThis skill is ready for commercial/non-commercial use.\n\n## Publisher:\n\n[wwqww1](https://clawhub.ai/user/wwqww1)\n\n### License/Terms of Use:\n\nMIT-0\n\n## Use Case:\n\nIMA users and developers use this skill to organize knowledge bases and notes, import files and webpages, export content, and prepare videos for import. It requires IMA API credentials and Node.js; video conversion also requires Python.\n\n### Deployment Geography for Use:\n\nGlobal\n\n## Known Risks and Mitigations:\n\nRisk: The skill instructs users to expose API keys in chat.\n\nMitigation: Obtain keys through the official flow, supply them through a secret manager or environment variables, and rotate any exposed keys.\n\nRisk: Exports and account-changing operations can proceed without script-level confirmation and may be irreversible.\n\nMitigation: Review or dry-run exports, permission and tag changes, knowledge-base joins, and note appends before execution.\n\n## Reference(s):\n\n- [ClawHub skill release](https://clawhub.ai/wwqww1/skills/ima-plus-skill)\n- [IMA API credential application](https://ima.qq.com/agent-interface)\n- [Knowledge base API reference](artifact/knowledge-base/references/api.md)\n- [Notes API reference](artifact/notes/references/api.md)\n\n## Skill Output:\n\n**Output Type(s):** [Text, Shell commands, Configuration guidance, Files]\n\n**Output Format:** [Markdown guidance and commands; JSON responses, exported ZIP archives, and video HTML files]\n\n**Output Parameters:** [1D]\n\n**Other Properties Related to Output:** [IMA operations require IMA_OPENAPI_CLIENTID and IMA_OPENAPI_APIKEY; video conversion requires Python.]\n\n## Skill Version(s):\n\n1.0.12 (source: ClawHub release metadata and skill frontmatter)\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.0.12:meta.json\n\n{\n  \"version\": \"1.0.11\",\n  \"required_binaries\": [\n    {\n      \"name\": \"node\",\n      \"min_version\": \"18.0.0\",\n      \"reason\": \"Runs all .cjs scripts (knowledge-base / notes) and inline node -e JSON parsing\"\n    },\n    {\n      \"name\": \"python3\",\n      \"min_version\": \"3.8.0\",\n      \"reason\": \"video module: video/scripts/video_to_html.py (mp4 -> embedded single-file HTML) and video/scripts/video_batch.py (batch wrap + upload)\"\n    }\n  ]\n}\n\nArchive v1.0.11: 43 files, 108223 bytes\n\nFiles: _lib.cjs (1647b), ima_api.cjs (5240b), knowledge-base/references/api.md (18844b), knowledge-base/scripts/cos-upload.cjs (6317b), knowledge-base/scripts/create_folder.cjs (2090b), knowledge-base/scripts/create_knowledge_base.cjs (1728b), knowledge-base/scripts/export_kb_zip.cjs (16197b), knowledge-base/scripts/export_media.cjs (2449b), knowledge-base/scripts/join_knowledge.cjs (1518b), knowledge-base/scripts/list_all_files.cjs (4883b), knowledge-base/scripts/move_knowledge.cjs (4096b), knowledge-base/scripts/preflight-check.cjs (13884b), knowledge-base/scripts/rename_knowledge.cjs (1628b), knowledge-base/scripts/search_knowledge_base_in_square.cjs (1549b), knowledge-base/scripts/set_knowledge_top.cjs (1650b), knowledge-base/scripts/tag_add.cjs (1569b), knowledge-base/scripts/tag_delete.cjs (1293b), knowledge-base/scripts/tag_list.cjs (1429b), knowledge-base/scripts/tag_remove.cjs (1398b), knowledge-base/scripts/tag_rename.cjs (1598b), knowledge-base/scripts/update_knowledge_access_status.cjs (2207b), knowledge-base/scripts/update_knowledge_base_basic_info.cjs (2262b), knowledge-base/scripts/update_knowledge_base_permission.cjs (2167b), knowledge-base/scripts/upload_to_kb.cjs (6807b), knowledge-base/SKILL.md (12370b), meta.json (439b), notes/references/api.md (10878b), notes/scripts/note-images.cjs (10376b), notes/scripts/notes_append.cjs (2929b), notes/scripts/notes_create.cjs (3551b), notes/scripts/resolve_notebook.cjs (2043b), notes/SKILL.md (19669b), references/api-call-templates.md (4118b), references/platform-notes.md (5045b), references/troubleshooting.md (11725b), resolve_path.cjs (18610b), skill-card.md (2121b), SKILL.md (18952b), video/assets/video-template.html (3121b), video/scripts/video_batch.py (7424b), video/scripts/video_to_html.py (4376b), video/SKILL.md (3431b), _meta.json (134b)\n\nFile v1.0.11:knowledge-base/SKILL.md\n\n---\nname: IMA 知识库模块\ndescription: IMA 知识库操作模块。负责上传文件、添加网页/微信文章到知识库、搜索与浏览知识库内容、获取知识库信息。\nallowed-tools: Bash,Read\nmetadata: {\"openclaw\":{\"emoji\":\"📚\",\"requires\":{\"bins\":[\"node\"]}}}\n---\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` 传入） | 见「脚本速查」upload_to_kb |\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| 检查文件名重复 | `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| 按名称找知识库 | `search_knowledge_base` | `query`，`cursor`，`limit`(1~20) |\n| 查看自己有哪些知识库 | `search_knowledge_base` | `query: \"\"` |\n| 添加内容但未指定库 | `get_addable_knowledge_base_list` | `cursor`，`limit`(1~50) |\n| 查看/导出原文 | `get_media_info` | `media_id`；下载时 URL 后追加 `response-content-type=application/octet-stream&response-content-disposition=attachment;filename=\"<名>\"` |\n| 创建文件夹 | `create_folder` | `knowledge_base_id`，`name`，可选 `folder_id`（父夹） |\n| 重命名文件/文件夹 | `rename_knowledge` | `knowledge_base_id`，`media_id`，`name` |\n| 移动文件（**不支持文件夹**） | `move_knowledge` | `src_knowledge_base_id`，`dst_knowledge_base_id`，`infos:[{media_id}]`，可选 `dst_folder_id` |\n| 获取下载链接 | `export_media_for_ima_sandbox` | `media_id`；返回 `url`+`headers`，下载需带 `headers` |\n| 创建知识库 | `create_knowledge_base` | `name`(必填)，`type`(1001/1002/1004)，可选 `description`/`cover-url`/`recommended-questions` |\n| 修改库基本信息 | `update_knowledge_base_basic_info` | `id`，自动推导 `update_fields`（1名 2封面 3简介 4推荐问题） |\n| 置顶/取消置顶 | `set_knowledge_top` | `knowledge_base_id`，`media_id`，`is_top`(布尔) |\n| 打/移除标签 | `tag_add` / `tag_remove` | `knowledge_base_id`，`item_id`(=media_id)，`tag_name` |\n| 列/搜标签 | `tag_list` | `knowledge_base_id`，可选 `keyword`/`cursor`，`limit` |\n| 重命名/删除标签 | `tag_rename` / `tag_delete` | 重命名新名存在自动合并；删除不可逆 |\n| 修改库权限 | `update_knowledge_base_permission` | `id`，自动推导 `update_fields`（1导出状态 2加入类型） |\n| 加入知识库 | `join_knowledge` | `knowledge_base_id`，`name`（**真实加入，有副作用**） |\n| 批量更新访问状态 | `update_knowledge_access_status` | `knowledge_base_id`，`infos:[{media_id}]`(≤10)，`access_status`(1/2/3) |\n| 广场发现 | `search_knowledge_base_in_square` | `question`(必填，**不是** query)，`cursor`(首次空)，`limit` |\n\n**`search_knowledge_base` vs `get_addable_knowledge_base_list`**：用户说了库名 → 前者按名搜；用户没说加到哪个库 → 后者列出可选库让用户选。**绝不要**在用户已明确库名时调 `get_addable_knowledge_base_list`。\n\n---\n\n## ⛔ 文件上传安全门（仅文件上传 → `add_knowledge` 流程）\n\n```\nGATE 1 [TYPE]   preflight-check.cjs 先行，pass=false 直接拒绝。视频/B站/YouTube/file:// → 引导用户用 IMA 客户端。绝不问\"还要试吗\"\nGATE 2 [NAME]   add_knowledge 的 title 必须等于 file_name（含扩展名），绝不改名/缩写/翻译\nGATE 3 [DUP]    所有文件上传前先 check_repeated_names；is_repeated=true → 问用户保留两者(追加 _YYYYMMDDHHmmss)或取消；不支持替换\nGATE 4 [EXIT]   cos-upload.cjs 非零退出 → 立即停止，不调 add_knowledge\n```\n\n## 上传文件到知识库\n\n**首选一键脚本** `upload_to_kb.cjs`（封装 GATE 1-4 全部五步，自动重名处理与 JSON 解析，失败即停）：\n\n```bash\nnode knowledge-base/scripts/upload_to_kb.cjs --file a.pdf --path \"我的知识库/项目/文档\"\nnode knowledge-base/scripts/upload_to_kb.cjs --file a.pdf --path \"我的知识库\"          # 根目录\nnode knowledge-base/scripts/upload_to_kb.cjs --file a.pdf --cancel-if-dup             # 重名时取消\n```\n\n目标库**必须显式指定**（`--path` 首选 / `--kb-name` 兼容 / `--folder` 指定文件夹），脚本不自动选库。批量重名检查见 `api.md`（最多 2000 个文件名）。\n\n### 添加网页 / 微信文章 / 笔记\n\n```bash\n# 网页/微信（无 GATE，非文件）\nima_api \"openapi/wiki/v1/import_urls\" '{\"knowledge_base_id\": \"<库ID>\", \"urls\": [\"https://...\"], \"folder_id\": \"<可选>\"}'\n# 返回 results 映射 {url: {url, ret_code, media_id}}\n\n# 笔记 → 知识库\nima_api \"openapi/wiki/v1/add_knowledge\" '{\"media_type\": 11, \"note_info\": {\"content_id\": \"<note_id>\"}, \"title\": \"笔记标题\", \"knowledge_base_id\": \"<库ID>\"}'\n\n# URL 指向可下载文件时：先探测 content-type → 下载 → preflight-check → 走上传流程（详见 api.md §URL Type Detection）\n```\n\n---\n\n## 🌐 自然语言目录解析（统一入口，优先使用）\n\n**所有需要知识库/文件夹的操作，用自然语言路径，禁止让用户提供 kb_id。**\n\n```bash\nnode resolve_path.cjs --path \"我的知识库/项目/文档\"   # → { kb_id, kb_name, folder_id, folder_name }\nnode resolve_path.cjs --path \"我的知识库\"             # folder_id 空 = 根目录\nnode resolve_path.cjs --path \"项目/文档\"              # 唯一库可省略库名\n```\n\n**使用规则**：\n1. 用户给了路径/名称 → **直接 `resolve_path.cjs --path`**，不要手动 search + list 逐步找 ID\n2. 解析结果分层缓存（防重名串库、无 TTL、失效自愈），重复解析同一路径 0 次 API\n3. 所有封装脚本支持 `--path \"库名/文件夹...\"` 直接传\n4. 用户没给位置 → 用 `--kb-name` 或让用户选择\n5. **面向用户永远只展示名称**，禁止暴露 kb_id / folder_id / media_id\n6. ⛔ **禁止擅自使用 `--kb <id>`**：即使解析拿到 ID 也不得主动用，一律 `--path`；仅用户明确要求指定 ID 时可用\n\n## 脚本速查\n\n> 所有脚本支持 `--path \"库名/文件夹...\"`（自动解析），兼容 `--kb-name`。详见各脚本头部 Usage 注释。\n\n```bash\n# 文件夹：创建（可多级）/ 浏览 / 重命名 / 置顶（仅文件夹，media_type=99）\nnode knowledge-base/scripts/create_folder.cjs --path \"库/父夹\" --name \"新夹\"\nnode knowledge-base/scripts/list_all_files.cjs --path \"库/夹\" [--json] [--with-url]\nnode knowledge-base/scripts/rename_knowledge.cjs --path \"库\" --media-id <id> --name \"新名\"\nnode knowledge-base/scripts/set_knowledge_top.cjs --path \"库\" --media-id <folder_id> --is-top true   # ⚠️ 仅文件夹，文件报 220001\n\n# 移动（仅文件，≤10 个） / 导出媒体\nnode knowledge-base/scripts/move_knowledge.cjs --src-path \"库A\" --dst-path \"库B/目标夹\" --media-id id1,id2\nnode knowledge-base/scripts/export_media.cjs --media-id <id> [--download --out /path/save]\n\n# 标签（文件夹不支持打标签；rename 重名自动合并、delete 不可逆，调用前确认）\nnode knowledge-base/scripts/tag_add.cjs --path \"库\" --media-id <id> --tag-name \"重要\"\nnode knowledge-base/scripts/tag_remove.cjs --path \"库\" --media-id <id> --tag-name \"重要\"\nnode knowledge-base/scripts/tag_list.cjs --path \"库\" [--keyword 关键词]\nnode knowledge-base/scripts/tag_rename.cjs --path \"库\" --old-tag-name 旧 --new-tag-name 新\nnode knowledge-base/scripts/tag_delete.cjs --path \"库\" --tag-name 待删\n\n# 知识库管理（普通成员写操作会 220030，需创建者/协作成员/管理员）\nnode knowledge-base/scripts/create_knowledge_base.cjs --name \"库名\" --type 1001        # 1001个人 1002共享 1004订阅\nnode knowledge-base/scripts/update_knowledge_base_basic_info.cjs --path \"库\" --name 新名 [--description 简介]\nnode knowledge-base/scripts/update_knowledge_base_permission.cjs --path \"库\" --visible-export-status 3 [--join-type 1]  # ⚠️ 影响全库成员，调用前确认\nnode knowledge-base/scripts/update_knowledge_access_status.cjs --path \"库\" --media-id id1,id2 --access-status 3\n\n# 广场发现 / 加入（join 真实加入公开库，调用前确认用户确实要加）\nnode knowledge-base/scripts/search_knowledge_base_in_square.cjs --question \"关键词\"\nnode knowledge-base/scripts/join_knowledge.cjs --path \"知识库名称\" --name \"知识库名称\"\n```\n\n## 打包导出为 zip（整库 / 文件夹 / 多文件）\n\n```bash\n# ① 整个库 / ② 某个文件夹（递归）/ ③ 指定多文件（--media-ids）\nnode knowledge-base/scripts/export_kb_zip.cjs --path \"我的知识库\" --out /path/out.zip\nnode knowledge-base/scripts/export_kb_zip.cjs --path \"我的知识库/项目\" --out /path/out.zip\nnode knowledge-base/scripts/export_kb_zip.cjs --path \"我的知识库\" --media-ids id1,id2 --out /path/out.zip\n\n# 打包前先看调用量：--count（JSON）/ --estimate / --dry-run（列出将导出的文件）\nnode knowledge-base/scripts/export_kb_zip.cjs --path \"我的知识库\" --count\n```\n\n- 导出需 API key **开通导出权限**（凭证见主 SKILL.md「Credential Check」；agent-interface 普通 key 会 220030）\n- 超 50 次/分钟自动限速；单文件失败跳过不中断，全部失败不生成 zip\n- ⚠️ 订阅库（普通成员）不可下载，引导用户到 IMA 客户端\n- 完整 SOP 见 `references/troubleshooting.md`「批量导出打包 SOP」\n\n---\n\n## 查询类工作流\n\n```bash\n# 库信息 / 浏览 / 搜索 / 可添加库列表\nima_api \"openapi/wiki/v1/get_knowledge_base\" '{\"ids\": [\"<库ID>\"]}'\nima_api \"openapi/wiki/v1/get_knowledge_list\" '{\"knowledge_base_id\": \"<库ID>\", \"cursor\": \"\", \"limit\": 20}'\nima_api \"openapi/wiki/v1/search_knowledge\" '{\"query\": \"关键词\", \"knowledge_base_id\": \"<库ID>\", \"cursor\": \"\"}'\nima_api \"openapi/wiki/v1/get_addable_knowledge_base_list\" '{\"cursor\": \"\", \"limit\": 20}'\n\n# 原文内容（get_media_info）处理分支：\n#   media_type=11 且有 notebook_ext_info.notebook_id → 作为 note_id 走 notes 模块 get_doc_content\n#   url_info.url 非空 → 用 url+headers 请求原文\n#   否则 → 提示用户用 IMA 客户端查看原文\n```\n\n`list_all_files.cjs` 递归遍历全库输出目录树（限深 20、单目录 2500 条保护），`--json` 输出结构化数组，`--with-url` 逐个拿下载链接（订阅库多为空/220030）。\n\n## 分页 / 响应 / 用户体验\n\n- **分页**：所有列表/搜索接口游标分页，首次 `cursor: \"\"`，用 `next_cursor` 翻页，`is_end=true` 停止\n- **响应**：统一 `{ code, msg, data }`；`code=0` 成功，`code≠0` 直接展示 `msg`\n- **隐藏 ID**：面向用户永不暴露 `knowledge_base_id` / `media_id` / `folder_id`，只展示名称\n- **精简进度**：不暴露内部步骤，只报告结果（如「正在上传 report.pdf…」→「已添加到知识库「XX」✓」）；批量操作汇总成功/失败\n- **格式化展示**：库列表带描述（ID 列表调 `get_knowledge_base` 补描述）；内容列表带 📁/📄 前缀与文件数；搜索结果显示所在文件夹\n\n## 注意事项\n\n- 文件夹是知识条目（`media_type=99`），其 `media_id` 即 `folder_id`\n- 扩展名用于 `media_type` 检测与 `file_ext`（无点号，如 `pdf`）；COS `--content-type` 传实际 MIME\n- URL 入库先检测是否文件型 → `api.md §URL Type Detection`；MediaType 枚举/大小限制 → `api.md §MediaType`\n- **IMA OpenAPI 不支持删除任何实体**（文件/文件夹/库），需客户端手动清理\n- 错误码（220030 / 51 / 220001 等）先读 `references/troubleshooting.md`\n\nFile v1.0.11:notes/SKILL.md\n\n---\nname: IMA 笔记模块\ndescription: IMA 笔记管理模块。负责搜索、浏览、创建、编辑（追加）用户个人笔记。\nallowed-tools: Bash,Read\nmetadata: {\"openclaw\":{\"emoji\":\"📝\",\"requires\":{\"bins\":[\"node\"]}}}\n---\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| 往笔记插入含图片的内容（本地/远程图片）                                           | `note-images.cjs` | `--note-id` + `--file`/`--content`；图片 < 3MiB，仅 PNG/JPEG/WebP         |\n| 编辑笔记前获取块结构（update_note 前置）                                          | `export_note_blocks` | `note_id` |\n| 按 block 精细编辑笔记（改/删/插某段）                                             | `update_note`     | `note_id` + `user_request_id`(UUIDv4) + `updates[]`(block_id/action/new_content) |\n| 重命名笔记本                                                                       | `rename_notebook` | `folder_id` + `new_folder_name` |\n| 导出整篇笔记（Markdown/纯文本/JSON）                                            | `export_note`     | `note_id` + `target_content_format`(推荐`1`) |\n| 智能推送：不存在则新建、存在则追加                                              | `push_note`       | `content`(可选)+`note_id`(可选)+`content_cos_key`(可选) |\n| 重命名单篇笔记标题                                                               | `rename_note`     | `note_id` + `title` |\n| 批量移动笔记到其他笔记本                                                         | `move_notes`      | `note_ids[]` + `target_folder_id` |\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**含图片的 Markdown 一律用 `notes/scripts/note-images.cjs` 写入**：它把内容按原顺序分批——连续文本合并为一批、每张图片单独一批，逐批 `append_doc`。图片会被规范化为 data URL，**无需先上传到网络**。\n\n- **支持来源**：本地路径 / `file://` URI / `http(s)` 远程图片 / base64 data URL\n- **支持格式**：PNG / JPEG / WebP，单张原始文件必须 **< 3 MiB**（不得压缩、转码规避）\n- **原始预检**：大小 + MIME + 真实文件签名一致性，任一不符立即拒绝\n\n```bash\n# 写入到已有笔记（--file 与 --content 二选一；建议先 --dry-run 预演）\nnode notes/scripts/note-images.cjs --note-id \"<笔记ID>\" --file \"/path/to/content.md\" --dry-run\nnode notes/scripts/note-images.cjs --note-id \"<笔记ID>\" --file \"/path/to/content.md\"\n\n# 仅把本地图片转成临时 download_url（此模式不接受远程 URL）\nnode notes/scripts/note-images.cjs --url \"/path/to/img.png\"\n```\n\n⚠️ **它是「追加」接口，不负责新建**：\n\n- 新建含图片的笔记 → 先用 `notes_create.cjs` 建好笔记（拿到 `note_id`），再用 `note-images.cjs` 追加含图片的正文\n- 同一段文本不要两边都传，否则会重复写入\n- 任一批次失败立即停止，已成功批次不回滚\n\n**降级规则（不走脚本时）**：直接调 `import_doc` / `append_doc` 时 `content` 仅支持 Markdown，**本地图片引用会被过滤**，只保留 `http(s)` 网络图片——`notes_create.cjs` / `notes_append.cjs` 也保留此过滤行为并会提示。需要插入本地图片时，请改用 `note-images.cjs`。\n\n## 跨平台调用说明（Windows / Linux）\n\n单一 Node.js 实现，命令跨平台一致（需 Node 18+）；**优先用封装脚本**（`notes_create.cjs` / `notes_append.cjs` / `note-images.cjs` / `resolve_notebook.cjs`），其余接口走 `ima_api.cjs`。下文 `ima_api \"<path>\" '<json>'` 即：\n\n- **Linux / macOS**：`node \"$SKILL_DIR/ima_api.cjs\" \"$1\" \"$2\"`\n- **Windows PowerShell**：`& node \"$env:SKILL_DIR/ima_api.cjs\" '<path>' '<json>'`\n- **Windows cmd**：先 `chcp 65001 >nul`，再 `node \"%SKILL_DIR%\\ima_api.cjs\" \"<path>\" \"<json>\"`\n\n中文编码：Linux/macOS 默认 UTF-8；PowerShell 5.1 须用 UTF-8 字节数组模式（Body 会被静默转 GBK）。完整写法、`ima_api` 包装函数与两层错误处理 → 见父级 `SKILL.md` 与 `references/api-call-templates.md`。\n\n## 🌐 笔记本名解析（统一入口，优先使用）\n\n**所有需要笔记本（folder_id）的操作，优先用笔记本名称，不要让用户提供 folder_id。**\n\n统一解析器 `notes/scripts/resolve_notebook.cjs`：\n\n```bash\n# 按名称解析笔记本\nnode notes/scripts/resolve_notebook.cjs --path \"学习笔记\"\n# → { \"note_folder_id\": \"...\", \"note_folder_name\": \"学习笔记\" }\n\n# 列出所有笔记本\nnode notes/scripts/resolve_notebook.cjs --list\n```\n\n**使用规则**：\n\n1. 用户说了笔记本名称（如\"存到学习笔记里\"）→ 先调 `resolve_notebook.cjs --path <名称>` 拿到 `note_folder_id`，再用于 `list_note` / `import_doc` / `move_notes` 等接口\n2. 解析不到时列出当前笔记本让用户确认，禁止猜测\n3. **面向用户永远只展示笔记本名称**，禁止暴露 folder_id\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# 0. 按名称解析笔记本 folder_id\nnode notes/scripts/resolve_notebook.cjs --path \"学习笔记\"\n# → { \"note_folder_id\": \"...\", \"note_folder_name\": \"学习笔记\" }\n\n# 1. 拉取该笔记本的笔记（首页 cursor 传 \"\"）\nima_api \"openapi/note/v1/list_note\" '{\"folder_id\": \"<解析出的note_folder_id>\", \"cursor\": \"\", \"limit\": 20}'\n```\n\n仅当需要手动探索时：\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**首选脚本**（自动 UTF-8 校验；本地图片会被过滤，含图片请改用 `note-images.cjs`）：\n\n```bash\n# 新建到默认位置\nnode notes/scripts/notes_create.cjs --content \"# 标题\n\n正文内容\"\n\n# 新建到指定笔记本（--path 自动解析 folder_id，带缓存）\nnode notes/scripts/notes_create.cjs --content \"# 标题\n\n正文内容\" --path \"学习笔记\"\n\n# 从文件新建\nnode notes/scripts/notes_create.cjs --file /tmp/note.md --path \"学习笔记\"\n# 返回 note_id，后续可用于 append_doc\n```\n\n也可以直接调接口（灵活场景）：\n\n```bash\nima_api \"openapi/note/v1/import_doc\" '{\"content_format\": 1, \"content\": \"# 标题\\n\\n正文内容\", \"folder_id\": \"<解析出的note_folder_id>\"}'\n```\n\n### 追加内容到已有笔记\n\n**首选脚本**（⚠️ 敏感操作，AI 必须确认目标笔记明确后再调用）：\n\n```bash\nnode notes/scripts/notes_append.cjs --note-id <笔记ID> --content \"\n## 补充内容\n\n追加的文本\"\nnode notes/scripts/notes_append.cjs --note-id <笔记ID> --file /tmp/extra.md\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编辑已有笔记中的某一段/某一块，需要两步：先用 `export_note_blocks` 获取块结构，再用 `update_note` 按 `block_id` 修改。\n\n```bash\n# 1. 获取块结构\nima_api \"openapi/note/v1/export_note_blocks\" '{\"note_id\": \"笔记ID\"}'\n# 从返回的 data.blocks[] 中取目标 block_id 和 editable 字段\n\n# 2. 按 block 修改：action 1=EDIT替换 / 2=DELETE删除 / 3=APPEND在该块后插入\nima_api \"openapi/note/v1/update_note\" '{\"note_id\": \"笔记ID\", \"user_request_id\": \"本轮UUIDv4\", \"updates\": [{\"block_id\": \"目标block_id\", \"action\": 1, \"new_content\": \"新的Markdown内容\"}]}'\n```\n\n**`user_request_id` 复用规则**：同一用户消息内的多次 `update_note` 调用必须复用同一个 UUID v4；收到新的用户消息时重新生成。未传或为空会返回 `210001`。\n\n**注意事项**：\n- `editable=false` 的块（图片/录音/附件/链接卡片/AI 生成块）只能作为 APPEND 锚点，对其下发 EDIT/DELETE 会返回 `210039`\n- `block_id` 必须来自 `export_note_blocks`，不可凭空构造\n- 虚拟锚点 `_begin_`（最前插入）/ `_end_`（末尾追加）配合 `action=3` 使用\n- 列表整体（`id1..idN`）作为一个逻辑块：EDIT 替换整个列表，DELETE 删除整个列表\n\n### 笔记本管理\n\n| 用户意图 | 调用接口 | 关键参数 |\n| -------- | -------- | -------- |\n| 列出笔记本 | `list_notebook` | `cursor`(首页`\"0\"`)+`limit` |\n| 创建笔记本 | `add_notebook` | `folder_name` |\n| 重命名笔记本 | `rename_notebook` | `folder_id`+`new_folder_name` |\n\n```bash\n# 重命名笔记本\nima_api \"openapi/note/v1/rename_notebook\" '{\"folder_id\": \"笔记本ID\", \"new_folder_name\": \"新名称\"}'\n```\n\n### 导出笔记（export_note）\n\n导出整篇笔记为文件，支持 Markdown / 纯文本 / JSON 三种格式。\n\n```bash\nima_api \"openapi/note/v1/export_note\" '{\"note_id\": \"笔记ID\", \"target_content_format\": 1}'\n```\n\n- 返回 `data.content_url` 为带签名的 COS 下载链接（时效约 3 小时），需二次 `curl` 该链接获取实际内容\n- `target_content_format`：`0`=纯文本 `.txt`，`1`=Markdown `.md`（推荐），`2`=JSON（Slate 编辑器 AST）`.json`\n- 需要作者权限\n\n### 智能推送（push_note）\n\n不确定笔记是否已存在时使用：note_id 为空则新建，不为空则追加到该笔记。\n\n```bash\nima_api \"openapi/note/v1/push_note\" '{\"content\": \"标题：项目排期。正文内容...\"}'\n```\n\n- `note_id` 可选（为空新建，不为空追加）；`content` 与 `content_cos_key` 不能同时为空\n- 长内容可先 `ima_cos_util -f <文件>` 上传拿 cosKey，再传 `content_cos_key`\n- 返回 `data.note_id`\n\n### 重命名笔记（rename_note）\n\n```bash\nima_api \"openapi/note/v1/rename_note\" '{\"note_id\": \"笔记ID\", \"title\": \"新标题\"}'\n```\n\n- 需要作者权限，返回空消息体\n\n### 移动笔记（move_notes）\n\n```bash\nima_api \"openapi/note/v1/move_notes\" '{\"note_ids\": [\"笔记ID1\", \"笔记ID2\"], \"target_folder_id\": \"目标笔记本ID\"}'\n```\n\n- `note_ids` 最多 100 条，`target_folder_name` 可选\n- 返回 `data.result` map（key=note_id, value=true/false），可能部分成功，需逐条检查\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**笔记列表条目**（`list_note` 响应数组字段是 `data.note_book_list`）：`NoteBookInfo` 关键字段：`note_id`、`title`、`summary`、`create_time`、`modify_time`、`cover_image`、`note_ext_info`（含 `folder_id`、`folder_name`）。\n\n**读取正文**（`get_doc_content`）：正文在 `data.content`（纯文本/Markdown 由 `target_content_format` 决定）。\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- 直接调 `import_doc` / `append_doc` 不支持本地图片；需插入本地/远程图片时用 `notes/scripts/note-images.cjs`（详见上方「🖼️ 图片写入」章节）\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\n> 遇到笔记接口错误码（210039 / 100009 / 100005 等）或异常现象，先读 `references/troubleshooting.md` 对照定位；UTF-8 强制校验与跨模块规则见父级 SKILL.md。\n\nFile v1.0.11:SKILL.md\n\n---\nname: ima_plus-skill\ndescription: IMA 知识库与笔记操作技能（版本 v1.0.11）：用 `--path` 自然语言定位知识库/文件夹/笔记本，支持文件上传导出、文件夹与条目管理、标签权限、网页入库、笔记增改与插图，以及把本地视频封装成单文件 HTML 入库（需环境变量 IMA_OPENAPI_CLIENTID / IMA_OPENAPI_APIKEY）。\nallowed-tools: Bash,Read\nmetadata:\n  openclaw:\n    emoji: \"🔧\"\n    requires:\n      bins:\n        - node\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 request base URL is hard-whitelisted to ima.qq.com: options.baseUrl / IMA_BASE_URL\n      overrides are rejected unless they resolve to ima.qq.com, so credentials can never be\n      forwarded to an arbitrary host.\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, and COS temporary credentials are\n      passed to the upload helper via environment variables (not argv).\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# ima_plus-skill\n\n> **版本：V1.0.11**\n>\n> **运行环境**：Node.js ≥ 18.0.0（所有 .cjs 脚本 + inline JSON 解析依赖）；视频模块另需 `python3` + `curl`（`ffprobe` 可选，取时长）\n\nUnified IMA OpenAPI skill. Currently supports: **notes**, **knowledge-base**, **video**（视频链接 → 内嵌 HTML → 入库）.\n\n## ⛔ MANDATORY RULES — read before ANY operation\n\n0. **自然语言路径优先（所有模块通用，强制）：** 用户给出知识库/文件夹/笔记本的名称或路径（如\"我的知识库/项目/文档\"、\"存到学习笔记\"）时，**一律用解析器自动转 ID，禁止让用户提供 kb_id / folder_id**。知识库用根目录 `resolve_path.cjs --path`，笔记本用 `notes/scripts/resolve_notebook.cjs --path`。面向用户永远只展示名称，禁止暴露任何 ID。\n   - ⛔ **禁止擅自使用 `--kb <kb_id>`**：即使解析过程中拿到了 kb_id，**也不得主动用它调用脚本**——所有脚本调用一律走 `--path \"知识库名/文件夹...\"`（内部自动解析）。`--kb` 仅在**用户明确要求使用某个具体 ID** 时才允许出现。违反此规则视为流程错误。\n   - 兼容参数 `--kb-name`（按名称匹配）可以正常使用，但 `--path` 是首选。\n\n### 🔧 路径解析缓存机制（V1.0.8+，无需手动管理）\n\n解析器会把「知识库名 → kb_id、文件夹路径 → folder_id」**分层树状持久化**到缓存文件，\n按「知识库 → 子文件夹 → 孙文件夹」嵌套，同名文件夹在不同库/不同父目录各占节点，不会串库。\n\n**缓存位置（强制检查，安装 skill 时必须确定）：**\n1. 环境变量 `IMA_RESOLVE_CACHE` 显式指定（所有环境，优先级最高）\n2. ima.copilot 环境未设置时默认 `/sandbox/workspace/.ima_cache/resolve_cache.json`（workspace 持久、平台不重置）\n3. **其他 agent / 自建环境未设置 `IMA_RESOLVE_CACHE` → 直接报错不可用**（与凭证同等强制）。\n   安装时须先设置：`export IMA_RESOLVE_CACHE=/path/to/resolve_cache.json`（可写入 ~/.bashrc 或 ~/.zshrc）\n\n- **无过期时间**：缓存长期有效；重复解析同一路径 **0 次 API 调用**（部分命中只补查缺失层级）。\n- **失效自愈**：所有消费脚本已包 `withPathRetry`——若操作因「目标不存在」（如库/夹被删或改名，`220001/invalid/不存在` 类）失败，自动失效该路径缓存 → 全 API 重新解析 → 重试一次；**重查任一层失败即报「目录位置不存在」，整个操作直接中止，不猜测后续层级**。权限（220030）/限流（200001）类错误不触发自愈。\n- **手动清缓存**（一般不需要）：删除缓存文件即可，下次解析自动重建。知识库/文件夹被删除后首次操作会自愈恢复。\n- 笔记本解析（`--notes` / `resolve_notebook.cjs`）同样缓存（`notebooks` 节）。\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 `references/platform-notes.md` 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?\" **视频文件（mp4/avi/mov/mkv…）不能作为文件直接上传**——必须走视频模块转成「内嵌单文件 HTML」再上传（见 § 📹 视频模块，细则读 `video/SKILL.md`）；Bilibili / YouTube URL 与 `file://` URL 仍不支持，引导用户改用 IMA 客户端。\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 `references/platform-notes.md`.\n6. **副作用操作必须显式确认（不得自行执行）：** `join_knowledge`（真实加入公开库）、`tag_delete` / `tag_rename`（不可逆；新名已存在时自动合并）、`update_knowledge_base_permission`（影响全库成员）、`append_doc` 追加已有笔记（不可撤销修改）——调用前必须得到用户明确同意，不确定时先问。\n\n## 🚀 高频操作快查表（30 秒上手）\n\n| 用户意图 | 直接执行 |\n| --- | --- |\n| 上传文件到知识库 | `node knowledge-base/scripts/upload_to_kb.cjs --path \"库名/文件夹\" --file <路径>` |\n| 打包知识库/文件夹为 zip | `node knowledge-base/scripts/export_kb_zip.cjs --path \"库名/文件夹\" --out /path/out.zip` |\n| 列出知识库内容 | `node knowledge-base/scripts/list_all_files.cjs --path \"库名\"` |\n| 创建文件夹 | `node knowledge-base/scripts/create_folder.cjs --path \"库名/父夹\" --name \"新夹\"` |\n| 新建笔记 | `node notes/scripts/notes_create.cjs --content \"内容\" --path \"笔记本名\"` |\n| 追加笔记 | `node notes/scripts/notes_append.cjs --note-id <id> --content \"内容\"` |\n| 笔记插入图片 | `node notes/scripts/note-images.cjs --note-id <id> --file <md>` |\n| 本地视频批量封装为 HTML 并入库 | `python3 video/scripts/video_batch.py --dir <视频目录> --path \"<知识库>/<文件夹>\"` |\n\n> 路径一律用 `--path \"知识库名/文件夹...\"` 自然语言，禁止 kb_id。其余操作见各模块 SKILL.md 与脚本头部 Usage 注释。\n\n## 📹 视频模块（V1.0.10 新增）\n\n把**本地视频文件**批量封装为「内嵌单文件 HTML」并上传到知识库文件夹。\n**只做封装与上传，不做下载**（视频文件不能直接上传知识库——服务端限制）。\n\n```bash\npython3 video/scripts/video_batch.py --dir <视频目录> --path \"<知识库>/<文件夹>\"\n```\n\n- HTML **超过 10MB 自动丢弃、不上传**；文件名不加序号，并清洗 `# ? & /` 等 URL 危险字符\n- 页面浅色极简（标题 + 视频），多端适配，兼容 iOS 12 Safari\n- **参数、行为约定、排障 → 见 `video/SKILL.md`**\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| 打包知识库 / 某个文件夹 / 多个文件为 zip 并发给用户                                         | knowledge-base | `knowledge-base/SKILL.md` |\n| 把本地视频批量转换成 HTML 并上传到知识库文件夹 | video | `video/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- 向笔记插入图片（本地/远程）必须由 notes 模块的 `note-images.cjs` 完成，**不得**调用 knowledge-base 的 `create_media` / `add_knowledge` / `get_media_info` 代替\n\n## ⚠️ 出错时查这里（按需读取）\n\n遇到后端错误码（`220030` / `51` / `210039` / `220001` 等）或任何异常现象，**先读 `references/troubleshooting.md`** 对照定位——那里汇总了全部实测沉淀的错误码对照表、权限边界、批量导出 SOP 与已知坑。正常执行时无需读取该文件。\n\n## ⚙️ 安装配置总览（必读）\n\n安装本 skill 只需配置 **两件事**（均为环境变量，强制设置，不设置无法使用）：\n\n| # | 配置项 | 环境变量 | 未设置时 |\n|---|--------|----------|----------|\n| 1 | 凭证 | `IMA_OPENAPI_CLIENTID` / `IMA_OPENAPI_APIKEY` | 报错不可用（`code=-100`） |\n| 2 | 缓存保存位置 | `IMA_RESOLVE_CACHE` | ima.copilot 默认 workspace 缓存；**其他环境报错不可用** |\n\n- ✅ **ima.copilot 环境：零配置直接可用**（平台已注入凭证 + 默认 `/sandbox/workspace/.ima_cache/` 缓存）\n- ⚠️ **其他 agent / 自建环境**：按下方「Credential Check」设置凭证、按「路径解析缓存机制」设置缓存位置，**两件都配好才能用**\n\n## Credential Check（凭证获取与配置）\n\n### 凭证从哪来（必读）\n\n凭证有 **两种来源，任选其一** 设置到环境变量即可：\n\n1. **ima app 内 copilot 会话环境变量中的凭证**（`IMA_OPENAPI_CLIENTID` / `IMA_OPENAPI_APIKEY`）\n   ——这套凭证**已开通导出权限**（`export_media` / `export_media_for_ima_sandbox` 可用），推荐。\n2. **https://ima.qq.com/agent-interface 申请的 API key**——普通功能（上传/建库/打标签/移动/搜索等）可用；\n   ⚠️ 但**导出类接口可能返回 `code=220030 无权限`**（导出权限未开通，非脚本缺陷），需要打包导出时请用来源 1 的凭证。\n\n> ⛔ **凭证强制从环境变量读取，单一来源，不设置技能无法使用**：\n> 不再支持 config.json / ~/.config/ima/ 等任何文件配置与自动降级。\n\n- ✅ **ima.copilot 环境**：平台已自动注入 `IMA_OPENAPI_CLIENTID` / `IMA_OPENAPI_APIKEY`，直接可用，无需任何配置。\n- ⚠️ **自建环境（自己的电脑 / 服务器）**：必须先主动设置环境变量（来源 1 或 2 任一），否则所有脚本报错退出（`code=-100`，提示未设置凭证）。\n\n### 自建环境设置方式\n\n**Linux / macOS**（写入 shell 配置文件，永久生效）：\n\n```bash\n# ~/.bashrc 或 ~/.zshrc 末尾追加（替换成你自己的凭证值）\nexport IMA_OPENAPI_CLIENTID=\"你的 clientId\"\nexport IMA_OPENAPI_APIKEY=\"你的 apiKey\"\nsource ~/.bashrc\n```\n\n**Windows**：系统设置 → 环境变量 → 新建 `IMA_OPENAPI_CLIENTID` / `IMA_OPENAPI_APIKEY`。\n\n### 一步获取凭证（完整指令）\n\n> 在 **ima app** 中打开 **copilot** 对话，原样发送以下指令：\n\n```\n请把环境变量里的 IMA 凭证发给我：IMA_OPENAPI_CLIENTID 和 IMA_OPENAPI_APIKEY 的值（我要配置 ima_plus-skill 技能的 clientId 和 apiKey）\n```\n\ncopilot 会从运行环境变量读取并返回 `clientId`（= `IMA_OPENAPI_CLIENTID`）与\n`apiKey`（= `IMA_OPENAPI_APIKEY`）。拿到后按上方方式 export 到自建环境。\n\n> ⚠️ **安全须知（V1.0.11）**：此操作会让凭证在对话中明文出现。请仅在**你自己的** ima 会话里执行，\n> 且只用于把凭证迁移到你的自建环境。**切勿**把该对话内容截图、转发或分享给他人/第三方 agent，\n> 也**不要**把凭证写入 skill 目录随 skill 一起分发。怀疑已泄露时，去\n> https://ima.qq.com/agent-interface 轮换凭证。\n\n### 验证\n\n```bash\nnode knowledge-base/scripts/export_kb_zip.cjs --path \"<你的个人库名>\" --dry-run\n```\n\n能列出文件清单即凭证有效。\n\n### 安全提醒\n\n- 该凭证绑定你的账号且已开通导出权限，**切勿外泄、切勿打包进公开分发的 zip**\n- 凭证只发送到 `ima.qq.com`，不写入任何日志、配置文件或外部文件\n- 凭证失效 / 导出报 220030 时，重新执行「一步获取凭证」更新环境变量即可\n\n### V1.0.11 安全加固（响应第三方安全审计）\n\n- **Base URL 白名单**：`ima_api.cjs` 拒绝一切非 `ima.qq.com` 的 base URL（`options.baseUrl` / `IMA_BASE_URL`），凭证不可能被转发到任意地址\n- **导出脱敏**：`export_media.cjs` 默认隐藏授权 header 取值（`--show-headers` 才显示），支持 `--quiet` 完全静默\n- **COS 凭证不再走 argv**：`upload_to_kb.cjs → cos-upload.cjs` 的临时凭证改经环境变量传递，不再出现在进程列表\n- **导出文件名净化**：`export_kb_zip.cjs` 对知识库条目标题做净化（去除 `/`、`..`、控制字符），防止路径遍历\n\n### 上下文瘦身（降低加载与运行时 token · 并入 v1.0.11）\n\n- **清单类输出紧凑化**：`list_all_files` 默认改紧凑格式（`路径\\t类型\\tmedia_id`），新增 `--summary`（只出统计）/ `--files-only` / `--json`(compact) / `--pretty`\n- **`export_kb_zip` 去重**：成功项不再打印两遍，`--verbose` 才输出明细\n- **文档下沉**：SKILL.md 的「API 调用模板」「UTF-8 / PowerShell 细节」移入 `references/api-call-templates.md`、`references/platform-notes.md`（按需读取）\n- **广场搜索 / 标签列表**输出改为紧凑 tab 分隔\n\n## 📎 按需参考（体积大，需要时再读）\n\n以下内容不属于高频路径，已拆为独立文件，**仅在需要时打开**，以降低常驻上下文：\n\n| 需要什么 | 文件 |\n| --- | --- |\n| API 调用模板 / 跨平台 shell 写法（bash · PowerShell · cmd） | `references/api-call-templates.md` |\n| UTF-8 编码规则、PowerShell 5.1 乱码处理（实现细节） | `references/platform-notes.md` |\n| 错误码对照 / 排障 / 批量导出 SOP | `references/troubleshooting.md` |\n\n\n## 核心心智：用 API 技能的 3 个原则\n\n| 原则 | 含义 | 反例 |\n|------|------|------|\n| **不猜** | 指代、ID、路径、枚举——拿不准就问/查 | 猜 media_type=11 是微信文章 |\n| **不省** | UTF-8 校验、双层 code 检查、双模块 SKILL.md | 跳过 encoding 直接写笔记 |\n| **不堆** | 结果分主题、ID 内部消化、摘要 + 下一步 | 50 行 ID 列表直接贴给用户 |\n\n> 最快的路径 = 凭证一次配置（问 copilot 拿环境变量凭证）+ Node 统一调用 + 浅读 SKILL.md + 模糊指令先问人。\n\nFile v1.0.11:video/SKILL.md\n\n# video 模块 —— 本地视频 → 内嵌 HTML → 知识库\n\n> 独立模块，与 `knowledge-base` / `notes` 同级。\n> **只做封装与上传，不做下载**（视频从哪来不归本模块管）。\n\n## 为什么必须封装成 HTML\n\n知识库**不接受 mp4 / avi / mov 等视频文件**（服务端限制）。\n唯一可行方式：视频 base64 内嵌进单文件 HTML（≤10MB），页面用 **Blob URL** 播放\n（data: URI 在部分 WebView 会加载失败；Blob 方案实测 3MB+ 正常）。\n\n> ⚠️ **条目名规则（最大的坑）**：条目名 = 文件名，不得含 `# ? & /` 等 URL 危险字符。\n> `#` 在 URL 中是锚点分隔符 → 打开条目时显示「无法打开网页」（与体积无关）。\n\n## 用法\n\n```bash\n# 批量：目录里的视频全部封装并上传\npython3 video/scripts/video_batch.py --dir <视频目录> --path \"<知识库>/<文件夹>\"\n\n# 只生成、不上传（本地检查）\npython3 video/scripts/video_batch.py --dir <视频目录> --path \"<知识库>/<文件夹>\" --skip-upload\n\n# 单个文件\npython3 video/scripts/video_to_html.py --mp4 a.mp4 --title \"标题\" --out-dir ./html\n```\n\n## video_batch.py 参数\n\n| 参数 | 必填 | 说明 |\n| --- | --- | --- |\n| `--dir` | ✅ | 视频所在目录（只读该层，不递归） |\n| `--path` | ✅ | 目标知识库路径，如 `\"库名/文件夹名\"` |\n| `--ext` | | 视频扩展名，默认 `mp4,m4v,mov,webm,avi,mkv` |\n| `--out-dir` | | HTML 输出目录，默认 `<dir>/kb_html` |\n| `--title-map` | | JSON `{\"文件名\":\"标题\"}`，自定义页面标题与文件名 |\n| `--template` | | 替换 HTML 模板 |\n| `--skip-upload` | | 只生成不上传 |\n| `--allow-dup` | | 允许重名重复入库（默认跳过重名） |\n| `--force` | | 覆盖已生成的 HTML |\n| `--max` | | 只处理前 N 个（调试用） |\n\n## 行为约定\n\n| 项 | 规则 |\n| --- | --- |\n| 输入 | 只处理本地目录里的视频文件（`--dir` 下一层） |\n| 文件名 | 沿用视频文件名/标题，清洗 URL 危险字符；**不加序号、不加后缀** |\n| 体积 | HTML **≤10MB**；**超过 10MB 自动丢弃、不上传**，汇总里单独列出 |\n| 页面 | 浅色极简：标题 + 视频 + 一行时长/大小小字；无按钮、无标签、无原始链接 |\n| 多端适配 | 手机全宽、电脑限高 78vh 居中、横屏矮窗压缩；兼容 iOS 12 Safari（不用 clamp()/gap/backdrop-filter/dvh） |\n| 模板 | `video/assets/video-template.html`，占位符：`__TITLE__` `__B64__` `__DUR__` `__SIZE__` |\n| 幂等 | HTML 已存在则跳过生成（`--force` 重建）；目标重名条目默认不重复入库 |\n\n## 排障\n\n| 现象 | 原因 / 处理 |\n| --- | --- |\n| 打开条目报「无法打开网页」 | 文件名含 `#` 等危险字符 → 重命名或换安全名重传 |\n| 上传报 `220010 添加知识失败` | HTML 超 10MB → 压缩视频或截短后重跑 |\n| 汇总出现「超 10MB 未上传」 | 预期行为，压缩后重跑该文件 |\n| 视频转圈 / 黑屏 | 预览环境不支持内嵌播放 → 确认模板走的是 Blob URL 而非 data: URI |\n\n## 文件构成\n\n| 文件 | 作用 |\n| --- | --- |\n| `video/scripts/video_batch.py` | 批量编排：遍历目录 → 封装 → 上传 |\n| `video/scripts/video_to_html.py` | 单个视频 → 单文件 HTML（命名清洗、10MB 校验） |\n| `video/assets/video-template.html` | 浅色极简模板（Blob 播放、多端适配） |\n\nFile v1.0.11:_meta.json\n\n{\n  \"ownerId\": \"kn7b5dm7qcadb0hdtk4pz07pwn89v0d0\",\n  \"slug\": \"ima-plus-skill\",\n  \"version\": \"1.0.11\",\n  \"publishedAt\": 1791220299001\n}\n\nFile v1.0.11:knowledge-base/references/api.md\n\n# IMA知识库 API\n\n## ⚠️ 必读约束\n\n> 认证 / 服务信息 / 响应格式见 SKILL.md：Base URL `https://ima.qq.com`、Base Path `/openapi/wiki/v1`、HTTP POST JSON body、Header `ima-openapi-clientid` / `ima-openapi-apikey` / `Content-Type`（`application/json`）、响应 `{code, msg, data}`（`code=0` 成功取 `data`，`code≠0` 把 `msg` 展示给用户）。完整示例 `POST https://ima.qq.com/openapi/wiki/v1/get_knowledge_base`。\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### 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等仅支持在 ima 桌面端内添加进知识库 |\n| 20 | HTML | `text/html`（.html 文件上传） |\n| 21 | EPUB | `application/epub+zip`（.epub 文件上传） |\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### 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### 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### 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### 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### 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### 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### 8. 检查文件名重复\n\nPOST /openapi/wiki/v1/check_repeated_names\n\n**触发场景**：上传文件到知识库前，检查目标知识库（及文件夹）中是否已存在同名文件。仅用于文件类型（media_type 1/3/4/5/7/9/13/14/20/21），不用于网页（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### 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### 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- `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## 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## 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| 文件类型 | media_type | 最大大小 |\n| --- | --- | --- |\n| Excel、TXT、Xmind、Markdown、HTML | 5/13/14/7/20 | 10 MB |\n| 图片 | 9 | 30 MB |\n| EPUB | 21 | 50 MB |\n| PDF、Word、PPT、音频及其他 | 1/3/4/15 等 | 200 MB |\n\n网页（2/6）、笔记（11）等非文件类型无大小限制。音频文件额外限制：最长 2 小时。\n\n## 游标翻页使用规范\n\n1. **首次请求**：`cursor` 传空字符串 `\"\"`\n2. 检查返回的 `is_end`：`false` 表示还有更多数据\n3. 将返回的 `next_cursor` 作为下次请求的 `cursor`\n4. `is_end = true` 时停止翻页\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.0.11:notes/references/api.md\n\n# IMA笔记 API\n\n## ⚠️ 必读约束\n\n> 认证 / 服务信息 / 响应格式：见 SKILL.md（Base URL `https://ima.qq.com`、Header `ima-openapi-clientid` / `ima-openapi-apikey`（环境变量 `IMA_OPENAPI_CLIENTID` / `IMA_OPENAPI_APIKEY`）、`Content-Type`（`application/json`）、响应 `{code, msg, data}`）。\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#### 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#### NoteExtinfo（笔记扩展字段）\n\n| 字段 | 类型 | 说明 |\n| --- | --- | --- |\n| `folder_id` | string | 所属笔记本 ID |\n| `folder_name` | string | 所属笔记本名称 |\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#### QueryInfo（搜索条件）\n\n| 字段 | 类型 | 说明 |\n| --- | --- | --- |\n| `title` | string | 标题搜索关键词 |\n| `content` | string | 正文搜索关键词 |\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#### 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#### 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#### 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#### 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#### 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#### ListNoteFolderReq\n\n| 字段 | 类型 | 必填 | 校验规则 | 说明 |\n| --- | --- | --- | --- | --- |\n| `cursor` | string | **是** | tsecstr | 游标，第一页传 `\"0\"`，后续传返回的 `next_cursor` |\n| `limit` | uint64 | **是** | 0 < limit ≤ 20 | 每页数量 |\n\n#### ListNoteFolderRsp\n\n| 字段 | 类型 | 说明 |\n| --- | --- | --- |\n| `note_folder_infos` | NoteFolderInfo[] | 笔记本列表，见 [NoteFolderInfo](#notefolderinfo笔记本信息) |\n| `next_cursor` | string | 下次请求的起始游标 |\n| `is_end` | bool | 是否为最后一批数据 |\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### 2. ListNote — 获取笔记列表\n\nPOST /openapi/note/v1/list_note\n\n**触发场景**：用户说「查看XX笔记本的笔记」「最近的笔记」「列出笔记」\n\n- **请求**：[ListNoteReq](#listnotereq)\n- **响应**：[ListNoteRsp](#listnotersp)\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### 4. ImportNote — 新建笔记\n\nPOST /openapi/note/v1/import_doc\n\n**触发场景**：用户说「新建笔记」「导入笔记」「把这段内容保存为笔记」\n\n- **请求**：[ImportNoteReq](#importnotereq)\n- **响应**：[ImportNoteRsp](#importnotersp)\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### 6. ListNoteFolder — 笔记本列表\n\nPOST /openapi/note/v1/list_notebook\n\n**触发场景**：用户说「列出笔记本」「有哪些分类」「查看笔记本目录」\n\n- **请求**：[ListNoteFolderReq](#listnotefolderreq)\n- **响应**：[ListNoteFolderRsp](#listnotefolderrsp)\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### 笔记本列表（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## 错误码（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.0.11:references/api-call-templates.md\n\n# API 调用模板（跨平台 shell 写法 · 按需查阅）\n\n> 由 SKILL.md 下沉，仅在**无脚本覆盖**的操作（笔记块编辑/移动/导出、自定义查询）时需要。\n> 常用操作见 SKILL.md「高频操作快查表」。\n\n\n> **先看「高频操作快查表」**：常用操作（上传/打包/标签/文件夹/笔记新建追加）已有封装脚本，直接调用脚本即可，无需手写 API。\n> 以下模板仅用于**无脚本覆盖的操作**（笔记块编辑/移动/导出、自定义查询等）。\n\n> **跨平台说明**：本 skill 的全部脚本（`.cjs`）为**单一 Node.js 实现**，Windows / Linux / macOS 命令本身完全一致；差异只在 shell 包装（捕获输出、检查退出码）与中文编码处理。**zip 打包为纯 Node 实现**（zlib + 手写 zip 结构），不依赖系统 `zip`/`tar` 命令，Windows 直接可用（含中文文件名 UTF-8）。下面分别给出两平台的规范写法。运行需 **Node 18+**（依赖全局 `fetch` 与 `node:` 前缀模块）。\n\n所有请求统一为 **HTTP POST + JSON Body**，仅发往官方 Base URL `https://ima.qq.com`。\n\n`ima_api` 已抽离到脚本：`./ima_api.cjs`\n\n```bash\n# ── Linux / macOS（bash / zsh）── 跨平台通用写法之一\n# SKILL_DIR = this skill's root directory\n# stdout = normal response JSON; stderr = structured error {\"code\":-100|-200,\"msg\":\"...\"}\nresp=$(node \"$SKILL_DIR/ima_api.cjs\" \"openapi/list_docs\" '{\"limit\":10}' 2>&1)\nif [ $? -ne 0 ]; then\n  # Extract error code & msg using Node (cross-platform, no jq needed)\n  err_info=$(node -e \"try{const e=JSON.parse(process.argv[1]);process.stdout.write(e.code+':'+e.msg)}catch(_){process.stdout.write('-100:unknown error')}\" \"$resp\")\n  err_code=\"${err_info%%:*}\"\n  err_msg=\"${err_info#*:}\"\n\n  if [ \"$err_code\" = \"-200\" ]; then\n    echo \"[update] $err_msg\" >&2\n  else\n    echo \"[error] $err_msg\" >&2\n  fi\n  exit 1\nfi\n\necho \"$resp\"\n```\n\n> **Windows 版（PowerShell 5.1 / 7+）：**\n>\n> ```powershell\n> # 用 & 调用避免别名/函数冲突；2>&1 合并错误流到 $resp\n> $resp = & node \"$env:SKILL_DIR/ima_api.cjs\" 'openapi/list_docs' '{\"limit\":10}' 2>&1\n> if ($LASTEXITCODE -ne 0) {\n>     $err = $resp | ConvertFrom-Json\n>     if ($err.code -eq -200) { Write-Host \"[update] $($err.msg)\" }\n>     else { Write-Host \"[error] $($err.msg)\" }\n>     exit 1\n> }\n> Write-Host $resp\n> ```\n>\n> ⚠️ **PowerShell 5.1 中文乱码必读**：PS 5.1 会静默把请求 Body 转成系统 ANSI（中文 Windows 为 GBK），导致服务端收到乱码。必须改用 UTF-8 字节数组模式发送，详见 `references/platform-notes.md`。PowerShell 7+ 默认 UTF-8，无需额外处理。\n>\n> **Windows 版（命令提示符 cmd）：**\n>\n> ```cmd\n> chcp 65001 >nul\n> node \"%SKILL_DIR%\\ima_api.cjs\" \"openapi/list_docs\" \"{\\\"limit\\\":10}\" 2>&1\n> @REM 成功：stdout 为响应 JSON；失败：进程非 0 退出，错误信息在 stderr\n> @REM 用 %ERRORLEVEL% 判断退出码；中文参数需先 chcp 65001 防止乱码\n> ```\n>\n> **cmd 提示**：`SET SKILL_DIR=...` 后，路径用 `%SKILL_DIR%` 引用；Windows 上 `\\` 与 `/` 均可作路径分隔符（Node 均接受）。若 `node` 不在 PATH，用完整路径（如 `\"C:\\Program Files\\nodejs\\node.exe\"`）；脚本内部已用 `process.execPath` 调用 node 子进程，通常无需手动处理。\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\nFile v1.0.11:references/platform-notes.md\n\n# 平台细节：UTF-8 编码 与 PowerShell 5.1（按需查阅）\n\n> 由 SKILL.md 下沉，为实现细节，仅在需要时阅读。\n\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.0.11:references/troubleshooting.md\n\n# Troubleshooting — 实测沉淀的错误码对照与避坑指南\n\n> **按需读取**：仅在 API 调用出错（`code≠0`、`-100`、`-200`、异常现象）时查阅本节对照定位。\n> 标注 `code=xxx` 为后端业务错误（stdout JSON 的 `code` 字段）；`退出码` 为脚本进程退出码。\n\n## 一、知识库接口坑对照\n\n| 接口 / 场景 | 试错现象 | 正确做法 |\n| --- | --- | --- |\n| `create_folder` | 手敲 `folder_name` → `code=51` 参数非法 | 字段名是 **`name`**（`--name` / 请求体 `name`） |\n| `search_knowledge_base_in_square`（广场发现） | 误用 `query` → `code=51` | 参数是 **`question`**（且必填非空），脚本用 `--question` |\n| `set_knowledge_top`（置顶） | ① 对单个**文件**置顶 → `code=220001 invalid media_id`；② `--media-id` 空时脚本误判成布尔 → `code=1 cannot unmarshal bool` | ① **仅支持文件夹**（`folder_...`，media_type=99）；② `is_top` 是布尔；③ `--media-id` 必须传真实 id |\n| `export_media` / `export_media_for_ima_sandbox` | `code=220030 无权限访问该接口` | **key 权限问题，非脚本缺陷**：导出接口需 API key 开通导出权限；个人在 agent-interface 申请的 key 默认未开通，需用 ima app 内 copilot 环境变量中的凭证（已开通）。凭证获取见主 SKILL.md「Credential Check」 |\n| `update_knowledge_base_permission` | 有**真实副作用**（影响该库所有成员） | 正式库改权限前**必须向用户确认** |\n| `join_knowledge` | 会**真实加入**公开库（副作用） | 调用前确认用户确实要加入；加入后需用户到 IMA 客户端退出 |\n| `get_media_info` 读取原文 | 订阅库（普通成员）返回 `code=220030 没有权限` | 仅**个人库（创建者）**能读文件/笔记原文；订阅库只能看列表，引导用户去客户端 |\n| `get_knowledge_list` 的 `folder_id` | 把 `knowledge_base_id` 当 `folder_id` 传入 → 返回根目录而非目标文件夹 | 根目录**省略** `folder_id`；子目录 ID 必须 `folder_xxxx` 开头；看到 `current_path` = 走对路径 |\n| `media_type` 枚举 | 曾误以为 `media_type=11` 是微信文章（其实是**笔记**），`6` 才是微信文章 | 速记：`1=PDF` `2=网页URL` `4=PPT` `5=Excel` `6=微信文章` `11=笔记` `16=网页视频` `20=HTML` `21=EPUB` `99=文件夹`；拿不准先搜样例 |\n| `search_*` 返回空 | `info_list:[]` 不一定是真没内容 | 换关键词 / 换接口（`get_knowledge_list` 翻文件夹）；别一次空就放弃 |\n| `check_repeated_names` 重名判定 | 刚上传完短时间内查同名可能 `is_repeated=false`（索引延迟） | 别仅凭一次查询认定无重名 |\n| `create_folder` 接口选择 | 早期误用 `add_knowledge`+`media_type=99` 建文件夹失败 | 正确接口是 `create_folder`（实测可成功，返回 `data.media_id` 即 `folder_id`） |\n| 删除类操作 | 试图删除文件/文件夹/知识库/标签 | **IMA OpenAPI 不支持任何实体删除**，测试留痕需用户到 IMA 客户端手动清理 |\n| `tag_delete` / `tag_rename` | 删除标签移除其与所有文件关联（**不可逆**）；`tag_rename` \n\nArchive v1.0.8: 35 files, 98828 bytes\n\nFiles: ima_api.cjs (4251b), knowledge-base/references/api.md (27408b), knowledge-base/scripts/cos-upload.cjs (5265b), knowledge-base/scripts/create_folder.cjs (3157b), knowledge-base/scripts/create_knowledge_base.cjs (2365b), knowledge-base/scripts/export_kb_zip.cjs (16165b), knowledge-base/scripts/export_media.cjs (2660b), knowledge-base/scripts/join_knowledge.cjs (2155b), knowledge-base/scripts/list_all_files.cjs (4624b), knowledge-base/scripts/move_knowledge.cjs (4781b), knowledge-base/scripts/preflight-check.cjs (12056b), knowledge-base/scripts/rename_knowledge.cjs (2695b), knowledge-base/scripts/search_knowledge_base_in_square.cjs (2210b), knowledge-base/scripts/set_knowledge_top.cjs (2669b), knowledge-base/scripts/tag_add.cjs (2588b), knowledge-base/scripts/tag_delete.cjs (2312b), knowledge-base/scripts/tag_list.cjs (2448b), knowledge-base/scripts/tag_remove.cjs (2417b), knowledge-base/scripts/tag_rename.cjs (2617b), knowledge-base/scripts/update_knowledge_access_status.cjs (3226b), knowledge-base/scripts/update_knowledge_base_basic_info.cjs (3281b), knowledge-base/scripts/update_knowledge_base_permission.cjs (3186b), knowledge-base/scripts/upload_to_kb.cjs (7773b), knowledge-base/SKILL.md (12370b), meta.json (235b), notes/references/api.md (15804b), notes/scripts/notes_append.cjs (3463b), notes/scripts/notes_create.cjs (4085b), notes/scripts/resolve_notebook.cjs (2332b), notes/SKILL.md (19100b), references/troubleshooting.md (11725b), resolve_path.cjs (18604b), skill-card.md (3088b), SKILL.md (24199b), _meta.json (133b)\n\nArchive v1.0.7: 33 files, 97316 bytes\n\nFiles: ima_api.cjs (4870b), knowledge-base/references/api.md (27408b), knowledge-base/scripts/cos-upload.cjs (5265b), knowledge-base/scripts/create_folder.cjs (2943b), knowledge-base/scripts/create_knowledge_base.cjs (2365b), knowledge-base/scripts/export_kb_zip.cjs (16369b), knowledge-base/scripts/export_media.cjs (2660b), knowledge-base/scripts/join_knowledge.cjs (1961b), knowledge-base/scripts/list_all_files.cjs (4432b), knowledge-base/scripts/move_knowledge.cjs (4448b), knowledge-base/scripts/preflight-check.cjs (12056b), knowledge-base/scripts/rename_knowledge.cjs (2497b), knowledge-base/scripts/search_knowledge_base_in_square.cjs (2210b), knowledge-base/scripts/set_knowledge_top.cjs (2483b), knowledge-base/scripts/tag_add.cjs (2404b), knowledge-base/scripts/tag_delete.cjs (2130b), knowledge-base/scripts/tag_list.cjs (2258b), knowledge-base/scripts/tag_remove.cjs (2233b), knowledge-base/scripts/tag_rename.cjs (2433b), knowledge-base/scripts/update_knowledge_access_status.cjs (3024b), knowledge-base/scripts/update_knowledge_base_basic_info.cjs (3071b), knowledge-base/scripts/update_knowledge_base_permission.cjs (2974b), knowledge-base/scripts/upload_to_kb.cjs (7603b), knowledge-base/SKILL.md (43397b), meta.json (235b), notes/references/api.md (15804b), notes/scripts/resolve_notebook.cjs (2481b), notes/SKILL.md (18219b), references/troubleshooting.md (9593b), resolve_path.cjs (9208b), skill-card.md (3049b), SKILL.md (20549b), _meta.json (133b)\n\nArchive v1.0.6: 31 files, 90010 bytes\n\nFiles: ima_api.cjs (4870b), knowledge-base/references/api.md (27408b), knowledge-base/scripts/cos-upload.cjs (5265b), knowledge-base/scripts/create_folder.cjs (3017b), knowledge-base/scripts/create_knowledge_base.cjs (2365b), knowledge-base/scripts/export_kb_zip.cjs (12348b), knowledge-base/scripts/export_media.cjs (2660b), knowledge-base/scripts/join_knowledge.cjs (1729b), knowledge-base/scripts/list_all_files.cjs (4544b), knowledge-base/scripts/move_knowledge.cjs (3509b), knowledge-base/scripts/preflight-check.cjs (12056b), knowledge-base/scripts/rename_knowledge.cjs (2821b), knowledge-base/scripts/search_knowledge_base_in_square.cjs (2210b), knowledge-base/scripts/set_knowledge_top.cjs (2764b), knowledge-base/scripts/tag_add.cjs (2685b), knowledge-base/scripts/tag_delete.cjs (2411b), knowledge-base/scripts/tag_list.cjs (2539b), knowledge-base/scripts/tag_remove.cjs (2514b), knowledge-base/scripts/tag_rename.cjs (2714b), knowledge-base/scripts/update_knowledge_access_status.cjs (3293b), knowledge-base/scripts/update_knowledge_base_basic_info.cjs (3352b), knowledge-base/scripts/update_knowledge_base_permission.cjs (3255b), knowledge-base/scripts/upload_to_kb.cjs (7916b), knowledge-base/SKILL.md (38828b), meta.json (236b), notes/references/api.md (15804b), notes/SKILL.md (16862b), references/troubleshooting.md (9526b), skill-card.md (3003b), SKILL.md (18858b), _meta.json (133b)\n\nArchive v1.0.5: 31 files, 96477 bytes\n\nFiles: config.json (39b), ima_api.cjs (4870b), knowledge-base/references/api.md (27034b), knowledge-base/scripts/cos-upload.cjs (5251b), knowledge-base/scripts/create_folder.cjs (3017b), knowledge-base/scripts/create_knowledge_base.cjs (2365b), knowledge-base/scripts/export_kb_zip.cjs (12348b), knowledge-base/scripts/export_media.cjs (2660b), knowledge-base/scripts/join_knowledge.cjs (1729b), knowledge-base/scripts/list_all_files.cjs (4544b), knowledge-base/scripts/move_knowledge.cjs (3509b), knowledge-base/scripts/preflight-check.cjs (12074b), knowledge-base/scripts/rename_knowledge.cjs (2821b), knowledge-base/scripts/search_knowledge_base_in_square.cjs (2210b), knowledge-base/scripts/set_knowledge_top.cjs (2764b), knowledge-base/scripts/tag_add.cjs (2685b), knowledge-base/scripts/tag_delete.cjs (2411b), knowledge-base/scripts/tag_list.cjs (2539b), knowledge-base/scripts/tag_remove.cjs (2514b), knowledge-base/scripts/tag_rename.cjs (2714b), knowledge-base/scripts/update_knowledge_access_status.cjs (3293b), knowledge-base/scripts/update_knowledge_base_basic_info.cjs (3352b), knowledge-base/scripts/update_knowledge_base_permission.cjs (3255b), knowledge-base/scripts/upload_to_kb.cjs (7916b), knowledge-base/SKILL.md (50941b), meta.json (20b), notes/references/api.md (15804b), notes/SKILL.md (18511b), skill-card.md (2916b), SKILL.md (36917b), _meta.json (133b)\n\nArchive v1.0.4: 31 files, 94417 bytes\n\nFiles: config.json (2b), ima_api.cjs (4870b), knowledge-base/references/api.md (27034b), knowledge-base/scripts/cos-upload.cjs (5251b), knowledge-base/scripts/create_folder.cjs (3017b), knowledge-base/scripts/create_knowledge_base.cjs (2365b), knowledge-base/scripts/export_kb_zip.cjs (8628b), knowledge-base/scripts/export_media.cjs (2660b), knowledge-base/scripts/join_knowledge.cjs (1729b), knowledge-base/scripts/list_all_files.cjs (4544b), knowledge-base/scripts/move_knowledge.cjs (3509b), knowledge-base/scripts/preflight-check.cjs (12074b), knowledge-base/scripts/rename_knowledge.cjs (2821b), knowledge-base/scripts/search_knowledge_base_in_square.cjs (2210b), knowledge-base/scripts/set_knowledge_top.cjs (2764b), knowledge-base/scripts/tag_add.cjs (2685b), knowledge-base/scripts/tag_delete.cjs (2411b), knowledge-base/scripts/tag_list.cjs (2539b), knowledge-base/scripts/tag_remove.cjs (2514b), knowledge-base/scripts/tag_rename.cjs (2714b), knowledge-base/scripts/update_knowledge_access_status.cjs (3293b), knowledge-base/scripts/update_knowledge_base_basic_info.cjs (3352b), knowledge-base/scripts/update_knowledge_base_permission.cjs (3255b), knowledge-base/scripts/upload_to_kb.cjs (7906b), knowledge-base/SKILL.md (50941b), meta.json (25b), notes/references/api.md (15804b), notes/SKILL.md (18511b), skill-card.md (2874b), SKILL.md (34522b), _meta.json (133b)\n\nArchive v1.0.0: 30 files, 94931 bytes\n\nFiles: config.json (3b), ima_api.cjs (7477b), knowledge-base/references/api.md (27034b), knowledge-base/scripts/cos-upload.cjs (5251b), knowledge-base/scripts/create_folder.cjs (3017b), knowledge-base/scripts/create_knowledge_base.cjs (2365b), knowledge-base/scripts/export_kb_zip.cjs (8628b), knowledge-base/scripts/export_media.cjs (2660b), knowledge-base/scripts/join_knowledge.cjs (1729b), knowledge-base/scripts/list_all_files.cjs (4544b), knowledge-base/scripts/move_knowledge.cjs (3509b), knowledge-base/scripts/preflight-check.cjs (12074b), knowledge-base/scripts/rename_knowledge.cjs (2821b), knowledge-base/scripts/search_knowledge_base_in_square.cjs (2210b), knowledge-base/scripts/set_knowledge_top.cjs (2764b), knowledge-base/scripts/tag_add.cjs (2685b), knowledge-base/scripts/tag_delete.cjs (2411b), knowledge-base/scripts/tag_list.cjs (2539b), knowledge-base/scripts/tag_remove.cjs (2514b), knowledge-base/scripts/tag_rename.cjs (2714b), knowledge-base/scripts/update_knowledge_access_status.cjs (3293b), knowledge-base/scripts/update_knowledge_base_basic_info.cjs (3352b), knowledge-base/scripts/update_knowledge_base_permission.cjs (3255b), knowledge-base/scripts/upload_to_kb.cjs (7906b), knowledge-base/SKILL.md (50941b), notes/references/api.md (15804b), notes/SKILL.md (18511b), skill-card.md (2507b), SKILL.md (34522b), _meta.json (133b)","readmeExcerpt":"Skill: ima.plus-skill-v1.0.12 Owner: wwqww1 Summary: 优化了上传视频转换成HTML的功能，有任何skill的问题或建议，请到QQ频道：pd86156007，IMA 知识库与笔记操作技能（版本 v1.0.12）：用 --path 自然语言定位知识库/文件夹/笔记本，支持文件上传、知识库/目录导出 zip、文件夹与条目管理、标签权限、网页入库、笔记增改与插图，以及把本地视频封装成单文件 HTML（页面内置「导出视频」，导出为 .bin 后缀、改名 .mp4 即播放）入库（需环境变量 IMA_OPENAPI_CLIENTID / IMA_OPENAPI_APIKEY）。 Tags: latest:1.0.12 Version history: v1.0.12 | 2026-10-11T02:20:07.976Z | user ima-plus-skill v1.0.12 - Upda","codeSnippets":[],"executableExamples":[{"language":"text","snippet":"GATE 1 [TYPE]   preflight-check.cjs 先行，pass=false 直接拒绝。视频/B站/YouTube/file:// → 引导用户用 IMA 客户端。绝不问\"还要试吗\"\nGATE 2 [NAME]   add_knowledge 的 title 必须等于 file_name（含扩展名），绝不改名/缩写/翻译\nGATE 3 [DUP]    所有文件上传前先 check_repeated_names；is_repeated=true → 问用户保留两者(追加 _YYYYMMDDHHmmss)或取消；不支持替换\nGATE 4 [EXIT]   cos-upload.cjs 非零退出 → 立即停止，不调 add_knowledge"},{"language":"bash","snippet":"node knowledge-base/scripts/upload_to_kb.cjs --file a.pdf --path \"我的知识库/项目/文档\"\nnode knowledge-base/scripts/upload_to_kb.cjs --file a.pdf --path \"我的知识库\"          # 根目录\nnode knowledge-base/scripts/upload_to_kb.cjs --file a.pdf --cancel-if-dup             # 重名时取消"},{"language":"bash","snippet":"# 网页/微信（无 GATE，非文件）\nima_api \"openapi/wiki/v1/import_urls\" '{\"knowledge_base_id\": \"<库ID>\", \"urls\": [\"https://...\"], \"folder_id\": \"<可选>\"}'\n# 返回 results 映射 {url: {url, ret_code, media_id}}\n\n# 笔记 → 知识库\nima_api \"openapi/wiki/v1/add_knowledge\" '{\"media_type\": 11, \"note_info\": {\"content_id\": \"<note_id>\"}, \"title\": \"笔记标题\", \"knowledge_base_id\": \"<库ID>\"}'\n\n# URL 指向可下载文件时：先探测 content-type → 下载 → preflight-check → 走上传流程（详见 api.md §URL Type Detection）"},{"language":"bash","snippet":"node resolve_path.cjs --path \"我的知识库/项目/文档\"   # → { kb_id, kb_name, folder_id, folder_name }\nnode resolve_path.cjs --path \"我的知识库\"             # folder_id 空 = 根目录\nnode resolve_path.cjs --path \"项目/文档\"              # 唯一库可省略库名"},{"language":"bash","snippet":"# 文件夹：创建（可多级）/ 浏览 / 重命名 / 置顶（仅文件夹，media_type=99）\nnode knowledge-base/scripts/create_folder.cjs --path \"库/父夹\" --name \"新夹\"\nnode knowledge-base/scripts/list_all_files.cjs --path \"库/夹\" [--json] [--with-url]\nnode knowledge-base/scripts/rename_knowledge.cjs --path \"库\" --media-id <id> --name \"新名\"\nnode knowledge-base/scripts/set_knowledge_top.cjs --path \"库\" --media-id <folder_id> --is-top true   # ⚠️ 仅文件夹，文件报 220001\n\n# 移动（仅文件，≤10 个） / 导出媒体\nnode knowledge-base/scripts/move_knowledge.cjs --src-path \"库A\" --dst-path \"库B/目标夹\" --media-id id1,id2\nnode knowledge-base/scripts/export_media.cjs --media-id <id> [--download --out /path/save]\n\n# 标签（文件夹不支持打标签；rename 重名自动合并、delete 不可逆，调用前确认）\nnode knowledge-base/scripts/tag_add.cjs --path \"库\" --media-id <id> --tag-name \"重要\"\nnode knowledge-base/scripts/tag_remove.cjs --path \"库\" --media-id <id> --tag-name \"重要\"\nnode knowledge-base/scripts/tag_list.cjs --path \"库\" [--keyword 关键词]\nnode knowledge-base/scripts/tag_rename.cjs --path \"库\" --old-tag-name 旧 --new-tag-name 新\nnode knowledge-base/scripts/tag_delete.cjs --path \"库\" --tag-name 待删\n\n# 知识库管理（普通成员写操作会 220030，需创建者/协作成员/管理员）\nnode knowledge-base/scripts/create_knowledge_base.cjs --name \"库名\" --type 1001        # 1001个人 1002共享 1004订阅\nnode knowledge-base/scripts/update_knowledge_base_basic_info.cjs --path \"库\" --name 新名 [--description 简介]\nnode knowledge-base/scripts/update_knowledge_base_permission.cjs --path \"库\" --visible-export-status 3 [--join-type 1]  # ⚠️ 影响全库成员，调用前确认\nnode knowledge-base/scripts/update_knowledge_access_status.cjs --path \"库\" --media-id id1,id2 --access-status 3\n\n# 广场发现 / 加入（join 真实加入公开库，调用前确认用户确实要加）\nnode knowledge-base/scripts/search_knowledge_base_in_square.cjs --question \"关键词\"\nnode knowledge-base/scripts/join_knowledge.cjs --path \"知识库名称\" --name \"知识库名称\""},{"language":"bash","snippet":"# ① 整个库 / ② 某个文件夹（递归）/ ③ 指定多文件（--media-ids）\nnode knowledge-base/scripts/export_kb_zip.cjs --path \"我的知识库\" --out /path/out.zip\nnode knowledge-base/scripts/export_kb_zip.cjs --path \"我的知识库/项目\" --out /path/out.zip\nnode knowledge-base/scripts/export_kb_zip.cjs --path \"我的知识库\" --media-ids id1,id2 --out /path/out.zip\n\n# 打包前先看调用量：--count（JSON）/ --estimate / --dry-run（列出将导出的文件）\nnode knowledge-base/scripts/export_kb_zip.cjs --path \"我的知识库\" --count"}],"parameters":null,"dependencies":[],"permissions":[],"extractedFiles":[{"path":"knowledge-base/SKILL.md","content":"---\nname: IMA 知识库模块\ndescription: IMA 知识库操作模块。负责上传文件、添加网页/微信文章到知识库、搜索与浏览知识库内容、获取知识库信息。\nallowed-tools: Bash,Read\nmetadata: {\"openclaw\":{\"emoji\":\"📚\",\"requires\":{\"bins\":[\"node\"]}}}\n---\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` 传入） | 见「脚本速查」upload_to_kb |\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| 检查文件名重复 | `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| 按名称找知识库 | `search_knowledge_base` | `query`，`cursor`，`limit`(1~20) |\n| 查看自己有哪些知识库 | `search_knowledge_base` | `query: \"\"` |\n| 添加内容但未指定库 | `get_addable_knowledge_base_list` | `cursor`，`limit`(1~50) |\n| 查看/导出原文 | `get_media_info` | `media_id`；下载时 URL 后追加 `response-content-type=application/octet-stream&response-content-disposition=attachment;filename=\"<名>\"` |\n| 创建文件夹 | `create_folder` | `knowledge_base_id`，`name`，可选 `folder_id`（父夹） |\n| 重命名文件/文件夹 | `rename_knowledge` | `knowledge_base_id`，`media_id`，`name` |\n| 移动文件（**不支持文件夹**） | `move_knowledge` | `src_knowledge_base_id`，`dst_knowledge_base_id`，`infos:[{media_id}]`，可选 `dst_folder_id` |\n| 获取下载链接 | `export_media_for_ima_sandbox` | `media_id`；返回 `url`+`headers`，下载需带 `headers` |\n| 创建知识库 | `create_knowledge_base` | `name`(必填)，`type`(1001/1002/1004)，可选 `description`/`cover-url`/`recommended-questions` |\n| 修改库基本信息 | `update_knowledge_base_basic_info` | `id`，自动推导 `update_fields`（1名 2封面 3简介 4推荐问题） |\n| 置顶/取消置顶 | `set_knowledge_top` | `knowledge_base_id`，`media_id`，`is_top`(布尔) |\n| 打/移除标签 | `tag_add` / `tag_remove` | `knowledge_base_id`，`item_id`(=media_id)，`tag_name` |\n| 列/搜标签 | `tag_list` | `knowledge_base_id`，可选 `keyword`/`cursor`，`limit` |\n| 重命名/删除标签 | `tag_rename` / `tag_delete` | 重命名新名存在自动合并；删除不可逆 |\n| 修改库权限 | `update_knowledge_base_permission` | `id`，自动推导 `update_fields`（1导出状态 2加入类型） |\n| 加入知识库 | `join_knowledge` | `knowledge_base_id`，`name`（**真实加入，有副作用**） |\n| 批量更新访问状态 | `update_knowledge_access_status` | `knowledge_base_id`，`infos:[{media_id}]`(≤10)，`access_status`(1/2/3) |\n| 广场发现 | `search_knowledge_base_in_square` | `question`(必填，**不是** query)，`cursor`(首次空)，`limit` |\n\n**`search_knowledge_base` vs `get_addable_knowledge_base_list`**：用户说了库名 → 前者按名搜；用户没说加到哪个库 → 后者列出可选库让用户选。**绝不要**在用户已明确库名时调 `get_addable_knowledge_base_list`。\n\n---\n\n## ⛔ 文件上传安全门（仅文件上传 → `add_knowledge` 流程）\n\n```\nGATE 1 [TYPE]   preflight-check.cjs 先行，pass=false 直接拒绝。视频/B站/YouTube/file:// → 引导用户用 I"},{"path":"notes/SKILL.md","content":"---\nname: IMA 笔记模块\ndescription: IMA 笔记管理模块。负责搜索、浏览、创建、编辑（追加）用户个人笔记。\nallowed-tools: Bash,Read\nmetadata: {\"openclaw\":{\"emoji\":\"📝\",\"requires\":{\"bins\":[\"node\"]}}}\n---\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| 往笔记插入含图片的内容（本地/远程图片）                                           | `note-images.cjs` | `--note-id` + `--file`/`--content`；图片 < 3MiB，仅 PNG/JPEG/WebP         |\n| 编辑笔记前获取块结构（update_note 前置）                                          | `export_note_blocks` | `note_id` |\n| 按 block 精细编辑笔记（改/删/插某段）                                             | `update_note`     | `note_id` + `user_request_id`(UUIDv4) + `updates[]`(block_id/action/new_content) |\n| 重命名笔记本                                                                       | `rename_notebook` | `folder_id` + `new_folder_name` |\n| 导出整篇笔记（Markdown/纯文本/JSON）                                            | `export_note`     | `note_id` + `target_content_format`(推荐`1`) |\n| 智能推送：不存在则新建、存在则追加                                              | `push_note`       | `content`(可选)+`note_id`(可选)+`content_cos_key`(可选) |\n| 重命名单篇笔记标题                                                               | `rename_note`     | `note_id` + `title` |\n| 批量移动笔记到其他笔记本                                                         | `move_notes`      | `note_ids[]` +"},{"path":"SKILL.md","content":"---\nname: ima_plus-skill\ndescription: IMA 知识库与笔记操作技能（版本 v1.0.12）：用 `--path` 自然语言定位知识库/文件夹/笔记本，支持文件上传、知识库/目录导出 zip、文件夹与条目管理、标签权限、网页入库、笔记增改与插图，以及把本地视频封装成单文件 HTML（页面内置「导出视频」，导出为 .bin 后缀、改名 .mp4 即播放）入库（需环境变量 IMA_OPENAPI_CLIENTID / IMA_OPENAPI_APIKEY）。\nallowed-tools: Bash,Read\nmetadata:\n  openclaw:\n    emoji: \"🔧\"\n    requires:\n      bins:\n        - node\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 request base URL is hard-whitelisted to ima.qq.com: options.baseUrl / IMA_BASE_URL\n      overrides are rejected unless they resolve to ima.qq.com, so credentials can never be\n      forwarded to an arbitrary host.\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, and COS temporary credentials are\n      passed to the upload helper via environment variables (not argv).\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# ima_plus-skill\n\n> **版本：V1.0.12**\n>\n> **运行环境**：Node.js ≥ 18.0.0（所有 .cjs 脚本 + inline JSON 解析依赖）；视频模块另需 `python3` + `curl`（`ffprobe` 可选，取时长）\n\nUnified IMA OpenAPI skill. Currently supports: **notes**, **knowledge-base**, **video**（视频链接 → 内嵌 HTML → 入库）.\n\n## ⛔ MANDATORY RULES — read before ANY operation\n\n0. **自然语言路径优先（所有模块通用，强制）：** 用户给出知识库/文件夹/笔记本的名称或路径（如\"我的知识库/项目/文档\"、\"存到学习笔记\"）时，**一律用解析器自动转 ID，禁止让用户提供 kb_id / folder_id**。知识库用根目录 `resolve_path.cjs --path`，笔记本用 `notes/scripts/resolve_notebook.cjs --path`。面向用户永远只展示名称，禁止暴露任何 ID。\n   - ⛔ **禁止擅自使用 `--kb <kb_id>`**：即使解析过程中拿到了 kb_id，**也不得主动用它调用脚本**——所有脚本调用一律走 `--path \"知识库名/文件夹...\"`（内部自动解析）。`--kb` 仅在**用户明确要求使用某个具体 ID** 时才允许出现。违反此规则视为流程错误。\n   - 兼容参数 `--kb-name`（按名称匹配）可以正常使用，但 `--path` 是首选。\n\n### 🔧 路径解析缓存机制（V1.0.8+，无需手动管理）\n\n解析器会把「知识库名 → kb_id、文件夹路径 → folder_id」**分层树状持久化**到缓存文件，\n按「知识库 → 子文件夹 → 孙文件夹」嵌套，同名文件夹在不同库/不同父目录各占节点，不会串库。\n\n**缓存位置（强制检查，安装 skill 时必须确定）：**\n1. 环境变量 `IMA_RESOLVE_CACHE` 显式指定（所有环境，优先级最高）\n2. ima.copilot 环境未设置时默认 `/sandbox/workspace/.ima_cache/resolve_cache.json`（workspace 持久、平台不重置）\n3. **其他 agent / 自建环境未设置 `IMA_RESOLVE_CACHE` → 直接报错不可用**（与凭证同等强制）。\n   安装时须先设置：`export IMA_RESOLVE_CACHE=/path/to/resolve_cache.json`（可写入 ~/.bashrc 或 ~/.zshrc）\n\n- **无过期时间**：缓存长期有效；重复解析同一路径 **0 次 API 调用**（部分命中只补查缺失层级）。\n- **失效自愈**：所有消费脚本已包 `withPathRetry`——若操作因「目标不存在」（如库/夹被删或改名，`220001/invalid/不存在` 类）失败，自动失效该路径缓存 → 全 API 重新解析 → 重试一次；**重查任一层失败即报「目录位置不存在」，整个操作直接中止，不猜测后续层级**。权限（220030）/限流（200001）类错误不触发自愈。\n- **手动清缓存**（一般不需要）：删除缓存文件即可，下次解析自动重建。知识库/文件夹被删除后首次操作会自愈恢复。\n- 笔记本解析（`--not"},{"path":"video/SKILL.md","content":"# video 模块 —— 本地视频 → 内嵌 HTML（可导出） → 知识库\n\n> 独立模块，与 `knowledge-base` / `notes` 同级。\n> **只做封装与上传，不做下载**（视频从哪来不归本模块管）。\n\n## 为什么必须封装成 HTML\n\n知识库**不接受 mp4 / avi / mov 等视频文件**（服务端限制）。\n唯一可行方式：视频 base64 内嵌进单文件 HTML（≤10MB），页面用 **Blob URL** 播放\n（data: URI 在部分 WebView 会加载失败；Blob 方案实测 3MB+ 正常）。\n\n> 💡 **可反向导出**：页面「导出视频」把内嵌视频还原为文件保存。\n> ⚠️ **导出文件必须用 `.bin` 后缀（关键）**：手机浏览器（华为等）会按后缀拦截\"网页现场生成的 `.mp4`\"\n> （防网页偷放视频的安全策略），表现为**下载进度卡 0% / 下载失败**；而 `.bin` 等中性后缀畅通。\n> 因此导出存为 `<标题>.bin`，页面提示用户**下载后把后缀改成 `.mp4`** 即可播放。\n> 实现要点：下载用 `Blob([bytes],{type:'application/octet-stream'})`（**非 `video/mp4`**），且与播放用的 blob URL **分开创建**。\n\n> ⚠️ **条目名规则（最大的坑）**：条目名 = 文件名，不得含 `# ? & /` 等 URL 危险字符。\n> `#` 在 URL 中是锚点分隔符 → 打开条目时显示「无法打开网页」（与体积无关）。\n\n## 用法\n\n```bash\n# 批量：目录里的视频全部封装并上传\npython3 video/scripts/video_batch.py --dir <视频目录> --path \"<知识库>/<文件夹>\"\n\n# 只生成、不上传（本地检查）\npython3 video/scripts/video_batch.py --dir <视频目录> --path \"<知识库>/<文件夹>\" --skip-upload\n\n# 单个文件\npython3 video/scripts/video_to_html.py --mp4 a.mp4 --title \"标题\" --out-dir ./html\n```\n\n## video_batch.py 参数\n\n| 参数 | 必填 | 说明 |\n| --- | --- | --- |\n| `--dir` | ✅ | 视频所在目录（只读该层，不递归） |\n| `--path` | ✅ | 目标知识库路径，如 `\"库名/文件夹名\"` |\n| `--ext` | | 视频扩展名，默认 `mp4,m4v,mov,webm,avi,mkv` |\n| `--out-dir` | | HTML 输出目录，默认 `<dir>/kb_html` |\n| `--title-map` | | JSON `{\"文件名\":\"标题\"}`，自定义页面标题与文件名（文件名本身即标题时可省略） |\n| `--template` | | 替换 HTML 模板 |\n| `--skip-upload` | | 只生成不上传 |\n| `--allow-dup` | | 允许重名重复入库（默认跳过重名） |\n| `--force` | | 覆盖已生成的 HTML |\n| `--max` | | 只处理前 N 个（调试用） |\n\n## 行为约定\n\n| 项 | 规则 |\n| --- | --- |\n| 输入 | 只处理本地目录里的视频文件（`--dir` 下一层） |\n| 文件名 | 沿用视频文件名/标题，清洗 URL 危险字符；**不加序号、不加后缀** |\n| 体积 | HTML **≤10MB**；**超过 10MB 自动丢弃、不上传**，汇总里单独列出 |\n| 页面 | 极简：标题 + 视频 + 一行「时长 · 大小 · 导出视频」+ 一行改名提示；无按钮块、无标签、无原始链接 |\n| 导出 | 点「导出视频」下载 `<标题>.bin`（blob + `application/octet-stream`）；**禁用 `.mp4` 后缀**（手机浏览器拦），页面提示改名为 `.mp4` |\n| 样式 | 只保留最小 CSS（无渐变 / 阴影 / 安全区 / 冗余媒体查询），减少页面占用 |\n| 多端适配 | 手机全宽、电脑限高 78vh 居中；兼容 iOS 12 Safari（不用 clamp()/gap/dvh） |\n| 模板 | `video/assets/video-template.html`，占位符：`__TITLE__` `__FILENAME__` `__B64__` `__DUR__` `__SIZE__` |\n| 幂等 | HTML 已存在则跳过生成（`--force` 重建）；目标重名条目默认不重复入库 |\n\n## 排障\n\n| 现象 | 原因 / 处理 |\n| --- | --- |\n| 打开条目报「无法打开网页」 | 文件名含 `#` 等危险字符 → 重命名或换安全名重传 |\n| 上传报 `220010 添加知识失败` | HTML 超 10MB → 压缩视频或截短后重跑 |\n| 汇总出现「超 10MB 未上传」 | 预期行为，压缩后重跑该文件 |\n| 视频转圈 / 黑屏 | 预览环境不支持内嵌播放 → 确认模板走的是 Blob URL 而非 data: URI |\n| 「导出视频」卡 0% / 下载失败 | 下载名用了 `.mp4` 后缀（手机浏览器按后缀拦截）→ 改 `.bin`（v1.0.12）；`data:` URI 同样被拦 |\n| 想直接下载 `.mp4` | 手机浏览器不允许网页生成 `.mp4` 下载；改用桌面浏览器打开，或让 Agent 发 mp4 直链 |\n\n## 文件构成\n\n| 文件 | 作用 |\n| --- | --- |\n| `video/scripts/video_batch.py` | 批量编排：遍历目录 → 封装 → 上传 |\n| `video/scripts/video_to_html.py` | 单个视频 → 单文件 HTML（命名清洗、10MB 校验） |\n| `video/assets/video-template.html` | 极简模板（Blob 播放 + .bin 导出、多端适配） |"},{"path":"_meta.json","content":"{\n  \"ownerId\": \"kn7b5dm7qcadb0hdtk4pz07pwn89v0d0\",\n  \"slug\": \"ima-plus-skill\",\n  \"version\": \"1.0.12\",\n  \"publishedAt\": 1791685207976\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-11T19:16:50.113Z","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-11T19:16:50.113Z","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-12T00:58:45.592Z","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"}]}}}