@barryfan2045/dsh-matrix 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 (206) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +286 -0
  3. package/THIRD_PARTY_NOTICES.md +53 -0
  4. package/assets/avatars/instance-01.png +0 -0
  5. package/assets/avatars/instance-02.png +0 -0
  6. package/assets/avatars/instance-03.png +0 -0
  7. package/assets/avatars/instance-04.png +0 -0
  8. package/assets/avatars/instance-05.png +0 -0
  9. package/assets/avatars/instance-06.png +0 -0
  10. package/assets/avatars/instance-07.png +0 -0
  11. package/assets/avatars/instance-08.png +0 -0
  12. package/assets/avatars/instance-09.png +0 -0
  13. package/assets/avatars/instance-10.png +0 -0
  14. package/assets/avatars/instance-11.png +0 -0
  15. package/assets/avatars/instance-12.png +0 -0
  16. package/assets/avatars/management.png +0 -0
  17. package/cordis.patch.yml +13 -0
  18. package/dist/auth/admin-commands.d.ts +47 -0
  19. package/dist/auth/admin-commands.d.ts.map +1 -0
  20. package/dist/auth/admin-commands.js +112 -0
  21. package/dist/auth/admin-commands.js.map +1 -0
  22. package/dist/auth/challenge.d.ts +93 -0
  23. package/dist/auth/challenge.d.ts.map +1 -0
  24. package/dist/auth/challenge.js +104 -0
  25. package/dist/auth/challenge.js.map +1 -0
  26. package/dist/auth/store.d.ts +55 -0
  27. package/dist/auth/store.d.ts.map +1 -0
  28. package/dist/auth/store.js +124 -0
  29. package/dist/auth/store.js.map +1 -0
  30. package/dist/bridge/agent-commands.d.ts +39 -0
  31. package/dist/bridge/agent-commands.d.ts.map +1 -0
  32. package/dist/bridge/agent-commands.js +243 -0
  33. package/dist/bridge/agent-commands.js.map +1 -0
  34. package/dist/bridge/attachments-ledger.d.ts +54 -0
  35. package/dist/bridge/attachments-ledger.d.ts.map +1 -0
  36. package/dist/bridge/attachments-ledger.js +68 -0
  37. package/dist/bridge/attachments-ledger.js.map +1 -0
  38. package/dist/bridge/commands.d.ts +28 -0
  39. package/dist/bridge/commands.d.ts.map +1 -0
  40. package/dist/bridge/commands.js +18 -0
  41. package/dist/bridge/commands.js.map +1 -0
  42. package/dist/bridge/crypto-health.d.ts +37 -0
  43. package/dist/bridge/crypto-health.d.ts.map +1 -0
  44. package/dist/bridge/crypto-health.js +38 -0
  45. package/dist/bridge/crypto-health.js.map +1 -0
  46. package/dist/bridge/group-gate.d.ts +38 -0
  47. package/dist/bridge/group-gate.d.ts.map +1 -0
  48. package/dist/bridge/group-gate.js +49 -0
  49. package/dist/bridge/group-gate.js.map +1 -0
  50. package/dist/bridge/instance-lock.d.ts +10 -0
  51. package/dist/bridge/instance-lock.d.ts.map +1 -0
  52. package/dist/bridge/instance-lock.js +82 -0
  53. package/dist/bridge/instance-lock.js.map +1 -0
  54. package/dist/bridge/interactions.d.ts +62 -0
  55. package/dist/bridge/interactions.d.ts.map +1 -0
  56. package/dist/bridge/interactions.js +237 -0
  57. package/dist/bridge/interactions.js.map +1 -0
  58. package/dist/bridge/management-room.d.ts +13 -0
  59. package/dist/bridge/management-room.d.ts.map +1 -0
  60. package/dist/bridge/management-room.js +27 -0
  61. package/dist/bridge/management-room.js.map +1 -0
  62. package/dist/bridge/multi-project.d.ts +34 -0
  63. package/dist/bridge/multi-project.d.ts.map +1 -0
  64. package/dist/bridge/multi-project.js +44 -0
  65. package/dist/bridge/multi-project.js.map +1 -0
  66. package/dist/bridge/pipeline.d.ts +151 -0
  67. package/dist/bridge/pipeline.d.ts.map +1 -0
  68. package/dist/bridge/pipeline.js +502 -0
  69. package/dist/bridge/pipeline.js.map +1 -0
  70. package/dist/bridge/pmctl.d.ts +50 -0
  71. package/dist/bridge/pmctl.d.ts.map +1 -0
  72. package/dist/bridge/pmctl.js +272 -0
  73. package/dist/bridge/pmctl.js.map +1 -0
  74. package/dist/bridge/power-levels.d.ts +57 -0
  75. package/dist/bridge/power-levels.d.ts.map +1 -0
  76. package/dist/bridge/power-levels.js +92 -0
  77. package/dist/bridge/power-levels.js.map +1 -0
  78. package/dist/bridge/power-sync.d.ts +64 -0
  79. package/dist/bridge/power-sync.d.ts.map +1 -0
  80. package/dist/bridge/power-sync.js +121 -0
  81. package/dist/bridge/power-sync.js.map +1 -0
  82. package/dist/bridge/projects.d.ts +97 -0
  83. package/dist/bridge/projects.d.ts.map +1 -0
  84. package/dist/bridge/projects.js +288 -0
  85. package/dist/bridge/projects.js.map +1 -0
  86. package/dist/bridge/quote-cache.d.ts +38 -0
  87. package/dist/bridge/quote-cache.d.ts.map +1 -0
  88. package/dist/bridge/quote-cache.js +56 -0
  89. package/dist/bridge/quote-cache.js.map +1 -0
  90. package/dist/bridge/reply.d.ts +31 -0
  91. package/dist/bridge/reply.d.ts.map +1 -0
  92. package/dist/bridge/reply.js +122 -0
  93. package/dist/bridge/reply.js.map +1 -0
  94. package/dist/bridge/space-identity.d.ts +43 -0
  95. package/dist/bridge/space-identity.d.ts.map +1 -0
  96. package/dist/bridge/space-identity.js +92 -0
  97. package/dist/bridge/space-identity.js.map +1 -0
  98. package/dist/bridge/space-sync.d.ts +94 -0
  99. package/dist/bridge/space-sync.d.ts.map +1 -0
  100. package/dist/bridge/space-sync.js +137 -0
  101. package/dist/bridge/space-sync.js.map +1 -0
  102. package/dist/bridge/turn-commands.d.ts +28 -0
  103. package/dist/bridge/turn-commands.d.ts.map +1 -0
  104. package/dist/bridge/turn-commands.js +97 -0
  105. package/dist/bridge/turn-commands.js.map +1 -0
  106. package/dist/cli/config-store.d.ts +32 -0
  107. package/dist/cli/config-store.d.ts.map +1 -0
  108. package/dist/cli/config-store.js +118 -0
  109. package/dist/cli/config-store.js.map +1 -0
  110. package/dist/cli/crypto-store.d.ts +42 -0
  111. package/dist/cli/crypto-store.d.ts.map +1 -0
  112. package/dist/cli/crypto-store.js +70 -0
  113. package/dist/cli/crypto-store.js.map +1 -0
  114. package/dist/cli/device-prune.d.ts +105 -0
  115. package/dist/cli/device-prune.d.ts.map +1 -0
  116. package/dist/cli/device-prune.js +163 -0
  117. package/dist/cli/device-prune.js.map +1 -0
  118. package/dist/cli/index.d.ts +4 -0
  119. package/dist/cli/index.d.ts.map +1 -0
  120. package/dist/cli/index.js +584 -0
  121. package/dist/cli/index.js.map +1 -0
  122. package/dist/cli/log-filter.d.ts +32 -0
  123. package/dist/cli/log-filter.d.ts.map +1 -0
  124. package/dist/cli/log-filter.js +40 -0
  125. package/dist/cli/log-filter.js.map +1 -0
  126. package/dist/cli/pnpm-builds.d.ts +32 -0
  127. package/dist/cli/pnpm-builds.d.ts.map +1 -0
  128. package/dist/cli/pnpm-builds.js +73 -0
  129. package/dist/cli/pnpm-builds.js.map +1 -0
  130. package/dist/cli/profile-patch.d.ts +26 -0
  131. package/dist/cli/profile-patch.d.ts.map +1 -0
  132. package/dist/cli/profile-patch.js +56 -0
  133. package/dist/cli/profile-patch.js.map +1 -0
  134. package/dist/cli/setup.d.ts +39 -0
  135. package/dist/cli/setup.d.ts.map +1 -0
  136. package/dist/cli/setup.js +234 -0
  137. package/dist/cli/setup.js.map +1 -0
  138. package/dist/cli/systemd-hint.d.ts +11 -0
  139. package/dist/cli/systemd-hint.d.ts.map +1 -0
  140. package/dist/cli/systemd-hint.js +46 -0
  141. package/dist/cli/systemd-hint.js.map +1 -0
  142. package/dist/cli/systemd.d.ts +32 -0
  143. package/dist/cli/systemd.d.ts.map +1 -0
  144. package/dist/cli/systemd.js +58 -0
  145. package/dist/cli/systemd.js.map +1 -0
  146. package/dist/config.d.ts +54 -0
  147. package/dist/config.d.ts.map +1 -0
  148. package/dist/config.js +107 -0
  149. package/dist/config.js.map +1 -0
  150. package/dist/dsh/backend.d.ts +110 -0
  151. package/dist/dsh/backend.d.ts.map +1 -0
  152. package/dist/dsh/backend.js +481 -0
  153. package/dist/dsh/backend.js.map +1 -0
  154. package/dist/dsh/interactions.d.ts +50 -0
  155. package/dist/dsh/interactions.d.ts.map +1 -0
  156. package/dist/dsh/interactions.js +141 -0
  157. package/dist/dsh/interactions.js.map +1 -0
  158. package/dist/dsh/stream.d.ts +32 -0
  159. package/dist/dsh/stream.d.ts.map +1 -0
  160. package/dist/dsh/stream.js +109 -0
  161. package/dist/dsh/stream.js.map +1 -0
  162. package/dist/formatting.d.ts +14 -0
  163. package/dist/formatting.d.ts.map +1 -0
  164. package/dist/formatting.js +63 -0
  165. package/dist/formatting.js.map +1 -0
  166. package/dist/index.d.ts +8 -0
  167. package/dist/index.d.ts.map +1 -0
  168. package/dist/index.js +232 -0
  169. package/dist/index.js.map +1 -0
  170. package/dist/logger.d.ts +9 -0
  171. package/dist/logger.d.ts.map +1 -0
  172. package/dist/logger.js +28 -0
  173. package/dist/logger.js.map +1 -0
  174. package/dist/matrix/matrix-events.d.ts +49 -0
  175. package/dist/matrix/matrix-events.d.ts.map +1 -0
  176. package/dist/matrix/matrix-events.js +89 -0
  177. package/dist/matrix/matrix-events.js.map +1 -0
  178. package/dist/matrix/transport.d.ts +192 -0
  179. package/dist/matrix/transport.d.ts.map +1 -0
  180. package/dist/matrix/transport.js +510 -0
  181. package/dist/matrix/transport.js.map +1 -0
  182. package/dist/ports/attachments.d.ts +51 -0
  183. package/dist/ports/attachments.d.ts.map +1 -0
  184. package/dist/ports/attachments.js +27 -0
  185. package/dist/ports/attachments.js.map +1 -0
  186. package/dist/ports/backend.d.ts +159 -0
  187. package/dist/ports/backend.d.ts.map +1 -0
  188. package/dist/ports/backend.js +25 -0
  189. package/dist/ports/backend.js.map +1 -0
  190. package/dist/ports/interactions.d.ts +65 -0
  191. package/dist/ports/interactions.d.ts.map +1 -0
  192. package/dist/ports/interactions.js +15 -0
  193. package/dist/ports/interactions.js.map +1 -0
  194. package/dist/ports/streaming.d.ts +45 -0
  195. package/dist/ports/streaming.d.ts.map +1 -0
  196. package/dist/ports/streaming.js +23 -0
  197. package/dist/ports/streaming.js.map +1 -0
  198. package/dist/ports/transport.d.ts +68 -0
  199. package/dist/ports/transport.d.ts.map +1 -0
  200. package/dist/ports/transport.js +2 -0
  201. package/dist/ports/transport.js.map +1 -0
  202. package/dist/types.d.ts +53 -0
  203. package/dist/types.d.ts.map +1 -0
  204. package/dist/types.js +2 -0
  205. package/dist/types.js.map +1 -0
  206. package/package.json +80 -0
