remnote-bridge 0.1.0

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 (135) hide show
  1. package/dist/cli/commands/connect.d.ts +12 -0
  2. package/dist/cli/commands/connect.js +124 -0
  3. package/dist/cli/commands/disconnect.d.ts +11 -0
  4. package/dist/cli/commands/disconnect.js +100 -0
  5. package/dist/cli/commands/edit-rem.d.ts +13 -0
  6. package/dist/cli/commands/edit-rem.js +83 -0
  7. package/dist/cli/commands/edit-tree.d.ts +14 -0
  8. package/dist/cli/commands/edit-tree.js +67 -0
  9. package/dist/cli/commands/health.d.ts +12 -0
  10. package/dist/cli/commands/health.js +100 -0
  11. package/dist/cli/commands/install-skill.d.ts +6 -0
  12. package/dist/cli/commands/install-skill.js +39 -0
  13. package/dist/cli/commands/read-context.d.ts +20 -0
  14. package/dist/cli/commands/read-context.js +77 -0
  15. package/dist/cli/commands/read-globe.d.ts +16 -0
  16. package/dist/cli/commands/read-globe.js +60 -0
  17. package/dist/cli/commands/read-rem.d.ts +16 -0
  18. package/dist/cli/commands/read-rem.js +80 -0
  19. package/dist/cli/commands/read-tree.d.ts +17 -0
  20. package/dist/cli/commands/read-tree.js +85 -0
  21. package/dist/cli/commands/search.d.ts +12 -0
  22. package/dist/cli/commands/search.js +65 -0
  23. package/dist/cli/config.d.ts +55 -0
  24. package/dist/cli/config.js +139 -0
  25. package/dist/cli/daemon/daemon.d.ts +11 -0
  26. package/dist/cli/daemon/daemon.js +186 -0
  27. package/dist/cli/daemon/dev-server.d.ts +26 -0
  28. package/dist/cli/daemon/dev-server.js +81 -0
  29. package/dist/cli/daemon/pid.d.ts +34 -0
  30. package/dist/cli/daemon/pid.js +67 -0
  31. package/dist/cli/daemon/send-request.d.ts +24 -0
  32. package/dist/cli/daemon/send-request.js +92 -0
  33. package/dist/cli/handlers/context-read-handler.d.ts +18 -0
  34. package/dist/cli/handlers/context-read-handler.js +24 -0
  35. package/dist/cli/handlers/edit-handler.d.ts +30 -0
  36. package/dist/cli/handlers/edit-handler.js +133 -0
  37. package/dist/cli/handlers/globe-read-handler.d.ts +17 -0
  38. package/dist/cli/handlers/globe-read-handler.js +23 -0
  39. package/dist/cli/handlers/read-handler.d.ts +16 -0
  40. package/dist/cli/handlers/read-handler.js +78 -0
  41. package/dist/cli/handlers/rem-cache.d.ts +19 -0
  42. package/dist/cli/handlers/rem-cache.js +63 -0
  43. package/dist/cli/handlers/tree-edit-handler.d.ts +30 -0
  44. package/dist/cli/handlers/tree-edit-handler.js +188 -0
  45. package/dist/cli/handlers/tree-parser.d.ts +95 -0
  46. package/dist/cli/handlers/tree-parser.js +506 -0
  47. package/dist/cli/handlers/tree-read-handler.d.ts +28 -0
  48. package/dist/cli/handlers/tree-read-handler.js +53 -0
  49. package/dist/cli/main.d.ts +7 -0
  50. package/dist/cli/main.js +300 -0
  51. package/dist/cli/protocol.d.ts +39 -0
  52. package/dist/cli/protocol.js +35 -0
  53. package/dist/cli/server/config-server.d.ts +26 -0
  54. package/dist/cli/server/config-server.js +363 -0
  55. package/dist/cli/server/ws-server.d.ts +68 -0
  56. package/dist/cli/server/ws-server.js +335 -0
  57. package/dist/cli/utils/output.d.ts +11 -0
  58. package/dist/cli/utils/output.js +13 -0
  59. package/dist/mcp/daemon-client.d.ts +31 -0
  60. package/dist/mcp/daemon-client.js +99 -0
  61. package/dist/mcp/index.d.ts +7 -0
  62. package/dist/mcp/index.js +68 -0
  63. package/dist/mcp/instructions.d.ts +1 -0
  64. package/dist/mcp/instructions.js +249 -0
  65. package/dist/mcp/resources/edit-tree-guide.d.ts +1 -0
  66. package/dist/mcp/resources/edit-tree-guide.js +197 -0
  67. package/dist/mcp/resources/error-reference.d.ts +1 -0
  68. package/dist/mcp/resources/error-reference.js +132 -0
  69. package/dist/mcp/resources/outline-format.d.ts +1 -0
  70. package/dist/mcp/resources/outline-format.js +104 -0
  71. package/dist/mcp/resources/rem-object-fields.d.ts +1 -0
  72. package/dist/mcp/resources/rem-object-fields.js +331 -0
  73. package/dist/mcp/resources/separator-flashcard.d.ts +1 -0
  74. package/dist/mcp/resources/separator-flashcard.js +120 -0
  75. package/dist/mcp/tools/edit-tools.d.ts +5 -0
  76. package/dist/mcp/tools/edit-tools.js +47 -0
  77. package/dist/mcp/tools/infra-tools.d.ts +5 -0
  78. package/dist/mcp/tools/infra-tools.js +43 -0
  79. package/dist/mcp/tools/read-tools.d.ts +5 -0
  80. package/dist/mcp/tools/read-tools.js +195 -0
  81. package/dist/mcp/types.d.ts +12 -0
  82. package/dist/mcp/types.js +4 -0
  83. package/docs/instruction/connect.md +158 -0
  84. package/docs/instruction/disconnect.md +146 -0
  85. package/docs/instruction/edit-rem.md +509 -0
  86. package/docs/instruction/edit-tree.md +419 -0
  87. package/docs/instruction/health.md +159 -0
  88. package/docs/instruction/overall.md +751 -0
  89. package/docs/instruction/read-context.md +353 -0
  90. package/docs/instruction/read-globe.md +206 -0
  91. package/docs/instruction/read-rem.md +476 -0
  92. package/docs/instruction/read-tree.md +428 -0
  93. package/docs/instruction/search.md +196 -0
  94. package/package.json +41 -0
  95. package/remnote-plugin/package.json +48 -0
  96. package/remnote-plugin/postcss.config.js +5 -0
  97. package/remnote-plugin/public/bridge-icon.svg +8 -0
  98. package/remnote-plugin/public/manifest.json +22 -0
  99. package/remnote-plugin/src/bridge/message-router.ts +57 -0
  100. package/remnote-plugin/src/bridge/websocket-client.ts +245 -0
  101. package/remnote-plugin/src/index.css +1 -0
  102. package/remnote-plugin/src/services/breadcrumb.ts +26 -0
  103. package/remnote-plugin/src/services/create-rem.ts +59 -0
  104. package/remnote-plugin/src/services/delete-rem.ts +29 -0
  105. package/remnote-plugin/src/services/index.ts +16 -0
  106. package/remnote-plugin/src/services/move-rem.ts +39 -0
  107. package/remnote-plugin/src/services/powerup-filter.ts +31 -0
  108. package/remnote-plugin/src/services/read-context.ts +368 -0
  109. package/remnote-plugin/src/services/read-globe.ts +197 -0
  110. package/remnote-plugin/src/services/read-rem.ts +284 -0
  111. package/remnote-plugin/src/services/read-tree.ts +222 -0
  112. package/remnote-plugin/src/services/rem-builder.ts +124 -0
  113. package/remnote-plugin/src/services/reorder-children.ts +61 -0
  114. package/remnote-plugin/src/services/search.ts +56 -0
  115. package/remnote-plugin/src/services/write-rem-fields.ts +254 -0
  116. package/remnote-plugin/src/settings.ts +12 -0
  117. package/remnote-plugin/src/style.css +45 -0
  118. package/remnote-plugin/src/test-scripts/AGENTS.md +46 -0
  119. package/remnote-plugin/src/test-scripts/test-actions.ts +230 -0
  120. package/remnote-plugin/src/test-scripts/test-powerup-rendering.ts +722 -0
  121. package/remnote-plugin/src/test-scripts/test-rem-type-mapping.ts +283 -0
  122. package/remnote-plugin/src/test-scripts/test-richtext-builder.ts +207 -0
  123. package/remnote-plugin/src/test-scripts/test-richtext-matrix.ts +332 -0
  124. package/remnote-plugin/src/test-scripts/test-richtext-remaining.ts +245 -0
  125. package/remnote-plugin/src/test-scripts/test-rw-fields.ts +399 -0
  126. package/remnote-plugin/src/types.ts +419 -0
  127. package/remnote-plugin/src/utils/elision.ts +45 -0
  128. package/remnote-plugin/src/utils/index.ts +10 -0
  129. package/remnote-plugin/src/utils/tree-serializer.ts +269 -0
  130. package/remnote-plugin/src/widgets/bridge_widget.tsx +170 -0
  131. package/remnote-plugin/src/widgets/index.tsx +82 -0
  132. package/remnote-plugin/tailwind.config.js +7 -0
  133. package/remnote-plugin/tsconfig.json +21 -0
  134. package/remnote-plugin/webpack.config.js +125 -0
  135. package/skill/SKILL.md +428 -0
