remnote-bridge 0.1.5 → 0.1.7
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/connect.js +5 -4
- 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 +1 -1
- package/dist/mcp/instructions.js +47 -9
- 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/package.json +1 -1
- 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 +42 -4
- package/skills/remnote-bridge/instructions/connect.md +11 -3
- 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/overall.md +18 -3
- package/skills/remnote-bridge/instructions/read-rem.md +5 -2
|
@@ -198,6 +198,10 @@ remnote-bridge edit-rem --json '{"remId":"kLrIOHJLyMd8Y2lyA","oldStr":"\"concept
|
|
|
198
198
|
│ ├─ 与缓存 JSON 严格比较
|
|
199
199
|
│ └─ 不匹配 → 抛出错误(不更新缓存,迫使 AI re-read)
|
|
200
200
|
│
|
|
201
|
+
├─ Portal 检测:type === 'portal'?
|
|
202
|
+
│ ├─ 是 → 进入 Portal 专用路径(简化 JSON 上执行 str_replace)
|
|
203
|
+
│ └─ 否 → 继续普通 Rem 路径
|
|
204
|
+
│
|
|
201
205
|
├─ 防线 3: str_replace 精确匹配
|
|
202
206
|
│ ├─ countOccurrences(cachedJson, oldStr)
|
|
203
207
|
│ ├─ 0 次 → 抛出"未找到"错误
|
|
@@ -338,11 +342,68 @@ edit-rem(remId, oldStr, newStr)
|
|
|
338
342
|
|
|
339
343
|
---
|
|
340
344
|
|
|
345
|
+
## Portal 编辑专用路径
|
|
346
|
+
|
|
347
|
+
当 edit-rem 检测到被编辑的 Rem 是 Portal(`type === 'portal'`)时,自动切换到 Portal 专用编辑路径。
|
|
348
|
+
|
|
349
|
+
### 简化 JSON 作为操作目标
|
|
350
|
+
|
|
351
|
+
**问题**:缓存中存储完整 51 字段 JSON,但 AI 看到的是 9 字段简化 JSON。oldStr 来自简化输出,在完整 JSON 上匹配不到。
|
|
352
|
+
|
|
353
|
+
**方案**:Portal 路径在**简化 JSON**(9 字段)上执行 str_replace:
|
|
354
|
+
|
|
355
|
+
1. 防线 1 + 2:不变(完整 JSON 对比)
|
|
356
|
+
2. **str_replace**:将缓存的完整 JSON 转换为简化 JSON,在简化 JSON 上执行 str_replace
|
|
357
|
+
3. 解析 str_replace 后的简化 JSON,推导变更字段
|
|
358
|
+
4. 调用写入
|
|
359
|
+
|
|
360
|
+
### Portal 简化 JSON 格式
|
|
361
|
+
|
|
362
|
+
```json
|
|
363
|
+
{
|
|
364
|
+
"id": "abc123",
|
|
365
|
+
"type": "portal",
|
|
366
|
+
"portalType": "portal",
|
|
367
|
+
"portalDirectlyIncludedRem": ["remId1", "remId2"],
|
|
368
|
+
"parent": "parentId",
|
|
369
|
+
"positionAmongstSiblings": 3,
|
|
370
|
+
"children": ["remId1", "remId2"],
|
|
371
|
+
"createdAt": 1709000000000,
|
|
372
|
+
"updatedAt": 1709000000000
|
|
373
|
+
}
|
|
374
|
+
```
|
|
375
|
+
|
|
376
|
+
### Portal 可写字段
|
|
377
|
+
|
|
378
|
+
| 字段 | 写入方式 |
|
|
379
|
+
|:-----|:---------|
|
|
380
|
+
| `portalDirectlyIncludedRem` | diff 数组,新增调 `addToPortal()`,移除调 `removeFromPortal()` |
|
|
381
|
+
| `parent` | 调 `setParent()` |
|
|
382
|
+
| `positionAmongstSiblings` | 调 `setParent(parent, position)` |
|
|
383
|
+
|
|
384
|
+
### Portal 只读字段
|
|
385
|
+
|
|
386
|
+
id、type、portalType、children、createdAt、updatedAt — 修改只产生警告。
|
|
387
|
+
|
|
388
|
+
### Portal 编辑示例
|
|
389
|
+
|
|
390
|
+
```bash
|
|
391
|
+
# 添加一个引用
|
|
392
|
+
edit-rem abc123 --old-str '"portalDirectlyIncludedRem": ["remId1", "remId2"]' \
|
|
393
|
+
--new-str '"portalDirectlyIncludedRem": ["remId1", "remId2", "remId3"]'
|
|
394
|
+
|
|
395
|
+
# 移除一个引用
|
|
396
|
+
edit-rem abc123 --old-str '"portalDirectlyIncludedRem": ["remId1", "remId2"]' \
|
|
397
|
+
--new-str '"portalDirectlyIncludedRem": ["remId1"]'
|
|
398
|
+
```
|
|
399
|
+
|
|
400
|
+
---
|
|
401
|
+
|
|
341
402
|
## 可编辑字段约束表
|
|
342
403
|
|
|
343
|
-
RemObject 51 个字段中,
|
|
404
|
+
RemObject 51 个字段中,21 个可编辑(RW),30 个只读(R + R-F)。
|
|
344
405
|
|
|
345
|
-
以下为
|
|
406
|
+
以下为 21 个可编辑字段及其写入约束:
|
|
346
407
|
|
|
347
408
|
| 字段 | SDK setter | 值类型 | 约束 / 特殊处理 |
|
|
348
409
|
|------|-----------|--------|-----------------|
|
|
@@ -366,6 +427,7 @@ RemObject 51 个字段中,20 个可编辑(RW),31 个只读(R + R-F)
|
|
|
366
427
|
| `tags` | `rem.addTag()` / `rem.removeTag()` | string[] | **Diff 机制**:对比当前 vs 目标,增删差异项 |
|
|
367
428
|
| `sources` | `rem.addSource()` / `rem.removeSource()` | string[] | **Diff 机制**:对比当前 vs 目标,增删差异项 |
|
|
368
429
|
| `positionAmongstSiblings` | `rem.setParent(parent, position)` | number \| null | 与 `parent` 联动(见下方说明) |
|
|
430
|
+
| `portalDirectlyIncludedRem` | `rem.addToPortal()` / `rem.removeFromPortal()` | string[] | **Portal-W Diff 机制**:仅 type=portal 时可修改。对比当前 vs 目标数组,逐项增删 |
|
|
369
431
|
|
|
370
432
|
### parent + positionAmongstSiblings 联动
|
|
371
433
|
|
|
@@ -400,13 +462,13 @@ for id in currentSet:
|
|
|
400
462
|
|
|
401
463
|
## 只读字段列表
|
|
402
464
|
|
|
403
|
-
以下
|
|
465
|
+
以下 30 个字段在 str_replace 中被修改时,**只产生警告,不执行写入**:
|
|
404
466
|
|
|
405
467
|
```
|
|
406
468
|
id,
|
|
407
469
|
children,
|
|
408
470
|
isTable,
|
|
409
|
-
portalType,
|
|
471
|
+
portalType,
|
|
410
472
|
propertyType,
|
|
411
473
|
aliases,
|
|
412
474
|
remsBeingReferenced, deepRemsBeingReferenced, remsReferencingThis,
|
|
@@ -652,4 +714,5 @@ newStr: "\"text\": [\n \"光合作用需要\",\n {\n \"cId\": \"cloz
|
|
|
652
714
|
| `invalid JSON` | 替换后的文本不是合法 JSON | 检查 newStr 的引号、逗号、括号完整性 |
|
|
653
715
|
| `Failed to update field` | SDK setter 调用失败 | 检查字段值是否在允许范围内(如 type 不能设为 portal) |
|
|
654
716
|
| `Field '...' is read-only and was ignored` | 修改了只读字段 | 该字段只能读取,不可通过 edit-rem 修改 |
|
|
717
|
+
| `old_str not found in the simplified Portal JSON` | Portal 编辑时 oldStr 在简化 JSON 中不匹配 | 检查 oldStr 是否匹配 9 字段简化 JSON 格式(而非完整 51 字段 JSON) |
|
|
655
718
|
| `守护进程未运行` | daemon 未启动 | 执行 `remnote-bridge connect` |
|
|
@@ -201,16 +201,78 @@ newStr:
|
|
|
201
201
|
| `` `text` `` | 创建代码块 |
|
|
202
202
|
| `---` | 创建分隔线 |
|
|
203
203
|
|
|
204
|
+
前缀可组合叠加,解析顺序为 Header → Todo → Code。例如 `## - [ ] text` 创建 H2 + 未完成待办。
|
|
205
|
+
|
|
204
206
|
#### 新增行的箭头分隔符
|
|
205
207
|
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
|
211
|
-
|
|
212
|
-
| `
|
|
213
|
-
| `
|
|
208
|
+
箭头分隔符分为两类:**中间箭头**(有 backText)和**尾部箭头**(无 backText,子节点为答案)。
|
|
209
|
+
|
|
210
|
+
**中间箭头**(格式:`问题 {箭头} 答案`):
|
|
211
|
+
|
|
212
|
+
| 箭头 | 效果 |
|
|
213
|
+
|------|------|
|
|
214
|
+
| ` → ` | forward 闪卡(单行) |
|
|
215
|
+
| ` ← ` | backward 闪卡(单行) |
|
|
216
|
+
| ` ↔ ` | both 闪卡(单行) |
|
|
217
|
+
| ` ↓ ` | forward 多行闪卡(带 backText) |
|
|
218
|
+
| ` ↑ ` | backward 多行闪卡(带 backText) |
|
|
219
|
+
| ` ↕ ` | both 多行闪卡(带 backText) |
|
|
220
|
+
|
|
221
|
+
**尾部箭头**(格式:`问题 {箭头}`,子节点为答案):
|
|
222
|
+
|
|
223
|
+
| 箭头 | 效果 |
|
|
224
|
+
|------|------|
|
|
225
|
+
| ` ↓` | forward 多行闪卡 |
|
|
226
|
+
| ` ↑` | backward 多行闪卡 |
|
|
227
|
+
| ` ↕` | both 多行闪卡 |
|
|
228
|
+
|
|
229
|
+
> 已知限制:使用 indexOf 匹配第一个箭头,如果新增行内容本身包含箭头字符(如 `A → B → C`),会被误切割为 text + backText。
|
|
230
|
+
|
|
231
|
+
#### 新增行的元数据注释
|
|
232
|
+
|
|
233
|
+
在新增行末尾添加 HTML 注释可设置 Rem 属性(type、isDocument、tag)。注意:这是**不含 remId 的纯元数据注释**,与已有行的行尾标记(`<!--remId metadata-->`)格式不同。
|
|
234
|
+
|
|
235
|
+
语法:`<!--token1 token2 ...-->`
|
|
236
|
+
|
|
237
|
+
| token | 效果 |
|
|
238
|
+
|-------|------|
|
|
239
|
+
| `type:concept` | 设置 Rem 类型为 concept |
|
|
240
|
+
| `type:descriptor` | 设置 Rem 类型为 descriptor |
|
|
241
|
+
| `doc` | 设置 isDocument = true |
|
|
242
|
+
| `tag:Name(tagRemId)` | 添加标签(括号内为标签 Rem 的 ID) |
|
|
243
|
+
|
|
244
|
+
示例:
|
|
245
|
+
|
|
246
|
+
```
|
|
247
|
+
新概念节点 <!--type:concept doc-->
|
|
248
|
+
新描述节点 <!--type:descriptor tag:MyTag(tagId123)-->
|
|
249
|
+
```
|
|
250
|
+
|
|
251
|
+
多个 token 之间用空格分隔,可任意组合。
|
|
252
|
+
|
|
253
|
+
#### Portal 新增行
|
|
254
|
+
|
|
255
|
+
在 newStr 中使用 Portal 专用注释创建新的 Portal:
|
|
256
|
+
|
|
257
|
+
```
|
|
258
|
+
<!--portal refs:remId1,remId2-->
|
|
259
|
+
<!--portal-->
|
|
260
|
+
```
|
|
261
|
+
|
|
262
|
+
- `refs:` 后面跟逗号分隔的 Rem ID 列表,指定 Portal 引用的目标 Rem
|
|
263
|
+
- 不带 `refs:` 则创建空 Portal
|
|
264
|
+
- Portal 创建分两步执行:先调用 `create_portal` 创建空 Portal 并设置父节点/位置,再逐个调用 `add_to_portal` 添加引用
|
|
265
|
+
|
|
266
|
+
示例:
|
|
267
|
+
|
|
268
|
+
```
|
|
269
|
+
oldStr:
|
|
270
|
+
子节点 A <!--idA-->
|
|
271
|
+
|
|
272
|
+
newStr:
|
|
273
|
+
<!--portal refs:refId1,refId2-->
|
|
274
|
+
子节点 A <!--idA-->
|
|
275
|
+
```
|
|
214
276
|
|
|
215
277
|
#### 嵌套新增
|
|
216
278
|
|
|
@@ -226,6 +288,30 @@ newStr:
|
|
|
226
288
|
|
|
227
289
|
嵌套新增行的父 ID 通过内部占位标记 `__new_N__` 管理,创建顺序保证从浅到深。
|
|
228
290
|
|
|
291
|
+
#### ⚠️ 插入位置:必须在兄弟末尾
|
|
292
|
+
|
|
293
|
+
新行**不能**插在一个有子节点的 Rem 和它的 children 之间,否则 children 会被新行"劫持",触发 `children_captured` 错误。
|
|
294
|
+
|
|
295
|
+
```
|
|
296
|
+
❌ 错误:插在父 Rem 和 children 之间
|
|
297
|
+
水分子 ↓ <!--idA-->
|
|
298
|
+
新行 ← children 被解析为新行的子节点!
|
|
299
|
+
化学式 → H₂O <!--idB role:card-item-->
|
|
300
|
+
|
|
301
|
+
✅ 正确:插在所有兄弟末尾
|
|
302
|
+
极性 → ... <!--idZ role:card-item-->
|
|
303
|
+
新行 ← 不影响任何已有节点
|
|
304
|
+
```
|
|
305
|
+
|
|
306
|
+
#### 两步操作:创建新节点并移入已有 children
|
|
307
|
+
|
|
308
|
+
如果需要"创建一个新父节点,把已有的 children 移到它下面",必须分两步完成:
|
|
309
|
+
|
|
310
|
+
1. **第一次 edit-tree**:在兄弟末尾创建新节点
|
|
311
|
+
2. **第二次 edit-tree**:新节点已获得 remId,将已有行的缩进改到新节点下(走正常 move 逻辑)
|
|
312
|
+
|
|
313
|
+
这是因为新增行没有 remId,diff 算法无法区分"移动到新父节点"和"重新创建"。
|
|
314
|
+
|
|
229
315
|
### 删除行
|
|
230
316
|
|
|
231
317
|
从 newStr 中移除带 remId 的行。**必须同时删除该行的所有可见子行**,否则报 orphan_detected 错误。
|
|
@@ -286,6 +372,7 @@ newStr:
|
|
|
286
372
|
| 删除行但保留子节点 | `orphan_detected` | Cannot delete {id} because it has children that were not removed. | 同时删除所有子行 |
|
|
287
373
|
| 删除/修改省略占位符 | `elided_modified` | Cannot delete or modify elided region directly. | 用更大的 depth/maxSiblings 重新 read-tree 展开 |
|
|
288
374
|
| 缩进跳级 | `indent_skip` | 缩进跳级:行 ... 的缩进级别为 N,但找不到上一级的父节点。 | 检查缩进是否正确(每级 2 空格) |
|
|
375
|
+
| 新行劫持已有子节点 | `children_captured` | New line "..." accidentally captured existing children (...). | 把新行插到兄弟末尾,不要插在父 Rem 和 children 之间 |
|
|
289
376
|
|
|
290
377
|
---
|
|
291
378
|
|
|
@@ -304,7 +391,8 @@ diff 算法生成的操作按以下顺序排列并执行(在 `diffTrees` 中
|
|
|
304
391
|
|
|
305
392
|
| 操作 | Plugin action | payload |
|
|
306
393
|
|------|---------------|---------|
|
|
307
|
-
| create | `create_rem` + `write_rem_fields` | content, parentId, position + Markdown 属性 |
|
|
394
|
+
| create(普通 Rem) | `create_rem` + `write_rem_fields` | content, parentId, position + Markdown 属性 + 元数据(type/doc/tag) |
|
|
395
|
+
| create(Portal) | `create_portal` + 逐个 `add_to_portal` | parentId, position + portalRefs |
|
|
308
396
|
| delete | `delete_rem` | remId |
|
|
309
397
|
| move | `move_rem` + 条件性 `write_rem_fields` | remId, newParentId, position |
|
|
310
398
|
| reorder | `reorder_children` | parentId, order[] |
|
|
@@ -376,12 +464,14 @@ RemNote SDK 存在已知 bug:
|
|
|
376
464
|
├─ 对比差异(diffTrees)
|
|
377
465
|
│ ├─ 根节点校验
|
|
378
466
|
│ ├─ 省略行防线
|
|
467
|
+
│ ├─ 子节点劫持检测(children_captured)
|
|
379
468
|
│ ├─ 内容变更检测
|
|
380
469
|
│ ├─ 折叠删除防线
|
|
381
470
|
│ ├─ 孤儿检测
|
|
382
471
|
│ └─ 生成操作列表(create → move → reorder → delete)
|
|
383
472
|
├─ 逐项执行操作(forwardToPlugin 调用原子操作)
|
|
384
|
-
│ ├─ create
|
|
473
|
+
│ ├─ create(普通): create_rem + write_rem_fields(Markdown 属性 + 元数据)
|
|
474
|
+
│ ├─ create(Portal): create_portal + 逐个 add_to_portal
|
|
385
475
|
│ ├─ move: move_rem + isCardItem 同步
|
|
386
476
|
│ ├─ reorder: reorder_children
|
|
387
477
|
│ └─ delete: delete_rem
|
|
@@ -71,7 +71,7 @@ Rem 有两个**独立维度**的类型:
|
|
|
71
71
|
| `concept` | 概念定义 | 文字**加粗** | `edit-rem` 设 `type: "concept"` |
|
|
72
72
|
| `descriptor` | 描述/属性 | 文字*斜体* | `edit-rem` 设 `type: "descriptor"` |
|
|
73
73
|
| `default` | 普通 Rem | 正常字重 | `edit-rem` 设 `type: "default"` |
|
|
74
|
-
| `portal` | 嵌入引用容器 | 紫色左边框 |
|
|
74
|
+
| `portal` | 嵌入引用容器 | 紫色左边框 | 不可通过 setType 创建(只能通过 createPortal),但引用列表可通过 edit-rem 修改 |
|
|
75
75
|
|
|
76
76
|
#### isDocument 字段(页面语义)
|
|
77
77
|
|
|
@@ -120,7 +120,17 @@ Rem 有两个**独立维度**的类型:
|
|
|
120
120
|
|:-----|:---------|:-----|:---------|:-----------|
|
|
121
121
|
| **Reference** | `[[` | RichText 中的引用元素 | 否(只是指针) | read-rem/read-tree 中显示为 `[[文本]]` |
|
|
122
122
|
| **Tag** | `##` | 将 Rem 作为标签附加 | 否(分类标记) | read-rem 的 `tags` 数组 |
|
|
123
|
-
| **Portal** | `((` | 嵌入 Rem 的实时视图 | 是(编辑同步) | read-tree 标记为 `type:portal
|
|
123
|
+
| **Portal** | `((` | 嵌入 Rem 的实时视图 | 是(编辑同步) | read-tree 标记为 `type:portal`;引用列表可通过 edit-rem 修改 |
|
|
124
|
+
|
|
125
|
+
#### Portal 操作速查
|
|
126
|
+
|
|
127
|
+
| 操作 | 命令 | 方式 |
|
|
128
|
+
|:-----|:-----|:-----|
|
|
129
|
+
| 创建 Portal | `edit-tree` | 新增行 `<!--portal refs:id1,id2-->` |
|
|
130
|
+
| 删除 Portal | `edit-tree` | 从大纲中移除 Portal 行(与删除普通行相同) |
|
|
131
|
+
| 修改引用列表(增删引用的 Rem) | `edit-rem` | str_replace 简化 JSON 中的 `portalDirectlyIncludedRem` 数组 |
|
|
132
|
+
| 移动 Portal(换父节点/位置) | `edit-tree` | 与移动普通行相同 |
|
|
133
|
+
| 读取 Portal | `read-rem` | 自动输出 9 字段简化 JSON |
|
|
124
134
|
|
|
125
135
|
### 2.6 Powerup 机制简述
|
|
126
136
|
|
|
@@ -427,6 +437,9 @@ daemon → CLI 响应:
|
|
|
427
437
|
| `delete_rem` | —(内部) | deleteRem() | edit-tree 的原子删除 |
|
|
428
438
|
| `move_rem` | —(内部) | moveRem() | edit-tree 的原子移动 |
|
|
429
439
|
| `reorder_children` | —(内部) | reorderChildren() | edit-tree 的原子重排 |
|
|
440
|
+
| `create_portal` | —(内部) | createPortal() | edit-tree Portal 创建 |
|
|
441
|
+
| `add_to_portal` | —(内部) | addToPortal() | Portal 引用管理 |
|
|
442
|
+
| `remove_from_portal` | —(内部) | removeFromPortal() | Portal 引用管理 |
|
|
430
443
|
|
|
431
444
|
`edit_rem` 和 `edit_tree` 在 daemon handler 中编排完成后,调用 `write_rem_fields`、`create_rem` 等原子操作。
|
|
432
445
|
|
|
@@ -458,7 +471,7 @@ RemObject 是本项目对 RemNote Rem 的标准化表示,包含 51 个字段
|
|
|
458
471
|
关联: tags [RW], sources [RW], aliases [R], remsReferencingThis [R]
|
|
459
472
|
位置: positionAmongstSiblings [RW]
|
|
460
473
|
时间: createdAt [R], updatedAt [R]
|
|
461
|
-
Portal:portalType [R], portalDirectlyIncludedRem [
|
|
474
|
+
Portal:portalType [R], portalDirectlyIncludedRem [Portal-W]
|
|
462
475
|
```
|
|
463
476
|
|
|
464
477
|
### 7.3 RichText 格式
|
|
@@ -703,6 +716,7 @@ edit-tree 使用 str_replace 对 Markdown 大纲进行结构编辑。详细文
|
|
|
703
716
|
| 删除有隐藏子节点的行 | `folded_delete` | 用更大的 depth 重新 read-tree |
|
|
704
717
|
| 删除节点但保留子节点 | `orphan_detected` | 必须同时删除所有子行 |
|
|
705
718
|
| 删除/修改省略占位符 | `elided_modified` | 用更大参数重新 read-tree 展开 |
|
|
719
|
+
| 新行劫持已有子节点 | `children_captured` | 把新行插到兄弟末尾,不要插在父 Rem 和 children 之间 |
|
|
706
720
|
|
|
707
721
|
### 10.3 新增行格式
|
|
708
722
|
|
|
@@ -800,6 +814,7 @@ Agent 遇到错误时的诊断和恢复指南:
|
|
|
800
814
|
| Content modification not allowed | edit-tree 中修改了已有行内容 | 使用 `edit-rem` 修改内容 |
|
|
801
815
|
| orphan_detected | 删除了父节点但保留了子节点 | 同时删除所有子行 |
|
|
802
816
|
| folded_delete | 删除了有隐藏子节点的行 | 用更大 depth 重新 read-tree |
|
|
817
|
+
| children_captured | 新行插在父 Rem 和子节点之间,劫持了已有 children | 把新行插到兄弟末尾 |
|
|
803
818
|
|
|
804
819
|
### 数据问题
|
|
805
820
|
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
`read-rem` 通过 Rem ID 读取一个 Rem 的所有可获取属性,返回标准化的 RemObject。读取结果会被缓存在 daemon 内存中,供后续 `edit-rem` 使用。
|
|
10
10
|
|
|
11
11
|
核心能力:
|
|
12
|
-
- 返回 51 个字段的完整 Rem 数据(默认 34 个,`--full` 时 51 个)
|
|
12
|
+
- 返回 51 个字段的完整 Rem 数据(默认 34 个,Portal 简化 9 个,`--full` 时 51 个)
|
|
13
13
|
- 支持 `--fields` 指定字段子集
|
|
14
14
|
- 支持 Powerup 噪音过滤(默认过滤)
|
|
15
15
|
- 自动缓存,为 `edit-rem` 建立编辑基础
|
|
@@ -159,6 +159,7 @@ remnote-bridge read-rem --json '{"remId":"kLrIOHJLyMd8Y2lyA"}'
|
|
|
159
159
|
├─ 字段过滤:
|
|
160
160
|
│ ├─ --full → 返回全部 51 字段
|
|
161
161
|
│ ├─ --fields → 返回指定字段 + id
|
|
162
|
+
│ ├─ type=portal → Portal 简化模式(返回 9 个关键字段)
|
|
162
163
|
│ └─ 默认 → 排除 R-F 字段(返回 34 字段)
|
|
163
164
|
└─ 附加 _cacheOverridden 元数据(若之前有缓存)
|
|
164
165
|
4. CLI 格式化输出(人类模式 pretty-print / JSON 模式单行)
|
|
@@ -237,7 +238,7 @@ RemObject 共 51 个字段,按读写权限分为三类:
|
|
|
237
238
|
| 字段 | 类型 | 权限 | 说明 |
|
|
238
239
|
|------|------|:----:|------|
|
|
239
240
|
| `portalType` | `PortalType \| null` | R | Portal 子类型。仅 type=portal 时有值 |
|
|
240
|
-
| `portalDirectlyIncludedRem` | `string[]` |
|
|
241
|
+
| `portalDirectlyIncludedRem` | `string[]` | Portal-W | Portal 直接包含的 Rem ID。**Portal 专用可写**:仅 type=portal 时可通过 edit-rem 修改(Diff 机制:addToPortal/removeFromPortal) |
|
|
241
242
|
|
|
242
243
|
### 属性类型
|
|
243
244
|
|
|
@@ -377,6 +378,7 @@ text | number | date | checkbox | single_select | multi_select | url | image | t
|
|
|
377
378
|
| 模式 | 输出字段数 | 说明 |
|
|
378
379
|
|------|:----------:|------|
|
|
379
380
|
| 默认 | 34 | RW + R 字段,覆盖常用场景 |
|
|
381
|
+
| Portal 简化 | 9 | type=portal 时自动使用(id、type、portalType、portalDirectlyIncludedRem、parent、positionAmongstSiblings、children、createdAt、updatedAt)。`--full` / `--fields` 可覆盖 |
|
|
380
382
|
| `--full` | 51 | 全部字段(含 R-F 低频字段) |
|
|
381
383
|
| `--fields` | 自选 + id | 仅返回指定字段(始终包含 id) |
|
|
382
384
|
|
|
@@ -420,6 +422,7 @@ localUpdatedAt, lastPracticed
|
|
|
420
422
|
| `tags` | `rem.addTag()` / `rem.removeTag()` | **Diff 机制**:对比当前 vs 目标,增删差异项。必须列出完整目标数组,缺少的会被删除 |
|
|
421
423
|
| `sources` | `rem.addSource()` / `rem.removeSource()` | **Diff 机制**:同 tags |
|
|
422
424
|
| `positionAmongstSiblings` | `rem.setParent(parent, position)` | 与 `parent` 联动(见下方说明) |
|
|
425
|
+
| `portalDirectlyIncludedRem` | `rem.addToPortal()` / `rem.removeFromPortal()` | string[] | **Portal-W Diff 机制**:仅 type=portal 时可修改。对比当前 vs 目标数组,逐项增删。调用方向:在被引用 Rem 上调用,参数是 Portal Rem |
|
|
423
426
|
|
|
424
427
|
### parent + positionAmongstSiblings 联动
|
|
425
428
|
|