remnote-bridge 0.1.12 → 0.1.14
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +141 -28
- package/README.zh-CN.md +368 -0
- package/dist/cli/commands/edit-rem.js +5 -5
- package/dist/cli/commands/health.js +231 -112
- package/dist/cli/commands/read-rem-in-tree.js +84 -0
- package/dist/cli/commands/read-rem.js +3 -1
- package/dist/cli/config.js +2 -0
- package/dist/cli/daemon/registry.js +8 -0
- package/dist/cli/handlers/edit-handler.js +49 -140
- package/dist/cli/handlers/patch-engine.js +347 -0
- package/dist/cli/handlers/read-handler.js +5 -57
- package/dist/cli/handlers/rem-cache.js +10 -5
- package/dist/cli/handlers/rem-field-filter.js +102 -0
- package/dist/cli/handlers/tree-edit-handler.js +67 -7
- package/dist/cli/handlers/tree-read-handler.js +4 -1
- package/dist/cli/handlers/tree-rem-read-handler.js +73 -0
- package/dist/cli/main.js +71 -12
- package/dist/cli/server/ws-server.js +9 -1
- package/dist/mcp/daemon-client.js +22 -2
- package/dist/mcp/format.js +43 -0
- package/dist/mcp/index.js +0 -55
- package/dist/mcp/instructions.js +447 -284
- package/dist/mcp/resources/edit-rem-guide.js +37 -157
- package/dist/mcp/resources/edit-tree-guide.js +1 -1
- package/dist/mcp/resources/error-reference.js +9 -13
- package/dist/mcp/resources/rem-object-fields.js +3 -3
- package/dist/mcp/tools/edit-tools.js +76 -10
- package/dist/mcp/tools/infra-tools.js +30 -33
- package/dist/mcp/tools/read-tools.js +221 -26
- package/package.json +1 -1
- package/remnote-plugin/dist/index-sandbox.js +24 -24
- package/remnote-plugin/dist/index.js +24 -24
- package/remnote-plugin/src/bridge/message-router.ts +3 -0
- package/remnote-plugin/src/services/read-rem-in-tree.ts +43 -0
- package/remnote-plugin/src/services/read-rem.ts +15 -0
- package/remnote-plugin/src/services/read-tree.ts +5 -0
- package/skills/remnote-bridge/SKILL.md +71 -38
- package/skills/remnote-bridge/instructions/connect.md +12 -1
- package/skills/remnote-bridge/instructions/disconnect.md +5 -0
- package/skills/remnote-bridge/instructions/edit-rem.md +105 -347
- package/skills/remnote-bridge/instructions/edit-tree.md +71 -2
- package/skills/remnote-bridge/instructions/health.md +81 -53
- package/skills/remnote-bridge/instructions/overall.md +55 -21
- package/skills/remnote-bridge/instructions/read-rem-in-tree.md +100 -0
- package/skills/remnote-bridge/instructions/read-rem.md +35 -16
- package/skills/remnote-bridge/instructions/search.md +4 -4
- package/skills/remnote-bridge/instructions/setup.md +5 -6
- package/skills/remnote-bridge-test/SKILL.md +847 -0
- package/skills/remnote-bridge-test/references/regression-suite.md +960 -0
- package/skills/remnote-bridge-test/references/verification-guide.md +161 -0
package/dist/mcp/instructions.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
export const SERVER_INSTRUCTIONS = `
|
|
2
2
|
# RemNote Bridge MCP Server — Agent 操作手册
|
|
3
3
|
|
|
4
|
-
RemNote
|
|
4
|
+
RemNote 知识库操作工具集。通过这些工具读取、搜索、编辑用户的 RemNote 笔记和知识结构。不能操控闪卡(Card/Flashcard)本身——闪卡由 RemNote 根据 Rem 属性自动生成。
|
|
5
5
|
|
|
6
|
-
> **架构备注**:本 MCP Server 是
|
|
6
|
+
> **架构备注**:本 MCP Server 是 \`remnote-bridge\` CLI 的包装层,每个工具调用在底层都会转化为一次 CLI 子进程调用(\`--json\` 模式)。错误消息中的"守护进程"/"daemon"指 CLI 的后台守护进程。
|
|
7
7
|
|
|
8
8
|
---
|
|
9
9
|
|
|
@@ -11,12 +11,10 @@ RemNote 知识库操作工具集。你可以通过这些工具读取、搜索、
|
|
|
11
11
|
|
|
12
12
|
### Everything is Rem
|
|
13
13
|
|
|
14
|
-
用户说的"笔记"、"文档"、"文件夹"、"闪卡",底层都是 **Rem**。不同形态通过属性区分:
|
|
15
|
-
|
|
16
14
|
| 用户说的 | 实际上是 | 区分方式 |
|
|
17
15
|
|:---------|:---------|:---------|
|
|
18
16
|
| 笔记 / 条目 | Rem | 最基本的数据单元 |
|
|
19
|
-
| 文档 / 页面 | Rem
|
|
17
|
+
| 文档 / 页面 | Rem(\`isDocument=true\`) | 可独立打开的页面 |
|
|
20
18
|
| 文件夹 | Rem(Document + 子节点全是 Document) | UI 概念,无独立标记 |
|
|
21
19
|
| 闪卡 | Card——由 Rem 属性自动生成 | **不可直接操控** |
|
|
22
20
|
|
|
@@ -26,79 +24,105 @@ Rem 有两个独立维度:**type**(闪卡语义)和 **isDocument**(页
|
|
|
26
24
|
|
|
27
25
|
| type | 含义 | UI 表现 |
|
|
28
26
|
|:-----|:-----|:--------|
|
|
29
|
-
|
|
|
30
|
-
|
|
|
31
|
-
|
|
|
32
|
-
|
|
|
27
|
+
| \`concept\` | 概念定义 | 文字**加粗** |
|
|
28
|
+
| \`descriptor\` | 描述/属性 | 正常字重 |
|
|
29
|
+
| \`default\` | 普通 Rem | 正常字重 |
|
|
30
|
+
| \`portal\` | 嵌入引用容器 | 紫色边框(**不可通过 setType 创建**) |
|
|
31
|
+
|
|
32
|
+
### 闪卡机制
|
|
33
33
|
|
|
34
|
-
|
|
34
|
+
闪卡由 Rem 的 \`type\`、\`backText\`、\`practiceDirection\` 三个字段控制。
|
|
35
35
|
|
|
36
|
-
|
|
36
|
+
**禁止**:在文本中插入分隔符(\`::\`、\`;;\`、\`>>\` 等)来创建闪卡。分隔符是 RemNote 编辑器语法,工具端无法识别。
|
|
37
37
|
|
|
38
|
-
|
|
38
|
+
#### 创建/修改闪卡
|
|
39
39
|
|
|
40
40
|
| 闪卡操作 | 方法 |
|
|
41
|
-
|
|
42
|
-
| 创建概念定义 |
|
|
43
|
-
| 创建正向问答 |
|
|
44
|
-
|
|
|
45
|
-
|
|
|
41
|
+
|:---------|:-----|
|
|
42
|
+
| 创建概念定义 | \`edit_tree\` 新增行 \`概念 ↔ 定义 <!--type:concept-->\` |
|
|
43
|
+
| 创建正向问答 | \`edit_tree\` 新增行 \`问题 → 答案\` |
|
|
44
|
+
| 创建反向问答 | \`edit_tree\` 新增行 \`问题 ← 答案\` |
|
|
45
|
+
| 创建多行答案 | \`edit_tree\` 新增行 \`问题 ↓\`(子行自动成为答案) |
|
|
46
|
+
| 改变闪卡类型/方向 | \`edit_rem\` 修改 \`type\`、\`backText\`、\`practiceDirection\` |
|
|
47
|
+
|
|
48
|
+
\`practiceDirection\` 取值:\`forward\`、\`backward\`、\`both\`、\`none\`。
|
|
49
|
+
|
|
50
|
+
#### 分隔符映射(理解用户意图)
|
|
51
|
+
|
|
52
|
+
用户在编辑器中用分隔符创建闪卡,提到时需映射到工具操作:
|
|
53
|
+
|
|
54
|
+
| 用户说 / 编辑器分隔符 | 对应 type | 对应 practiceDirection |
|
|
55
|
+
|:----------------------|:----------|:----------------------|
|
|
56
|
+
| \`::\` | concept | both |
|
|
57
|
+
| \`;;\` | descriptor | forward |
|
|
58
|
+
| \`>>\` / \`<<\` / \`<>\` | default | forward / backward / both |
|
|
59
|
+
| \`>>>\` / \`::>\` / \`;;>\` | default / concept / descriptor | 多行(子 Rem 为答案) |
|
|
60
|
+
| \`{{}}\` | default | forward(完形填空) |
|
|
61
|
+
|
|
62
|
+
### CDF(Concept-Descriptor Framework)
|
|
63
|
+
|
|
64
|
+
RemNote 推荐的知识结构化方法——用 Concept 和 Descriptor 构建可自动生成闪卡的知识网络:
|
|
65
|
+
|
|
66
|
+
- **Concept**(type:concept):核心概念——回答"X 是什么?",文字加粗显示
|
|
67
|
+
- **Descriptor**(type:descriptor):概念的属性——回答"X 的 Y 是什么?"
|
|
46
68
|
|
|
47
|
-
|
|
69
|
+
在 CLI 大纲中的表现:
|
|
70
|
+
\`\`\`
|
|
71
|
+
线性回归 ↔ 最基本的回归模型 <!--id1 type:concept-->
|
|
72
|
+
假设 → 因变量与自变量呈线性关系 <!--id2 type:descriptor-->
|
|
73
|
+
损失函数 → 均方误差 (MSE) <!--id3 type:descriptor-->
|
|
74
|
+
\`\`\`
|
|
48
75
|
|
|
49
|
-
|
|
76
|
+
CDF 的核心优势:Concept 自动生成双向闪卡("什么是线性回归?"↔"最基本的回归模型"),Descriptor 自动生成正向闪卡("线性回归的假设?"→"因变量与自变量呈线性关系"),层级关系自动维护上下文。
|
|
50
77
|
|
|
51
|
-
|
|
52
|
-
|:----------------------|:-----------|:-----------------------|
|
|
53
|
-
| \\\`::\\\` | concept | both |
|
|
54
|
-
| \\\`;;\\\` | descriptor | forward |
|
|
55
|
-
| \\\`>>\\\` / \\\`<<\\\` / \\\`<>\\\` | default | forward / backward / both |
|
|
56
|
-
| \\\`>>>\\\` / \\\`::>\\\` / \\\`;;>\\\` | default / concept / descriptor | forward / both / forward(多行) |
|
|
78
|
+
### 完形填空(Cloze)
|
|
57
79
|
|
|
58
|
-
|
|
80
|
+
通过 RichText 中的 \`cId\` 标记实现(不是分隔符),练习时 \`cId\` 标记的文本被遮盖:
|
|
81
|
+
|
|
82
|
+
\`\`\`json
|
|
83
|
+
["The ", {"cId": "cloze1", "i": "m", "text": "capital"}, " of France is Paris"]
|
|
84
|
+
\`\`\`
|
|
85
|
+
|
|
86
|
+
通过 \`edit_rem\` 操作 RichText 来创建/修改完形填空——在 \`changes.text\` 数组中为目标文字片段添加 \`cId\` 字段。每个 cloze 需要唯一的 \`cId\` 值。
|
|
59
87
|
|
|
60
88
|
### 链接机制
|
|
61
89
|
|
|
62
90
|
| 机制 | 用户操作 | 说明 |
|
|
63
91
|
|:-----|:---------|:-----|
|
|
64
|
-
| Reference
|
|
65
|
-
| Tag
|
|
66
|
-
| Portal
|
|
92
|
+
| Reference \`[[\` | 文本内引用 | 只是指针,不同步编辑 |
|
|
93
|
+
| Tag \`##\` | 附加标签 | 分类标记 |
|
|
94
|
+
| Portal \`((\` | 嵌入实时视图 | **编辑同步**,大纲中标为 \`type:portal\` |
|
|
67
95
|
|
|
68
|
-
|
|
96
|
+
#### Portal 操作速查
|
|
69
97
|
|
|
70
98
|
| 操作 | 命令 | 方式 |
|
|
71
99
|
|:-----|:-----|:-----|
|
|
72
|
-
| 创建 Portal |
|
|
73
|
-
| 删除 Portal |
|
|
74
|
-
|
|
|
75
|
-
| 移动 Portal
|
|
76
|
-
| 读取 Portal |
|
|
100
|
+
| 创建 Portal | \`edit_tree\` | 新增行 \`<!--portal refs:id1,id2-->\` |
|
|
101
|
+
| 删除 Portal | \`edit_tree\` | 从大纲中移除 Portal 行 |
|
|
102
|
+
| 修改引用列表 | \`edit_rem\` | 修改 \`portalDirectlyIncludedRem\` 数组 |
|
|
103
|
+
| 移动 Portal | \`edit_tree\` | 与移动普通行相同 |
|
|
104
|
+
| 读取 Portal | \`read_rem\` | 自动输出 8 字段简化 JSON |
|
|
77
105
|
|
|
78
106
|
### Powerup 过滤
|
|
79
107
|
|
|
80
|
-
RemNote
|
|
108
|
+
RemNote 格式设置(标题、高亮、代码等)底层通过 Powerup 机制实现,会向 Rem 注入隐藏的系统 Tag(\`isPowerup===true\`)和子 Rem(\`isPowerupProperty\`/\`isPowerupSlot\`)。
|
|
81
109
|
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
## 2. Session Lifecycle
|
|
110
|
+
**默认自动过滤**(\`includePowerup=false\`),返回值中 \`powerupFiltered\` 字段统计被过滤的数量(如 \`{tags: 2, children: 3}\`)。
|
|
85
111
|
|
|
86
|
-
|
|
112
|
+
\`includePowerup=true\` 参数可恢复完整数据(调试用)。\`read_tree\` 支持此参数,\`read_globe\` 和 \`read_context\` 硬编码过滤。
|
|
87
113
|
|
|
88
|
-
|
|
114
|
+
通常无需关心 Powerup 过滤,除非你需要理解某个 Rem 为什么有额外的 children 或 tags。
|
|
89
115
|
|
|
90
|
-
|
|
116
|
+
---
|
|
91
117
|
|
|
92
|
-
|
|
93
|
-
- \\\`health(instance="work")\\\` — 检查 "work" 实例状态
|
|
94
|
-
- \\\`disconnect(instance="work")\\\` — 停止 "work" 实例
|
|
118
|
+
## 2. Session Lifecycle
|
|
95
119
|
|
|
96
|
-
|
|
120
|
+
所有操作都依赖一个活跃的会话(= 守护进程的生命周期)。
|
|
97
121
|
|
|
98
122
|
### 标准模式(需要用户配合)
|
|
99
123
|
|
|
100
|
-
|
|
101
|
-
connect → 启动 daemon
|
|
124
|
+
\`\`\`
|
|
125
|
+
connect → 启动 daemon(幂等)
|
|
102
126
|
↓
|
|
103
127
|
⚠️ 用户操作:确保 RemNote 中已加载插件(见下方说明)
|
|
104
128
|
↓
|
|
@@ -107,85 +131,70 @@ health → 确认三层就绪(daemon / Plugin / SDK)
|
|
|
107
131
|
业务操作(read / search / edit)
|
|
108
132
|
↓
|
|
109
133
|
disconnect → 关闭 daemon,清空所有缓存
|
|
110
|
-
|
|
134
|
+
\`\`\`
|
|
111
135
|
|
|
112
136
|
### Headless 模式(自动连接)
|
|
113
137
|
|
|
114
|
-
|
|
138
|
+
通过 setup(一次性)+ headless Chrome 实现自动连接,后续 connect 无需用户介入。
|
|
115
139
|
|
|
116
|
-
**⚠️ 模式选择建议**:日常使用推荐**标准模式**。Headless 模式下 Chrome 在后台运行,**无法感知用户正在 RemNote
|
|
140
|
+
**⚠️ 模式选择建议**:日常使用推荐**标准模式**。Headless 模式下 Chrome 在后台运行,**无法感知用户正在 RemNote 中浏览和操作的界面**(\`read_context\` 返回的是 headless Chrome 的上下文,而非用户的浏览器)。只有在全自动化场景才建议使用 Headless 模式。
|
|
117
141
|
|
|
118
142
|
#### 首次使用(setup)
|
|
119
143
|
|
|
120
|
-
|
|
121
|
-
1. **登录 RemNote**
|
|
122
|
-
2. **配置 dev plugin**:插件图标 → 开发你的插件 → 填入 connect 输出的 Plugin 服务地址(如 \\\`http://localhost:29101\\\`)
|
|
123
|
-
|
|
124
|
-
完成后**彻底退出 Chrome**(macOS 必须 Cmd+Q,仅关窗口不够)。
|
|
144
|
+
\`setup\` 会弹出 Chrome 窗口,用户只需 **登录 RemNote**,然后**彻底退出 Chrome**(macOS 必须 Cmd+Q,仅关窗口不够)。setup 只负责保存登录凭证。
|
|
125
145
|
|
|
126
146
|
**你必须这样与用户交互**:
|
|
127
|
-
1. 调用
|
|
128
|
-
2. 立即告知用户:
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
2. 在 RemNote 中配置开发插件:点击左下角插件图标 → 开发你的插件 → 输入 connect 输出的 Plugin 服务地址
|
|
132
|
-
3. 完成后彻底退出 Chrome(macOS 请按 Cmd+Q)"
|
|
133
|
-
3. 等待 \\\`setup\\\` 返回(阻塞,最长 10 分钟)
|
|
134
|
-
4. 成功 → 进入下一步 \\\`connect(headless=true)\\\`
|
|
147
|
+
1. 调用 \`setup\`
|
|
148
|
+
2. 立即告知用户:"已打开 Chrome 浏览器。请登录 RemNote,完成后彻底退出 Chrome(macOS 请按 Cmd+Q)"
|
|
149
|
+
3. 等待 \`setup\` 返回(阻塞,最长 10 分钟)
|
|
150
|
+
4. 成功 → 进入下一步 \`connect(headless=true)\`
|
|
135
151
|
|
|
136
|
-
setup 只需执行一次。之后每次连接直接用
|
|
152
|
+
setup 只需执行一次。之后每次连接直接用 \`connect(headless=true)\`。
|
|
137
153
|
|
|
138
154
|
#### 后续使用
|
|
139
155
|
|
|
140
|
-
|
|
156
|
+
\`\`\`
|
|
141
157
|
connect(headless=true) → 启动 daemon + headless Chrome 自动加载 RemNote 和 Plugin
|
|
142
|
-
↓
|
|
158
|
+
↓ MCP Server 自动记住 headless 状态
|
|
143
159
|
health → 等待三层就绪(Plugin 需要 10-30 秒连接,可多次轮询)
|
|
144
|
-
↓
|
|
160
|
+
↓ 后续所有工具自动路由到 headless 实例
|
|
145
161
|
业务操作(read / search / edit)
|
|
146
162
|
↓
|
|
147
|
-
disconnect → 关闭 daemon + headless Chrome
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
**无需任何用户操作**——headless Chrome 在后台自动完成登录和 Plugin 加载。
|
|
163
|
+
disconnect → 关闭 daemon + headless Chrome,清空所有缓存,清除 headless 状态
|
|
164
|
+
\`\`\`
|
|
151
165
|
|
|
152
166
|
#### 排查
|
|
153
167
|
|
|
154
|
-
-
|
|
155
|
-
-
|
|
156
|
-
-
|
|
157
|
-
|
|
158
|
-
**关键要点**:
|
|
159
|
-
- \\\`connect\\\` 是所有业务操作的前提,未 connect 时任何命令都会报"守护进程未运行"
|
|
160
|
-
- \\\`health\\\` 检查三层状态:daemon 运行 → Plugin 已连接 → SDK 就绪,三者全部通过才能执行业务命令
|
|
161
|
-
- \\\`disconnect\\\` 会销毁所有缓存,之前的 read 结果全部失效
|
|
162
|
-
- daemon 默认 30 分钟无活动自动关闭
|
|
163
|
-
|
|
164
|
-
### Windows 注意事项
|
|
165
|
-
|
|
166
|
-
- **默认模式秒级启动**:使用预构建 plugin,无需安装依赖
|
|
167
|
-
- **\`--dev\` 模式首次较慢**:会自动安装 remnote-plugin 的依赖(约 600+ 个包),在 Windows 上可能需要 30-60 秒,connect 超时设为 60 秒
|
|
168
|
-
- **\`--dev\` 依赖自动修复**:如果 webpack-dev-server 因依赖损坏而崩溃,daemon 会自动清洁重装依赖(删除 node_modules 后重新安装)并重试,最多重试 2 次
|
|
169
|
-
- **端口残留**:多次 connect 失败后可能出现端口被占用(EADDRINUSE),用 \\\`remnote-bridge disconnect\\\` 或手动终止占用端口的进程后重试
|
|
168
|
+
- \`health(diagnose=true)\`:截图 + Chrome 状态 + console 错误
|
|
169
|
+
- \`health(reload=true)\`:重载 headless Chrome 页面
|
|
170
|
+
- Plugin 始终不连接 → 可能登录 session 过期,需重新 setup
|
|
170
171
|
|
|
171
172
|
### ⚠️ 标准模式:connect 后需要用户配合(重要)
|
|
172
173
|
|
|
173
|
-
|
|
174
|
+
\`connect\`(不传 headless)成功只意味着 daemon 和 Plugin 服务已启动,**Plugin 并未自动连接**。
|
|
174
175
|
|
|
175
176
|
**首次使用**(RemNote 从未加载过此插件):
|
|
176
177
|
1. 打开 RemNote 桌面端或网页端
|
|
177
178
|
2. 点击左侧边栏底部的插件图标(拼图形状)
|
|
178
179
|
3. 点击「开发你的插件」(Develop Your Plugin)
|
|
179
|
-
4. 在输入框中填入 connect 输出的 Plugin 服务地址(如
|
|
180
|
+
4. 在输入框中填入 connect 输出的 Plugin 服务地址(如 \`http://localhost:29101\`)
|
|
180
181
|
5. 等待插件加载完成
|
|
181
182
|
|
|
182
183
|
**非首次使用**(之前已加载过此插件):
|
|
183
|
-
- 只需**刷新 RemNote 页面**即可(浏览器 F5 或 Cmd+R
|
|
184
|
+
- 只需**刷新 RemNote 页面**即可(浏览器 F5 或 Cmd+R)
|
|
185
|
+
|
|
186
|
+
**你必须**:执行 \`connect\` 后,**立即告知用户需要完成上述操作**,不要直接调用业务命令。引导用户完成后,用 \`health\` 确认三层就绪再继续。
|
|
187
|
+
|
|
188
|
+
### Windows 注意事项
|
|
184
189
|
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
190
|
+
- 默认模式秒级启动(预构建 plugin)
|
|
191
|
+
- 端口残留:多次 connect 失败后可能 EADDRINUSE,用 \`disconnect\` 或手动终止进程后重试
|
|
192
|
+
|
|
193
|
+
### 关键要点
|
|
194
|
+
|
|
195
|
+
- daemon 默认 **30 分钟**无活动自动关闭,每次请求重置计时器
|
|
196
|
+
- \`disconnect\` 会销毁所有缓存,之前的 read 结果全部失效
|
|
197
|
+
- \`health\` 检查 daemon → Plugin → SDK 链式依赖,三者全通过才能执行业务命令
|
|
189
198
|
|
|
190
199
|
---
|
|
191
200
|
|
|
@@ -193,161 +202,191 @@ disconnect → 关闭 daemon + headless Chrome,清空所有缓存
|
|
|
193
202
|
|
|
194
203
|
### 场景 A:探索知识库
|
|
195
204
|
|
|
196
|
-
>
|
|
205
|
+
> "帮我看看知识库里有什么"、"有哪些文档"
|
|
197
206
|
|
|
198
|
-
|
|
207
|
+
\`read_globe\` → 返回所有 Document 的层级鸟瞰图 → 拿到感兴趣的 remId 后用 \`read_tree\` 深入。
|
|
199
208
|
|
|
200
209
|
### 场景 B:搜索并深入
|
|
201
210
|
|
|
202
|
-
>
|
|
203
|
-
|
|
204
|
-
先用 \\\`search\\\` 搜索关键词,获得匹配的 Rem 列表(含 remId)。返回结果中的 \\\`source\\\` 字段标识搜索来源:\\\`"rag"\\\` 为语义搜索(配置中启用 remnote-rag addon 时),\\\`"sdk"\\\` 为 SDK 全文搜索。RAG 模式额外返回 backText、ancestorPath、type、tags、score。然后根据需要:
|
|
205
|
-
- 用 \\\`read_rem\\\` 查看某条结果的详细属性
|
|
206
|
-
- 用 \\\`read_tree\\\` 展开某条结果的子树结构
|
|
211
|
+
> "搜一下关于 X 的笔记"
|
|
207
212
|
|
|
208
|
-
|
|
213
|
+
\`search\` → 获得匹配 Rem 列表 → \`read_rem\`/\`read_tree\` 查看详情。
|
|
209
214
|
|
|
210
|
-
|
|
215
|
+
**中文搜索限制**:SDK 全文搜索基于空格分词,中文等无空格语言效果差。策略:先用完整词搜索 → 无结果则用单个最具区分度的字重试 → 仍无结果则改用 \`read_globe\` → \`read_tree\` 手动定位。RAG 模式(启用 remnote-rag addon)对中文支持更好。
|
|
211
216
|
|
|
212
|
-
|
|
217
|
+
### 场景 C:了解当前上下文(⚠️ 主动调用时机)
|
|
213
218
|
|
|
214
|
-
|
|
215
|
-
- 用户提到了你没有上下文的内容(如"这个"、"当前页面"、"这里")
|
|
216
|
-
- 用户的描述与你已知的信息对不上
|
|
217
|
-
- 你搜索不到用户提到的某些内容
|
|
218
|
-
- 用户似乎在引用他正在查看的界面
|
|
219
|
+
> "我现在在看什么"、"当前页面"
|
|
219
220
|
|
|
220
|
-
|
|
221
|
+
**用户正在看的页面对你不可见。** 当你发现以下情况时,**必须主动调用 \`read_context\`**:
|
|
222
|
+
- 用户提到"这个"、"当前页面"、"这里"等无上下文的指代
|
|
223
|
+
- 用户的描述与你已知信息对不上
|
|
224
|
+
- 搜索不到用户提到的内容
|
|
221
225
|
|
|
222
|
-
|
|
223
|
-
- **focus 模式**(默认):以用户当前光标所在的 Rem 为中心,构建鱼眼视图——焦点处完全展开,周围递减。焦点行以 \\\`* \\\` 前缀标记。需要用户在 RemNote 中已点击某个 Rem。可通过 \\\`focusRemId\\\` 指定任意 Rem 作为鱼眼中心,此时不依赖用户焦点。
|
|
224
|
-
- **page 模式**:以当前打开的页面为根,均匀展开子树。
|
|
225
|
-
|
|
226
|
-
两种模式都会返回面包屑路径,帮助你理解当前位置在知识库中的层级。
|
|
226
|
+
\`read_context\`:focus 模式(默认)以用户焦点为中心构建鱼眼视图;page 模式以当前页面为根展开。两者都返回面包屑路径。
|
|
227
227
|
|
|
228
228
|
### 场景 D:修改文本或属性
|
|
229
229
|
|
|
230
|
-
>
|
|
231
|
-
|
|
232
|
-
工作流程:**必须先 read 再 edit**。
|
|
233
|
-
|
|
234
|
-
1. \\\`read_rem\\\` 获取目标 Rem 的 JSON 属性(建立缓存)
|
|
235
|
-
2. 在返回的 JSON 文本中定位要修改的部分
|
|
236
|
-
3. \\\`edit_rem\\\` 用 str_replace 替换:oldStr 精确匹配原文,newStr 是修改后的文本
|
|
237
|
-
|
|
238
|
-
str_replace 操作的是 \\\`JSON.stringify(remObject, null, 2)\\\` 格式化文本。oldStr 要包含足够上下文(如字段名 + 值),避免模糊匹配。替换后必须是合法 JSON。
|
|
239
|
-
|
|
240
|
-
**RichText 编辑要点**(\\\`text\\\` 和 \\\`backText\\\` 字段):
|
|
241
|
-
|
|
242
|
-
RichText 在格式化 JSON 中是多行结构,对象内 key 按**字母序**排列(\\\`_id\\\` 排最前,因为 \\\`_\\\` < \\\`a\\\`)。
|
|
230
|
+
> "把标题改成..."、"改成概念"、"加个高亮"
|
|
243
231
|
|
|
244
|
-
|
|
232
|
+
\`read_rem\` → 确认当前属性 → \`edit_rem\` 传入 changes 对象。只需包含要修改的字段,未提及字段保持不变。
|
|
245
233
|
|
|
246
|
-
|
|
247
|
-
oldStr: "text": [\\n "普通标题"\\n ]
|
|
248
|
-
newStr: "text": [\\n {\\n "b": true,\\n "i": "m",\\n "text": "粗体标题"\\n }\\n ]
|
|
249
|
-
\\\`\\\`\\\`
|
|
234
|
+
**注意**:\`read_rem\` 默认模式启用 Token Slimming——省略处于默认值的字段,未返回的字段即默认值(如 type 未显示 = "default",isTodo 未显示 = false,tags 未显示 = [])。需要完整字段用 \`full=true\`。
|
|
250
235
|
|
|
251
|
-
|
|
236
|
+
> **批量修改多个节点时**:改用 \`read_rem_in_tree\` 一次性获取全部节点属性,避免逐个 read_rem。详见场景 D2。
|
|
252
237
|
|
|
253
|
-
|
|
254
|
-
oldStr: "text": [\\n "点击访问官网"\\n ]
|
|
255
|
-
newStr: "text": [\\n "点击",\\n {\\n "i": "m",\\n "iUrl": "https://remnote.com",\\n "text": "访问官网"\\n }\\n ]
|
|
256
|
-
\\\`\\\`\\\`
|
|
238
|
+
#### edit_rem changes 示例
|
|
257
239
|
|
|
258
|
-
|
|
240
|
+
\`\`\`jsonc
|
|
241
|
+
// 修改类型
|
|
242
|
+
changes: { "type": "concept" }
|
|
243
|
+
// 设置整行高亮背景色
|
|
244
|
+
changes: { "highlightColor": "Yellow" }
|
|
245
|
+
// 粗体文本(RichText 数组)
|
|
246
|
+
changes: { "text": [{"b": true, "i": "m", "text": "粗体标题"}] }
|
|
247
|
+
// 超链接(注意用 iUrl 不是 url)
|
|
248
|
+
changes: { "text": ["点击", {"i": "m", "iUrl": "https://remnote.com", "text": "访问官网"}] }
|
|
249
|
+
// 文字颜色(tc 是数字,RemColor 枚举)
|
|
250
|
+
changes: { "text": [{"i": "m", "tc": 1, "text": "红色文字"}] }
|
|
251
|
+
// 批量修改多个字段
|
|
252
|
+
changes: { "type": "concept", "highlightColor": "Yellow", "fontSize": "H1" }
|
|
253
|
+
\`\`\`
|
|
259
254
|
|
|
260
|
-
|
|
255
|
+
#### highlightColor(Rem 级别)vs h(RichText 行内)
|
|
261
256
|
|
|
262
257
|
| 属性 | 位置 | 值类型 | 效果 | 修改方式 |
|
|
263
258
|
|:-----|:-----|:-------|:-----|:---------|
|
|
264
|
-
|
|
|
265
|
-
|
|
|
259
|
+
| \`highlightColor\` | RemObject 顶层 | 字符串 \`"Red"\`/\`"Yellow"\` 等或 \`null\` | 整行背景色 | changes 直接设置 |
|
|
260
|
+
| \`h\` | RichText 元素内 | 数字 0-9(RemColor 枚举) | 文字片段荧光底色 | changes.text 整体替换 |
|
|
266
261
|
|
|
267
|
-
|
|
262
|
+
两者完全独立,互不影响。
|
|
263
|
+
|
|
264
|
+
#### RichText h 颜色值对照表
|
|
268
265
|
|
|
269
266
|
| 值 | 颜色 | 值 | 颜色 | 值 | 颜色 |
|
|
270
267
|
|:---|:-----|:---|:-----|:---|:-----|
|
|
271
|
-
| 0 |
|
|
268
|
+
| 0 | 无/默认 | 4 | Green | 7 | Gray |
|
|
272
269
|
| 1 | Red | 5 | Purple | 8 | Brown |
|
|
273
270
|
| 2 | Orange | 6 | Blue | 9 | Pink |
|
|
274
271
|
| 3 | Yellow | — | — | — | — |
|
|
275
272
|
|
|
276
|
-
|
|
273
|
+
#### 特殊字段处理规则
|
|
277
274
|
|
|
278
|
-
|
|
275
|
+
- **tags / sources**:传入**目标 ID 数组**,系统自动计算 diff(逐项 add/remove),不是整体替换。必须列出完整目标数组,缺少的 ID 会被删除
|
|
276
|
+
- **backText**:\`null\` → 清除背面(调用 \`setBackText([])\`);传 RichText 数组设置背面内容;裸字符串自动包装为 \`[string]\`
|
|
277
|
+
- **parent + positionAmongstSiblings**:共享同一 SDK 调用 \`setParent(parentId, position)\`,应在同一次 changes 中同时修改
|
|
278
|
+
- **portalDirectlyIncludedRem**:仅 type=portal 的 Rem 可修改,传目标 ID 数组,系统自动 diff(逐项 addToPortal/removeFromPortal)
|
|
279
|
+
- **highlightColor**:\`null\` → 调用 \`removePowerup('h')\`(SDK 不接受 null)
|
|
280
|
+
- **fontSize**:\`null\` → 调用 \`setFontSize(undefined)\`(恢复普通大小)
|
|
281
|
+
- **todoStatus**:依赖 \`isTodo=true\` 才生效;清除 todo 应设 \`isTodo=false\`
|
|
282
|
+
- **type**:不可设为 \`portal\`(Portal 只能通过 SDK \`createPortal()\` 或 edit_tree \`<!--portal-->\` 创建)
|
|
279
283
|
|
|
280
|
-
|
|
284
|
+
### 场景 D2:批量读取 + 标注(课本划重点)
|
|
281
285
|
|
|
282
|
-
|
|
283
|
-
// 设置为黄色背景
|
|
284
|
-
oldStr: "highlightColor": null
|
|
285
|
-
newStr: "highlightColor": "Yellow"
|
|
286
|
+
> "帮我标注这些笔记的重点"、"给关键词加高亮"、"批量修改格式"
|
|
286
287
|
|
|
287
|
-
|
|
288
|
-
oldStr: "highlightColor": "Yellow"
|
|
289
|
-
newStr: "highlightColor": null
|
|
290
|
-
\\\`\\\`\\\`
|
|
288
|
+
当需要读取一棵子树并对**多个节点**进行属性或富文本修改时,使用 \`read_rem_in_tree\` 一次性获取全部信息:
|
|
291
289
|
|
|
292
|
-
|
|
290
|
+
\`read_rem_in_tree\` → 同时获取大纲 + 每个节点的 RemObject(含完整 RichText)
|
|
291
|
+
↓
|
|
292
|
+
对目标节点直接调用 \`edit_rem\`(rem 缓存已就绪,无需再逐个 read_rem)
|
|
293
|
+
+
|
|
294
|
+
如需结构变更,直接调用 \`edit_tree\`(tree 缓存已就绪,无需再 read_tree)
|
|
293
295
|
|
|
294
|
-
|
|
296
|
+
**为什么不用 read_tree + N×read_rem?** \`read_rem_in_tree\` 一次调用建立双重缓存,省去 N+1 次网络往返。对 30+ 节点的子树,差异是 1 次调用 vs 31+ 次调用。
|
|
295
297
|
|
|
296
|
-
|
|
297
|
-
// "Todo List" 文字加黄色荧光(h: 0 → 3)
|
|
298
|
-
// ⚠️ 只替换包含目标文字的那一行 h 值,用上下文确保唯一匹配
|
|
299
|
-
oldStr: "h": 0,\\n "i": "m",\\n "text": "Todo List "
|
|
300
|
-
newStr: "h": 3,\\n "i": "m",\\n "text": "Todo List "
|
|
298
|
+
**注意**:\`read_rem_in_tree\` 默认 maxNodes=50(每节点需 40+ SDK 调用),大子树需显式设置 maxNodes。
|
|
301
299
|
|
|
302
|
-
|
|
303
|
-
oldStr: "h": 3,\\n "i": "m",\\n "text": "Todo List "
|
|
304
|
-
newStr: "h": 0,\\n "i": "m",\\n "text": "Todo List "
|
|
305
|
-
\\\`\\\`\\\`
|
|
300
|
+
### 场景 E:修改结构(新增/删除/移动/重排)
|
|
306
301
|
|
|
307
|
-
|
|
302
|
+
> "在这下面加几个子项"、"删掉这个"
|
|
308
303
|
|
|
309
|
-
|
|
304
|
+
\`read_tree\` → 查看大纲 → \`edit_tree\` 用 str_replace 修改。
|
|
310
305
|
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
newStr: "type": "concept"
|
|
315
|
-
\\\`\\\`\\\`
|
|
306
|
+
**关键红线**:
|
|
307
|
+
- edit_tree **禁止修改行内容**(改内容用 edit_rem)
|
|
308
|
+
- 新增行必须插在兄弟**末尾**,不能插在有子节点的 Rem 和其 children 之间(否则触发 \`children_captured\`)
|
|
316
309
|
|
|
317
|
-
|
|
310
|
+
#### 新增行格式说明
|
|
318
311
|
|
|
319
|
-
|
|
320
|
-
// 加红色文字颜色(与 h 类似,tc 也是数字 0-9)
|
|
321
|
-
oldStr: "i": "m",\\n "text": "重要内容"
|
|
322
|
-
newStr: "i": "m",\\n "tc": 1,\\n "text": "重要内容"
|
|
323
|
-
\\\`\\\`\\\`
|
|
312
|
+
新增行(无 remId 注释的行)支持以下格式:
|
|
324
313
|
|
|
325
|
-
|
|
314
|
+
**Markdown 前缀**:\`# \` \`## \` \`### \` \`- [ ] \` \`- [x] \` \\\`code\\\` \`---\`
|
|
326
315
|
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
| \\\`read_tree\\\` | 写入缓存 | 供 \\\`edit_tree\\\` 使用 |
|
|
331
|
-
| \\\`search\\\` / \\\`read_globe\\\` / \\\`read_context\\\` | **不缓存** | 不能作为 edit 前置 |
|
|
316
|
+
**箭头分隔符**:
|
|
317
|
+
- 单行:\`→\`(forward)\`←\`(backward)\`↔\`(both)——格式 \`text → backText\`
|
|
318
|
+
- 多行:\`↓\`(forward)\`↑\`(backward)\`↕\`(both)——子行自动成为答案
|
|
332
319
|
|
|
333
|
-
|
|
320
|
+
**元数据注释**(可选,行尾追加):
|
|
321
|
+
- \`<!--type:concept-->\` \`<!--type:descriptor-->\` \`<!--doc-->\`
|
|
322
|
+
- \`<!--tag:标签名(tagId)-->\`(可多个,空格分隔)
|
|
323
|
+
- 可组合:\`<!--type:concept doc tag:数学(tag01)-->\`
|
|
324
|
+
|
|
325
|
+
**Portal 新增**:
|
|
326
|
+
- \`<!--portal refs:id1,id2-->\`(创建并引用指定 Rem)
|
|
327
|
+
- \`<!--portal-->\`(创建空 Portal)
|
|
328
|
+
|
|
329
|
+
#### str_replace 构造示例
|
|
330
|
+
|
|
331
|
+
**示例 1:在末尾新增行**
|
|
332
|
+
\`\`\`
|
|
333
|
+
oldStr:
|
|
334
|
+
最后一个兄弟 <!--idZ-->
|
|
335
|
+
newStr:
|
|
336
|
+
最后一个兄弟 <!--idZ-->
|
|
337
|
+
新增行
|
|
338
|
+
\`\`\`
|
|
339
|
+
|
|
340
|
+
**示例 2:删除一个带子节点的行(必须一起删)**
|
|
341
|
+
\`\`\`
|
|
342
|
+
oldStr:
|
|
343
|
+
子节点 A <!--idA-->
|
|
344
|
+
孙节点 A1 <!--idA1-->
|
|
345
|
+
子节点 B <!--idB-->
|
|
346
|
+
newStr:
|
|
347
|
+
子节点 B <!--idB-->
|
|
348
|
+
\`\`\`
|
|
334
349
|
|
|
335
|
-
|
|
350
|
+
**示例 3:创建多行闪卡**
|
|
351
|
+
\`\`\`
|
|
352
|
+
oldStr:
|
|
353
|
+
子节点 A <!--idA-->
|
|
354
|
+
newStr:
|
|
355
|
+
什么是线性回归? ↓
|
|
356
|
+
一种基本的回归分析方法
|
|
357
|
+
假设因变量与自变量呈线性关系
|
|
358
|
+
子节点 A <!--idA-->
|
|
359
|
+
\`\`\`
|
|
336
360
|
|
|
337
|
-
|
|
361
|
+
#### 行引用模板 \`{{remId}}\`
|
|
338
362
|
|
|
339
|
-
|
|
340
|
-
2. 在大纲中用 str_replace 进行结构修改:
|
|
341
|
-
- **新增**:插入无 remId 注释的新行(通过缩进确定父子关系)。可在行尾加元数据注释指定属性:\\\`新行 <!--type:concept doc tag:Name(id)-->\\\`
|
|
342
|
-
- **删除**:移除带 remId 的行(必须同时删除所有子行)
|
|
343
|
-
- **移动**:改变行的缩进级别或位置
|
|
344
|
-
- **重排**:调换同级行的顺序
|
|
363
|
+
在 oldStr/newStr 中使用 \`{{remId}}\` 引用缓存大纲中已有行的完整内容(不含缩进)。系统在 str_replace 前自动展开。
|
|
345
364
|
|
|
346
|
-
|
|
365
|
+
**优势**:避免抄写完整行内容(remId、元数据标记),减少 token 浪费和复制错误。
|
|
347
366
|
|
|
348
|
-
|
|
367
|
+
**示例:重排两个节点**
|
|
368
|
+
\`\`\`
|
|
369
|
+
// 不用模板:
|
|
370
|
+
oldStr: " 动态数组 <!--id1_1 type:concept-->\\n 静态数组 <!--id1_2 type:concept-->"
|
|
371
|
+
newStr: " 静态数组 <!--id1_2 type:concept-->\\n 动态数组 <!--id1_1 type:concept-->"
|
|
349
372
|
|
|
350
|
-
|
|
373
|
+
// 用模板:
|
|
374
|
+
oldStr: " {{id1_1}}\\n {{id1_2}}"
|
|
375
|
+
newStr: " {{id1_2}}\\n {{id1_1}}"
|
|
376
|
+
\`\`\`
|
|
377
|
+
|
|
378
|
+
**规则**:
|
|
379
|
+
- \`{{remId}}\` 展开为**不含缩进**的完整行内容,缩进由你控制
|
|
380
|
+
- 只匹配纯字母数字(\`[a-zA-Z0-9]+\`),与 RemNote cloze 语法 \`{{text}}\` 不冲突(cloze 含中文/空格/标点,不会被匹配)
|
|
381
|
+
- 匹配到但不在缓存大纲中的 \`{{xxx}}\` 原样保留(可能是 cloze),并输出 warning
|
|
382
|
+
- 新增行不能用 \`{{}}\`(新增行没有 remId)
|
|
383
|
+
- 可以混用:部分行用 \`{{id}}\`,部分行手动写
|
|
384
|
+
|
|
385
|
+
#### ⚠️ children_captured 详解
|
|
386
|
+
|
|
387
|
+
在有子节点的 Rem 和其 children 之间插入新行,会导致新行"劫持"已有 children:
|
|
388
|
+
|
|
389
|
+
\`\`\`
|
|
351
390
|
❌ 错误:插在父 Rem 和 children 之间
|
|
352
391
|
oldStr: 水分子 ↓ <!--idA-->
|
|
353
392
|
newStr: 水分子 ↓ <!--idA-->
|
|
@@ -357,57 +396,46 @@ newStr: 水分子 ↓ <!--idA-->
|
|
|
357
396
|
oldStr: 最后一个兄弟 <!--idZ-->
|
|
358
397
|
newStr: 最后一个兄弟 <!--idZ-->
|
|
359
398
|
新行
|
|
360
|
-
|
|
399
|
+
\`\`\`
|
|
400
|
+
|
|
401
|
+
#### 创建新节点并移动已有 children
|
|
361
402
|
|
|
362
|
-
|
|
363
|
-
1. 第一次 \\\`edit_tree\\\`:在末尾创建新节点(获得 remId)
|
|
364
|
-
2. 第二次 \\\`edit_tree\\\`:把已有行移动到新节点下面(此时新节点已有 remId,走正常 move 逻辑)
|
|
403
|
+
当需要在已有 children 的 Rem 下插入一个新的中间层时,不能一步完成(否则触发 children_captured)。正确做法是**两步**:
|
|
365
404
|
|
|
366
|
-
|
|
405
|
+
1. 先在大纲**末尾**新增节点(避免劫持)
|
|
406
|
+
2. 再发一次 \`edit_tree\`,将已有 children 移动到新节点下(通过调整缩进实现移动)
|
|
367
407
|
|
|
368
|
-
|
|
408
|
+
### 场景 F:创建/修改闪卡
|
|
369
409
|
|
|
370
|
-
|
|
410
|
+
> "创建概念定义"、"做个正向问答卡"
|
|
371
411
|
|
|
372
|
-
|
|
373
|
-
-
|
|
374
|
-
-
|
|
375
|
-
-
|
|
376
|
-
-
|
|
377
|
-
-
|
|
412
|
+
**创建新闪卡**(\`edit_tree\` 新增行 + 箭头 + 可选元数据注释):
|
|
413
|
+
- 正向:\`问题 → 答案\`
|
|
414
|
+
- 双向:\`问题 ↔ 答案\`
|
|
415
|
+
- 多行:\`问题 ↓\`(子行自动成为答案)
|
|
416
|
+
- 概念定义:\`概念 ↔ 定义 <!--type:concept-->\`(一步完成)
|
|
417
|
+
- 描述属性:\`属性 → 值 <!--type:descriptor-->\`(与 Concept 配合使用)
|
|
378
418
|
|
|
379
|
-
|
|
380
|
-
-
|
|
381
|
-
-
|
|
382
|
-
-
|
|
419
|
+
**Concept vs Descriptor 使用场景**:
|
|
420
|
+
- Concept(概念定义):独立的核心概念,回答"X 是什么?"——如"线性回归 ↔ 最基本的回归模型"
|
|
421
|
+
- Descriptor(描述属性):作为某个 Concept 的子 Rem,回答"X 的 Y 是什么?"——如"假设 → 因变量与自变量呈线性关系"
|
|
422
|
+
- 通常 Descriptor 是 Concept 的直接子节点,二者配合构成完整的 CDF 知识结构
|
|
383
423
|
|
|
384
|
-
|
|
424
|
+
**修改现有 Rem 的闪卡行为**(\`read_rem\` → \`edit_rem\`):修改 \`type\`、\`practiceDirection\`、\`backText\` 字段。
|
|
385
425
|
|
|
386
426
|
### 场景 G:排查连接问题
|
|
387
427
|
|
|
388
|
-
|
|
428
|
+
\`health\` 默认查询所有活跃实例的三层状态(daemon / Plugin / SDK),返回 \`instances\` 数组。有 \`--instance\` 或 \`--headless\` 时只查询指定实例。每个实例的 \`plugin.isTwin\` 标记是否为孪生连接。
|
|
389
429
|
|
|
390
|
-
|
|
391
|
-
- daemon 未运行 → 执行 \\\`connect\\\`,然后引导用户在 RemNote 中加载插件
|
|
392
|
-
- Plugin 未连接 → 提醒用户:首次使用需在 RemNote 的「开发你的插件」中填入对应 Plugin 服务地址(如 \\\`http://localhost:29101\\\`);非首次使用只需刷新 RemNote 页面
|
|
393
|
-
- SDK 未就绪 → 等待几秒后重试 health
|
|
430
|
+
故障定位:无活跃实例 → \`connect\`;Plugin 未连接 → 引导用户操作 RemNote(或使用 headless 模式);SDK 未就绪 → 等待重试。
|
|
394
431
|
|
|
395
432
|
### 场景 H:管理增强项目
|
|
396
433
|
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
使用 \\\`addon\\\` 工具管理增强项目:
|
|
400
|
-
- \\\`addon(action="list")\\\` — 查看所有可用增强项目及状态
|
|
401
|
-
- \\\`addon(action="install", name="remnote-rag")\\\` — 安装指定增强项目
|
|
402
|
-
- \\\`addon(action="uninstall", name="remnote-rag")\\\` — 卸载指定增强项目
|
|
403
|
-
|
|
404
|
-
安装后需在配置页面中填写必需的配置项(如 API Key)。
|
|
434
|
+
\`addon\`:\`action="list"\` 查看状态、\`action="install"\` 安装、\`action="uninstall"\` 卸载。
|
|
405
435
|
|
|
406
436
|
### 场景 I:重置环境
|
|
407
437
|
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
使用 \\\`clean\\\` 工具彻底清理所有 daemon 进程、PID 文件、注册表和 addon 数据。清理后需重新 \\\`connect\\\`。
|
|
438
|
+
\`clean\` 彻底清理所有 daemon 进程、PID 文件、注册表和 addon 数据。清理后需重新 \`connect\`。
|
|
411
439
|
|
|
412
440
|
---
|
|
413
441
|
|
|
@@ -415,88 +443,223 @@ newStr: 最后一个兄弟 <!--idZ-->
|
|
|
415
443
|
|
|
416
444
|
### 黄金法则:先 read 再 edit
|
|
417
445
|
|
|
418
|
-
-
|
|
419
|
-
-
|
|
446
|
+
- \`edit_rem\` 前必须先 \`read_rem\` 或 \`read_rem_in_tree\` 同一个 remId
|
|
447
|
+
- \`edit_tree\` 前必须先 \`read_tree\` 或 \`read_rem_in_tree\` 同一个 remId
|
|
448
|
+
- \`read_rem_in_tree\` 同时建立两种缓存,调用后可直接 \`edit_tree\` 和 \`edit_rem\`
|
|
449
|
+
- \`search\`/\`read_globe\`/\`read_context\` **不写入缓存**,不能作为 edit 前置
|
|
420
450
|
|
|
421
|
-
跳过 read 直接 edit
|
|
451
|
+
跳过 read 直接 edit 会被拒绝(硬性要求)。
|
|
422
452
|
|
|
423
|
-
###
|
|
453
|
+
### 两道防线
|
|
424
454
|
|
|
425
|
-
每次 edit 操作都经过三重安全检查:
|
|
426
455
|
1. **缓存存在**:必须有对应的 read 缓存
|
|
427
|
-
2. **并发检测**:edit
|
|
428
|
-
3. **精确匹配**:oldStr 必须在目标文本中恰好匹配 1 次
|
|
456
|
+
2. **并发检测**:edit 时重新读取最新数据与缓存比较,Rem 被外部修改则拒绝——必须重新 read
|
|
429
457
|
|
|
430
458
|
### edit_tree 禁止事项
|
|
431
459
|
|
|
432
|
-
-
|
|
433
|
-
-
|
|
434
|
-
-
|
|
435
|
-
-
|
|
436
|
-
-
|
|
437
|
-
|
|
438
|
-
|
|
460
|
+
- \`content_modified\`:修改已有行内容 → 用 edit_rem
|
|
461
|
+
- \`root_modified\`:删除/修改根节点
|
|
462
|
+
- \`folded_delete\`:删除有隐藏子节点的行 → 更大 depth 重新 read_tree
|
|
463
|
+
- \`orphan_detected\`:删父留子 → 必须一起删
|
|
464
|
+
- \`elided_modified\`:修改/删除省略占位符 → 更大参数重新 read_tree
|
|
465
|
+
- \`children_captured\`:新行劫持已有子节点 → 插在兄弟末尾
|
|
466
|
+
- \`indent_skip\`:缩进跳级 → 每级 2 空格
|
|
467
|
+
|
|
468
|
+
### 缓存行为速查表
|
|
469
|
+
|
|
470
|
+
| 场景 | 缓存行为 | 重试策略 |
|
|
471
|
+
|:-----|:---------|:---------|
|
|
472
|
+
| edit_rem 写入成功 | 从 Plugin 重新读取 → 更新缓存 | 可继续编辑 |
|
|
473
|
+
| edit_rem 防线拒绝/部分失败 | 不更新缓存 | 必须重新 read_rem |
|
|
474
|
+
| edit_tree 成功 | 自动 re-read → 更新缓存 | 可连续 edit |
|
|
475
|
+
| edit_tree 防线 3 拒绝(str_replace 不匹配等) | 缓存保持不变 | 调整 oldStr/newStr 后直接重试 |
|
|
476
|
+
| edit_tree 执行中异常 | 已执行操作保留(**无回滚**),不更新缓存 | 必须重新 read_tree |
|
|
477
|
+
| 枚举值非法(edit_rem) | 报错拒绝,缓存不变 | 检查允许的值范围后重试 |
|
|
478
|
+
|
|
479
|
+
### 可写字段列表(21 个)
|
|
480
|
+
|
|
481
|
+
\`\`\`
|
|
482
|
+
text, backText, type, isDocument, parent,
|
|
483
|
+
fontSize, highlightColor,
|
|
484
|
+
isTodo, todoStatus, isCode, isQuote, isListItem, isCardItem, isSlot, isProperty,
|
|
485
|
+
enablePractice, practiceDirection,
|
|
486
|
+
tags, sources, positionAmongstSiblings, portalDirectlyIncludedRem
|
|
487
|
+
\`\`\`
|
|
488
|
+
|
|
489
|
+
### 枚举约束速查
|
|
490
|
+
|
|
491
|
+
| 字段 | 允许的值 |
|
|
492
|
+
|:-----|:---------|
|
|
493
|
+
| \`type\` | \`concept\` / \`descriptor\` / \`default\`(\`portal\` 不可设置) |
|
|
494
|
+
| \`practiceDirection\` | \`forward\` / \`backward\` / \`both\` / \`none\` |
|
|
495
|
+
| \`highlightColor\` | \`Red\` / \`Orange\` / \`Yellow\` / \`Green\` / \`Blue\` / \`Purple\` / \`Gray\` / \`Brown\` / \`Pink\` / \`null\` |
|
|
496
|
+
| \`fontSize\` | \`H1\` / \`H2\` / \`H3\` / \`null\` |
|
|
497
|
+
| \`todoStatus\` | \`Finished\` / \`Unfinished\` / \`null\`(需先 \`isTodo=true\`) |
|
|
439
498
|
|
|
440
499
|
---
|
|
441
500
|
|
|
442
501
|
## 5. Output Format Quick Reference
|
|
443
502
|
|
|
444
|
-
|
|
503
|
+
\`read_tree\`、\`read_globe\`、\`read_context\` 返回 Markdown 大纲。
|
|
445
504
|
|
|
446
505
|
### 行结构
|
|
447
506
|
|
|
448
|
-
|
|
449
|
-
{缩进}{
|
|
450
|
-
|
|
507
|
+
\`\`\`
|
|
508
|
+
{缩进}{前缀}{内容}{箭头}{backText} <!-- {remId} {标记} -->
|
|
509
|
+
\`\`\`
|
|
451
510
|
|
|
452
511
|
- 缩进:每级 2 空格
|
|
453
|
-
-
|
|
512
|
+
- 前缀:\`# \`(H1)、\`## \`(H2)、\`### \`(H3)、\`- [ ] \`(待办)、\`- [x] \`(已完成)、\\\`...\\\`(代码)、\`---\`(分隔线)
|
|
454
513
|
|
|
455
|
-
###
|
|
514
|
+
### 元数据标记
|
|
456
515
|
|
|
457
516
|
| 标记 | 含义 |
|
|
458
517
|
|:-----|:-----|
|
|
459
|
-
|
|
|
460
|
-
|
|
|
461
|
-
|
|
|
462
|
-
|
|
|
463
|
-
|
|
|
464
|
-
|
|
|
518
|
+
| \`type:concept\` / \`type:descriptor\` / \`type:portal\` | Rem 类型(default 不标记) |
|
|
519
|
+
| \`doc\` | 是文档页面 |
|
|
520
|
+
| \`top\` | 知识库顶层 Rem |
|
|
521
|
+
| \`children:N\` | 有 N 个未展开的子节点 |
|
|
522
|
+
| \`role:card-item\` | 多行闪卡答案行 |
|
|
523
|
+
| \`tag:Name(id)\` | 已附加的标签 |
|
|
524
|
+
| \`refs:id1,id2\` | Portal 引用的 Rem ID |
|
|
465
525
|
|
|
466
526
|
### 箭头含义
|
|
467
527
|
|
|
468
|
-
|
|
469
|
-
|
|
528
|
+
| 箭头 | practiceDirection | 格式 |
|
|
529
|
+
|:-----|:------------------|:-----|
|
|
530
|
+
| \`→\` \`←\` \`↔\` | forward / backward / both | \`text → backText\`(单行) |
|
|
531
|
+
| \`↓\` \`↑\` \`↕\` | forward / backward / both | \`text ↓\` 或 \`text ↓ backText\`(多行,子行为答案) |
|
|
470
532
|
|
|
471
533
|
### 省略占位符
|
|
472
534
|
|
|
473
|
-
|
|
474
|
-
<!--...elided 3 siblings (parent:
|
|
475
|
-
<!--...elided >=10 nodes (parent:
|
|
476
|
-
|
|
535
|
+
\`\`\`
|
|
536
|
+
<!--...elided 3 siblings (parent:id range:2-4 total:5)--> 精确省略(超 maxSiblings)
|
|
537
|
+
<!--...elided >=10 nodes (parent:id range:5-14 total:20)--> 非精确省略(maxNodes 耗尽)
|
|
538
|
+
\`\`\`
|
|
539
|
+
|
|
540
|
+
精确省略保留前 70% + 后 30%。**省略占位符不可删除或修改**。
|
|
541
|
+
|
|
542
|
+
### edit_tree 新增行格式
|
|
543
|
+
|
|
544
|
+
新增行(无 remId 注释的行)在 newStr 中出现时,会被创建为新的 Rem。格式选项:
|
|
545
|
+
|
|
546
|
+
- 纯文本行:\`新内容\`
|
|
547
|
+
- 带前缀:\`# 新标题\`、\`- [ ] 新待办\`
|
|
548
|
+
- 带箭头:\`问题 → 答案\`、\`概念 ↔ 定义\`、\`题目 ↓\`
|
|
549
|
+
- 带元数据注释(metadata-only,无 remId):\`新行 <!--type:concept doc-->\`
|
|
550
|
+
- Portal 行:\`<!--portal refs:id1,id2-->\`
|
|
551
|
+
- 嵌套新增(父+子一起创建):
|
|
552
|
+
\`\`\`
|
|
553
|
+
新父节点 ↓
|
|
554
|
+
新子行 1
|
|
555
|
+
新子行 2
|
|
556
|
+
\`\`\`
|
|
557
|
+
|
|
558
|
+
### 完整示例大纲
|
|
559
|
+
|
|
560
|
+
\`\`\`markdown
|
|
561
|
+
# 数据结构 <!--kLr type:concept doc top-->
|
|
562
|
+
## 线性结构 <!--ABC type:concept-->
|
|
563
|
+
数组 → Array <!--DEF-->
|
|
564
|
+
链表 ↓ <!--GHI type:concept-->
|
|
565
|
+
单向链表 <!--JKL role:card-item-->
|
|
566
|
+
双向链表 <!--MNO role:card-item-->
|
|
567
|
+
- [x] 复习完成 <!--PQR-->
|
|
568
|
+
## 树结构 <!--VWX type:concept children:8-->
|
|
569
|
+
<!--...elided 3 siblings (parent:kLr range:3-5 total:6)-->
|
|
570
|
+
嵌入视图 <!--p01 type:portal refs:ref1,ref2-->
|
|
571
|
+
重要概念 <!--QRS tag:数学(tag01) tag:基础(tag02)-->
|
|
572
|
+
\`\`\`
|
|
573
|
+
|
|
574
|
+
---
|
|
575
|
+
|
|
576
|
+
## 6. RichText 格式参考
|
|
577
|
+
|
|
578
|
+
\`text\` 和 \`backText\` 字段是 JSON 数组(RichText),元素为纯字符串或格式化对象。
|
|
579
|
+
|
|
580
|
+
### 元素类型表
|
|
581
|
+
|
|
582
|
+
| \`i\` 值 | 含义 | 必填字段 | 可选字段 |
|
|
583
|
+
|:---------|:-----|:---------|:---------|
|
|
584
|
+
| (纯 string) | 纯文本片段 | — | — |
|
|
585
|
+
| \`"m"\` | 带格式文本 | \`text\` | \`b\`, \`l\`, \`u\`, \`h\`, \`tc\`, \`q\`, \`code\`, \`language\`, \`cId\`, \`iUrl\` |
|
|
586
|
+
| \`"q"\` | Rem 引用 | \`_id\` | \`content\`, \`showFullName\`, \`aliasId\` |
|
|
587
|
+
| \`"i"\` | 图片 | \`url\` | \`width\`, \`height\`, \`percent\`(25/50/100) |
|
|
588
|
+
| \`"x"\` | LaTeX | \`text\` | \`block\`(true=块级公式) |
|
|
589
|
+
| \`"a"\` | 音频/视频 | \`url\`, \`onlyAudio\`(**必填**) | \`width\`, \`height\` |
|
|
590
|
+
| \`"s"\` | 卡片分隔符 | — | \`delimiterCharacterForSerialization\` |
|
|
591
|
+
|
|
592
|
+
### 格式标记表(\`i:"m"\` 主要,但 \`i:"q"\` 等也支持部分标记)
|
|
593
|
+
|
|
594
|
+
| 字段 | 类型 | 含义 |
|
|
595
|
+
|:-----|:-----|:-----|
|
|
596
|
+
| \`b\` | \`true\` | 加粗 |
|
|
597
|
+
| \`l\` | \`true\` | 斜体(小写 L,不是大写 I) |
|
|
598
|
+
| \`u\` | \`true\` | 下划线 |
|
|
599
|
+
| \`h\` | number | 高亮颜色(RemColor 0-9) |
|
|
600
|
+
| \`tc\` | number | 文字颜色(RemColor 0-9) |
|
|
601
|
+
| \`q\` | \`true\` | 行内代码(红色等宽样式) |
|
|
602
|
+
| \`code\` | \`true\` | 代码块(带语言标签和复制按钮) |
|
|
603
|
+
| \`language\` | string | 代码语言(如 \`"python"\`) |
|
|
604
|
+
| \`cId\` | string | 完形填空 ID |
|
|
605
|
+
| \`hiddenCloze\` | \`true\` | 完形填空隐藏状态 |
|
|
606
|
+
| \`iUrl\` | string | 超链接 URL(**不是 \`url\`!**) |
|
|
607
|
+
| \`qId\` | string | 行内引用的 Rem ID |
|
|
608
|
+
|
|
609
|
+
### RemColor 颜色枚举(\`h\` 和 \`tc\` 共用)
|
|
610
|
+
|
|
611
|
+
| 值 | 颜色 | 值 | 颜色 | 值 | 颜色 |
|
|
612
|
+
|:---|:-----|:---|:-----|:---|:-----|
|
|
613
|
+
| 0 | 无/默认 | 4 | Green | 7 | Gray |
|
|
614
|
+
| 1 | Red | 5 | Purple | 8 | Brown |
|
|
615
|
+
| 2 | Orange | 6 | Blue | 9 | Pink |
|
|
616
|
+
| 3 | Yellow | — | — | — | — |
|
|
617
|
+
|
|
618
|
+
### 常用构造示例(key 字母序排列)
|
|
619
|
+
|
|
620
|
+
\`\`\`jsonc
|
|
621
|
+
{"b": true, "i": "m", "text": "粗体"} // 粗体
|
|
622
|
+
{"i": "m", "q": true, "text": "code"} // 行内代码
|
|
623
|
+
{"i": "m", "iUrl": "https://...", "text": "链接"} // 超链接(iUrl 不是 url!)
|
|
624
|
+
{"b": true, "h": 1, "i": "m", "text": "重点"} // 粗体+红色高亮
|
|
625
|
+
{"cId": "c1", "i": "m", "text": "答案"} // 完形填空
|
|
626
|
+
{"_id": "remId", "b": true, "i": "q"} // Rem 引用加粗
|
|
627
|
+
{"i": "x", "text": "E = mc^2"} // LaTeX
|
|
628
|
+
{"i": "a", "onlyAudio": false, "url": "..."} // 视频(onlyAudio 必填!)
|
|
629
|
+
{"i": "a", "onlyAudio": true, "url": "..."} // 音频
|
|
630
|
+
\`\`\`
|
|
477
631
|
|
|
478
|
-
|
|
632
|
+
### ⚠️ 关键陷阱
|
|
479
633
|
|
|
480
|
-
|
|
634
|
+
- \`i:"a"\` 的 \`onlyAudio\` 是**必填**字段(\`true\`=音频,\`false\`=视频),缺少会导致 SDK 拒绝写入
|
|
635
|
+
- 超链接必须用 \`iUrl\`,\`url\` 字段已废弃无效
|
|
636
|
+
- RichText 对象内部按 **key 字母序排列**(\`_id\` < \`b\` < \`cId\` < \`h\` < \`i\` < \`iUrl\` < \`text\`),确保序列化一致性
|
|
637
|
+
- \`highlightColor\`(RemObject 顶层,字符串 \`"Red"\`)与 \`h\`(RichText 内部,数字 \`1\`)完全独立——前者是整行背景色,后者是文字片段荧光底色
|
|
638
|
+
- 防线 2(乐观并发检测)依赖 key 字母序的确定性序列化来比较缓存与最新数据
|
|
481
639
|
|
|
482
640
|
---
|
|
483
641
|
|
|
484
|
-
##
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
642
|
+
## 7. Error Quick Reference
|
|
643
|
+
|
|
644
|
+
### 诊断决策树
|
|
645
|
+
|
|
646
|
+
\`\`\`
|
|
647
|
+
命令报错
|
|
648
|
+
├─ "守护进程未运行" → connect 未执行或 daemon 已超时 → 执行 connect
|
|
649
|
+
├─ "Plugin 未连接" → RemNote 未打开或插件未加载 → 引导用户操作 RemNote
|
|
650
|
+
├─ "SDK 未就绪" → 知识库尚未加载 → 等待并重试 health
|
|
651
|
+
├─ "has not been read yet" → 未先 read → 执行对应 read 后重试
|
|
652
|
+
├─ "has been modified since last read" → 被外部修改 → 必须重新 read(不可直接重试)
|
|
653
|
+
├─ "Invalid value" → 枚举字段值不合法 → 检查允许的值范围
|
|
654
|
+
├─ "old_str not found" → oldStr 不精确 → 检查缩进、空格、换行
|
|
655
|
+
├─ "old_str matches N locations" → oldStr 不够具体 → 扩大范围包含更多上下文
|
|
656
|
+
├─ "content_modified" → edit_tree 中改了行内容 → 用 edit_rem
|
|
657
|
+
├─ "orphan_detected" → 删了父但留了子 → 同时删除所有子行
|
|
658
|
+
├─ "folded_delete" → 删了有隐藏子节点的行 → 更大 depth 重新 read_tree
|
|
659
|
+
├─ "elided_modified" → 删/改了省略占位符 → 更大参数重新 read_tree
|
|
660
|
+
├─ "children_captured" → 新行劫持已有子节点 → 新行插到兄弟末尾
|
|
661
|
+
├─ "indent_skip" → 缩进跳级 → 每级 2 空格不可跳级
|
|
662
|
+
├─ "Rem not found" → remId 无效或已删除 → 用 search 重新定位
|
|
663
|
+
└─ "focusRemId 仅在 focus 模式下有效" → page 模式不支持 → 去掉参数或改用 focus 模式
|
|
664
|
+
\`\`\`
|
|
502
665
|
`;
|