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,300 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * remnote-bridge 主入口
4
+ *
5
+ * 伞命令:CLI 命令 + mcp 子命令 + install 子命令。
6
+ */
7
+ import { Command } from 'commander';
8
+ import { connectCommand } from './commands/connect.js';
9
+ import { healthCommand } from './commands/health.js';
10
+ import { disconnectCommand } from './commands/disconnect.js';
11
+ import { readRemCommand } from './commands/read-rem.js';
12
+ import { editRemCommand } from './commands/edit-rem.js';
13
+ import { readTreeCommand } from './commands/read-tree.js';
14
+ import { editTreeCommand } from './commands/edit-tree.js';
15
+ import { readGlobeCommand } from './commands/read-globe.js';
16
+ import { readContextCommand } from './commands/read-context.js';
17
+ import { searchCommand } from './commands/search.js';
18
+ import { installSkillCommand } from './commands/install-skill.js';
19
+ const program = new Command();
20
+ /**
21
+ * --json 模式下解析 JSON 输入参数。
22
+ * 返回 null 表示解析失败(已输出错误并设置 exitCode)。
23
+ */
24
+ function parseJsonInput(command, jsonStr, requiredFields = []) {
25
+ if (!jsonStr) {
26
+ console.log(JSON.stringify({ ok: false, command, error: '--json 模式需要传入 JSON 参数,例如: command --json \'{"remId":"..."}\'' }));
27
+ process.exitCode = 1;
28
+ return null;
29
+ }
30
+ let input;
31
+ try {
32
+ input = JSON.parse(jsonStr);
33
+ }
34
+ catch {
35
+ console.log(JSON.stringify({ ok: false, command, error: `JSON 解析失败: ${jsonStr}` }));
36
+ process.exitCode = 1;
37
+ return null;
38
+ }
39
+ if (!input.remId) {
40
+ console.log(JSON.stringify({ ok: false, command, error: 'JSON 参数中缺少 remId 字段' }));
41
+ process.exitCode = 1;
42
+ return null;
43
+ }
44
+ for (const field of requiredFields) {
45
+ if (input[field] === undefined) {
46
+ console.log(JSON.stringify({ ok: false, command, error: `JSON 参数中缺少 ${field} 字段` }));
47
+ process.exitCode = 1;
48
+ return null;
49
+ }
50
+ }
51
+ return input;
52
+ }
53
+ program
54
+ .name('remnote-bridge')
55
+ .description('RemNote Bridge — CLI + MCP Server + Plugin')
56
+ .version('0.1.0')
57
+ .option('--json', '以 JSON 格式输出(适用于程序化调用)');
58
+ program
59
+ .command('connect')
60
+ .description('启动守护进程(WS Server + webpack-dev-server),等待 Plugin 连接')
61
+ .action(async () => {
62
+ const { json } = program.opts();
63
+ await connectCommand({ json });
64
+ });
65
+ program
66
+ .command('health')
67
+ .description('检查守护进程、Plugin 连接和 SDK 状态')
68
+ .action(async () => {
69
+ const { json } = program.opts();
70
+ await healthCommand({ json });
71
+ });
72
+ program
73
+ .command('disconnect')
74
+ .description('停止守护进程,释放端口和资源')
75
+ .action(async () => {
76
+ const { json } = program.opts();
77
+ await disconnectCommand({ json });
78
+ });
79
+ program
80
+ .command('read-rem [remIdOrJson]')
81
+ .description('读取单个 Rem 的完整 JSON 对象')
82
+ .option('--fields <fields>', '只返回指定字段(逗号分隔)')
83
+ .option('--full', '输出全部 51 个字段(含 R-F 低频字段)')
84
+ .option('--includePowerup', '包含 Powerup 系统数据(默认过滤)')
85
+ .action(async (remIdOrJson, cmdOpts) => {
86
+ const { json } = program.opts();
87
+ if (json) {
88
+ const input = parseJsonInput('read-rem', remIdOrJson);
89
+ if (!input)
90
+ return;
91
+ await readRemCommand(input.remId, { json, fields: input.fields?.join(','), full: input.full, includePowerup: input.includePowerup });
92
+ }
93
+ else {
94
+ if (!remIdOrJson) {
95
+ console.error('错误: 缺少 remId');
96
+ process.exitCode = 1;
97
+ return;
98
+ }
99
+ await readRemCommand(remIdOrJson, { json, ...cmdOpts });
100
+ }
101
+ });
102
+ program
103
+ .command('read-tree [remIdOrJson]')
104
+ .description('读取 Rem 子树并序列化为 Markdown 大纲')
105
+ .option('--depth <depth>', '展开深度(默认 3,-1 = 全部展开)')
106
+ .option('--max-nodes <maxNodes>', '全局节点上限(默认 200)')
107
+ .option('--max-siblings <maxSiblings>', '每个父节点下展示的 children 上限(默认 20)')
108
+ .option('--ancestor-levels <ancestorLevels>', '向上追溯祖先层数(默认 0,上限 10)')
109
+ .option('--includePowerup', '包含 Powerup 系统数据(默认过滤)')
110
+ .action(async (remIdOrJson, cmdOpts) => {
111
+ const { json } = program.opts();
112
+ if (json) {
113
+ const input = parseJsonInput('read-tree', remIdOrJson);
114
+ if (!input)
115
+ return;
116
+ await readTreeCommand(input.remId, {
117
+ json,
118
+ depth: input.depth?.toString(),
119
+ maxNodes: input.maxNodes?.toString(),
120
+ maxSiblings: input.maxSiblings?.toString(),
121
+ ancestorLevels: input.ancestorLevels?.toString(),
122
+ includePowerup: input.includePowerup,
123
+ });
124
+ }
125
+ else {
126
+ if (!remIdOrJson) {
127
+ console.error('错误: 缺少 remId');
128
+ process.exitCode = 1;
129
+ return;
130
+ }
131
+ await readTreeCommand(remIdOrJson, { json, ...cmdOpts });
132
+ }
133
+ });
134
+ program
135
+ .command('read-globe [jsonStr]')
136
+ .description('读取知识库全局概览(仅 Document 层级)')
137
+ .option('--depth <depth>', 'Document 嵌套深度(默认 -1 无限)')
138
+ .option('--max-nodes <maxNodes>', '全局节点上限(默认 200)')
139
+ .option('--max-siblings <maxSiblings>', '每个父节点下展示的 children 上限(默认 20)')
140
+ .action(async (jsonStr, cmdOpts) => {
141
+ const { json } = program.opts();
142
+ if (json) {
143
+ let input = {};
144
+ if (jsonStr) {
145
+ try {
146
+ input = JSON.parse(jsonStr);
147
+ }
148
+ catch {
149
+ console.log(JSON.stringify({ ok: false, command: 'read-globe', error: `JSON 解析失败: ${jsonStr}` }));
150
+ process.exitCode = 1;
151
+ return;
152
+ }
153
+ }
154
+ await readGlobeCommand({
155
+ json,
156
+ depth: input.depth?.toString(),
157
+ maxNodes: input.maxNodes?.toString(),
158
+ maxSiblings: input.maxSiblings?.toString(),
159
+ });
160
+ }
161
+ else {
162
+ await readGlobeCommand({ json, ...cmdOpts });
163
+ }
164
+ });
165
+ program
166
+ .command('read-context [jsonStr]')
167
+ .description('读取当前上下文视图(focus 鱼眼 / page 页面)')
168
+ .option('--mode <mode>', '模式:focus(默认)或 page')
169
+ .option('--ancestor-levels <levels>', '向上追溯几层祖先(默认 2,仅 focus 模式)')
170
+ .option('--depth <depth>', '展开深度(默认 3,仅 page 模式)')
171
+ .option('--max-nodes <maxNodes>', '全局节点上限(默认 200)')
172
+ .option('--max-siblings <maxSiblings>', '每个父节点下展示的 children 上限(默认 20)')
173
+ .action(async (jsonStr, cmdOpts) => {
174
+ const { json } = program.opts();
175
+ if (json) {
176
+ let input = {};
177
+ if (jsonStr) {
178
+ try {
179
+ input = JSON.parse(jsonStr);
180
+ }
181
+ catch {
182
+ console.log(JSON.stringify({ ok: false, command: 'read-context', error: `JSON 解析失败: ${jsonStr}` }));
183
+ process.exitCode = 1;
184
+ return;
185
+ }
186
+ }
187
+ await readContextCommand({
188
+ json,
189
+ mode: input.mode,
190
+ ancestorLevels: input.ancestorLevels?.toString(),
191
+ depth: input.depth?.toString(),
192
+ maxNodes: input.maxNodes?.toString(),
193
+ maxSiblings: input.maxSiblings?.toString(),
194
+ });
195
+ }
196
+ else {
197
+ await readContextCommand({ json, ...cmdOpts });
198
+ }
199
+ });
200
+ program
201
+ .command('edit-tree [remIdOrJson]')
202
+ .description('通过 str_replace 编辑 Rem 子树结构(行级增/删/移/重排)')
203
+ .option('--old-str <oldStr>', '要替换的原始文本片段')
204
+ .option('--new-str <newStr>', '替换后的新文本片段')
205
+ .action(async (remIdOrJson, cmdOpts) => {
206
+ const { json } = program.opts();
207
+ if (json) {
208
+ const input = parseJsonInput('edit-tree', remIdOrJson, ['oldStr', 'newStr']);
209
+ if (!input)
210
+ return;
211
+ await editTreeCommand(input.remId, { json, oldStr: input.oldStr, newStr: input.newStr });
212
+ }
213
+ else {
214
+ if (!remIdOrJson) {
215
+ console.error('错误: 缺少 remId');
216
+ process.exitCode = 1;
217
+ return;
218
+ }
219
+ if (!cmdOpts.oldStr || cmdOpts.newStr === undefined) {
220
+ console.error('错误: --old-str 和 --new-str 是必需的');
221
+ process.exitCode = 1;
222
+ return;
223
+ }
224
+ await editTreeCommand(remIdOrJson, { json, oldStr: cmdOpts.oldStr, newStr: cmdOpts.newStr });
225
+ }
226
+ });
227
+ program
228
+ .command('search [queryOrJson]')
229
+ .description('在知识库中按文本搜索 Rem')
230
+ .option('--limit <limit>', '结果数量上限(默认 20)')
231
+ .action(async (queryOrJson, cmdOpts) => {
232
+ const { json } = program.opts();
233
+ if (json) {
234
+ let input = {};
235
+ if (queryOrJson) {
236
+ try {
237
+ input = JSON.parse(queryOrJson);
238
+ }
239
+ catch {
240
+ console.log(JSON.stringify({ ok: false, command: 'search', error: `JSON 解析失败: ${queryOrJson}` }));
241
+ process.exitCode = 1;
242
+ return;
243
+ }
244
+ }
245
+ if (!input.query) {
246
+ console.log(JSON.stringify({ ok: false, command: 'search', error: 'JSON 参数中缺少 query 字段' }));
247
+ process.exitCode = 1;
248
+ return;
249
+ }
250
+ await searchCommand(input.query, { json, limit: input.numResults?.toString() });
251
+ }
252
+ else {
253
+ if (!queryOrJson) {
254
+ console.error('错误: 缺少搜索关键词');
255
+ process.exitCode = 1;
256
+ return;
257
+ }
258
+ await searchCommand(queryOrJson, { json, ...cmdOpts });
259
+ }
260
+ });
261
+ program
262
+ .command('edit-rem [remIdOrJson]')
263
+ .description('通过 str_replace 编辑 Rem 的 JSON 字段')
264
+ .option('--old-str <oldStr>', '要替换的原始文本片段')
265
+ .option('--new-str <newStr>', '替换后的新文本片段')
266
+ .action(async (remIdOrJson, cmdOpts) => {
267
+ const { json } = program.opts();
268
+ if (json) {
269
+ const input = parseJsonInput('edit-rem', remIdOrJson, ['oldStr', 'newStr']);
270
+ if (!input)
271
+ return;
272
+ await editRemCommand(input.remId, { json, oldStr: input.oldStr, newStr: input.newStr });
273
+ }
274
+ else {
275
+ if (!remIdOrJson) {
276
+ console.error('错误: 缺少 remId');
277
+ process.exitCode = 1;
278
+ return;
279
+ }
280
+ if (!cmdOpts.oldStr || cmdOpts.newStr === undefined) {
281
+ console.error('错误: --old-str 和 --new-str 是必需的');
282
+ process.exitCode = 1;
283
+ return;
284
+ }
285
+ await editRemCommand(remIdOrJson, { json, oldStr: cmdOpts.oldStr, newStr: cmdOpts.newStr });
286
+ }
287
+ });
288
+ // mcp 子命令
289
+ program.command('mcp')
290
+ .description('启动 MCP Server(stdio)')
291
+ .action(async () => {
292
+ const { startMcpServer } = await import('../mcp/index.js');
293
+ await startMcpServer();
294
+ });
295
+ // install 子命令组
296
+ const installCmd = program.command('install').description('安装组件');
297
+ installCmd.command('skill')
298
+ .description('安装 Skill 到 ~/.claude/skills/remnote-bridge/')
299
+ .action(async () => { await installSkillCommand(); });
300
+ program.parse();
@@ -0,0 +1,39 @@
1
+ /**
2
+ * WS 通信协议类型定义
3
+ *
4
+ * 定义 CLI 守护进程与 Plugin 之间的 WebSocket 消息格式。
5
+ * 与 remnote-plugin 各自独立定义,不共享代码。
6
+ */
7
+ export type ConnectionStatus = 'disconnected' | 'connecting' | 'connected';
8
+ export interface HelloMessage {
9
+ type: 'hello';
10
+ version: string;
11
+ sdkReady: boolean;
12
+ }
13
+ export interface PingMessage {
14
+ type: 'ping';
15
+ }
16
+ export interface PongMessage {
17
+ type: 'pong';
18
+ }
19
+ export interface BridgeRequest {
20
+ id: string;
21
+ action: string;
22
+ payload: Record<string, unknown>;
23
+ }
24
+ export interface BridgeResponse {
25
+ id: string;
26
+ result?: unknown;
27
+ error?: string;
28
+ }
29
+ export interface StatusResult {
30
+ pluginConnected: boolean;
31
+ sdkReady: boolean;
32
+ uptime: number;
33
+ timeoutRemaining: number;
34
+ }
35
+ export declare function isHelloMessage(msg: unknown): msg is HelloMessage;
36
+ export declare function isPingMessage(msg: unknown): msg is PingMessage;
37
+ export declare function isPongMessage(msg: unknown): msg is PongMessage;
38
+ export declare function isBridgeRequest(msg: unknown): msg is BridgeRequest;
39
+ export declare function isBridgeResponse(msg: unknown): msg is BridgeResponse;
@@ -0,0 +1,35 @@
1
+ /**
2
+ * WS 通信协议类型定义
3
+ *
4
+ * 定义 CLI 守护进程与 Plugin 之间的 WebSocket 消息格式。
5
+ * 与 remnote-plugin 各自独立定义,不共享代码。
6
+ */
7
+ // ── 消息类型判断辅助 ──
8
+ export function isHelloMessage(msg) {
9
+ return (typeof msg === 'object' &&
10
+ msg !== null &&
11
+ msg.type === 'hello' &&
12
+ typeof msg.version === 'string');
13
+ }
14
+ export function isPingMessage(msg) {
15
+ return (typeof msg === 'object' &&
16
+ msg !== null &&
17
+ msg.type === 'ping');
18
+ }
19
+ export function isPongMessage(msg) {
20
+ return (typeof msg === 'object' &&
21
+ msg !== null &&
22
+ msg.type === 'pong');
23
+ }
24
+ export function isBridgeRequest(msg) {
25
+ return (typeof msg === 'object' &&
26
+ msg !== null &&
27
+ typeof msg.id === 'string' &&
28
+ typeof msg.action === 'string');
29
+ }
30
+ export function isBridgeResponse(msg) {
31
+ return (typeof msg === 'object' &&
32
+ msg !== null &&
33
+ typeof msg.id === 'string' &&
34
+ !('action' in msg));
35
+ }
@@ -0,0 +1,26 @@
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
+ export interface ConfigServerOptions {
11
+ port: number;
12
+ host?: string;
13
+ projectRoot: string;
14
+ onRestart: () => Promise<void>;
15
+ onLog?: (message: string, level: 'info' | 'warn' | 'error') => void;
16
+ }
17
+ export declare class ConfigServer {
18
+ private server;
19
+ private options;
20
+ constructor(options: ConfigServerOptions);
21
+ private log;
22
+ start(): Promise<void>;
23
+ stop(): Promise<void>;
24
+ private handleRequest;
25
+ private renderPage;
26
+ }