@@ -0,0 +1,363 @@
1
+ /**
2
+ * ConfigServer — HTTP 配置管理服务器
3
+ *
4
+ * 绑定 127.0.0.1:<configPort>,提供可视化配置页面。
5
+ * - GET / — 返回内联 HTML/CSS/JS 配置页面
6
+ * - GET /api/config — 返回当前配置 JSON
7
+ * - POST /api/config — 校验 → saveConfig → 返回成功
8
+ * - POST /api/restart — 调用 onRestart() 回调 → 返回成功
9
+ */
10
+ import http from 'http';
11
+ import { DEFAULT_CONFIG, DEFAULT_DEFAULTS, loadConfig, saveConfig, configFilePath } from '../config.js';
12
+ export class ConfigServer {
13
+ server = null;
14
+ options;
15
+ constructor(options) {
16
+ this.options = options;
17
+ }
18
+ log(message, level = 'info') {
19
+ this.options.onLog?.(message, level);
20
+ }
21
+ start() {
22
+ return new Promise((resolve, reject) => {
23
+ this.server = http.createServer((req, res) => this.handleRequest(req, res));
24
+ this.server.on('error', (err) => {
25
+ this.log(`ConfigServer 错误: ${err.message}`, 'error');
26
+ reject(err);
27
+ });
28
+ this.server.listen(this.options.port, this.options.host ?? '127.0.0.1', () => {
29
+ this.log(`ConfigServer 监听 ${this.options.host ?? '127.0.0.1'}:${this.options.port}`);
30
+ resolve();
31
+ });
32
+ });
33
+ }
34
+ stop() {
35
+ return new Promise((resolve) => {
36
+ if (this.server) {
37
+ this.server.close(() => {
38
+ this.server = null;
39
+ resolve();
40
+ });
41
+ }
42
+ else {
43
+ resolve();
44
+ }
45
+ });
46
+ }
47
+ async handleRequest(req, res) {
48
+ const url = req.url ?? '/';
49
+ try {
50
+ if (req.method === 'GET' && url === '/') {
51
+ res.writeHead(200, { 'Content-Type': 'text/html; charset=utf-8' });
52
+ res.end(this.renderPage());
53
+ return;
54
+ }
55
+ if (req.method === 'GET' && url === '/api/config') {
56
+ const config = loadConfig(this.options.projectRoot);
57
+ res.writeHead(200, { 'Content-Type': 'application/json' });
58
+ res.end(JSON.stringify(config));
59
+ return;
60
+ }
61
+ if (req.method === 'POST' && url === '/api/config') {
62
+ const body = await readBody(req);
63
+ const newConfig = JSON.parse(body);
64
+ // 端口冲突校验
65
+ const ports = [newConfig.wsPort, newConfig.devServerPort, newConfig.configPort];
66
+ if (new Set(ports).size !== ports.length) {
67
+ res.writeHead(400, { 'Content-Type': 'application/json' });
68
+ res.end(JSON.stringify({ ok: false, error: 'wsPort, devServerPort, configPort 不能重复' }));
69
+ return;
70
+ }
71
+ const filePath = configFilePath(this.options.projectRoot);
72
+ saveConfig(filePath, newConfig);
73
+ this.log('配置已保存');
74
+ res.writeHead(200, { 'Content-Type': 'application/json' });
75
+ res.end(JSON.stringify({ ok: true }));
76
+ return;
77
+ }
78
+ if (req.method === 'POST' && url === '/api/restart') {
79
+ this.log('收到软重启请求');
80
+ try {
81
+ await this.options.onRestart();
82
+ res.writeHead(200, { 'Content-Type': 'application/json' });
83
+ res.end(JSON.stringify({ ok: true }));
84
+ }
85
+ catch (err) {
86
+ res.writeHead(500, { 'Content-Type': 'application/json' });
87
+ res.end(JSON.stringify({ ok: false, error: String(err) }));
88
+ }
89
+ return;
90
+ }
91
+ res.writeHead(404, { 'Content-Type': 'application/json' });
92
+ res.end(JSON.stringify({ error: 'Not found' }));
93
+ }
94
+ catch (err) {
95
+ this.log(`请求处理错误: ${err}`, 'error');
96
+ res.writeHead(500, { 'Content-Type': 'application/json' });
97
+ res.end(JSON.stringify({ ok: false, error: String(err) }));
98
+ }
99
+ }
100
+ renderPage() {
101
+ return `<!DOCTYPE html>
102
+ <html lang="zh-CN">
103
+ <head>
104
+ <meta charset="utf-8">
105
+ <meta name="viewport" content="width=device-width,initial-scale=1">
106
+ <title>RemNote Bridge 配置</title>
107
+ <style>
108
+ * { box-sizing: border-box; margin: 0; padding: 0; }
109
+ body { font-family: system-ui, -apple-system, sans-serif; background: #f5f5f5; color: #333; }
110
+ .container { max-width: 720px; margin: 40px auto; padding: 0 20px; }
111
+ h1 { font-size: 24px; margin-bottom: 8px; }
112
+ .subtitle { color: #666; margin-bottom: 24px; font-size: 14px; }
113
+ .card { background: #fff; border-radius: 8px; padding: 24px; margin-bottom: 16px; box-shadow: 0 1px 3px rgba(0,0,0,.1); }
114
+ .card h2 { font-size: 16px; margin-bottom: 16px; padding-bottom: 8px; border-bottom: 1px solid #eee; }
115
+ .field { display: flex; align-items: center; margin-bottom: 12px; }
116
+ .field:last-child { margin-bottom: 0; }
117
+ .field label { flex: 0 0 240px; font-size: 13px; color: #555; }
118
+ .field input, .field select { flex: 1; padding: 6px 10px; border: 1px solid #ddd; border-radius: 4px; font-size: 13px; }
119
+ .field input:focus, .field select:focus { outline: none; border-color: #4a9eff; box-shadow: 0 0 0 2px rgba(74,158,255,.2); }
120
+ .field .hint { font-size: 11px; color: #999; margin-left: 8px; white-space: nowrap; }
121
+ .actions { display: flex; gap: 12px; margin-top: 24px; }
122
+ button { padding: 8px 20px; border-radius: 6px; font-size: 14px; cursor: pointer; border: 1px solid #ddd; background: #fff; }
123
+ button.primary { background: #4a9eff; color: #fff; border-color: #4a9eff; }
124
+ button.primary:hover { background: #3a8eef; }
125
+ button:hover { background: #f9f9f9; }
126
+ .toast { position: fixed; top: 20px; right: 20px; padding: 12px 20px; border-radius: 6px; font-size: 14px; color: #fff; opacity: 0; transition: opacity .3s; z-index: 100; }
127
+ .toast.success { background: #22c55e; }
128
+ .toast.error { background: #ef4444; }
129
+ .toast.show { opacity: 1; }
130
+ .warning { background: #fef3c7; border: 1px solid #f59e0b; border-radius: 6px; padding: 12px; margin-bottom: 16px; font-size: 12px; color: #92400e; }
131
+ </style>
132
+ </head>
133
+ <body>
134
+ <div class="container">
135
+ <h1>RemNote Bridge 配置</h1>
136
+ <p class="subtitle">修改后需保存并重启才能生效</p>
137
+
138
+ <div class="card">
139
+ <h2>服务端口</h2>
140
+ <div class="field">
141
+ <label>WebSocket 端口 (wsPort)</label>
142
+ <input type="number" id="wsPort" min="1" max="65535">
143
+ </div>
144
+ <div class="field">
145
+ <label>Dev Server 端口 (devServerPort)</label>
146
+ <input type="number" id="devServerPort" min="1" max="65535">
147
+ </div>
148
+ <div class="field">
149
+ <label>配置页端口 (configPort)</label>
150
+ <input type="number" id="configPort" min="1" max="65535">
151
+ <span class="hint">变更需 disconnect→connect</span>
152
+ </div>
153
+ <div class="field">
154
+ <label>守护进程超时 (分钟)</label>
155
+ <input type="number" id="daemonTimeoutMinutes" min="1">
156
+ </div>
157
+ </div>
158
+
159
+ <div class="card">
160
+ <h2>共享默认值</h2>
161
+ <div class="field">
162
+ <label>最大节点数 (maxNodes)</label>
163
+ <input type="number" id="maxNodes" min="1">
164
+ </div>
165
+ <div class="field">
166
+ <label>最大同级数 (maxSiblings)</label>
167
+ <input type="number" id="maxSiblings" min="1">
168
+ </div>
169
+ <div class="field">
170
+ <label>缓存上限 (cacheMaxSize)</label>
171
+ <input type="number" id="cacheMaxSize" min="1">
172
+ </div>
173
+ </div>
174
+
175
+ <div class="card">
176
+ <h2>read-tree 默认值</h2>
177
+ <div class="field">
178
+ <label>展开深度 (readTreeDepth)</label>
179
+ <input type="number" id="readTreeDepth" min="-1">
180
+ <span class="hint">-1 = 全部展开</span>
181
+ </div>
182
+ <div class="field">
183
+ <label>祖先链层数 (readTreeAncestorLevels)</label>
184
+ <input type="number" id="readTreeAncestorLevels" min="0">
185
+ </div>
186
+ <div class="field">
187
+ <label>包含 Powerup (readTreeIncludePowerup)</label>
188
+ <select id="readTreeIncludePowerup">
189
+ <option value="false">否</option>
190
+ <option value="true">是</option>
191
+ </select>
192
+ </div>
193
+ </div>
194
+
195
+ <div class="card">
196
+ <h2>read-globe 默认值</h2>
197
+ <div class="field">
198
+ <label>展开深度 (readGlobeDepth)</label>
199
+ <input type="number" id="readGlobeDepth" min="-1">
200
+ <span class="hint">-1 = 全部展开</span>
201
+ </div>
202
+ </div>
203
+
204
+ <div class="card">
205
+ <h2>read-context 默认值</h2>
206
+ <div class="field">
207
+ <label>模式 (readContextMode)</label>
208
+ <select id="readContextMode">
209
+ <option value="focus">focus</option>
210
+ <option value="page">page</option>
211
+ </select>
212
+ </div>
213
+ <div class="field">
214
+ <label>祖先链层数 (readContextAncestorLevels)</label>
215
+ <input type="number" id="readContextAncestorLevels" min="0">
216
+ </div>
217
+ <div class="field">
218
+ <label>展开深度 (readContextDepth)</label>
219
+ <input type="number" id="readContextDepth" min="-1">
220
+ </div>
221
+ </div>
222
+
223
+ <div class="card">
224
+ <h2>search 默认值</h2>
225
+ <div class="field">
226
+ <label>结果数量 (searchNumResults)</label>
227
+ <input type="number" id="searchNumResults" min="1">
228
+ </div>
229
+ </div>
230
+
231
+ <div class="actions">
232
+ <button class="primary" onclick="saveConfig()">保存配置</button>
233
+ <button onclick="resetDefaults()">恢复默认值</button>
234
+ </div>
235
+ </div>
236
+
237
+ <div class="toast" id="toast"></div>
238
+
239
+ <script>
240
+ const DEFAULTS = ${JSON.stringify({ ...DEFAULT_CONFIG, defaults: { ...DEFAULT_DEFAULTS } })};
241
+
242
+ const TOP_FIELDS = ['wsPort', 'devServerPort', 'configPort', 'daemonTimeoutMinutes'];
243
+ const DEFAULTS_FIELDS = [
244
+ 'maxNodes', 'maxSiblings', 'cacheMaxSize',
245
+ 'readTreeDepth', 'readTreeAncestorLevels', 'readTreeIncludePowerup',
246
+ 'readGlobeDepth',
247
+ 'readContextMode', 'readContextAncestorLevels', 'readContextDepth',
248
+ 'searchNumResults'
249
+ ];
250
+
251
+ function showToast(msg, type) {
252
+ const t = document.getElementById('toast');
253
+ t.textContent = msg;
254
+ t.className = 'toast ' + type + ' show';
255
+ setTimeout(() => t.classList.remove('show'), 3000);
256
+ }
257
+
258
+ function fillForm(config) {
259
+ TOP_FIELDS.forEach(k => {
260
+ document.getElementById(k).value = config[k];
261
+ });
262
+ DEFAULTS_FIELDS.forEach(k => {
263
+ const el = document.getElementById(k);
264
+ const val = config.defaults[k];
265
+ if (el.tagName === 'SELECT') {
266
+ el.value = String(val);
267
+ } else {
268
+ el.value = val;
269
+ }
270
+ });
271
+ }
272
+
273
+ function readForm() {
274
+ const config = { defaults: {} };
275
+ TOP_FIELDS.forEach(k => {
276
+ config[k] = Number(document.getElementById(k).value);
277
+ });
278
+ DEFAULTS_FIELDS.forEach(k => {
279
+ const el = document.getElementById(k);
280
+ if (k === 'readTreeIncludePowerup') {
281
+ config.defaults[k] = el.value === 'true';
282
+ } else if (k === 'readContextMode') {
283
+ config.defaults[k] = el.value;
284
+ } else {
285
+ config.defaults[k] = Number(el.value);
286
+ }
287
+ });
288
+ return config;
289
+ }
290
+
291
+ async function loadConfig() {
292
+ try {
293
+ const res = await fetch('/api/config');
294
+ const config = await res.json();
295
+ fillForm(config);
296
+ } catch (e) {
297
+ showToast('加载配置失败: ' + e, 'error');
298
+ }
299
+ }
300
+
301
+ async function saveConfig() {
302
+ const config = readForm();
303
+ // 端口冲突校验
304
+ const ports = [config.wsPort, config.devServerPort, config.configPort];
305
+ if (new Set(ports).size !== ports.length) {
306
+ showToast('端口不能重复', 'error');
307
+ return;
308
+ }
309
+
310
+ try {
311
+ const res = await fetch('/api/config', {
312
+ method: 'POST',
313
+ headers: { 'Content-Type': 'application/json' },
314
+ body: JSON.stringify(config),
315
+ });
316
+ const result = await res.json();
317
+ if (!result.ok) {
318
+ showToast('保存失败: ' + result.error, 'error');
319
+ return;
320
+ }
321
+ showToast('配置已保存', 'success');
322
+
323
+ // 弹出确认框
324
+ if (confirm('配置已保存。是否立即重启以应用配置?\\n\\n注意:如果修改了 configPort,当前页面将无法访问新端口。需要 disconnect→connect 重新启动。')) {
325
+ try {
326
+ const rr = await fetch('/api/restart', { method: 'POST' });
327
+ const rrResult = await rr.json();
328
+ if (rrResult.ok) {
329
+ showToast('软重启成功', 'success');
330
+ // 重新加载配置显示
331
+ setTimeout(loadConfig, 1000);
332
+ } else {
333
+ showToast('重启失败: ' + rrResult.error, 'error');
334
+ }
335
+ } catch (e) {
336
+ showToast('重启请求失败: ' + e, 'error');
337
+ }
338
+ }
339
+ } catch (e) {
340
+ showToast('保存请求失败: ' + e, 'error');
341
+ }
342
+ }
343
+
344
+ function resetDefaults() {
345
+ if (confirm('确定要恢复所有配置为默认值吗?')) {
346
+ fillForm(DEFAULTS);
347
+ }
348
+ }
349
+
350
+ loadConfig();
351
+ </script>
352
+ </body>
353
+ </html>`;
354
+ }
355
+ }
356
+ function readBody(req) {
357
+ return new Promise((resolve, reject) => {
358
+ const chunks = [];
359
+ req.on('data', (chunk) => chunks.push(chunk));
360
+ req.on('end', () => resolve(Buffer.concat(chunks).toString('utf-8')));
361
+ req.on('error', reject);
362
+ });
363
+ }
@@ -0,0 +1,68 @@
1
+ /**
2
+ * WebSocket Server
3
+ *
4
+ * 守护进程的核心基础设施:监听端口,管理 Plugin 和 CLI 命令的连接。
5
+ * - 接受 Plugin 的 hello 握手
6
+ * - 向 Plugin 发送 ping 心跳
7
+ * - 分发 CLI 请求到对应的 handler
8
+ * - 只允许一个 Plugin 连接
9
+ *
10
+ * 业务编排逻辑在 handlers/ 中,本文件只做连接管理和请求分发。
11
+ */
12
+ import type { StatusResult } from '../protocol.js';
13
+ import type { DefaultsConfig } from '../config.js';
14
+ export interface BridgeServerConfig {
15
+ port: number;
16
+ host?: string;
17
+ pingIntervalMs?: number;
18
+ pongTimeoutMs?: number;
19
+ onLog?: (message: string, level: 'info' | 'warn' | 'error') => void;
20
+ /** 获取守护进程超时剩余秒数(由 daemon 注入) */
21
+ getTimeoutRemaining?: () => number;
22
+ /** 业务默认值(由 daemon 注入) */
23
+ defaults?: DefaultsConfig;
24
+ }
25
+ export declare class BridgeServer {
26
+ private wss;
27
+ private pluginSocket;
28
+ private pluginVersion;
29
+ private pluginSdkReady;
30
+ private pingTimer;
31
+ private pongTimer;
32
+ private startTime;
33
+ private pendingPluginRequests;
34
+ private readHandler;
35
+ private editHandler;
36
+ private treeReadHandler;
37
+ private treeEditHandler;
38
+ private globeReadHandler;
39
+ private contextReadHandler;
40
+ private defaults;
41
+ private config;
42
+ /** 每当收到 CLI 命令请求时触发(用于刷新守护进程超时计时器) */
43
+ onCliRequest?: () => void;
44
+ constructor(config: BridgeServerConfig);
45
+ private log;
46
+ /**
47
+ * 启动 WS Server。返回 Promise,监听成功后 resolve。
48
+ */
49
+ start(): Promise<void>;
50
+ /**
51
+ * 关闭 WS Server。
52
+ */
53
+ stop(): Promise<void>;
54
+ private handleConnection;
55
+ private handlePluginHello;
56
+ private handleCliRequest;
57
+ /**
58
+ * 向 Plugin 发送子请求并等待响应。
59
+ * 生成独立的请求 ID,通过 pendingPluginRequests 关联 Promise。
60
+ */
61
+ forwardToPlugin(action: string, payload: Record<string, unknown>): Promise<unknown>;
62
+ private handlePluginResponse;
63
+ private handlePong;
64
+ private startPingInterval;
65
+ private stopPingInterval;
66
+ /** 获取当前状态(timeoutRemaining 通过构造时注入的回调获取) */
67
+ getStatus(): StatusResult;
68
+ }