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.
@@ -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
  > 多步骤组合链路,模拟真实的知识整理流程。