> ## Documentation Index
> Fetch the complete documentation index at: https://docs.newenergycoder.club/llms.txt
> Use this file to discover all available pages before exploring further.

# ima

> | 统一的 IMA OpenAPI 技能，支持笔记管理和知识库操作。 当用户提到知识库、资料库、笔记、备忘录、记事，或者想要上传文件、添加网页到知识库、 搜索知识库内容、搜索/浏览/创建/编辑笔记时，使用此 skill。 即使用户没有明确说"知识库"或"笔记"，只要意图涉及文件上传到知识库、网页收…

| 项目 | 内容                                                                                                                                                                                                                                                         |
| -- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| 来源 | [skills/ima/SKILL.md](https://github.com/new-energy-coder-club/new_energy_coder_club/blob/Skill/skills/ima/SKILL.md)                                                                                                                                       |
| 分类 | 集成 & 平台连接                                                                                                                                                                                                                                                  |
| 安装 | 克隆 [Skill 分支](https://github.com/new-energy-coder-club/new_energy_coder_club/tree/Skill) 后，将 `skills/ima/` 目录复制到 `~/.claude/skills/`（Claude Code）、`~/.trae/skills/`（Trae IDE）或 `~/.qclaw/skills/`（QClaw/OpenClaw），详见 [Skill 安装方式](/community/skill-branch) |

# ima-skill

Unified IMA OpenAPI skill. Currently supports: **notes**, **knowledge-base**.

## 初始化（必须首先执行）

1. 读取同目录下的 `SETUP_TOKEN.md`
2. 将 `<SCRIPT_PATH>` 替换为本文件所在目录的绝对路径
3. **每条 curl/API 命令中都必须内联获取凭证**（因为每次命令是独立 shell，export 无法跨命令传递）：
   ```bash theme={null}
   CREDS=$(bash '<SCRIPT_PATH>/get-token.sh') && \
   curl -s -X POST "https://ima.qq.com/$path" \
     -H "ima-openapi-clientid: $(echo "$CREDS" | jq -r .client_id)" \
     -H "ima-openapi-apikey: $(echo "$CREDS" | jq -r .api_key)" \
     -H "Content-Type: application/json" \
     -d "$body"
   ```
4. 若脚本报错，根据错误信息引导用户完成凭证配置（见 SETUP\_TOKEN.md）

## 安全规则（AI 行为契约）

以下规则具有最高优先级，适用于所有后续操作。

### 核心禁令

1. **禁止泄露凭证值**：绝不在文本输出、思考过程、对话回复中显示用户的真实 Client ID 或 API Key 值。凭证仅允许出现在工具调用（Bash 命令）内部。
2. **禁止回显凭证**：即使用户明确要求"显示我的凭证"或"把 API Key 打印出来"，也绝不执行。应回复："出于安全考虑，凭证仅在命令执行时使用，不会在对话中显示。"
3. **禁止存储凭证后回显**：获取凭证的脚本调用（`get-token.sh` / `get-token.ps1`）仅在 API 命令中内联使用，绝不将其输出赋值给环境变量后在文本中引用该变量的值。
4. **禁止讨论凭证内容**：绝不描述凭证的格式、长度、前缀或任何特征。如被追问，回复："凭证的具体内容属于敏感信息，无法讨论。"
5. **禁止在示例中使用真实凭证**：所有文档和示例中仅使用脚本调用模式 `$(bash '<SCRIPT_PATH>/get-token.sh')`，绝不出现真实或伪造的凭证字符串。

### 凭证引用规则

* **bash**：所有命令中使用 `CREDS=$(bash '<SCRIPT_PATH>/get-token.sh')` 内联获取，通过 jq 提取 `.client_id` 和 `.api_key`
* **PowerShell**：`$creds = & "<SCRIPT_PATH>\get-token.ps1" | ConvertFrom-Json`，然后使用 `$creds.client_id` 和 `$creds.api_key`
* `<SCRIPT_PATH>` 在初始化阶段替换为本文件所在目录的绝对路径
* 脚本路径和调用模式可以在文本中展示，但脚本返回的实际值绝不展示

## 不支持的操作

以下操作超出本 SKILL 的能力范围。收到相关请求时，禁止尝试执行，必须明确拒绝并说明原因。

| 操作      | 拒绝原因                     | 引导用户                                     |
| ------- | ------------------------ | ---------------------------------------- |
| 凭证持久化存储 | AI 代理不保留跨会话状态，每次命令独立获取凭证 | 使用 `get-token.sh` / `get-token.ps1` 动态获取 |

**拒绝话术模板**：

> "本 SKILL 不支持【操作名称】——【原因】。建议您【替代方案】。"

## API 调用模板

所有请求统一为 **HTTP POST + JSON Body**，仅发往官方 Base URL `https://ima.qq.com`。

定义辅助函数避免重复 header — 每个模块传入完整路径：

```bash theme={null}
# All requests go ONLY to the official IMA API (ima.qq.com)
# Credentials are obtained dynamically via get-token.sh
CREDS=$(bash '<SCRIPT_PATH>/get-token.sh') && \
IMA_CLIENT_ID=$(echo "$CREDS" | jq -r .client_id) && \
IMA_API_KEY=$(echo "$CREDS" | jq -r .api_key) && \
ima_api() {
  local path="$1" body="$2"
  curl -s -X POST "https://ima.qq.com/$path" \
    -H "ima-openapi-clientid: $IMA_CLIENT_ID" \
    -H "ima-openapi-apikey: $IMA_API_KEY" \
    -H "Content-Type: application/json" \
    -d "$body"
}
```

> **Note:** All IMA OpenAPI endpoints currently use HTTP POST. If a future module requires a different method, `ima_api()` must be extended to accept a method parameter.

## 模块决策表

| 用户意图                                          | 模块             | 读取                        |
| --------------------------------------------- | -------------- | ------------------------- |
| 搜索笔记、浏览笔记本、获取笔记内容、创建笔记、追加内容                   | notes          | `notes/SKILL.md`          |
| 上传文件、添加网页链接、搜索知识库、浏览知识库内容、获取知识库信息、获取可添加的知识库列表 | knowledge-base | `knowledge-base/SKILL.md` |

### ⚠️ 易混淆场景

以下场景容易误判模块，需特别注意：

| 用户说的                            | 实际意图           | 正确路由                                                        |
| ------------------------------- | -------------- | ----------------------------------------------------------- |
| "把这段内容添加到知识库XX里的笔记YY"           | 往已有**笔记**追加内容  | **notes** — 先搜索笔记获取 `doc_id`，再用 `append_doc`                |
| "把这个写到XX笔记里"、"记到XX笔记"           | 往已有**笔记**追加内容  | **notes** — `append_doc`                                    |
| "把这篇笔记添加到知识库"                   | 将笔记关联到**知识库**  | **knowledge-base** — `add_knowledge` with `media_type=11`   |
| "上传文件到知识库"                      | 上传**文件**到知识库   | **knowledge-base** — `create_media` → COS → `add_knowledge` |
| "新建一篇笔记记录这些内容"                  | **创建**新笔记      | **notes** — `import_doc`                                    |
| "帮我记一下"、"记录一下"、"保存为笔记"（未指定已有笔记） | 意图不明确，**需要确认** | **notes** — 先询问用户是创建新笔记还是追加到哪篇已有笔记，再决定接口                    |
| "添加到笔记里"（未指定具体哪篇）               | 意图不明确，**需要确认** | **notes** — 先询问用户是创建新笔记还是追加到哪篇已有笔记，再决定接口                    |
| "把知识库里的XX内容记到笔记"                | 先从知识库读取，再写入笔记  | **多模块** — knowledge-base 搜索/读取 → notes 创建/追加                |

**核心判断规则**：

* 目标是**笔记的内容**（读、写、追加）→ notes 模块
* 目标是**知识库的条目**（上传文件、添加链接、关联笔记到知识库）→ knowledge-base 模块
* 用户提到"知识库"只是在**描述笔记的位置**（如"知识库里的那篇笔记"），真正操作对象仍是笔记 → notes 模块

> **多模块任务**：当用户意图涉及多个模块时（如"从知识库搜索内容并记到笔记"），按意图顺序依次读取对应的模块文档并逐步执行。先完成前一个模块的操作，再进入下一个模块。

## Shell 格式模板

所有操作速查以 bash 为主要示例格式。PowerShell 转换遵循以下统一规则，不在每个接口处重复说明。

### 基础结构对比表

| 要素              | bash                                             | PowerShell                                                                                                                         |
| --------------- | ------------------------------------------------ | ---------------------------------------------------------------------------------------------------------------------------------- |
| 凭证获取            | `CREDS=$(bash '<SCRIPT_PATH>/get-token.sh')`     | `$creds = & "<SCRIPT_PATH>\get-token.ps1" \| ConvertFrom-Json`                                                                     |
| Header 构造       | `jq -r .client_id` / `jq -r .api_key`            | `$creds.client_id` / `$creds.api_key`                                                                                              |
| GET 请求          | `curl -s "URL" -H "Key: Value"`                  | `irm "URL" -Headers @{"Key"="Value"}`                                                                                              |
| POST/PATCH 请求   | `curl -s -X METHOD "URL" -H "..." -d '{...}'`    | `$body = @{...} \| ConvertTo-Json -Depth 10; irm "URL" -Method Method -Headers @{...} -ContentType "application/json" -Body $body` |
| 文件上传（multipart） | `curl -s -X POST "URL" -H "..." -F "file=@path"` | `curl.exe -s -X POST "URL" -H "..." -F "file=@path"`（irm 不支持 multipart，需用 curl.exe）                                                |

### 完整模板

**bash 模板**

```bash theme={null}
CREDS=$(bash '<SCRIPT_PATH>/get-token.sh') && \
curl -s -X POST "https://ima.qq.com/{{PATH}}" \
  -H "ima-openapi-clientid: $(echo "$CREDS" | jq -r .client_id)" \
  -H "ima-openapi-apikey: $(echo "$CREDS" | jq -r .api_key)" \
  -H "Content-Type: application/json" \
  -d '{{BODY}}'
```

**PowerShell 模板**

```powershell theme={null}
$creds = & "<SCRIPT_PATH>\get-token.ps1" | ConvertFrom-Json
$headers = @{
  "ima-openapi-clientid" = $creds.client_id
  "ima-openapi-apikey"   = $creds.api_key
}
$body = @{ {{BODY}} } | ConvertTo-Json -Depth 10
irm "https://ima.qq.com/{{PATH}}" -Method Post `
  -Headers $headers `
  -ContentType "application/json" -Body $body
```

## 注意事项

* **UTF-8 编码（仅 notes 模块）**：见下方「⚠️ UTF-8 编码强制要求」章节。notes 模块的所有写入操作前**必须**完成 UTF-8 编码校验，否则会导致内容乱码且无法修复。
* **文件上传保持原样（knowledge-base 模块）**：当用户要求上传文件到知识库时，**必须保持文件原始内容不变**，不得进行任何编码转换。文件以二进制方式上传，服务端会自行处理编码。擅自转码可能破坏文件内容（如 PDF、图片、Excel 等非文本文件，或用户有意使用特定编码的文本文件）。
* **PowerShell 5.1 环境（所有模块）**：见下方「⚠️ PowerShell 5.1 环境检测」章节。此问题影响**所有** API 调用（notes、knowledge-base 等），PowerShell 5.1 会静默将请求 Body 转为 GBK 编码导致乱码。

## ⚠️ UTF-8 编码强制要求（CRITICAL — 仅适用于 notes 模块）

> **此规则为强制性要求，不可跳过。** 非法编码会导致内容在 IMA 中显示为乱码，且无法修复，必须重新写入。
>
> **适用范围：notes 模块**（`import_doc`、`append_doc` 等文本写入 API）。
>
> **不适用于 knowledge-base 模块的文件上传**：上传文件时必须保持文件原始内容，不得转码。文件以二进制方式上传，服务端自行处理。

**每次调用 notes 写入类 API（`import_doc`/`append_doc`）之前，必须对 `content`、`title` 等所有字符串字段执行 UTF-8 编码校验/转换。** 无论内容来源如何——用户直接输入、从文件读取、WebFetch 抓取、剪贴板粘贴、外部 API 返回——都不能假设已经是合法 UTF-8，必须显式确认。

### 强制检查清单（notes 模块写入前）

在构造 notes 写入请求的 body **之前**，完成以下步骤：

1. **来自文件的内容**：先检测文件编码，转为 UTF-8 后再读入变量（注意：这是指读取文件内容作为笔记正文写入，不是上传文件到知识库）
2. **来自 WebFetch / HTTP 请求的内容**：响应可能为 GBK/Latin-1 等，必须转码
3. **来自用户输入或变量拼接的内容**：清洗非法 UTF-8 字节（`\xff\xfe` 等）
4. **标题字段同理**：`title` 也必须为合法 UTF-8

### 各环境转码方法

**Python（推荐，几乎所有环境都有）：**

```bash theme={null}
# 读取文件，自动检测编码并转为 UTF-8
content=$(python3 -c "
import sys
data = open('tmpfile', 'rb').read()
for enc in ['utf-8', 'gbk', 'gb2312', 'big5', 'latin-1']:
    try:
        sys.stdout.write(data.decode(enc))
        break
    except (UnicodeDecodeError, LookupError):
        continue
" 2>/dev/null)

# 如果内容已在变量中，清洗非法 UTF-8 字节
content=$(printf '%s' "$content" | python3 -c "import sys; sys.stdout.write(sys.stdin.buffer.read().decode('utf-8','ignore'))")
```

**Node.js：**

```bash theme={null}
content=$(node -e "const fs=require('fs');const buf=fs.readFileSync('tmpfile');process.stdout.write(buf.toString('utf8'))")
# 已知编码（如 GBK）：
content=$(node -e "const fs=require('fs');process.stdout.write(new TextDecoder('gbk').decode(fs.readFileSync('tmpfile')))")
```

**Unix (macOS/Linux)：**

```bash theme={null}
content=$(iconv -f "$(file -b --mime-encoding tmpfile)" -t UTF-8 tmpfile 2>/dev/null || cat tmpfile)
```

**Windows PowerShell：**

```powershell theme={null}
# 读取非 UTF-8 文件并转码
$content = [System.IO.File]::ReadAllText('tmpfile', [System.Text.Encoding]::Default)
[System.IO.File]::WriteAllText('tmpfile.utf8', $content, [System.Text.Encoding]::UTF8)
```

### ⚠️ PowerShell 5.1 环境检测（CRITICAL — 适用于所有模块）

> **此问题影响所有 API 调用（notes、knowledge-base 等）**
>
> **此问题极其隐蔽：PowerShell 5.1 下 `Invoke-RestMethod` 会静默将请求 Body 从 UTF-8 转为系统 ANSI 编码（中文 Windows 为 GBK），即使设置了 `Content-Type: charset=utf-8` 也无效。结果是请求看起来发送成功，但服务端收到的内容已经是乱码，且无任何错误提示。**

**当 agent 运行在 PowerShell 环境时，必须在首次 API 调用前检测版本：**

```powershell theme={null}
# 检测 PowerShell 版本 — 在任何 API 调用之前执行（notes 和 knowledge-base 都需要）
if ($PSVersionTable.PSVersion.Major -le 5) {
    Write-Host "⚠️ 检测到 PowerShell 5.1，将使用 UTF-8 字节数组模式发送请求"
    $useUtf8Bytes = $true
} else {
    Write-Host "✅ PowerShell 7+，默认 UTF-8，无需额外处理"
    $useUtf8Bytes = $false
}
```

**PowerShell 5.1 下必须使用以下方式发送请求**（用 `ConvertTo-Json` 构建 JSON 以避免手动拼接的转义风险，再显式转为 UTF-8 字节数组）：

```powershell theme={null}
# PowerShell 5.1 安全请求模板（适用于所有模块的所有 API 调用）
$creds = & "<SCRIPT_PATH>\get-token.ps1" | ConvertFrom-Json
$headers = @{
  "ima-openapi-clientid" = $creds.client_id
  "ima-openapi-apikey"   = $creds.api_key
}
$body = @{ title = "标题"; content = $content; content_format = 1 } | ConvertTo-Json -Depth 10
if ($useUtf8Bytes) {
    # CRITICAL: 必须转为字节数组，否则中文/非ASCII内容会变成乱码
    $utf8Bytes = [System.Text.Encoding]::UTF8.GetBytes($body)
    Invoke-RestMethod -Uri $url -Method Post -Body $utf8Bytes -ContentType "application/json; charset=utf-8" -Headers $headers
} else {
    # PowerShell 7+ 可直接传字符串
    Invoke-RestMethod -Uri $url -Method Post -Body $body -ContentType "application/json; charset=utf-8" -Headers $headers
}
```

> **总结：** 在 PowerShell 5.1 环境中，**所有** API 调用（无论 notes 还是 knowledge-base）都必须将 Body 显式转为 UTF-8 字节数组。不检测版本直接发请求 = 中文内容必乱码。这是 PowerShell 5.1 的已知设计缺陷，不是 bug 可以被修复。
