remnote-bridge 0.1.11 → 0.1.12

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.
Files changed (64) hide show
  1. package/dist/cli/addon/addon-manager.js +163 -0
  2. package/dist/cli/addon/registry.js +24 -0
  3. package/dist/cli/commands/addon.js +149 -0
  4. package/dist/cli/commands/clean.js +121 -52
  5. package/dist/cli/commands/connect.js +72 -33
  6. package/dist/cli/commands/disconnect.js +19 -19
  7. package/dist/cli/commands/edit-rem.js +3 -31
  8. package/dist/cli/commands/edit-tree.js +3 -20
  9. package/dist/cli/commands/health.js +19 -18
  10. package/dist/cli/commands/read-context.js +3 -20
  11. package/dist/cli/commands/read-globe.js +3 -20
  12. package/dist/cli/commands/read-rem.js +3 -31
  13. package/dist/cli/commands/read-tree.js +3 -20
  14. package/dist/cli/commands/search.js +97 -21
  15. package/dist/cli/config.js +148 -72
  16. package/dist/cli/daemon/daemon.js +104 -24
  17. package/dist/cli/daemon/dev-server.js +9 -1
  18. package/dist/cli/daemon/pid.js +36 -22
  19. package/dist/cli/daemon/registry.js +160 -0
  20. package/dist/cli/daemon/send-request.js +11 -11
  21. package/dist/cli/daemon/static-server.js +97 -34
  22. package/dist/cli/handlers/read-handler.js +4 -3
  23. package/dist/cli/handlers/tree-parser.js +16 -9
  24. package/dist/cli/main.js +49 -9
  25. package/dist/cli/protocol.js +18 -4
  26. package/dist/cli/server/config-server.js +280 -14
  27. package/dist/cli/server/ws-server.js +93 -44
  28. package/dist/cli/utils/output.js +29 -0
  29. package/dist/mcp/instructions.js +101 -9
  30. package/dist/mcp/resources/edit-rem-guide.js +3 -4
  31. package/dist/mcp/resources/error-reference.js +2 -2
  32. package/dist/mcp/resources/rem-object-fields.js +3 -3
  33. package/dist/mcp/tools/infra-tools.js +54 -6
  34. package/dist/mcp/tools/read-tools.js +9 -2
  35. package/package.json +2 -2
  36. package/remnote-plugin/dist/bridge_widget-sandbox.js +17 -17
  37. package/remnote-plugin/dist/bridge_widget.js +17 -17
  38. package/remnote-plugin/dist/index-sandbox.js +31 -31
  39. package/remnote-plugin/dist/index.js +31 -31
  40. package/remnote-plugin/dist/manifest.json +1 -1
  41. package/remnote-plugin/package.json +1 -1
  42. package/remnote-plugin/public/manifest.json +1 -1
  43. package/remnote-plugin/src/bridge/multi-connection-manager.ts +151 -0
  44. package/remnote-plugin/src/bridge/websocket-client.ts +62 -16
  45. package/remnote-plugin/src/services/index.ts +0 -8
  46. package/remnote-plugin/src/services/read-rem.ts +1 -9
  47. package/remnote-plugin/src/services/search.ts +13 -10
  48. package/remnote-plugin/src/settings.ts +9 -7
  49. package/remnote-plugin/src/utils/index.ts +0 -5
  50. package/remnote-plugin/src/widgets/bridge_widget.tsx +105 -20
  51. package/remnote-plugin/src/widgets/index.tsx +41 -44
  52. package/remnote-plugin/webpack.config.js +35 -0
  53. package/skills/remnote-bridge/SKILL.md +14 -9
  54. package/skills/remnote-bridge/instructions/addon.md +134 -0
  55. package/skills/remnote-bridge/instructions/clean.md +110 -0
  56. package/skills/remnote-bridge/instructions/connect.md +80 -37
  57. package/skills/remnote-bridge/instructions/disconnect.md +22 -9
  58. package/skills/remnote-bridge/instructions/edit-rem.md +37 -9
  59. package/skills/remnote-bridge/instructions/health.md +23 -13
  60. package/skills/remnote-bridge/instructions/install-skill.md +58 -0
  61. package/skills/remnote-bridge/instructions/overall.md +76 -21
  62. package/skills/remnote-bridge/instructions/read-rem.md +10 -10
  63. package/skills/remnote-bridge/instructions/search.md +73 -14
  64. package/skills/remnote-bridge/instructions/setup.md +1 -1
