remnote-bridge 0.1.15 → 0.1.16
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/dist/cli/commands/edit-tree.js +12 -1
- package/dist/cli/handlers/tree-edit-handler.js +3 -1
- package/dist/cli/handlers/tree-parser.js +17 -0
- package/dist/mcp/instructions.js +5 -3
- package/dist/mcp/tools/edit-tools.js +2 -1
- package/package.json +1 -1
- package/remnote-plugin/dist/index-sandbox.js +19 -19
- package/remnote-plugin/dist/index.js +19 -19
- package/remnote-plugin/src/services/rem-builder.ts +8 -2
- package/remnote-plugin/src/utils/tree-serializer.ts +10 -0
- package/skills/remnote-bridge/SKILL.md +4 -0
- package/skills/remnote-bridge/instructions/edit-tree.md +11 -1
- package/skills/remnote-bridge/instructions/overall.md +10 -0
- package/skills/remnote-bridge-test/SKILL.md +3 -0
- package/skills/remnote-bridge-test/references/regression-suite.md +64 -0
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
* 依赖方向:services/rem-builder → utils/tree-serializer(单向)
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
|
-
import type { ReactRNPlugin, PluginRem as Rem } from '@remnote/plugin-sdk';
|
|
10
|
+
import type { ReactRNPlugin, PluginRem as Rem, RichTextInterface } from '@remnote/plugin-sdk';
|
|
11
11
|
import type { SerializableRem } from '../utils/tree-serializer';
|
|
12
12
|
import { filterNoisyTags } from './powerup-filter';
|
|
13
13
|
|
|
@@ -21,7 +21,7 @@ export async function safeToMarkdown(
|
|
|
21
21
|
richText: unknown[],
|
|
22
22
|
): Promise<string> {
|
|
23
23
|
try {
|
|
24
|
-
return await plugin.richText.toMarkdown(richText);
|
|
24
|
+
return await plugin.richText.toMarkdown(richText as RichTextInterface);
|
|
25
25
|
} catch {
|
|
26
26
|
return richTextFallback(richText);
|
|
27
27
|
}
|
|
@@ -93,6 +93,8 @@ export async function buildFullSerializableRem(
|
|
|
93
93
|
isTodo,
|
|
94
94
|
todoStatus,
|
|
95
95
|
isCode,
|
|
96
|
+
isQuote,
|
|
97
|
+
isListItem,
|
|
96
98
|
hasDvPowerup,
|
|
97
99
|
portalIncludedRems,
|
|
98
100
|
] = await Promise.all([
|
|
@@ -114,6 +116,8 @@ export async function buildFullSerializableRem(
|
|
|
114
116
|
rem.isTodo(),
|
|
115
117
|
rem.getTodoStatus(),
|
|
116
118
|
rem.isCode(),
|
|
119
|
+
rem.isQuote(),
|
|
120
|
+
rem.isListItem(),
|
|
117
121
|
rem.hasPowerup('dv'),
|
|
118
122
|
rem.type === 6 ? rem.getPortalDirectlyIncludedRem() : Promise.resolve([]),
|
|
119
123
|
]);
|
|
@@ -151,6 +155,8 @@ export async function buildFullSerializableRem(
|
|
|
151
155
|
isTodo,
|
|
152
156
|
todoStatus: (todoStatus as 'Finished' | 'Unfinished' | null) ?? null,
|
|
153
157
|
isCode,
|
|
158
|
+
isQuote,
|
|
159
|
+
isListItem,
|
|
154
160
|
isDivider,
|
|
155
161
|
isTopLevel: rem.parent === null,
|
|
156
162
|
};
|
|
@@ -65,6 +65,8 @@ export interface SerializableRem {
|
|
|
65
65
|
isTodo: boolean;
|
|
66
66
|
todoStatus: 'Finished' | 'Unfinished' | null;
|
|
67
67
|
isCode: boolean;
|
|
68
|
+
isQuote: boolean;
|
|
69
|
+
isListItem: boolean;
|
|
68
70
|
isDivider: boolean;
|
|
69
71
|
/** 是否为知识库顶级 Rem(无父节点) */
|
|
70
72
|
isTopLevel?: boolean;
|
|
@@ -131,6 +133,12 @@ function buildLineContent(rem: SerializableRem): string {
|
|
|
131
133
|
// Code 包裹(最内层)
|
|
132
134
|
if (rem.isCode) baseContent = '`' + baseContent + '`';
|
|
133
135
|
|
|
136
|
+
// ListItem 前缀(有序列表)
|
|
137
|
+
if (rem.isListItem) baseContent = '1. ' + baseContent;
|
|
138
|
+
|
|
139
|
+
// Quote 前缀(引用块)
|
|
140
|
+
if (rem.isQuote) baseContent = '> ' + baseContent;
|
|
141
|
+
|
|
134
142
|
// Todo 前缀
|
|
135
143
|
if (rem.isTodo) {
|
|
136
144
|
const cb = rem.todoStatus === 'Finished' ? '- [x] ' : '- [ ] ';
|
|
@@ -207,6 +215,8 @@ export function createMinimalSerializableRem(
|
|
|
207
215
|
isTodo: false,
|
|
208
216
|
todoStatus: null,
|
|
209
217
|
isCode: false,
|
|
218
|
+
isQuote: false,
|
|
219
|
+
isListItem: false,
|
|
210
220
|
isDivider: false,
|
|
211
221
|
...overrides,
|
|
212
222
|
};
|
|
@@ -451,6 +451,8 @@ read-tree / read-globe / read-context 输出 Markdown 大纲,edit-tree 基于
|
|
|
451
451
|
|:-----|:-----|
|
|
452
452
|
| `# ` / `## ` / `### ` | H1/H2/H3 标题 |
|
|
453
453
|
| `- [ ] ` / `- [x] ` | 未完成/已完成待办 |
|
|
454
|
+
| `> ` | 引用块 |
|
|
455
|
+
| `1. ` | 有序列表项 |
|
|
454
456
|
| `` `...` `` | 代码块 |
|
|
455
457
|
| `---` | 分隔线 |
|
|
456
458
|
|
|
@@ -521,6 +523,8 @@ read-tree / read-globe / read-context 输出 Markdown 大纲,edit-tree 基于
|
|
|
521
523
|
新闪卡 → 答案
|
|
522
524
|
问题 ↔ 回答
|
|
523
525
|
- [ ] 新待办
|
|
526
|
+
> 引用内容
|
|
527
|
+
1. 列表项
|
|
524
528
|
`代码块`
|
|
525
529
|
```
|
|
526
530
|
|
|
@@ -251,10 +251,20 @@ newStr: " 新增节点\n 子节点 A <!--idA-->"
|
|
|
251
251
|
| `### text` | 创建 H3 标题 |
|
|
252
252
|
| `- [ ] text` | 创建未完成待办 |
|
|
253
253
|
| `- [x] text` | 创建已完成待办 |
|
|
254
|
+
| `1. text` | 创建有序列表项 |
|
|
254
255
|
| `` `text` `` | 创建代码块 |
|
|
255
256
|
| `---` | 创建分隔线 |
|
|
256
257
|
|
|
257
|
-
前缀可组合叠加,解析顺序为 Header → Todo → Code。例如 `## - [ ] text` 创建 H2 + 未完成待办。
|
|
258
|
+
前缀可组合叠加,解析顺序为 Header → Todo → Quote → ListItem → Code。例如 `## - [ ] text` 创建 H2 + 未完成待办。
|
|
259
|
+
|
|
260
|
+
> **⚠️ 有序列表必须用 `1. ` 前缀**
|
|
261
|
+
>
|
|
262
|
+
> RemNote 的有序列表采用 Lazy Numbering 风格——所有列表项统一写 `1. `,RemNote 按层级自动编号为 1./2./3./A./B./I./II. 等。
|
|
263
|
+
>
|
|
264
|
+
> - **正确**:`1. 第一项`、`1. 第二项`、`1. 第三项`(全部用 `1. `)
|
|
265
|
+
> - **错误**:`2. 第二项`、`3. 第三项`(手动编号无意义,RemNote 会忽略)
|
|
266
|
+
>
|
|
267
|
+
> 系统会容错处理 `2. `~`9. ` 前缀(自动归一化为 `isListItem=true` 并返回 `templateWarnings` 警告),但 `10. ` 及以上不会被识别为有序列表,而是作为纯文本保留。
|
|
258
268
|
|
|
259
269
|
#### 新增行的箭头分隔符
|
|
260
270
|
|
|
@@ -642,9 +642,17 @@ read-tree / read-globe / read-context 的输出核心是 Markdown 大纲文本
|
|
|
642
642
|
| `### ` | H3 标题 | `fontSize: 'H3'` |
|
|
643
643
|
| `- [ ] ` | 未完成待办 | `isTodo: true, todoStatus: 'Unfinished'` |
|
|
644
644
|
| `- [x] ` | 已完成待办 | `isTodo: true, todoStatus: 'Finished'` |
|
|
645
|
+
| `> ` | 引用块 | `isQuote: true` |
|
|
646
|
+
| `1. ` | 有序列表项(⚠️ 见下方说明) | `isListItem: true` |
|
|
645
647
|
| `` `...` `` | 代码块 | `isCode: true` |
|
|
646
648
|
| `---` | 分隔线 | Divider Powerup |
|
|
647
649
|
|
|
650
|
+
> **⚠️ 有序列表必须用 `1. ` 前缀(Lazy Numbering)**
|
|
651
|
+
>
|
|
652
|
+
> RemNote 有序列表采用 Lazy Numbering——所有列表项统一写 `1. `,RemNote 按层级自动编号(1./2./3./A./B./I./II.)。不要手动编号。
|
|
653
|
+
> - `2. `~`9. ` 会被容错处理(归一化为 `isListItem=true`,返回 `templateWarnings` 警告)
|
|
654
|
+
> - `10. ` 及以上**不会**被识别为有序列表,而是作为纯文本内容保留
|
|
655
|
+
|
|
648
656
|
### 8.3 箭头分隔符
|
|
649
657
|
|
|
650
658
|
箭头编码 `practiceDirection`(闪卡练习方向),不编码 type(type 由元数据标记承载)。
|
|
@@ -811,6 +819,8 @@ edit-tree 使用 str_replace 对 Markdown 大纲进行结构编辑。详细文
|
|
|
811
819
|
# 新标题 H1
|
|
812
820
|
新闪卡 → 答案
|
|
813
821
|
- [ ] 新待办
|
|
822
|
+
> 引用内容
|
|
823
|
+
1. 列表项
|
|
814
824
|
`代码块内容`
|
|
815
825
|
```
|
|
816
826
|
|
|
@@ -140,6 +140,9 @@ Skill 接口加 `s` 后缀(**s** = Skill)。这样两个 subagent 创建的
|
|
|
140
140
|
### Step 2:构造 subagent 并执行
|
|
141
141
|
|
|
142
142
|
使用 haiku subagent 执行测试。
|
|
143
|
+
严禁只使用单个 sub-agent 进行测试。
|
|
144
|
+
除非测试用例有特别说明,否则必须同时启用 MCP 和 Skill 两个 sub-agent 进行测试。根据测试要求,动态决定是否并行。
|
|
145
|
+
严禁只测一个 sub-agent 的行为。
|
|
143
146
|
|
|
144
147
|
#### 双接口策略
|
|
145
148
|
|
|
@@ -270,6 +270,70 @@
|
|
|
270
270
|
|
|
271
271
|
---
|
|
272
272
|
|
|
273
|
+
### L2-05: Markdown 前缀转换(有序列表 + 引用块)
|
|
274
|
+
|
|
275
|
+
**task_description**:
|
|
276
|
+
```
|
|
277
|
+
测试 Markdown 前缀(有序列表 `1. ` 和引用块 `> `)的双向转换能力。
|
|
278
|
+
|
|
279
|
+
1. 确认连接正常
|
|
280
|
+
2. 读取测试页面的子树(read_tree)
|
|
281
|
+
3. 在测试页面下创建以下结构(edit_tree),包含有序列表和引用块,层级嵌套到 4 层:
|
|
282
|
+
|
|
283
|
+
{prefix} Markdown 前缀测试
|
|
284
|
+
## 有序列表测试
|
|
285
|
+
1. 第一层列表项A
|
|
286
|
+
1. 第二层列表项A-1
|
|
287
|
+
1. 第三层列表项A-1-a
|
|
288
|
+
1. 第四层列表项A-1-a-i
|
|
289
|
+
1. 第四层列表项A-1-a-ii
|
|
290
|
+
1. 第三层列表项A-1-b
|
|
291
|
+
1. 第二层列表项A-2
|
|
292
|
+
1. 第一层列表项B
|
|
293
|
+
1. 第二层列表项B-1
|
|
294
|
+
1. 第二层列表项B-2
|
|
295
|
+
1. 第三层列表项B-2-a
|
|
296
|
+
## 引用块测试
|
|
297
|
+
> 这是一段引用文本
|
|
298
|
+
> 这是另一段引用
|
|
299
|
+
普通文本(不是引用)
|
|
300
|
+
## 混合格式测试
|
|
301
|
+
1. 有序列表项带闪卡 → 答案内容
|
|
302
|
+
> 引用块带闪卡 → 引用中的答案
|
|
303
|
+
- [ ] 待办事项
|
|
304
|
+
`代码块内容`
|
|
305
|
+
|
|
306
|
+
4. 重新读取子树(read_tree,depth=5),验证:
|
|
307
|
+
- 有序列表项都有 `1. ` 前缀
|
|
308
|
+
- 引用块都有 `> ` 前缀
|
|
309
|
+
- 4 层嵌套的有序列表层级正确
|
|
310
|
+
- 普通文本没有 `1. ` 或 `> ` 前缀
|
|
311
|
+
- 混合格式中各前缀正确(`1. `、`> `、`- [ ] `、反引号)
|
|
312
|
+
|
|
313
|
+
5. 对任意 2 个有序列表节点和 1 个引用块节点执行 read_rem,验证:
|
|
314
|
+
- 有序列表节点 isListItem=true
|
|
315
|
+
- 引用块节点 isQuote=true
|
|
316
|
+
- 普通文本节点 isListItem=false, isQuote=false
|
|
317
|
+
```
|
|
318
|
+
|
|
319
|
+
**Chrome 验证**:
|
|
320
|
+
- ⬜ "{prefix} Markdown 前缀测试" 存在
|
|
321
|
+
- ⬜ "有序列表测试" 下的节点显示为数字编号(1. 2. 3...),而非 bullet
|
|
322
|
+
- ⬜ 有序列表嵌套到 4 层,每层都有数字编号
|
|
323
|
+
- ⬜ "引用块测试" 下有灰色引用样式(左侧竖线 + 浅灰背景)
|
|
324
|
+
- ⬜ "普通文本(不是引用)" 是正常样式,没有引用标记
|
|
325
|
+
- ⬜ 混合格式区域各格式正确(有序列表、引用、待办、代码块共存)
|
|
326
|
+
|
|
327
|
+
**断言**:
|
|
328
|
+
- [ ] edit_tree 成功创建包含 `1. ` 和 `> ` 前缀的结构
|
|
329
|
+
- [ ] read_tree 输出中有序列表项带 `1. ` 前缀
|
|
330
|
+
- [ ] read_tree 输出中引用块带 `> ` 前缀
|
|
331
|
+
- [ ] 4 层嵌套有序列表结构完整
|
|
332
|
+
- [ ] read_rem 确认 isListItem=true / isQuote=true
|
|
333
|
+
- [ ] 混合格式互不干扰
|
|
334
|
+
|
|
335
|
+
---
|
|
336
|
+
|
|
273
337
|
## L3 多步工作流
|
|
274
338
|
|
|
275
339
|
> 多步骤组合链路,模拟真实的知识整理流程。
|