@@ -0,0 +1,243 @@
1
+ /** Table doubles as /help rendering; handlers register by the same names. */
2
+ export const BRIDGE_COMMANDS = [
3
+ { name: 'model', args: '[provider/id]', description: '查看或切换模型' },
4
+ { name: 'models', description: '列出可用模型' },
5
+ { name: 'thinking', args: '[档位]', description: '查看支持档位或设置思考强度' },
6
+ { name: 'sessions', description: '列出本进程已知的会话(哪些房间已经有会话)' },
7
+ { name: 'name', args: '<标题>', description: '重命名当前会话' },
8
+ { name: 'status', description: '当前会话与模型状态' },
9
+ { name: 'export', description: '导出会话记录' },
10
+ { name: 'help', description: '显示这张命令表' },
11
+ ];
12
+ /** Parsed slash line: name is lowercase, rest keeps the user's spacing. */
13
+ function parseLine(text) {
14
+ const trimmed = text.trim();
15
+ if (!trimmed.startsWith('/'))
16
+ return undefined;
17
+ const space = trimmed.search(/\s/);
18
+ const head = space === -1 ? trimmed.slice(1) : trimmed.slice(1, space);
19
+ if (!/^[A-Za-z0-9_-]+$/.test(head))
20
+ return undefined;
21
+ const arg = space === -1 ? '' : trimmed.slice(space + 1);
22
+ return { name: head.toLowerCase(), arg };
23
+ }
24
+ export function createCommandRouter(deps) {
25
+ const { backend, transport, logger } = deps;
26
+ async function reply(ctx, text) {
27
+ await transport.send(ctx.roomId, text);
28
+ }
29
+ // ── handlers (one per bridge command; later slices fill the model/session ones) ──
30
+ async function handleHelp(ctx) {
31
+ const lines = ['dsh-matrix 桥命令:'];
32
+ for (const c of BRIDGE_COMMANDS) {
33
+ lines.push(`/${c.name}${c.args ? ` ${c.args}` : ''} — ${c.description}`);
34
+ }
35
+ let passthrough = [];
36
+ try {
37
+ passthrough = await backend.listPassthroughCommands(ctx.roomId);
38
+ }
39
+ catch (error) {
40
+ logger.warn('listPassthroughCommands failed:', error instanceof Error ? error.message : error);
41
+ }
42
+ lines.push('', 'DSH 透传命令(由当前 profile 注册):');
43
+ if (passthrough.length === 0) {
44
+ lines.push('(本房间尚无会话或 profile 未挂载命令服务,发一条消息后再 /help)');
45
+ }
46
+ for (const c of passthrough) {
47
+ lines.push(`/${c.name}${c.hint ? ` ${c.hint}` : ''} — ${c.description}`);
48
+ }
49
+ lines.push('', '未列出的 /命令 会报"未知命令",不会进入模型。');
50
+ await reply(ctx, lines.join('\n'));
51
+ }
52
+ async function handleExport(ctx) {
53
+ // Base profile fact (verified): dsh-session-log-export has no row in the
54
+ // matrix bundle composition, so there is nothing to call here.
55
+ await reply(ctx, 'dsh-matrix: 该 profile 未挂载会话导出组件(session-log-export),/export 暂不可用。');
56
+ }
57
+ // ── T4 slice 3: model commands ──
58
+ async function handleModels(ctx) {
59
+ const models = await backend.listModels();
60
+ if (models.length === 0) {
61
+ await reply(ctx, '当前 profile 没有可用的模型服务(listModels 为空)。');
62
+ return;
63
+ }
64
+ const byProvider = new Map();
65
+ for (const m of models) {
66
+ const list = byProvider.get(m.provider) ?? [];
67
+ list.push(`${m.provider}/${m.model}${m.name ? ` — ${m.name}` : ''}`);
68
+ byProvider.set(m.provider, list);
69
+ }
70
+ const lines = ['可用模型(/model <provider/id> 切换):'];
71
+ for (const [provider, rows] of byProvider) {
72
+ lines.push('', provider);
73
+ lines.push(...rows.map((r) => ` ${r}`));
74
+ }
75
+ await reply(ctx, lines.join('\n'));
76
+ }
77
+ async function handleModel(ctx, arg) {
78
+ let want = arg.trim();
79
+ if (!want) {
80
+ const cur = await backend.currentModel(ctx.roomId);
81
+ if (!cur) {
82
+ await reply(ctx, '该房间还没有会话:先发一条消息,再用 /model <provider/id> 选择模型。');
83
+ return;
84
+ }
85
+ await reply(ctx, `当前模型:${cur.provider}/${cur.model}${cur.reasoningEffort ? ` (thinking: ${cur.reasoningEffort})` : ''}`);
86
+ return;
87
+ }
88
+ // 允许尾随思考档位:/model <provider/id> [effort]
89
+ const tokens = want.split(/\s+/);
90
+ want = tokens[0];
91
+ const effort = tokens[1];
92
+ const slash = want.indexOf('/');
93
+ if (slash > 0 && slash < want.length - 1) {
94
+ // provider/id 形式:直接选
95
+ const sel = await backend.selectModel(ctx.roomId, want.slice(0, slash), want.slice(slash + 1), effort);
96
+ await reply(ctx, `已切换模型:${sel.provider}/${sel.model}${sel.reasoningEffort ? ` (thinking: ${sel.reasoningEffort})` : ''}`);
97
+ return;
98
+ }
99
+ // 裸 id:在目录里解析
100
+ const models = await backend.listModels();
101
+ const hits = models.filter((m) => m.model === want);
102
+ if (hits.length === 0) {
103
+ await reply(ctx, `模型 ${want} 不在目录里:/models 查看全部可用模型(带 provider/id)。`);
104
+ return;
105
+ }
106
+ if (hits.length > 1) {
107
+ const where = hits.map((m) => `${m.provider}/${m.model}`).join('、');
108
+ await reply(ctx, `${want} 在多个 provider 下都有(${where}),请用 /model <provider/id> 指明。`);
109
+ return;
110
+ }
111
+ const hit = hits[0];
112
+ const sel = await backend.selectModel(ctx.roomId, hit.provider, hit.model);
113
+ await reply(ctx, `已切换模型:${sel.provider}/${sel.model}`);
114
+ }
115
+ // ── thinking / name / status ──
116
+ async function handleThinking(ctx, arg) {
117
+ const cur = await backend.currentModel(ctx.roomId);
118
+ if (!cur?.provider || !cur.model) {
119
+ await reply(ctx, '该房间还没有会话:先发一条消息,再用 /thinking 设置档位。');
120
+ return;
121
+ }
122
+ const efforts = await backend.listThinkingEfforts(cur.provider, cur.model);
123
+ if (efforts.length === 0) {
124
+ await reply(ctx, `模型 ${cur.provider}/${cur.model} 不支持思考档位设置。`);
125
+ return;
126
+ }
127
+ let want = arg.trim();
128
+ if (!want) {
129
+ const lines = [`当前:${cur.provider}/${cur.model},档位:${cur.reasoningEffort ?? '(默认)'}`, '可用档位:'];
130
+ for (const e of efforts)
131
+ lines.push(` ${e.id}${e.description ? ` — ${e.description}` : ''}`);
132
+ lines.push('用法:/thinking <档位>');
133
+ await reply(ctx, lines.join('\n'));
134
+ return;
135
+ }
136
+ const hit = efforts.find((e) => e.id === want || e.name === want);
137
+ if (!hit) {
138
+ await reply(ctx, `没有叫 ${want} 的档位,可用:${efforts.map((e) => e.id).join('、')}。`);
139
+ return;
140
+ }
141
+ await backend.selectModel(ctx.roomId, cur.provider, cur.model, hit.id);
142
+ await reply(ctx, `思考档位已设为:${hit.id}`);
143
+ }
144
+ async function handleName(ctx, arg) {
145
+ const title = arg.trim();
146
+ if (!title) {
147
+ await reply(ctx, '用法:/name <会话标题>');
148
+ return;
149
+ }
150
+ await backend.renameSession(ctx.roomId, title);
151
+ await reply(ctx, `✅ 会话已命名为:${title}`);
152
+ }
153
+ async function handleStatus(ctx) {
154
+ const cur = await backend.currentModel(ctx.roomId);
155
+ const session = backend.peekSession(ctx.roomId);
156
+ if (!cur && !session) {
157
+ await reply(ctx, '该房间还没有会话。');
158
+ return;
159
+ }
160
+ const queue = session ? await session.queuedItems() : [];
161
+ const lines = [
162
+ `模型:${cur?.provider ?? '?'}/${cur?.model ?? '?'}${cur?.reasoningEffort ? ` (thinking: ${cur.reasoningEffort})` : ''}`,
163
+ `状态:${session?.isRunning() ? '回合运行中' : '空闲'}`,
164
+ `队列:${queue.length} 条`,
165
+ ];
166
+ await reply(ctx, lines.join('\n'));
167
+ }
168
+ /**
169
+ * T11(/sessions):列出本进程已知的房间↔会话绑定。
170
+ *
171
+ * 刻意不做 /switch:本桥的房间与会话是确定性一对一(`sessionIdFor(roomId)`),
172
+ * 不存在 pi-courier 那种"一个实例多个会话、可把房间切到另一个"的模型 ——
173
+ * 宣传一个语义上不存在的命令,只会让用户白试一次。
174
+ */
175
+ async function handleSessions(ctx) {
176
+ const entries = await backend.listSessions();
177
+ if (entries.length === 0) {
178
+ await reply(ctx, '本进程还没有任何会话。在房间里发一条普通消息就会建会话(重启后按房间懒恢复)。');
179
+ return;
180
+ }
181
+ const lines = [`本进程已知会话(${entries.length} 个):`];
182
+ for (const e of entries) {
183
+ lines.push(`• ${e.roomId} — ${e.running ? '回合运行中' : '空闲'}${e.roomId === ctx.roomId ? ' ← 本房间' : ''}`);
184
+ }
185
+ await reply(ctx, lines.join('\n'));
186
+ }
187
+ const handlers = new Map([
188
+ ['help', (ctx) => handleHelp(ctx)],
189
+ ['export', (ctx) => handleExport(ctx)],
190
+ ['models', (ctx) => handleModels(ctx)],
191
+ ['model', (ctx, arg) => handleModel(ctx, arg)],
192
+ ['thinking', (ctx, arg) => handleThinking(ctx, arg)],
193
+ ['sessions', (ctx) => handleSessions(ctx)],
194
+ ['name', (ctx, arg) => handleName(ctx, arg)],
195
+ ['status', (ctx) => handleStatus(ctx)],
196
+ ]);
197
+ async function passthrough(ctx, line, name) {
198
+ let out;
199
+ try {
200
+ out = await backend.executeCommand(ctx.roomId, line.trim());
201
+ }
202
+ catch (error) {
203
+ await reply(ctx, error instanceof Error ? error.message : String(error));
204
+ return;
205
+ }
206
+ if (out === undefined) {
207
+ await reply(ctx, `未知命令:/${name} — 输入 /help 查看桥命令与当前可用的透传命令。`);
208
+ return;
209
+ }
210
+ if (out === '') {
211
+ await reply(ctx, `命令 /${name} 已执行(无输出文本)。`);
212
+ return;
213
+ }
214
+ await reply(ctx, out);
215
+ }
216
+ return {
217
+ isCommand(text) {
218
+ return text.trim().startsWith('/');
219
+ },
220
+ async handle(text, ctx) {
221
+ const parsed = parseLine(text);
222
+ if (!parsed) {
223
+ // Looks like a command (starts with '/'), but not parseable as one.
224
+ const name = text.trim().slice(1).split(/\s/)[0] ?? '';
225
+ await reply(ctx, `未知命令:/${name} — 输入 /help 查看可用命令。`);
226
+ return;
227
+ }
228
+ const handler = handlers.get(parsed.name);
229
+ if (handler) {
230
+ try {
231
+ await handler(ctx, parsed.arg);
232
+ }
233
+ catch (error) {
234
+ logger.error('command handler failed:', error instanceof Error ? error.stack : error);
235
+ await reply(ctx, `命令 /${parsed.name} 执行失败:${error instanceof Error ? error.message : String(error)}`);
236
+ }
237
+ return;
238
+ }
239
+ await passthrough(ctx, text, parsed.name);
240
+ },
241
+ };
242
+ }
243
+ //# sourceMappingURL=agent-commands.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"agent-commands.js","sourceRoot":"","sources":["../../src/bridge/agent-commands.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,54 @@
1
+ /**
2
+ * T6 pending-attachment ledger (US25-28), ported from pi-courier's
3
+ * message-router attachment stage (issue #66 票1/票3 semantics):
4
+ *
5
+ * - keyed by ROOM + SENDER (`attachmentLedgerKey`): in a group, Alice's
6
+ * photo is never consumed by Bob's next message;
7
+ * - consumption lives OUTSIDE this module on purpose: only the pipeline's
8
+ * successful prompt path calls clear() (commands / question answers /
9
+ * steer return before it), so commands never consume;
10
+ * - purely in-memory: a bridge restart drops every pending ledger (each
11
+ * save already echoed the receipt, so nothing is silently lost);
12
+ * - mxc dedup within one pending window: a re-forwarded copy of the same
13
+ * media is not admitted twice.
14
+ */
15
+ import type { MediaMsgtype, PreparedAttachment } from '../ports/attachments.ts';
16
+ /** A ledger entry: the prepared bytes plus the mxc it came from (dedup key). */
17
+ export interface LedgerItem extends PreparedAttachment {
18
+ readonly mxc: string;
19
+ }
20
+ export interface AttachmentsLedgerOptions {
21
+ /** Hard cap per attachment, in bytes (config attachments.maxMb × MiB). */
22
+ maxBytes: number;
23
+ }
24
+ export interface AttachmentsLedger {
25
+ /**
26
+ * Admit one download result and return the room receipt text.
27
+ * Oversized real bytes and duplicate mxcs are refused (nothing stored).
28
+ */
29
+ save(roomId: string, sender: string, item: LedgerItem): string;
30
+ /** True when this exact mxc is already pending for the room+sender pair. */
31
+ has(roomId: string, sender: string, mxc: string): boolean;
32
+ /** Pending list for the next prompt. Does NOT consume (pi-courier keeps
33
+ * the ledger parked until the send succeeded). */
34
+ peek(roomId: string, sender: string): LedgerItem[];
35
+ /** Consume: drop the whole pending list for the key. */
36
+ clear(roomId: string, sender: string): void;
37
+ }
38
+ /** 附件清单的记账键:房间 + 发送者(pi-courier attachmentLedgerKey 同构)。 */
39
+ export declare function attachmentLedgerKey(roomId: string, sender: string): string;
40
+ /** m.image/m.sticker 进模型;其余(m.file/m.audio/m.video)落盘走路径。 */
41
+ export declare function attachmentKindFor(msgtype: MediaMsgtype): 'image' | 'file';
42
+ export declare function formatBytes(bytes: number): string;
43
+ /** 保存成功回执(US25:先回执,下一条消息才带上)。 */
44
+ export declare function attachmentSavedReply(item: LedgerItem): string;
45
+ /** 超限拒绝回执(US28)。 */
46
+ export declare function attachmentTooLargeReply(bytes: number, maxBytes: number): string;
47
+ /** 重复 mxc 去重回执(同一待消费窗口内)。 */
48
+ export declare function duplicateAttachmentReply(): string;
49
+ /** 下载/解密失败回执:原因原样透传到房间(US29/US42 不许静默)。 */
50
+ export declare function downloadFailureReply(reason: string): string;
51
+ /** 非媒体且非文本消息(m.location 等)的礼貌回执(蓝本票3"消灭静默")。 */
52
+ export declare function unsupportedTypeReply(msgtype: string): string;
53
+ export declare function createAttachmentsLedger(opts: AttachmentsLedgerOptions): AttachmentsLedger;
54
+ //# sourceMappingURL=attachments-ledger.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"attachments-ledger.d.ts","sourceRoot":"","sources":["../../src/bridge/attachments-ledger.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AACH,OAAO,KAAK,EAAE,YAAY,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAA;AAE/E,gFAAgF;AAChF,MAAM,WAAW,UAAW,SAAQ,kBAAkB;IACpD,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAA;CACrB;AAED,MAAM,WAAW,wBAAwB;IACvC,0EAA0E;IAC1E,QAAQ,EAAE,MAAM,CAAA;CACjB;AAED,MAAM,WAAW,iBAAiB;IAChC;;;OAGG;IACH,IAAI,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,UAAU,GAAG,MAAM,CAAA;IAC9D,4EAA4E;IAC5E,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAA;IACzD;uDACmD;IACnD,IAAI,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,UAAU,EAAE,CAAA;IAClD,wDAAwD;IACxD,KAAK,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,IAAI,CAAA;CAC5C;AAED,4DAA4D;AAC5D,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,CAE1E;AAED,6DAA6D;AAC7D,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,YAAY,GAAG,OAAO,GAAG,MAAM,CAEzE;AAED,wBAAgB,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAIjD;AAED,iCAAiC;AACjC,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,UAAU,GAAG,MAAM,CAG7D;AAED,oBAAoB;AACpB,wBAAgB,uBAAuB,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAG/E;AAED,6BAA6B;AAC7B,wBAAgB,wBAAwB,IAAI,MAAM,CAEjD;AAED,2CAA2C;AAC3C,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAE3D;AAED,gDAAgD;AAChD,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAE5D;AAED,wBAAgB,uBAAuB,CAAC,IAAI,EAAE,wBAAwB,GAAG,iBAAiB,CAiCzF"}
@@ -0,0 +1,68 @@
1
+ /** 附件清单的记账键:房间 + 发送者(pi-courier attachmentLedgerKey 同构)。 */
2
+ export function attachmentLedgerKey(roomId, sender) {
3
+ return `${roomId}\u0000${sender}`;
4
+ }
5
+ /** m.image/m.sticker 进模型;其余(m.file/m.audio/m.video)落盘走路径。 */
6
+ export function attachmentKindFor(msgtype) {
7
+ return msgtype === 'm.image' || msgtype === 'm.sticker' ? 'image' : 'file';
8
+ }
9
+ export function formatBytes(bytes) {
10
+ if (bytes >= 1024 * 1024)
11
+ return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
12
+ if (bytes >= 1024)
13
+ return `${(bytes / 1024).toFixed(0)} KB`;
14
+ return `${bytes} B`;
15
+ }
16
+ /** 保存成功回执(US25:先回执,下一条消息才带上)。 */
17
+ export function attachmentSavedReply(item) {
18
+ const name = item.filename || item.mimeType || '附件';
19
+ return `📎 附件已接收: ${name}(${formatBytes(item.bytes.length)})\n下一条消息发送时会自动带上它。`;
20
+ }
21
+ /** 超限拒绝回执(US28)。 */
22
+ export function attachmentTooLargeReply(bytes, maxBytes) {
23
+ const cap = maxBytes >= 1024 * 1024 ? `${Math.round(maxBytes / (1024 * 1024))} MB` : formatBytes(maxBytes);
24
+ return `❌ 拒绝:附件超过 ${cap} 上限(实际 ${formatBytes(bytes)}),未接收。请压缩后重发,或调大 attachments.maxMb 配置。`;
25
+ }
26
+ /** 重复 mxc 去重回执(同一待消费窗口内)。 */
27
+ export function duplicateAttachmentReply() {
28
+ return '⏭️ 同一附件已接收过,本次重复发送已去重。';
29
+ }
30
+ /** 下载/解密失败回执:原因原样透传到房间(US29/US42 不许静默)。 */
31
+ export function downloadFailureReply(reason) {
32
+ return `❌ 附件下载失败: ${reason}`;
33
+ }
34
+ /** 非媒体且非文本消息(m.location 等)的礼貌回执(蓝本票3"消灭静默")。 */
35
+ export function unsupportedTypeReply(msgtype) {
36
+ return `🤷 暂不支持的消息类型(${msgtype}),已忽略。文字、图片和文件都可以直接发给我。`;
37
+ }
38
+ export function createAttachmentsLedger(opts) {
39
+ const pending = new Map();
40
+ return {
41
+ save(roomId, sender, item) {
42
+ // Re-check against REAL bytes - info.size is a hint, servers lie
43
+ // (pi-courier AttachmentStore.save 同款双保险)。
44
+ if (item.bytes.length > opts.maxBytes) {
45
+ return attachmentTooLargeReply(item.bytes.length, opts.maxBytes);
46
+ }
47
+ const key = attachmentLedgerKey(roomId, sender);
48
+ const list = pending.get(key) ?? [];
49
+ if (list.some((i) => i.mxc === item.mxc)) {
50
+ return duplicateAttachmentReply();
51
+ }
52
+ list.push(item);
53
+ pending.set(key, list);
54
+ return attachmentSavedReply(item);
55
+ },
56
+ has(roomId, sender, mxc) {
57
+ const list = pending.get(attachmentLedgerKey(roomId, sender));
58
+ return list !== undefined && list.some((i) => i.mxc === mxc);
59
+ },
60
+ peek(roomId, sender) {
61
+ return [...(pending.get(attachmentLedgerKey(roomId, sender)) ?? [])];
62
+ },
63
+ clear(roomId, sender) {
64
+ pending.delete(attachmentLedgerKey(roomId, sender));
65
+ },
66
+ };
67
+ }
68
+ //# sourceMappingURL=attachments-ledger.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"attachments-ledger.js","sourceRoot":"","sources":["../../src/bridge/attachments-ledger.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,28 @@
1
+ /**
2
+ * T2: minimal bridge command table - a name→handler registry the pipeline
3
+ * consults BEFORE the prompt path. T3/T4 extend the table (turn control,
4
+ * sessions, pass-through); this ticket only registers the admin commands.
5
+ *
6
+ * Deliberately not "parse everything": unknown slash text is NOT handled
7
+ * here (T4 decides the unknown-command UX per the spec), so the pipeline
8
+ * keeps its current behavior for anything unregistered.
9
+ */
10
+ import type { IncomingMessage } from '../types.ts';
11
+ export interface CommandContext {
12
+ msg: IncomingMessage;
13
+ /** Reply to the room the command came from (m.text). */
14
+ respond(text: string): Promise<void>;
15
+ }
16
+ export type CommandHandler = (ctx: CommandContext) => void | Promise<void>;
17
+ export interface CommandRegistry {
18
+ /** Register `/name`. Re-registering replaces the previous handler. */
19
+ register(name: string, handler: CommandHandler): void;
20
+ /** Match a message against registered commands; undefined if not one. */
21
+ match(text: string): {
22
+ name: string;
23
+ args: string[];
24
+ handler: CommandHandler;
25
+ } | undefined;
26
+ }
27
+ export declare function createCommandRegistry(): CommandRegistry;
28
+ //# sourceMappingURL=commands.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"commands.d.ts","sourceRoot":"","sources":["../../src/bridge/commands.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,aAAa,CAAA;AAElD,MAAM,WAAW,cAAc;IAC7B,GAAG,EAAE,eAAe,CAAA;IACpB,wDAAwD;IACxD,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;CACrC;AAED,MAAM,MAAM,cAAc,GAAG,CAAC,GAAG,EAAE,cAAc,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;AAE1E,MAAM,WAAW,eAAe;IAC9B,sEAAsE;IACtE,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,cAAc,GAAG,IAAI,CAAA;IACrD,yEAAyE;IACzE,KAAK,CAAC,IAAI,EAAE,MAAM,GAAG;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,EAAE,CAAC;QAAC,OAAO,EAAE,cAAc,CAAA;KAAE,GAAG,SAAS,CAAA;CAC3F;AAED,wBAAgB,qBAAqB,IAAI,eAAe,CAevD"}
@@ -0,0 +1,18 @@
1
+ export function createCommandRegistry() {
2
+ const handlers = new Map();
3
+ return {
4
+ register(name, handler) {
5
+ handlers.set(name.toLowerCase().replace(/^\//, ''), handler);
6
+ },
7
+ match(text) {
8
+ const trimmed = text.trim();
9
+ if (!trimmed.startsWith('/'))
10
+ return undefined;
11
+ const parts = trimmed.split(/\s+/);
12
+ const name = parts[0].slice(1).toLowerCase();
13
+ const handler = handlers.get(name);
14
+ return handler ? { name, args: parts.slice(1), handler } : undefined;
15
+ },
16
+ };
17
+ }
18
+ //# sourceMappingURL=commands.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"commands.js","sourceRoot":"","sources":["../../src/bridge/commands.ts"],"names":[],"mappings":"AA0BA,MAAM,UAAU,qBAAqB;IACnC,MAAM,QAAQ,GAAG,IAAI,GAAG,EAA0B,CAAA;IAClD,OAAO;QACL,QAAQ,CAAC,IAAI,EAAE,OAAO;YACpB,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,EAAE,OAAO,CAAC,CAAA;QAC9D,CAAC;QACD,KAAK,CAAC,IAAI;YACR,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,EAAE,CAAA;YAC3B,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,GAAG,CAAC;gBAAE,OAAO,SAAS,CAAA;YAC9C,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,CAAA;YAClC,MAAM,IAAI,GAAG,KAAK,CAAC,CAAC,CAAE,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,WAAW,EAAE,CAAA;YAC7C,MAAM,OAAO,GAAG,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,CAAA;YAClC,OAAO,OAAO,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,CAAC,CAAC,CAAC,SAAS,CAAA;QACtE,CAAC;KACF,CAAA;AACH,CAAC"}
@@ -0,0 +1,37 @@
1
+ /**
2
+ * T13:E2EE 解密的健康观测。
3
+ *
4
+ * 背景(见 docs/tickets/13-crypto-store-health.md):crypto 存储一旦坏掉,E2EE 会**静默
5
+ * 失效** —— 桥照常启动、照常打 "E2EE 已启用",只是每条密文都解不开。用户看到的是
6
+ * "bot 突然不理我了",而日志里只有 matrix-bot-sdk 自己的一行 error。
7
+ *
8
+ * matrix-bot-sdk 其实给了**一等公民事件**:
9
+ * - 解密失败 → `room.failed_decryption(roomId, event, error)`
10
+ * - 解密成功 → `room.decrypted_event(roomId, event)`
11
+ * 所以这里不猜、不采样:直接数连续失败,到阈值就告警**一次**;一旦有一次成功解密就
12
+ * 认为恢复,重置计数、并允许下一次再告警。
13
+ *
14
+ * 防刷屏的粒度是"一次坏掉的过程"(episode),不是每条消息:存储坏掉会持续产生失败,
15
+ * 那只会把日志刷满,对排查没有额外信息。
16
+ */
17
+ import type { Logger } from '../types.ts';
18
+ export interface CryptoHealthOptions {
19
+ /** 连续失败到多少条才告警(缺省 3:偶发一条可能只是密钥还没到)。 */
20
+ threshold?: number;
21
+ logger?: Logger;
22
+ /** 可选:额外通知(例如发到管理房间)。同一次故障只调一次。 */
23
+ notify?: (text: string) => void;
24
+ }
25
+ export interface CryptoHealth {
26
+ /** 收到一条解密失败。 */
27
+ onFailedDecryption(roomId: string, eventId?: string): void;
28
+ /** 有一条解密成功 → 视为恢复。 */
29
+ onDecrypted(roomId: string): void;
30
+ /** 当前是否处于"连续失败已告警"的状态(诊断与测试用)。 */
31
+ isDegraded(): boolean;
32
+ /** 连续失败计数(诊断与测试用)。 */
33
+ failures(): number;
34
+ }
35
+ export declare const DEFAULT_FAILURE_THRESHOLD = 3;
36
+ export declare function createCryptoHealth(opts?: CryptoHealthOptions): CryptoHealth;
37
+ //# sourceMappingURL=crypto-health.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"crypto-health.d.ts","sourceRoot":"","sources":["../../src/bridge/crypto-health.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AACH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,aAAa,CAAA;AAEzC,MAAM,WAAW,mBAAmB;IAClC,uCAAuC;IACvC,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,mCAAmC;IACnC,MAAM,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAA;CAChC;AAED,MAAM,WAAW,YAAY;IAC3B,gBAAgB;IAChB,kBAAkB,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IAC1D,sBAAsB;IACtB,WAAW,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAA;IACjC,kCAAkC;IAClC,UAAU,IAAI,OAAO,CAAA;IACrB,sBAAsB;IACtB,QAAQ,IAAI,MAAM,CAAA;CACnB;AAED,eAAO,MAAM,yBAAyB,IAAI,CAAA;AAE1C,wBAAgB,kBAAkB,CAAC,IAAI,GAAE,mBAAwB,GAAG,YAAY,CAwC/E"}
@@ -0,0 +1,38 @@
1
+ export const DEFAULT_FAILURE_THRESHOLD = 3;
2
+ export function createCryptoHealth(opts = {}) {
3
+ const threshold = opts.threshold ?? DEFAULT_FAILURE_THRESHOLD;
4
+ let consecutive = 0;
5
+ let degraded = false;
6
+ /** 告警里提到过的房间(取前几个,便于用户去那个房间看)。 */
7
+ const rooms = new Set();
8
+ return {
9
+ onFailedDecryption(roomId, eventId) {
10
+ consecutive += 1;
11
+ rooms.add(roomId);
12
+ if (consecutive < threshold || degraded)
13
+ return;
14
+ degraded = true;
15
+ const where = [...rooms].slice(0, 3).join('、');
16
+ const detail = `⚠️ 连续 ${consecutive} 条加密消息解不开(房间:${where || '?'}` +
17
+ `${eventId ? `,最近事件 ${eventId}` : ''})。` +
18
+ '这通常意味着 crypto 存储坏了或与设备身份不匹配 —— 桥仍会照常收发明文,但加密房间会静默失效。';
19
+ opts.logger?.warn(detail);
20
+ opts.notify?.(`${detail}\n\n自救:在服务器上跑 \`dsh-matrix reset-crypto\`(会换设备身份、需重新验证;` +
21
+ '详见 README 的排障一节)。');
22
+ },
23
+ onDecrypted(_roomId) {
24
+ if (degraded)
25
+ opts.logger?.info('✅ E2EE 解密已恢复(收到一条可解密的消息),告警状态重置');
26
+ consecutive = 0;
27
+ degraded = false;
28
+ rooms.clear();
29
+ },
30
+ isDegraded() {
31
+ return degraded;
32
+ },
33
+ failures() {
34
+ return consecutive;
35
+ },
36
+ };
37
+ }
38
+ //# sourceMappingURL=crypto-health.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"crypto-health.js","sourceRoot":"","sources":["../../src/bridge/crypto-health.ts"],"names":[],"mappings":"AAqCA,MAAM,CAAC,MAAM,yBAAyB,GAAG,CAAC,CAAA;AAE1C,MAAM,UAAU,kBAAkB,CAAC,OAA4B,EAAE;IAC/D,MAAM,SAAS,GAAG,IAAI,CAAC,SAAS,IAAI,yBAAyB,CAAA;IAC7D,IAAI,WAAW,GAAG,CAAC,CAAA;IACnB,IAAI,QAAQ,GAAG,KAAK,CAAA;IACpB,kCAAkC;IAClC,MAAM,KAAK,GAAG,IAAI,GAAG,EAAU,CAAA;IAE/B,OAAO;QACL,kBAAkB,CAAC,MAAc,EAAE,OAAgB;YACjD,WAAW,IAAI,CAAC,CAAA;YAChB,KAAK,CAAC,GAAG,CAAC,MAAM,CAAC,CAAA;YACjB,IAAI,WAAW,GAAG,SAAS,IAAI,QAAQ;gBAAE,OAAM;YAC/C,QAAQ,GAAG,IAAI,CAAA;YACf,MAAM,KAAK,GAAG,CAAC,GAAG,KAAK,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAA;YAC9C,MAAM,MAAM,GACV,SAAS,WAAW,gBAAgB,KAAK,IAAI,GAAG,EAAE;gBAClD,GAAG,OAAO,CAAC,CAAC,CAAC,SAAS,OAAO,EAAE,CAAC,CAAC,CAAC,EAAE,IAAI;gBACxC,sDAAsD,CAAA;YACxD,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,MAAM,CAAC,CAAA;YACzB,IAAI,CAAC,MAAM,EAAE,CACX,GAAG,MAAM,yDAAyD;gBAChE,mBAAmB,CACtB,CAAA;QACH,CAAC;QAED,WAAW,CAAC,OAAe;YACzB,IAAI,QAAQ;gBAAE,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,iCAAiC,CAAC,CAAA;YAClE,WAAW,GAAG,CAAC,CAAA;YACf,QAAQ,GAAG,KAAK,CAAA;YAChB,KAAK,CAAC,KAAK,EAAE,CAAA;QACf,CAAC;QAED,UAAU;YACR,OAAO,QAAQ,CAAA;QACjB,CAAC;QAED,QAAQ;YACN,OAAO,WAAW,CAAA;QACpB,CAAC;KACF,CAAA;AACH,CAAC"}
@@ -0,0 +1,38 @@
1
+ /**
2
+ * T8 (US32): the group gate — per-room policy for group chats.
3
+ *
4
+ * Consulted by the pipeline for every group message, BEFORE the command
5
+ * table. Policy state lives in AuthState.channels (schema shipped in T2);
6
+ * room modes: 'all' (everyone), 'mentions' (only @bot), 'trusted-only'.
7
+ * Not-yet-enabled rooms are silent with two exceptions:
8
+ * - a trusted sender's `/enable …` passes through so it can reach the
9
+ * command table (this is how a room gets enabled in the first place);
10
+ * - the trusted sender's FIRST other message gets a one-time enable hint
11
+ * (room-join hints share the same once-per-room budget);
12
+ * - strangers keep the T1 reject notice — pre-T8 behavior for the room
13
+ * they can't control anyway (and no policy leaks to non-members' eyes).
14
+ */
15
+ import type { IncomingMessage } from '../types.ts';
16
+ import type { AuthStore } from '../auth/store.ts';
17
+ export type GroupDecision = {
18
+ action: 'pass';
19
+ } | {
20
+ action: 'silence';
21
+ } | {
22
+ action: 'enable-hint';
23
+ text: string;
24
+ } | {
25
+ action: 'reject-notice';
26
+ };
27
+ export interface GroupGate {
28
+ /** Decide what a group message may do. `isTrusted` is the pipeline's verdict. */
29
+ check(msg: IncomingMessage, isTrusted: boolean): GroupDecision;
30
+ /** One-time join hint text for a group room, or undefined when none is due. */
31
+ joinHint(roomId: string): string | undefined;
32
+ }
33
+ /** True when the room holds more than the bot + one other (T8 transport fact). */
34
+ export declare function isGroupMessage(msg: IncomingMessage): boolean;
35
+ export declare function createGroupGate(deps: {
36
+ store: AuthStore;
37
+ }): GroupGate;
38
+ //# sourceMappingURL=group-gate.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"group-gate.d.ts","sourceRoot":"","sources":["../../src/bridge/group-gate.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AACH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,aAAa,CAAA;AAClD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAA;AAEjD,MAAM,MAAM,aAAa,GACrB;IAAE,MAAM,EAAE,MAAM,CAAA;CAAE,GAClB;IAAE,MAAM,EAAE,SAAS,CAAA;CAAE,GACrB;IAAE,MAAM,EAAE,aAAa,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GACvC;IAAE,MAAM,EAAE,eAAe,CAAA;CAAE,CAAA;AAE/B,MAAM,WAAW,SAAS;IACxB,iFAAiF;IACjF,KAAK,CAAC,GAAG,EAAE,eAAe,EAAE,SAAS,EAAE,OAAO,GAAG,aAAa,CAAA;IAC9D,+EAA+E;IAC/E,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAAA;CAC7C;AAED,kFAAkF;AAClF,wBAAgB,cAAc,CAAC,GAAG,EAAE,eAAe,GAAG,OAAO,CAE5D;AAMD,wBAAgB,eAAe,CAAC,IAAI,EAAE;IAAE,KAAK,EAAE,SAAS,CAAA;CAAE,GAAG,SAAS,CAuCrE"}
@@ -0,0 +1,49 @@
1
+ /** True when the room holds more than the bot + one other (T8 transport fact). */
2
+ export function isGroupMessage(msg) {
3
+ return msg.isGroup ?? !msg.isDm;
4
+ }
5
+ const ENABLE_HINT = '🤖 我已加入这个群聊,但默认不回应群消息。\n' +
6
+ '启用方式:在群里发 /enable mentions(或 /enable all / /enable trusted-only;仅 trusted 用户可启用)';
7
+ export function createGroupGate(deps) {
8
+ // Rooms that already spent their one-time hint budget (join or message).
9
+ const hinted = new Set();
10
+ function consumeHint(roomId) {
11
+ if (hinted.has(roomId))
12
+ return { action: 'silence' };
13
+ hinted.add(roomId);
14
+ return { action: 'enable-hint', text: ENABLE_HINT };
15
+ }
16
+ return {
17
+ check(msg, isTrusted) {
18
+ if (!isGroupMessage(msg))
19
+ return { action: 'pass' };
20
+ const channel = deps.store.get().channels[msg.roomId];
21
+ if (channel?.enabled) {
22
+ switch (channel.mode) {
23
+ case 'all':
24
+ return { action: 'pass' };
25
+ case 'mentions':
26
+ return msg.mentionsBot ? { action: 'pass' } : { action: 'silence' };
27
+ case 'trusted-only':
28
+ return isTrusted ? { action: 'pass' } : { action: 'silence' };
29
+ }
30
+ }
31
+ // Not enabled.
32
+ if (!isTrusted)
33
+ return { action: 'reject-notice' };
34
+ // The enabling command must reach the command table.
35
+ if (msg.text.trim().split(/\s+/)[0]?.toLowerCase() === '/enable')
36
+ return { action: 'pass' };
37
+ return consumeHint(msg.roomId);
38
+ },
39
+ joinHint(roomId) {
40
+ if (deps.store.get().channels[roomId]?.enabled)
41
+ return undefined;
42
+ if (hinted.has(roomId))
43
+ return undefined;
44
+ hinted.add(roomId);
45
+ return ENABLE_HINT;
46
+ },
47
+ };
48
+ }
49
+ //# sourceMappingURL=group-gate.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"group-gate.js","sourceRoot":"","sources":["../../src/bridge/group-gate.ts"],"names":[],"mappings":"AA8BA,kFAAkF;AAClF,MAAM,UAAU,cAAc,CAAC,GAAoB;IACjD,OAAO,GAAG,CAAC,OAAO,IAAI,CAAC,GAAG,CAAC,IAAI,CAAA;AACjC,CAAC;AAED,MAAM,WAAW,GACf,0BAA0B;IAC1B,kFAAkF,CAAA;AAEpF,MAAM,UAAU,eAAe,CAAC,IAA0B;IACxD,yEAAyE;IACzE,MAAM,MAAM,GAAG,IAAI,GAAG,EAAU,CAAA;IAEhC,SAAS,WAAW,CAAC,MAAc;QACjC,IAAI,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC;YAAE,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,CAAA;QACpD,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,CAAA;QAClB,OAAO,EAAE,MAAM,EAAE,aAAa,EAAE,IAAI,EAAE,WAAW,EAAE,CAAA;IACrD,CAAC;IAED,OAAO;QACL,KAAK,CAAC,GAAG,EAAE,SAAS;YAClB,IAAI,CAAC,cAAc,CAAC,GAAG,CAAC;gBAAE,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,CAAA;YAEnD,MAAM,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,QAAQ,CAAC,GAAG,CAAC,MAAM,CAAC,CAAA;YACrD,IAAI,OAAO,EAAE,OAAO,EAAE,CAAC;gBACrB,QAAQ,OAAO,CAAC,IAAI,EAAE,CAAC;oBACrB,KAAK,KAAK;wBACR,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,CAAA;oBAC3B,KAAK,UAAU;wBACb,OAAO,GAAG,CAAC,WAAW,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,SAAS,EAAE,CAAA;oBACrE,KAAK,cAAc;wBACjB,OAAO,SAAS,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,SAAS,EAAE,CAAA;gBACjE,CAAC;YACH,CAAC;YAED,eAAe;YACf,IAAI,CAAC,SAAS;gBAAE,OAAO,EAAE,MAAM,EAAE,eAAe,EAAE,CAAA;YAClD,qDAAqD;YACrD,IAAI,GAAG,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,WAAW,EAAE,KAAK,SAAS;gBAAE,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,CAAA;YAC3F,OAAO,WAAW,CAAC,GAAG,CAAC,MAAM,CAAC,CAAA;QAChC,CAAC;QACD,QAAQ,CAAC,MAAM;YACb,IAAI,IAAI,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,OAAO;gBAAE,OAAO,SAAS,CAAA;YAChE,IAAI,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC;gBAAE,OAAO,SAAS,CAAA;YACxC,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,CAAA;YAClB,OAAO,WAAW,CAAA;QACpB,CAAC;KACF,CAAA;AACH,CAAC"}