@@ -1,55 +1,59 @@
1
1
  import { declareIndexPlugin, type ReactRNPlugin, WidgetLocation } from '@remnote/plugin-sdk';
2
2
  import '../style.css';
3
3
  import '../index.css';
4
- import { SETTING_WS_URL, DEFAULT_WS_URL, DEFAULT_PLUGIN_VERSION } from '../settings';
5
- import { WebSocketClient } from '../bridge/websocket-client';
4
+ import { DEFAULT_PLUGIN_VERSION } from '../settings';
5
+ import { MultiConnectionManager } from '../bridge/multi-connection-manager';
6
6
  import { createMessageRouter } from '../bridge/message-router';
7
- // test-scripts 已完成数据收集,不再打包进生产代码
8
- // 如需重跑,取消注释对应 import 和 onActivate 调用
9
- // import { runActionTests } from '../test-scripts/test-actions';
10
- // import { runRichTextBuilderTest } from '../test-scripts/test-richtext-builder';
11
- // import { runRichTextRemainingTest } from '../test-scripts/test-richtext-remaining';
12
- // import { runRichTextMatrixTest } from '../test-scripts/test-richtext-matrix';
13
- // import { runPowerupRenderingTest } from '../test-scripts/test-powerup-rendering';
14
7
 
15
- let wsClient: WebSocketClient | null = null;
8
+ let connectionManager: MultiConnectionManager | null = null;
16
9
  // 本地日志缓冲区:避免 onLog 并发读写 plugin.storage 的竞态
17
10
  const logBuffer: Array<{ time: number; message: string; level: string }> = [];
18
11
  let logFlushPending = false;
19
12
 
