remnote-bridge 0.1.6 → 0.1.8
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 +30 -6
- package/dist/cli/commands/connect.js +31 -2
- package/dist/cli/commands/health.js +111 -1
- package/dist/cli/commands/setup.js +112 -0
- package/dist/cli/daemon/daemon.js +101 -20
- package/dist/cli/daemon/headless-browser.js +291 -0
- package/dist/cli/daemon/static-server.js +84 -0
- package/dist/cli/handlers/edit-handler.js +89 -3
- package/dist/cli/handlers/read-handler.js +16 -0
- package/dist/cli/handlers/tree-edit-handler.js +59 -28
- package/dist/cli/handlers/tree-parser.js +110 -3
- package/dist/cli/main.js +22 -6
- package/dist/cli/server/ws-server.js +62 -1
- package/dist/mcp/daemon-client.js +4 -1
- package/dist/mcp/instructions.js +97 -12
- package/dist/mcp/resources/edit-rem-guide.js +53 -0
- package/dist/mcp/resources/edit-tree-guide.js +60 -0
- package/dist/mcp/resources/error-reference.js +8 -1
- package/dist/mcp/resources/outline-format.js +29 -1
- package/dist/mcp/resources/rem-object-fields.js +6 -4
- package/dist/mcp/resources/separator-flashcard.js +5 -5
- package/dist/mcp/tools/infra-tools.js +39 -9
- package/package.json +5 -1
- package/remnote-plugin/dist/bridge-icon.svg +8 -0
- package/remnote-plugin/dist/bridge_widget-sandbox.js +65 -0
- package/remnote-plugin/dist/bridge_widget.js +65 -0
- package/remnote-plugin/dist/index-sandbox.css +591 -0
- package/remnote-plugin/dist/index-sandbox.js +64 -0
- package/remnote-plugin/dist/index.css +591 -0
- package/remnote-plugin/dist/index.html +9 -0
- package/remnote-plugin/dist/index.js +64 -0
- package/remnote-plugin/dist/manifest.json +22 -0
- package/remnote-plugin/src/bridge/message-router.ts +11 -0
- package/remnote-plugin/src/services/add-to-portal.ts +40 -0
- package/remnote-plugin/src/services/create-portal.ts +47 -0
- package/remnote-plugin/src/services/remove-from-portal.ts +40 -0
- package/remnote-plugin/src/services/write-rem-fields.ts +39 -0
- package/remnote-plugin/src/types.ts +7 -4
- package/skills/remnote-bridge/SKILL.md +90 -8
- package/skills/remnote-bridge/instructions/connect.md +48 -10
- package/skills/remnote-bridge/instructions/disconnect.md +1 -1
- package/skills/remnote-bridge/instructions/edit-rem.md +67 -4
- package/skills/remnote-bridge/instructions/edit-tree.md +100 -10
- package/skills/remnote-bridge/instructions/health.md +67 -1
- package/skills/remnote-bridge/instructions/overall.md +19 -4
- package/skills/remnote-bridge/instructions/read-rem.md +5 -2
- package/skills/remnote-bridge/instructions/setup.md +130 -0
|
@@ -45,10 +45,36 @@ newStr:
|
|
|
45
45
|
| \\\` → \\\` | \\\`问题 → 答案\\\` | 创建 forward 闪卡(单行) |
|
|
46
46
|
| \\\` ← \\\` | \\\`问题 ← 答案\\\` | 创建 backward 闪卡(单行) |
|
|
47
47
|
| \\\` ↔ \\\` | \\\`问题 ↔ 答案\\\` | 创建 both 闪卡(单行) |
|
|
48
|
+
| \\\` ↓ \\\` | \\\`问题 ↓ 答案\\\` | 创建 forward 多行闪卡(有 backText) |
|
|
49
|
+
| \\\` ↑ \\\` | \\\`问题 ↑ 答案\\\` | 创建 backward 多行闪卡(有 backText) |
|
|
50
|
+
| \\\` ↕ \\\` | \\\`问题 ↕ 答案\\\` | 创建 both 多行闪卡(有 backText) |
|
|
48
51
|
| \\\` ↓\\\` | \\\`问题 ↓\\\` | 创建 forward 多行闪卡(子节点为答案) |
|
|
49
52
|
| \\\` ↑\\\` | \\\`问题 ↑\\\` | 创建 backward 多行闪卡 |
|
|
50
53
|
| \\\` ↕\\\` | \\\`问题 ↕\\\` | 创建 both 多行闪卡 |
|
|
51
54
|
|
|
55
|
+
#### 新增行的元数据注释
|
|
56
|
+
|
|
57
|
+
新增行可以在行尾添加 HTML 注释来指定元数据属性(注意:没有 remId,以 \\\`type:\\\`/\\\`doc\\\`/\\\`tag:\\\` 开头):
|
|
58
|
+
|
|
59
|
+
\\\`\\\`\\\`
|
|
60
|
+
新概念 <!--type:concept-->
|
|
61
|
+
新描述 <!--type:descriptor-->
|
|
62
|
+
新文档 <!--doc-->
|
|
63
|
+
带标签 <!--tag:TagName(tagRemId)-->
|
|
64
|
+
组合使用 <!--type:concept doc tag:Physics(abc123)-->
|
|
65
|
+
\\\`\\\`\\\`
|
|
66
|
+
|
|
67
|
+
| 标记 | 效果 |
|
|
68
|
+
|------|------|
|
|
69
|
+
| \\\`type:concept\\\` | 设置 Rem 类型为 Concept |
|
|
70
|
+
| \\\`type:descriptor\\\` | 设置 Rem 类型为 Descriptor |
|
|
71
|
+
| \\\`doc\\\` | 将 Rem 标记为 Document |
|
|
72
|
+
| \\\`tag:Name(remId)\\\` | 添加指定 remId 的 Tag(可多个) |
|
|
73
|
+
|
|
74
|
+
与已有行行尾标记的区别:
|
|
75
|
+
- 已有行:\\\`文本 <!--remId type:concept doc-->\\\`(以 remId 开头)
|
|
76
|
+
- 新增行:\\\`文本 <!--type:concept doc-->\\\`(无 remId,直接以属性开头)
|
|
77
|
+
|
|
52
78
|
#### 嵌套新增
|
|
53
79
|
|
|
54
80
|
新增行下面可以再嵌套新增行,通过缩进表示父子关系:
|
|
@@ -63,6 +89,10 @@ newStr:
|
|
|
63
89
|
|
|
64
90
|
嵌套新增行的父 ID 通过内部占位标记管理,创建顺序保证从浅到深。
|
|
65
91
|
|
|
92
|
+
#### ⚠️ 插入位置
|
|
93
|
+
|
|
94
|
+
新行**不能**插在一个有子节点的 Rem 和它的 children 之间,否则 children 会被新行"劫持",触发 \\\`children_captured\\\` 错误。新行必须插在目标层级所有兄弟的**末尾**。
|
|
95
|
+
|
|
66
96
|
### 2. 删除行
|
|
67
97
|
|
|
68
98
|
从 newStr 中移除带 remId 的行。**必须同时删除该行的所有可见子行**,否则报 orphan_detected 错误。
|
|
@@ -123,6 +153,7 @@ newStr:
|
|
|
123
153
|
| 删除行但保留子节点 | \\\`orphan_detected\\\` | Cannot delete {id} because it has children that were not removed. | 同时删除所有子行 |
|
|
124
154
|
| 删除/修改省略占位符 | \\\`elided_modified\\\` | Cannot delete or modify elided region directly. | 用更大的 depth/maxSiblings 重新 read_tree 展开 |
|
|
125
155
|
| 缩进跳级 | \\\`indent_skip\\\` | 缩进跳级:行 ... 的缩进级别为 N,但找不到上一级的父节点。 | 检查缩进是否正确(每级 2 空格) |
|
|
156
|
+
| 新行劫持已有子节点 | \\\`children_captured\\\` | New line "..." accidentally captured existing children (...). | 把新行插到兄弟末尾,不要插在父 Rem 和 children 之间 |
|
|
126
157
|
|
|
127
158
|
---
|
|
128
159
|
|
|
@@ -194,4 +225,33 @@ newStr:
|
|
|
194
225
|
\\\`\\\`\\\`
|
|
195
226
|
|
|
196
227
|
结果:创建一个多行 forward 闪卡,问题为"什么是线性回归?",两个子行自动成为答案(isCardItem=true)。
|
|
228
|
+
|
|
229
|
+
## 示例 4:创建 Portal
|
|
230
|
+
|
|
231
|
+
Portal 新增行使用 \\\`<!--portal refs:id1,id2-->\\\` 语法(无文本内容,纯参数行):
|
|
232
|
+
|
|
233
|
+
\\\`\\\`\\\`
|
|
234
|
+
oldStr:
|
|
235
|
+
子节点 A <!--idA-->
|
|
236
|
+
|
|
237
|
+
newStr:
|
|
238
|
+
<!--portal refs:refId1,refId2-->
|
|
239
|
+
子节点 A <!--idA-->
|
|
240
|
+
\\\`\\\`\\\`
|
|
241
|
+
|
|
242
|
+
结果:创建一个 Portal,引用 refId1 和 refId2 两个 Rem。
|
|
243
|
+
|
|
244
|
+
空 Portal(无引用):
|
|
245
|
+
|
|
246
|
+
\\\`\\\`\\\`
|
|
247
|
+
<!--portal-->
|
|
248
|
+
\\\`\\\`\\\`
|
|
249
|
+
|
|
250
|
+
Portal 新增行与已有 Portal 行的区别:
|
|
251
|
+
- 已有 Portal:\\\`<!--remId type:portal refs:id1,id2-->\\\`(有 remId)
|
|
252
|
+
- 新增 Portal:\\\`<!--portal refs:id1,id2-->\\\`(无 remId,以 \\\`portal\\\` 关键字开头)
|
|
253
|
+
|
|
254
|
+
删除 Portal 与删除普通行相同——从 newStr 中移除该 Portal 行即可。
|
|
255
|
+
|
|
256
|
+
**注意**:修改已有 Portal 的引用列表(增删引用的 Rem)请使用 \\\`edit_rem\\\`,通过 str_replace 修改简化 JSON 中的 \\\`portalDirectlyIncludedRem\\\` 数组。
|
|
197
257
|
`;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
export const ERROR_REFERENCE_CONTENT = `
|
|
2
2
|
# Error Reference
|
|
3
3
|
|
|
4
|
-
|
|
4
|
+
所有工具错误的完整参考,按类别分组。
|
|
5
5
|
|
|
6
6
|
---
|
|
7
7
|
|
|
@@ -54,6 +54,8 @@ export const ERROR_REFERENCE_CONTENT = `
|
|
|
54
54
|
| Failed to update field '{field}': ... | SDK setter 调用失败 | 检查字段值是否在允许范围内 |
|
|
55
55
|
| Field '{fieldName}' is read-only and was ignored | 修改了只读字段 | **警告**(非阻断),该字段不可修改 |
|
|
56
56
|
| Setting 'todoStatus' without 'isTodo: true' may have no effect | todoStatus 非 null 但 isTodo=false | 先将 isTodo 设为 true |
|
|
57
|
+
| old_str not found in the simplified Portal JSON of rem {remId} | Portal 编辑时 oldStr 在 9 字段简化 JSON 中不匹配 | 检查 oldStr 是否匹配 Portal 简化 JSON 格式(9 字段:id、type、portalType、portalDirectlyIncludedRem、parent、positionAmongstSiblings、children、createdAt、updatedAt) |
|
|
58
|
+
| old_str matches {N} locations in Portal rem {remId}. Make old_str more specific to match exactly once. | Portal 编辑时 oldStr 在简化 JSON 中匹配多处 | 扩大 oldStr 范围以唯一定位 |
|
|
57
59
|
|
|
58
60
|
---
|
|
59
61
|
|
|
@@ -67,6 +69,7 @@ export const ERROR_REFERENCE_CONTENT = `
|
|
|
67
69
|
| Cannot delete {id} because it has children that were not removed. | \\\`orphan_detected\\\` | 删除了父行但保留了子行 | 必须同时删除所有子行 |
|
|
68
70
|
| Cannot delete or modify elided region directly. | \\\`elided_modified\\\` | 删除或修改了省略占位符 | 用更大的 depth/maxSiblings 重新 \\\`read_tree\\\` 展开 |
|
|
69
71
|
| 缩进跳级:行 ... 的缩进级别为 N,但找不到上一级的父节点。 | \\\`indent_skip\\\` | 新增行的缩进不正确 | 检查缩进(每级 2 空格) |
|
|
72
|
+
| New line "..." accidentally captured existing children (...). Insert the new line after the last child, not between a parent Rem and its children. | \\\`children_captured\\\` | 新增行插在了一个有子节点的 Rem 和它的 children 之间,劫持了已有子节点 | 把新行插到目标层级所有兄弟的**末尾**,不要插在父 Rem 紧后面 |
|
|
70
73
|
|
|
71
74
|
---
|
|
72
75
|
|
|
@@ -106,6 +109,7 @@ export const ERROR_REFERENCE_CONTENT = `
|
|
|
106
109
|
│
|
|
107
110
|
├─ "old_str not found"
|
|
108
111
|
│ ├─ 检查空格、换行、引号是否精确匹配
|
|
112
|
+
│ ├─ Portal Rem?检查是否匹配 9 字段简化 JSON(非完整 JSON)
|
|
109
113
|
│ └─ 重新 read 确认当前内容
|
|
110
114
|
│
|
|
111
115
|
├─ "old_str matches N locations"
|
|
@@ -117,6 +121,9 @@ export const ERROR_REFERENCE_CONTENT = `
|
|
|
117
121
|
├─ "Content modification not allowed"
|
|
118
122
|
│ └─ 改用 edit_rem 修改内容
|
|
119
123
|
│
|
|
124
|
+
├─ "children_captured"
|
|
125
|
+
│ └─ 把新行插到所有兄弟末尾,不要插在父 Rem 和 children 之间
|
|
126
|
+
│
|
|
120
127
|
├─ "orphan_detected"
|
|
121
128
|
│ └─ 同时删除父行的所有子行
|
|
122
129
|
│
|
|
@@ -86,7 +86,35 @@ read_tree / read_globe / read_context 的输出核心是 Markdown 大纲文本
|
|
|
86
86
|
|
|
87
87
|
---
|
|
88
88
|
|
|
89
|
-
## 6.
|
|
89
|
+
## 6. edit-tree 新增行的特殊格式
|
|
90
|
+
|
|
91
|
+
### 新增 Portal 行
|
|
92
|
+
|
|
93
|
+
在 edit-tree 的 newStr 中,用以下格式新增 Portal:
|
|
94
|
+
|
|
95
|
+
\\\`\\\`\\\`
|
|
96
|
+
<!--portal refs:id1,id2--> 新增 Portal 并引用 id1、id2
|
|
97
|
+
<!--portal--> 新增空 Portal(无引用)
|
|
98
|
+
\\\`\\\`\\\`
|
|
99
|
+
|
|
100
|
+
与已有 Portal 行(\\\`<!--remId type:portal refs:id1,id2-->\\\`)不同,新增 Portal 行没有 remId,以 \\\`<!--portal\\\` 开头。
|
|
101
|
+
|
|
102
|
+
### 新增行的 metadata-only 注释
|
|
103
|
+
|
|
104
|
+
新增行(无 remId)可在行尾用 HTML 注释指定类型、文档属性和标签,格式为仅包含元数据标记(不含 remId):
|
|
105
|
+
|
|
106
|
+
\\\`\\\`\\\`
|
|
107
|
+
新概念 <!--type:concept-->
|
|
108
|
+
新文档页 <!--type:concept doc-->
|
|
109
|
+
带标签 <!--type:descriptor tag:数学(tag01)-->
|
|
110
|
+
多标记组合 <!--type:concept doc tag:基础(tag02) tag:数学(tag01)-->
|
|
111
|
+
\\\`\\\`\\\`
|
|
112
|
+
|
|
113
|
+
支持的标记:\\\`type:concept\\\`、\\\`type:descriptor\\\`、\\\`doc\\\`、\\\`tag:Name(id)\\\`(可多个)。
|
|
114
|
+
|
|
115
|
+
---
|
|
116
|
+
|
|
117
|
+
## 7. 完整示例
|
|
90
118
|
|
|
91
119
|
\\\`\\\`\\\`markdown
|
|
92
120
|
# 数据结构 <!--kLr type:concept doc top-->
|
|
@@ -10,6 +10,7 @@ RemObject 是本项目对 RemNote Rem 的标准化表示,包含 51 个字段
|
|
|
10
10
|
| 标记 | 含义 | 数量 | 输出条件 |
|
|
11
11
|
|:-----|:-----|:-----|:---------|
|
|
12
12
|
| RW | 可读可写 | 20 | 默认输出 |
|
|
13
|
+
| Portal-W | Portal 专用可写 | 1 | 默认输出(Portal 简化模式) |
|
|
13
14
|
| R | 只读 | 14 | 默认输出 |
|
|
14
15
|
| R-F | 只读低频 | 17 | 仅 \\\`--full\\\` 输出 |
|
|
15
16
|
|
|
@@ -78,7 +79,7 @@ RemObject 是本项目对 RemNote Rem 的标准化表示,包含 51 个字段
|
|
|
78
79
|
| 字段 | 类型 | 权限 | 说明 |
|
|
79
80
|
|------|------|:----:|------|
|
|
80
81
|
| \\\`portalType\\\` | \\\`PortalType \\| null\\\` | R | Portal 子类型。仅 type=portal 时有值 |
|
|
81
|
-
| \\\`portalDirectlyIncludedRem\\\` | \\\`string[]\\\` |
|
|
82
|
+
| \\\`portalDirectlyIncludedRem\\\` | \\\`string[]\\\` | Portal-W | Portal 直接包含的 Rem ID。仅 type=portal 时可通过 edit-rem 修改(Diff 机制:addToPortal/removeFromPortal) |
|
|
82
83
|
|
|
83
84
|
## 属性类型
|
|
84
85
|
|
|
@@ -155,7 +156,7 @@ RemObject 是本项目对 RemNote Rem 的标准化表示,包含 51 个字段
|
|
|
155
156
|
|
|
156
157
|
## 可编辑字段约束表
|
|
157
158
|
|
|
158
|
-
以下为
|
|
159
|
+
以下为 21 个可编辑字段(RW + Portal-W)及其写入约束:
|
|
159
160
|
|
|
160
161
|
| 字段 | SDK setter | 值类型 | 约束 / 特殊处理 |
|
|
161
162
|
|------|-----------|--------|-----------------|
|
|
@@ -179,6 +180,7 @@ RemObject 是本项目对 RemNote Rem 的标准化表示,包含 51 个字段
|
|
|
179
180
|
| \\\`tags\\\` | \\\`rem.addTag()\\\` / \\\`rem.removeTag()\\\` | string[] | **Diff 机制**:对比当前 vs 目标,增删差异项 |
|
|
180
181
|
| \\\`sources\\\` | \\\`rem.addSource()\\\` / \\\`rem.removeSource()\\\` | string[] | **Diff 机制**:对比当前 vs 目标,增删差异项 |
|
|
181
182
|
| \\\`positionAmongstSiblings\\\` | \\\`rem.setParent(parent, position)\\\` | number \\| null | 与 \\\`parent\\\` 联动 |
|
|
183
|
+
| \\\`portalDirectlyIncludedRem\\\` | \\\`rem.addToPortal()\\\` / \\\`rem.removeFromPortal()\\\` | string[] | **Portal-W Diff 机制**:仅 type=portal 时可修改。对比当前 vs 目标数组,逐项增删 |
|
|
182
184
|
|
|
183
185
|
### parent + positionAmongstSiblings 联动
|
|
184
186
|
|
|
@@ -213,13 +215,13 @@ for id in currentSet:
|
|
|
213
215
|
|
|
214
216
|
## 只读字段列表
|
|
215
217
|
|
|
216
|
-
以下
|
|
218
|
+
以下 30 个字段在 str_replace 中被修改时,**只产生警告,不执行写入**:
|
|
217
219
|
|
|
218
220
|
\\\`\\\`\\\`
|
|
219
221
|
id,
|
|
220
222
|
children,
|
|
221
223
|
isTable,
|
|
222
|
-
portalType,
|
|
224
|
+
portalType,
|
|
223
225
|
propertyType,
|
|
224
226
|
aliases,
|
|
225
227
|
remsBeingReferenced, deepRemsBeingReferenced, remsReferencingThis,
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
export const SEPARATOR_FLASHCARD_CONTENT = `
|
|
2
2
|
# Separator & Flashcard Reference
|
|
3
3
|
|
|
4
|
-
**重要**:分隔符(\\\`::\\\`、\\\`;;\\\`、\\\`>>\\\` 等)是 RemNote
|
|
4
|
+
**重要**:分隔符(\\\`::\\\`、\\\`;;\\\`、\\\`>>\\\` 等)是 RemNote 编辑器的输入语法,**工具端不使用分隔符**。创建/修改闪卡,操作的是 \\\`type\\\`、\\\`backText\\\`、\\\`practiceDirection\\\` 字段和大纲箭头(\\\`→←↔↓↑↕\\\`)。本参考表用于理解用户意图——当用户提到分隔符时,映射到对应的工具操作。
|
|
5
5
|
|
|
6
6
|
---
|
|
7
7
|
|
|
8
|
-
## 1. 用户意图映射:编辑器分隔符 →
|
|
8
|
+
## 1. 用户意图映射:编辑器分隔符 → 工具操作
|
|
9
9
|
|
|
10
10
|
当用户提到以下分隔符时,对应的 Rem 属性为:
|
|
11
11
|
|
|
@@ -24,7 +24,7 @@ export const SEPARATOR_FLASHCARD_CONTENT = `
|
|
|
24
24
|
|
|
25
25
|
---
|
|
26
26
|
|
|
27
|
-
## 2.
|
|
27
|
+
## 2. 操作方式:大纲箭头
|
|
28
28
|
|
|
29
29
|
在 Markdown 大纲(read_tree / edit_tree)中,practiceDirection 编码为 Unicode 箭头:
|
|
30
30
|
|
|
@@ -66,7 +66,7 @@ RemNote 推荐的知识结构化方法:
|
|
|
66
66
|
- **Concept**(type:concept):需要理解的核心概念——"X 是什么?"
|
|
67
67
|
- **Descriptor**(type:descriptor):概念的属性/描述——"X 的 Y 是什么?"
|
|
68
68
|
|
|
69
|
-
|
|
69
|
+
在大纲中的表现(注意:用箭头和元数据标记,不用分隔符):
|
|
70
70
|
|
|
71
71
|
\\\`\\\`\\\`
|
|
72
72
|
线性回归 ↔ 最基本的回归模型 <!--id1 type:concept-->
|
|
@@ -76,7 +76,7 @@ RemNote 推荐的知识结构化方法:
|
|
|
76
76
|
|
|
77
77
|
---
|
|
78
78
|
|
|
79
|
-
## 5.
|
|
79
|
+
## 5. 创建闪卡
|
|
80
80
|
|
|
81
81
|
### 使用 edit_tree 新增行
|
|
82
82
|
|
|
@@ -1,18 +1,38 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* 基础设施工具:connect、disconnect、health
|
|
2
|
+
* 基础设施工具:setup、connect、disconnect、health
|
|
3
3
|
*/
|
|
4
4
|
import { z } from 'zod';
|
|
5
5
|
import { callCli } from '../daemon-client.js';
|
|
6
6
|
export function registerInfraTools(server) {
|
|
7
7
|
// -------------------------------------------------------------------------
|
|
8
|
-
//
|
|
8
|
+
// setup
|
|
9
9
|
// -------------------------------------------------------------------------
|
|
10
10
|
server.addTool({
|
|
11
|
-
name: '
|
|
12
|
-
description: '
|
|
11
|
+
name: 'setup',
|
|
12
|
+
description: '启动 Chrome 浏览器让用户登录 RemNote,保存登录凭证到本地 profile。这是使用 headless 模式(connect --headless)的前置步骤。\n\n调用后 Chrome 窗口会弹出,你需要立即告知用户:"已打开 Chrome,请在浏览器中登录 RemNote,并在 RemNote 中配置 dev plugin URL(http://localhost:8080),完成后用 Cmd+Q(macOS)或关闭窗口彻底退出 Chrome"。此工具会阻塞等待用户关闭 Chrome 后返回结果。\n\n幂等:已完成 setup 后重复调用返回 alreadyDone: true。\n超时:600 秒(用户可能需要较长时间完成登录、2FA 验证等)。\n前置条件:需要桌面环境(GUI),无 GUI 环境会报错。\n关联工具:connect(启动会话,传 headless 参数实现无人值守连接)',
|
|
13
13
|
parameters: z.object({}),
|
|
14
14
|
execute: async () => {
|
|
15
|
-
const response = await callCli('
|
|
15
|
+
const response = await callCli('setup', undefined, { timeoutMs: 600_000 });
|
|
16
|
+
return JSON.stringify(response, null, 2);
|
|
17
|
+
},
|
|
18
|
+
});
|
|
19
|
+
// -------------------------------------------------------------------------
|
|
20
|
+
// connect
|
|
21
|
+
// -------------------------------------------------------------------------
|
|
22
|
+
server.addTool({
|
|
23
|
+
name: 'connect',
|
|
24
|
+
description: '启动守护进程(daemon),建立 CLI 与 RemNote Plugin 之间的通信通道。这是所有业务命令(read_rem、edit_rem、search 等)的前置步骤。\n\n适用场景:\n- 开始一次 RemNote 操作会话前,必须先调用此工具\n- 不确定 daemon 是否在运行时,也可安全调用(幂等)\n\n两种模式:\n- 标准模式(默认):启动 daemon 后需要用户在 RemNote 中手动加载 Plugin\n- Headless 模式(headless=true):自动启动 headless Chrome 加载 Plugin,无需用户操作。需先完成 setup(保存登录凭证)\n\n输出:返回 JSON,关键字段 ok、alreadyRunning(是否已运行)、pid、wsPort、headless。\n幂等:重复调用不会启动多个 daemon。daemon 默认 30 分钟无活动自动关闭。\n关联工具:setup(headless 前置)、disconnect(结束会话)、health(检查状态)',
|
|
25
|
+
parameters: z.object({
|
|
26
|
+
headless: z.boolean().optional().describe('启用 headless 模式:自动启动 Chrome 加载 Plugin(需先 setup)'),
|
|
27
|
+
}),
|
|
28
|
+
execute: async (args) => {
|
|
29
|
+
const flags = [];
|
|
30
|
+
if (args.headless)
|
|
31
|
+
flags.push('--headless');
|
|
32
|
+
const response = await callCli('connect', undefined, {
|
|
33
|
+
timeoutMs: 90_000,
|
|
34
|
+
flags: flags.length > 0 ? flags : undefined,
|
|
35
|
+
});
|
|
16
36
|
return JSON.stringify(response, null, 2);
|
|
17
37
|
},
|
|
18
38
|
});
|
|
@@ -33,10 +53,20 @@ export function registerInfraTools(server) {
|
|
|
33
53
|
// -------------------------------------------------------------------------
|
|
34
54
|
server.addTool({
|
|
35
55
|
name: 'health',
|
|
36
|
-
description: '检查系统三层状态(daemon 守护进程 / Plugin 连接 / SDK 就绪),用于诊断连接问题。\n\n适用场景:\n- 业务命令失败时,首先调用 health 定位故障层级\n- 执行 connect 后确认通道是否完全就绪\n- 长时间未操作后,检查 daemon 是否仍在运行\n\n输出:返回 JSON,关键字段 ok(三层是否全部健康)、daemon.running、plugin.connected、sdk.ready、timeoutRemaining
|
|
37
|
-
parameters: z.object({
|
|
38
|
-
|
|
39
|
-
|
|
56
|
+
description: '检查系统三层状态(daemon 守护进程 / Plugin 连接 / SDK 就绪),用于诊断连接问题。\n\n适用场景:\n- 业务命令失败时,首先调用 health 定位故障层级\n- 执行 connect 后确认通道是否完全就绪\n- 长时间未操作后,检查 daemon 是否仍在运行\n\n输出:返回 JSON,关键字段 ok(三层是否全部健康)、daemon.running、plugin.connected、sdk.ready、timeoutRemaining。headless 模式下额外包含 headless 对象。\n三层有严格依赖:daemon 运行 → Plugin 连接 → SDK 就绪。\nok 为 false 时:daemon 未运行则 connect;Plugin 未连接则确认 RemNote 已打开(或使用 headless 模式);SDK 未就绪则等待重试。\n\n--diagnose 模式(headless 专用):截图 + 详细状态 + console 错误 + 排查建议。\n--reload 模式(headless 专用):重载 headless Chrome 页面。\n\n只读不写,不改变任何状态(--reload 除外)。\n关联工具:connect(启动)、disconnect(结束)',
|
|
57
|
+
parameters: z.object({
|
|
58
|
+
diagnose: z.boolean().optional().describe('诊断 headless Chrome(截图 + 状态 + console 错误)'),
|
|
59
|
+
reload: z.boolean().optional().describe('重载 headless Chrome 页面'),
|
|
60
|
+
}),
|
|
61
|
+
execute: async (args) => {
|
|
62
|
+
const flags = [];
|
|
63
|
+
if (args.diagnose)
|
|
64
|
+
flags.push('--diagnose');
|
|
65
|
+
if (args.reload)
|
|
66
|
+
flags.push('--reload');
|
|
67
|
+
const response = await callCli('health', undefined, {
|
|
68
|
+
flags: flags.length > 0 ? flags : undefined,
|
|
69
|
+
});
|
|
40
70
|
return JSON.stringify(response, null, 2);
|
|
41
71
|
},
|
|
42
72
|
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "remnote-bridge",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.8",
|
|
4
4
|
"description": "RemNote 自动化桥接工具集:CLI + MCP Server + Plugin",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
},
|
|
10
10
|
"files": [
|
|
11
11
|
"dist/**/*.js",
|
|
12
|
+
"remnote-plugin/dist/",
|
|
12
13
|
"remnote-plugin/src/bridge/",
|
|
13
14
|
"remnote-plugin/src/services/",
|
|
14
15
|
"remnote-plugin/src/utils/",
|
|
@@ -27,12 +28,15 @@
|
|
|
27
28
|
],
|
|
28
29
|
"scripts": {
|
|
29
30
|
"build": "tsc",
|
|
31
|
+
"build:plugin": "cd remnote-plugin && npm install && npm run build",
|
|
32
|
+
"prepublishOnly": "npm run build && npm run build:plugin",
|
|
30
33
|
"dev": "tsx src/cli/main.ts",
|
|
31
34
|
"test": "vitest run",
|
|
32
35
|
"lint:deps": "node scripts/check-layer-deps.cjs"
|
|
33
36
|
},
|
|
34
37
|
"dependencies": {
|
|
35
38
|
"commander": "^12.1.0",
|
|
39
|
+
"puppeteer-core": "^24.0.0",
|
|
36
40
|
"ws": "^8.16.0",
|
|
37
41
|
"fastmcp": "latest",
|
|
38
42
|
"zod": "^3.23.0"
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
2
|
+
<!-- Bidirectional arrows -->
|
|
3
|
+
<path d="M3 8 L9 8 M7 6 L9 8 L7 10" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" fill="none"/>
|
|
4
|
+
<path d="M21 8 L15 8 M17 6 L15 8 L17 10" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" fill="none"/>
|
|
5
|
+
|
|
6
|
+
<!-- MCP text -->
|
|
7
|
+
<text x="12" y="19" text-anchor="middle" font-size="7" fill="currentColor" font-weight="700" font-family="system-ui, -apple-system, sans-serif">MCP</text>
|
|
8
|
+
</svg>
|