@wenbin_wb/dsh-bridge 2.10.1 → 2.10.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +39 -0
- package/README.en.md +2 -0
- package/README.md +2 -0
- package/client/client.js +103 -1
- package/client/index.js +83 -0
- package/lib/bridge-rpc-constants.js +1 -0
- package/lib/bridge-rpc.js +10 -0
- package/lib/feishu/node.js +10 -4
- package/lib/index.js +126 -14
- package/lib/platform/conversation-bridge.js +8 -3
- package/lib/platform/message-split.js +39 -1
- package/lib/qq/node.js +539 -532
- package/lib/session-strip.js +57 -0
- package/lib/telegram/node.js +0 -27
- package/lib/tunnel-client.mjs +419 -426
- package/lib/wechat/gateway.js +17 -4
- package/package.json +2 -2
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
// DSH Bridge - 会话响应投影剥离(共享逻辑)
|
|
2
|
+
//
|
|
3
|
+
// contextHeaders / contextTimeline 是 DSH 会话投影里的两个大字段:每轮完整系统提示
|
|
4
|
+
// + 工具定义(单会话 4.8MB+,session.list 数百会话可达 60MB+),但没有客户端 UI
|
|
5
|
+
// 读取它们(会话打开时通过 WebSocket 实时获取,见 dsh-session-projection-cache 注释)。
|
|
6
|
+
// 剥离后可大幅降低传输体积(session.history gzip 1.2MB -> ~150KB,约 8 倍)。
|
|
7
|
+
//
|
|
8
|
+
// 本模块被两个转发层复用:
|
|
9
|
+
// - tunnel-client.mjs(自建隧道)
|
|
10
|
+
// - index.js ProxyServer(局域网 / Cloudflare 隧道 / 外部隧道登记 —— 所有公网入口)
|
|
11
|
+
// 命中失败(非 200 / 解析失败 / 结构不符)时原样返回,绝不破坏响应。
|
|
12
|
+
|
|
13
|
+
const STRIP_PATHS = new Set(['/api/session.list', '/api/session.history']);
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* 剥离 session.list / session.history 响应中的 contextHeaders 与 contextTimeline。
|
|
17
|
+
* @param {string} pathname 请求路径(不含 query)
|
|
18
|
+
* @param {Buffer} bodyBuf 原始响应体
|
|
19
|
+
* @returns {{ body: Buffer, stripped: boolean }} stripped=true 表示发生了剥离(调用方需更新 content-length)
|
|
20
|
+
*/
|
|
21
|
+
export function stripSessionProjections(pathname, bodyBuf) {
|
|
22
|
+
const cleanPath = String(pathname || '').split('?')[0];
|
|
23
|
+
if (!STRIP_PATHS.has(cleanPath) || !Buffer.isBuffer(bodyBuf)) {
|
|
24
|
+
return { body: bodyBuf, stripped: false };
|
|
25
|
+
}
|
|
26
|
+
try {
|
|
27
|
+
const json = JSON.parse(bodyBuf.toString('utf8'));
|
|
28
|
+
if (json?.result?.ok) {
|
|
29
|
+
const v = json.result.value;
|
|
30
|
+
let changed = false;
|
|
31
|
+
// session.list: items[].projections.values
|
|
32
|
+
if (v?.items) {
|
|
33
|
+
for (const item of v.items) {
|
|
34
|
+
const proj = item?.projections?.values;
|
|
35
|
+
if (proj && (proj.contextHeaders !== undefined || proj.contextTimeline !== undefined)) {
|
|
36
|
+
delete proj.contextHeaders;
|
|
37
|
+
delete proj.contextTimeline;
|
|
38
|
+
changed = true;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
// session.history: projections.values
|
|
43
|
+
if (v?.projections?.values) {
|
|
44
|
+
const proj = v.projections.values;
|
|
45
|
+
if (proj.contextHeaders !== undefined || proj.contextTimeline !== undefined) {
|
|
46
|
+
delete proj.contextHeaders;
|
|
47
|
+
delete proj.contextTimeline;
|
|
48
|
+
changed = true;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
if (changed) {
|
|
52
|
+
return { body: Buffer.from(JSON.stringify(json), 'utf8'), stripped: true };
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
} catch { /* 解析失败则原样发送 */ }
|
|
56
|
+
return { body: bodyBuf, stripped: false };
|
|
57
|
+
}
|
package/lib/telegram/node.js
CHANGED
|
@@ -206,33 +206,6 @@ export class TelegramConversationNode extends ConversationBridge {
|
|
|
206
206
|
}
|
|
207
207
|
}
|
|
208
208
|
|
|
209
|
-
async sendApprovalCard(approvalId, request) {
|
|
210
|
-
const peerId = this._lastPeer?.chatId || this.peerId
|
|
211
|
-
if (!peerId || !this.gateway) return
|
|
212
|
-
|
|
213
|
-
const toolName = request?.name || request?.tool || '系统操作'
|
|
214
|
-
const desc = request?.description || request?.summary || ''
|
|
215
|
-
const command = request?.command || request?.cmd || ''
|
|
216
|
-
|
|
217
|
-
const lines = [
|
|
218
|
-
`⚠️ **操作权限确认** (ID: <code>${approvalId}</code>)`,
|
|
219
|
-
'',
|
|
220
|
-
`• **工具**:<code>${toolName}</code>`,
|
|
221
|
-
]
|
|
222
|
-
if (desc) lines.push(`• **说明**:${desc}`)
|
|
223
|
-
if (command) lines.push(`• **命令**:<code>${command}</code>`)
|
|
224
|
-
lines.push('', '请选择审批决议(亦可直接输入 <code>1</code> 批准,<code>2</code> 拒绝):')
|
|
225
|
-
|
|
226
|
-
const buttons = [
|
|
227
|
-
[
|
|
228
|
-
{ text: '✓ 批准执行', callback_data: `approve:${approvalId}` },
|
|
229
|
-
{ text: '✕ 拒绝执行', callback_data: `reject:${approvalId}` },
|
|
230
|
-
],
|
|
231
|
-
]
|
|
232
|
-
|
|
233
|
-
return this.gateway.sendKeyboard(peerId, lines.join('\n'), buttons)
|
|
234
|
-
}
|
|
235
|
-
|
|
236
209
|
async _sendTextNow(text, opts = {}) {
|
|
237
210
|
// T2.3:轮次绑定的 outboundPeer(chat 级目标)优先生效
|
|
238
211
|
const peerId = opts?.outboundPeer?.peerId || this._lastPeer?.chatId || this.peerId
|