20
13
  async function onActivate(plugin: ReactRNPlugin) {
21
- // 注册 WS Server URL 设置
22
- await plugin.settings.registerStringSetting({
23
- id: SETTING_WS_URL,
24
- title: 'Bridge WS Server URL',
25
- description: '守护进程 WebSocket Server 地址(默认 ws://127.0.0.1:3002)',
26
- defaultValue: DEFAULT_WS_URL,
27
- });
28
-
29
14
  // 注册 Bridge Widget(右侧边栏)
30
15
  await plugin.app.registerWidget('bridge_widget', WidgetLocation.RightSidebar, {
31
16
  dimensions: { height: 'auto', width: '100%' },
32
17
  widgetTabIcon: 'https://cdn.jsdelivr.net/npm/lucide-static@0.460.0/icons/globe.svg',
33
18
  });
34
19
 
35
- // 读取 WS URL 设置
36
- const wsUrl =
37
- (await plugin.settings.getSetting<string>(SETTING_WS_URL)) || DEFAULT_WS_URL;
20
+ // 自动发现孪生槽位:Plugin daemon 的 static-server 提供服务,
21
+ // fetch('/api/discovery') 是同源请求,返回 daemon 的 slotIndex 等信息
22
+ let twinSlotIndex = 0;
23
+ let instanceName = '';
24
+ let configPort = 29102;
25
+ try {
26
+ const resp = await fetch('/api/discovery');
27
+ if (resp.ok) {
28
+ const data = await resp.json();
29
+ if (typeof data.slotIndex === 'number') {
30
+ twinSlotIndex = data.slotIndex;
31
+ }
32
+ if (data.instance) {
33
+ instanceName = data.instance;
34
+ }
35
+ if (data.configPort) {
36
+ configPort = data.configPort;
37
+ }
38
+ }
39
+ } catch {
40
+ // discovery 失败(dev 模式 / 非 daemon 环境),使用默认值
41
+ }
42
+ // 存储实例名和配置端口,供 widget 显示
43
+ await plugin.storage.setSession('bridge-instance', instanceName);
44
+ await plugin.storage.setSession('bridge-config-port', configPort);
38
45
 
39
- // onActivate 中建立 WebSocket 连接(插件激活即连接,无需打开 widget)
40
- wsClient = new WebSocketClient({
41
- url: wsUrl,
46
+ // 创建 MultiConnectionManager
47
+ connectionManager = new MultiConnectionManager({
48
+ twinSlotIndex,
42
49
  pluginVersion: DEFAULT_PLUGIN_VERSION,
43
50
  sdkReady: true,
44
- maxReconnectAttempts: 10,
45
- initialReconnectDelay: 1000,
46
- maxReconnectDelay: 30000,
47
- onStatusChange: (status) => {
48
- void plugin.storage.setSession('bridge-status', status);
51
+ onSlotsChange: (slots) => {
52
+ void plugin.storage.setSession('bridge-slots', slots);
49
53
  },
50
- onLog: (message, level) => {
51
- logBuffer.push({ time: Date.now(), message, level });
52
- if (logBuffer.length > 30) logBuffer.splice(0, logBuffer.length - 30);
54
+ onLog: (slotIndex, message, level) => {
55
+ logBuffer.push({ time: Date.now(), message: `[${slotIndex}] ${message}`, level });
56
+ if (logBuffer.length > 50) logBuffer.splice(0, logBuffer.length - 50);
53
57
  // 合并写入:避免并发 read-modify-write 竞态
54
58
  if (!logFlushPending) {
55
59
  logFlushPending = true;
@@ -61,22 +65,15 @@ async function onActivate(plugin: ReactRNPlugin) {
61
65
  },
62
66
  });
63
67
 
64
- // 路由守护进程转发的请求到 services
65
- wsClient.setMessageHandler(createMessageRouter(plugin));
66
-
67
- wsClient.connect();
68
+ // 路由守护进程转发的请求到 services 层(所有连接共享同一个 router)
69
+ connectionManager.setMessageHandler(createMessageRouter(plugin));
68
70
 
69
- // test-scripts 已完成数据收集,不再自动运行
70
- // runActionTests(plugin).catch((err) => console.error('[ACTION-TEST] 顶层错误:', err));
71
- // runRichTextBuilderTest(plugin).catch((err) => console.error('[RICHTEXT-BUILDER-TEST] 顶层错误:', err));
72
- // runRichTextRemainingTest(plugin).catch((err) => console.error('[RICHTEXT-REMAINING-TEST] 顶层错误:', err));
73
- // runRichTextMatrixTest(plugin).catch((err) => console.error('[RICHTEXT-MATRIX-TEST] 顶层错误:', err));
74
- // runPowerupRenderingTest(plugin).catch((err) => console.error('[POWERUP-RENDER] 顶层错误:', err));
71
+ connectionManager.start();
75
72
  }
76
73
 
77
74
  async function onDeactivate(_: ReactRNPlugin) {
78
- wsClient?.disconnect();
79
- wsClient = null;
75
+ connectionManager?.stop();
76
+ connectionManager = null;
80
77
  }
81
78
 
82
79
  declareIndexPlugin(onActivate, onDeactivate);
@@ -119,6 +119,41 @@ if (isProd) {
119
119
  'Access-Control-Allow-Origin': '*',
120
120
  'Access-Control-Allow-Headers': 'baggage, sentry-trace',
121
121
  },
122
+ // 劫持 /api/discovery 和 /manifest.json,与 StaticServer 行为一致
123
+ setupMiddlewares: (middlewares, devServer) => {
124
+ const instance = process.env.DISCOVERY_INSTANCE || 'default';
125
+
126
+ devServer.app.get('/api/discovery', (req, res) => {
127
+ res.json({
128
+ wsPort: parseInt(process.env.DISCOVERY_WS_PORT || '29100', 10),
129
+ configPort: parseInt(process.env.DISCOVERY_CONFIG_PORT || '29102', 10),
130
+ instance,
131
+ slotIndex: parseInt(process.env.DISCOVERY_SLOT_INDEX || '0', 10),
132
+ });
133
+ });
134
+
135
+ // 多实例支持:非 default 实例动态修改 manifest 的 id 和 name,
136
+ // 使 RemNote 能同时加载多个同源 Plugin(RemNote 按 id 去重)
137
+ if (instance !== 'default') {
138
+ devServer.app.get('/manifest.json', (req, res) => {
139
+ const fs = require('fs');
140
+ const manifestPath = path.resolve(__dirname, 'public', 'manifest.json');
141
+ try {
142
+ const manifest = JSON.parse(fs.readFileSync(manifestPath, 'utf-8'));
143
+ manifest.id = `${manifest.id}_${instance}`;
144
+ manifest.name = `${manifest.name} (${instance})`;
145
+ // webpack-dev-server 的 headers 配置不覆盖自定义路由,需手动设置 CORS
146
+ res.set('Access-Control-Allow-Origin', '*');
147
+ res.set('Cache-Control', 'no-cache, no-store, must-revalidate');
148
+ res.json(manifest);
149
+ } catch (err) {
150
+ res.status(500).send('manifest parse error');
151
+ }
152
+ });
153
+ }
154
+
155
+ return middlewares;
156
+ },
122
157
  };
123
158
  }
124
159
 
@@ -22,6 +22,9 @@ description: "RemNote 知识库操作指南。通过 remnote-bridge 命令行工
22
22
  | read-globe | `instructions/read-globe.md` |
23
23
  | read-context | `instructions/read-context.md` |
24
24
  | search | `instructions/search.md` |
25
+ | addon | `instructions/addon.md` |
26
+ | clean | `instructions/clean.md` |
27
+ | install-skill | `instructions/install-skill.md` |
25
28
  | 全局概览 | `instructions/overall.md` |
26
29
 
27
30
  ---
@@ -99,7 +102,7 @@ Portal 的编辑同步意味着修改一处会影响另一处。Portal 引用的
99
102
  | 删除 Portal | `edit-tree` | 从大纲中移除 Portal 行(与删除普通行相同) |
100
103
  | 修改引用列表(增删引用的 Rem) | `edit-rem` | str_replace 简化 JSON 中的 `portalDirectlyIncludedRem` 数组 |
101
104
  | 移动 Portal(换父节点/位置) | `edit-tree` | 与移动普通行相同 |
102
- | 读取 Portal | `read-rem` | 自动输出 9 字段简化 JSON |
105
+ | 读取 Portal | `read-rem` | 自动输出 8 字段简化 JSON |
103
106
 
104
107
  ### RichText 格式
105
108
 
@@ -255,7 +258,7 @@ Rem 的属性(文本、类型、格式、标签) → edit-rem (前置
255
258
  1. 打开 RemNote 桌面端或网页端
256
259
  2. 点击左侧边栏底部的插件图标(拼图形状)
257
260
  3. 点击「开发你的插件」(Develop Your Plugin)
258
- 4. 在输入框中填入 `http://localhost:8080`(即 connect 输出的 Plugin 服务地址)
261
+ 4. 在输入框中填入 connect 输出的 Plugin 服务地址(如 `http://localhost:29101`)
259
262
  5. 等待插件加载完成
260
263
 
261
264
  **非首次使用**(之前已加载过此插件):
@@ -273,7 +276,7 @@ Rem 的属性(文本、类型、格式、标签) → edit-rem (前置
273
276
 
274
277
  setup 会弹出 Chrome 窗口,用户需要完成两件事:
275
278
  1. **登录 RemNote**
276
- 2. **配置 dev plugin**:插件图标 → 开发你的插件 → 填入 `http://localhost:8080`
279
+ 2. **配置 dev plugin**:插件图标 → 开发你的插件 → 填入 connect 输出的 Plugin 服务地址(如 `http://localhost:29101`)
277
280
 
278
281
  完成后**彻底退出 Chrome**(macOS 必须 Cmd+Q,仅关窗口不够)。
279
282
 
@@ -283,7 +286,7 @@ setup 会弹出 Chrome 窗口,用户需要完成两件事:
283
286
  2. 立即告知用户:
284
287
  "已打开 Chrome 浏览器。请完成以下操作:
285
288
  1. 登录 RemNote
286
- 2. 在 RemNote 中配置开发插件:点击左下角插件图标 → 开发你的插件 → 输入 http://localhost:8080
289
+ 2. 在 RemNote 中配置开发插件:点击左下角插件图标 → 开发你的插件 → 输入 connect 输出的 Plugin 服务地址
287
290
  3. 完成后彻底退出 Chrome(macOS 请按 Cmd+Q)"
288
291
  3. 等待 setup 返回(阻塞,最长 10 分钟)
289
292
  4. 成功 → 进入下一步 connect --headless
@@ -575,7 +578,7 @@ tags, sources, positionAmongstSiblings, portalDirectlyIncludedRem
575
578
  | `type` | 不可设为 `portal`(只能通过 SDK `createPortal()` 创建) |
576
579
  | `parent` + `positionAmongstSiblings` | 共享同一 SDK 调用 `setParent(parentId, position)`,**应在同一次 str_replace 中同时修改** |
577
580
  | `tags` / `sources` | **Diff 机制**:对比当前 vs 目标数组,逐项 add/remove。必须列出完整目标数组,缺少的会被删除 |
578
- | `portalDirectlyIncludedRem` | Portal 专用可写。**Diff 机制**:对比当前 vs 目标数组,逐项 addToPortal/removeFromPortal。仅 type=portal 时可修改。edit-rem 对 Portal 使用 9 字段简化 JSON |
581
+ | `portalDirectlyIncludedRem` | Portal 专用可写。**Diff 机制**:对比当前 vs 目标数组,逐项 addToPortal/removeFromPortal。仅 type=portal 时可修改。edit-rem 对 Portal 使用 8 字段简化 JSON |
579
582
 
580
583
  ### 常用只读字段(修改只产生警告,不生效)
581
584
 
@@ -588,8 +591,8 @@ aliases, descendants, siblingRem, isTable, portalType, propertyType
588
591
 
589
592
  | 模式 | 字段数 | 用法 |
590
593
  |:-----|:-------|:-----|
591
- | 默认 | 34(RW + R) | 常用场景 |
592
- | Portal 简化 | 9(id, type, portalType, portalDirectlyIncludedRem, parent, positionAmongstSiblings, children, createdAt, updatedAt) | type=portal 时自动切换,`--full` 和 `--fields` 可覆盖 |
594
+ | 默认 | 33(RW + R) | 常用场景 |
595
+ | Portal 简化 | 8(id, type, portalType, portalDirectlyIncludedRem, parent, positionAmongstSiblings, createdAt, updatedAt) | type=portal 时自动切换,`--full` 和 `--fields` 可覆盖 |
593
596
  | `--full` | 51(含低频 R-F) | 需要 Powerup 标识、时间戳等 |
594
597
  | `--fields` | 自选 + id | 精确获取特定字段 |
595
598
 
@@ -621,6 +624,8 @@ aliases, descendants, siblingRem, isTable, portalType, propertyType
621
624
 
622
625
  ## 10. 配置
623
626
 
624
- 配置文件:`.remnote-bridge.json`(项目根目录)
627
+ 配置文件:`~/.remnote-bridge/config.json`(全局目录,所有实例共享)
625
628
 
626
- 关键默认值:WS 端口 3002、dev-server 8080、config 3003、超时 30 分钟、maxNodes 200、maxSiblings 20、readTreeDepth 3、readGlobeDepth -1(无限)、缓存上限 200 条。
629
+ 端口由槽位自动分配(槽位 0: 29100/29101/29102,槽位 1: 29110/29111/29112,以此类推),最多 4 个并发实例。
630
+
631
+ 关键默认值:超时 30 分钟、maxNodes 200、maxSiblings 20、readTreeDepth 3、readGlobeDepth -1(无限)、缓存上限 200 条。
@@ -0,0 +1,134 @@
1
+ # addon
2
+
3
+ > 管理增强项目(addon):查看状态、安装、卸载。
4
+
5
+ ---
6
+
7
+ ## 功能
8
+
9
+ `addon` 命令组管理 remnote-bridge 的增强项目(如 `remnote-rag` 语义搜索)。增强项目是独立安装的可选组件,扩展核心功能。
10
+
11
+ 三个子命令:
12
+
13
+ | 子命令 | 功能 |
14
+ |:-------|:-----|
15
+ | `addon list` | 查看所有可用增强项目的状态 |
16
+ | `addon install <name>` | 安装并启用指定增强项目 |
17
+ | `addon uninstall <name>` | 卸载指定增强项目 |
18
+
19
+ ---
20
+
21
+ ## 用法
22
+
23
+ ### 人类模式
24
+
25
+ ```bash
26
+ # 查看所有增强项目
27
+ remnote-bridge addon list
28
+
29
+ # 安装增强项目
30
+ remnote-bridge addon install remnote-rag
31
+
32
+ # 卸载增强项目
33
+ remnote-bridge addon uninstall remnote-rag
34
+
35
+ # 卸载并清理数据目录
36
+ remnote-bridge addon uninstall remnote-rag --purge
37
+ ```
38
+
39
+ ### JSON 模式
40
+
41
+ ```bash
42
+ remnote-bridge --json addon list
43
+ remnote-bridge --json addon install remnote-rag
44
+ remnote-bridge --json addon uninstall remnote-rag
45
+ ```
46
+
47
+ ---
48
+
49
+ ## JSON 输出
50
+
51
+ ### addon list
52
+
53
+ ```json
54
+ {
55
+ "ok": true,
56
+ "command": "addon-list",
57
+ "addons": [
58
+ {
59
+ "name": "remnote-rag",
60
+ "enabled": true,
61
+ "installed": true,
62
+ "settingsValid": true,
63
+ "missingSettings": [],
64
+ "description": "语义搜索增强"
65
+ }
66
+ ]
67
+ }
68
+ ```
69
+
70
+ ### addon install(成功)
71
+
72
+ ```json
73
+ {
74
+ "ok": true,
75
+ "command": "addon-install",
76
+ "name": "remnote-rag",
77
+ "action": "installed"
78
+ }
79
+ ```
80
+
81
+ ### addon install(已安装)
82
+
83
+ ```json
84
+ {
85
+ "ok": true,
86
+ "command": "addon-install",
87
+ "name": "remnote-rag",
88
+ "action": "already-installed"
89
+ }
90
+ ```
91
+
92
+ ### addon uninstall
93
+
94
+ ```json
95
+ {
96
+ "ok": true,
97
+ "command": "addon-uninstall",
98
+ "name": "remnote-rag",
99
+ "purged": false
100
+ }
101
+ ```
102
+
103
+ ### 失败
104
+
105
+ ```json
106
+ {
107
+ "ok": false,
108
+ "command": "addon-install",
109
+ "name": "unknown-addon",
110
+ "error": "未知的增强项目: unknown-addon。可用项目: remnote-rag"
111
+ }
112
+ ```
113
+
114
+ ---
115
+
116
+ ## 退出码
117
+
118
+ | 退出码 | 含义 |
119
+ |:-------|:-----|
120
+ | 0 | 操作成功 |
121
+ | 1 | 操作失败(未知名称、安装/卸载错误等) |
122
+
123
+ ---
124
+
125
+ ## 幂等性
126
+
127
+ - `addon install`:已安装时返回 `action: "already-installed"`,自动标记为启用
128
+ - `addon uninstall`:已卸载时安全返回
129
+
130
+ ---
131
+
132
+ ## 配置依赖
133
+
134
+ 增强项目的启用/禁用状态保存在全局配置 `~/.remnote-bridge/config.json` 中。每个 addon 的独立配置存储在 `~/.remnote-bridge/addons/<name>/config.json` 中。安装后需要在配置页面或配置文件中填写必需的配置项(如 API Key)。
@@ -0,0 +1,110 @@
1
+ # clean
2
+
3
+ > 清理所有 daemon 进程、PID 文件、日志、注册表和 addon 数据。
4
+
5
+ ---
6
+
7
+ ## 功能
8
+
9
+ `clean` 执行全面清理,适用于系统状态异常或需要彻底重置的场景。
10
+
11
+ 按顺序执行以下清理步骤:
12
+
13
+ 1. **停止所有运行中的 daemon**(遍历注册表,SIGTERM → 5 秒后 SIGKILL)
14
+ 2. **清理实例文件**(`~/.remnote-bridge/instances/` 下的 PID 和日志文件)
15
+ 3. **清理注册表**(`~/.remnote-bridge/registry.json`)
16
+ 4. **清理旧版项目根文件**(`.remnote-bridge.pid`、`.remnote-bridge.log`、`.remnote-bridge.json`,向后兼容)
17
+ 5. **清理已安装的 Skill**(`~/.claude/skills/remnote-bridge/`)
18
+ 6. **清理 addon 数据目录**(如 remnote-rag 的索引数据)
19
+
20
+ ---
21
+
22
+ ## 用法
23
+
24
+ ### 人类模式
25
+
26
+ ```bash
27
+ remnote-bridge clean
28
+ ```
29
+
30
+ 输出示例:
31
+
32
+ ```
33
+ 已删除: /Users/xxx/.remnote-bridge/instances/0.pid
34
+ 已删除: /Users/xxx/.remnote-bridge/instances/0.log
35
+ 已删除: /Users/xxx/.remnote-bridge/registry.json
36
+
37
+ 清理完成,共删除 3 项
38
+ ```
39
+
40
+ ### JSON 模式
41
+
42
+ ```bash
43
+ remnote-bridge --json clean
44
+ ```
45
+
46
+ ---
47
+
48
+ ## JSON 输出
49
+
50
+ ### 清理成功
51
+
52
+ ```json
53
+ {
54
+ "ok": true,
55
+ "command": "clean",
56
+ "removed": [
57
+ "/Users/xxx/.remnote-bridge/instances/0.pid",
58
+ "/Users/xxx/.remnote-bridge/instances/0.log",
59
+ "/Users/xxx/.remnote-bridge/registry.json"
60
+ ]
61
+ }
62
+ ```
63
+
64
+ ### 部分失败
65
+
66
+ ```json
67
+ {
68
+ "ok": false,
69
+ "command": "clean",
70
+ "removed": ["/Users/xxx/.remnote-bridge/instances/0.pid"],
71
+ "errors": ["删除失败: /Users/xxx/.remnote-bridge/instances/0.log — EPERM"]
72
+ }
73
+ ```
74
+
75
+ ### 无需清理
76
+
77
+ ```json
78
+ {
79
+ "ok": true,
80
+ "command": "clean",
81
+ "removed": []
82
+ }
83
+ ```
84
+
85
+ ---
86
+
87
+ ## 退出码
88
+
89
+ | 退出码 | 含义 |
90
+ |:-------|:-----|
91
+ | 0 | 清理完成(包括无需清理的情况) |
92
+
93
+ ---
94
+
95
+ ## 适用场景
96
+
97
+ | 场景 | 说明 |
98
+ |:-----|:-----|
99
+ | daemon 进程残留 | `disconnect` 无法正常停止时 |
100
+ | 端口被占用 | 多次启动失败后的端口残留 |
101
+ | 注册表损坏 | 注册表文件不一致时重置 |
102
+ | 完整重装 | 清除所有状态从零开始 |
103
+
104
+ ---
105
+
106
+ ## AI Agent 注意事项
107
+
108
+ - `clean` 是**破坏性操作**——会停止所有 daemon、清空所有缓存和注册表
109
+ - 执行 `clean` 后需要重新 `connect` 才能继续操作
110
+ - 通常只在排查问题或重置环境时使用,正常流程不需要