@cxyhhhhh/dsh-qqbot 0.5.1-dev.202610121442 → 0.5.2-dev.202610201829
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 +7 -0
- package/CHANGELOG_EN.md +7 -0
- package/dist/features/approval-channel.d.ts +17 -7
- package/dist/features/approval-channel.d.ts.map +1 -1
- package/dist/features/approval-channel.js +14 -14
- package/dist/features/approval-channel.js.map +1 -1
- package/dist/gateway/bootstrap.d.ts.map +1 -1
- package/dist/gateway/bootstrap.js +13 -2
- package/dist/gateway/bootstrap.js.map +1 -1
- package/dist/transport/events.d.ts +23 -0
- package/dist/transport/events.d.ts.map +1 -1
- package/dist/transport/events.js +31 -0
- package/dist/transport/events.js.map +1 -1
- package/dist/transport/outbound-buffer.d.ts +2 -0
- package/dist/transport/outbound-buffer.d.ts.map +1 -1
- package/dist/transport/outbound-buffer.js +5 -0
- package/dist/transport/outbound-buffer.js.map +1 -1
- package/dist/transport/outbound.d.ts +14 -3
- package/dist/transport/outbound.d.ts.map +1 -1
- package/dist/transport/outbound.js +46 -5
- package/dist/transport/outbound.js.map +1 -1
- package/dist/transport/streaming-writer.d.ts +8 -0
- package/dist/transport/streaming-writer.d.ts.map +1 -1
- package/dist/transport/streaming-writer.js +12 -0
- package/dist/transport/streaming-writer.js.map +1 -1
- package/lib/client.js +19 -11
- package/lib/client.js.map +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -6,6 +6,13 @@
|
|
|
6
6
|
|
|
7
7
|
格式遵循 [Keep a Changelog](https://keepachangelog.com/zh-CN/1.0.0/)。
|
|
8
8
|
|
|
9
|
+
## [0.5.2] - 2026-10-12
|
|
10
|
+
|
|
11
|
+
### 问题修复
|
|
12
|
+
|
|
13
|
+
- **修复全新安装无法启动的问题**:0.5.1 的依赖声明仍为旧版 QQ Bot SDK 范围(`^1.0.4`),全新安装解析到 1.0.4 后,掉线日志功能在启动时崩溃(`TypeError`),插件无法激活。现已更正为 `^1.0.5`。
|
|
14
|
+
- **旧版 SDK 兼容降级**:对已残留旧版 SDK 的环境,掉线日志监听降级为跳过并输出升级提示,不再阻断插件启动。
|
|
15
|
+
|
|
9
16
|
## [0.5.1] - 2026-10-12
|
|
10
17
|
|
|
11
18
|
### 新功能
|
package/CHANGELOG_EN.md
CHANGED
|
@@ -6,6 +6,13 @@ This file records significant dsh-qqbot updates from a product perspective, focu
|
|
|
6
6
|
|
|
7
7
|
The format follows [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
|
|
8
8
|
|
|
9
|
+
## [0.5.2] - 2026-10-12
|
|
10
|
+
|
|
11
|
+
### Fixed
|
|
12
|
+
|
|
13
|
+
- **Fixed clean installs failing to activate**: 0.5.1 shipped with the old SDK range (`^1.0.4`), so clean installs resolved 1.0.4 and the disconnect logging feature crashed at startup (`TypeError`), failing plugin activation. The range is now `^1.0.5`.
|
|
14
|
+
- **Graceful degradation on stale SDKs**: environments that still carry an older SDK now skip the disconnect listener with an upgrade hint instead of failing activation.
|
|
15
|
+
|
|
9
16
|
## [0.5.1] - 2026-10-12
|
|
10
17
|
|
|
11
18
|
### Added
|
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
* 每个会话同一时间最多一个 pending 审批(审批是阻塞式的);outcome 是 dsh
|
|
8
8
|
* 协议的闭合集合,无 allow-always,只提供「允许一次 / 拒绝」两个按钮。
|
|
9
9
|
*/
|
|
10
|
+
import type { EventOptions } from '@deepseek-ai/cordis';
|
|
10
11
|
import type { InteractionEvent } from '@tencent-connect/qqbot-nodejs';
|
|
11
12
|
import type { ChatScope, Logger, ReplyTarget } from '../types.ts';
|
|
12
13
|
export type ApprovalOutcome = 'allowed-once' | 'rejected' | 'cancelled' | 'unavailable';
|
|
@@ -22,8 +23,13 @@ interface ApprovalSessionEvent {
|
|
|
22
23
|
export interface ApprovalRequest {
|
|
23
24
|
agent: {
|
|
24
25
|
id: string;
|
|
25
|
-
|
|
26
|
-
|
|
26
|
+
/**
|
|
27
|
+
* dsh-agent 的 `Agent.session` 在类型上是必选,但审批请求可能来自跨进程或
|
|
28
|
+
* 投影后的上下文,运行时拿不到 live session(类型契约与运行时的 gap)。此时
|
|
29
|
+
* 只是无法回显命令原文,不应让整个审批失败,故这里标为可选。
|
|
30
|
+
*/
|
|
31
|
+
session?: {
|
|
32
|
+
events?: ApprovalSessionEvent[];
|
|
27
33
|
};
|
|
28
34
|
};
|
|
29
35
|
toolName: string;
|
|
@@ -49,10 +55,7 @@ export interface ApprovalChannelSenderLike {
|
|
|
49
55
|
}
|
|
50
56
|
/** approval/request waterfall 的 answerer handler */
|
|
51
57
|
export interface ApprovalChannelContext {
|
|
52
|
-
|
|
53
|
-
on(event: string, handler: (...args: unknown[]) => unknown, options?: {
|
|
54
|
-
prepend?: boolean;
|
|
55
|
-
}): void;
|
|
58
|
+
on(event: string, handler: (...args: unknown[]) => unknown, options?: EventOptions): () => boolean;
|
|
56
59
|
}
|
|
57
60
|
export declare class ApprovalChannel {
|
|
58
61
|
private readonly pending;
|
|
@@ -61,7 +64,14 @@ export declare class ApprovalChannel {
|
|
|
61
64
|
private readonly logger;
|
|
62
65
|
constructor(manager: ApprovalChannelManagerLike, sender: ApprovalChannelSenderLike, logger: Logger);
|
|
63
66
|
/**
|
|
64
|
-
* 注册 approval/request waterfall answerer。
|
|
67
|
+
* 注册 approval/request waterfall answerer。
|
|
68
|
+
*
|
|
69
|
+
* 不再探测 approval 服务是否已挂载:它是 optional peer,挂载时机可能晚于
|
|
70
|
+
* 本插件的 apply,一次性探测失败会让通道永久失效。监听事件本身不依赖服务
|
|
71
|
+
* 存在——服务就绪后请求自然经过同一条瀑布,未挂载时不会有请求到达。
|
|
72
|
+
*
|
|
73
|
+
* `global` 是必需的:approval/request 按 agent 作用域派发,根作用域注册的
|
|
74
|
+
* 监听器不带 global 会被作用域过滤掉。
|
|
65
75
|
*/
|
|
66
76
|
install(ctx: ApprovalChannelContext): void;
|
|
67
77
|
/** 会话回收时清理其 pending 审批,避免 Promise 悬挂 */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"approval-channel.d.ts","sourceRoot":"","sources":["../../src/features/approval-channel.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,+BAA+B,CAAC;AACtE,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAMlE,MAAM,MAAM,eAAe,GAAG,cAAc,GAAG,UAAU,GAAG,WAAW,GAAG,aAAa,CAAC;AAExF,uDAAuD;AACvD,UAAU,oBAAoB;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE;QAAE,MAAM,CAAC,EAAE,OAAO,CAAC;QAAC,SAAS,CAAC,EAAE,OAAO,CAAC;QAAC,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAA;KAAE,CAAC;CAC1E;AAED,MAAM,WAAW,eAAe;IAC9B,KAAK,EAAE;QACL,EAAE,EAAE,MAAM,CAAC;QACX,OAAO,EAAE;YAAE,MAAM,EAAE,oBAAoB,EAAE,CAAA;SAAE,CAAC;
|
|
1
|
+
{"version":3,"file":"approval-channel.d.ts","sourceRoot":"","sources":["../../src/features/approval-channel.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AACxD,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,+BAA+B,CAAC;AACtE,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAMlE,MAAM,MAAM,eAAe,GAAG,cAAc,GAAG,UAAU,GAAG,WAAW,GAAG,aAAa,CAAC;AAExF,uDAAuD;AACvD,UAAU,oBAAoB;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE;QAAE,MAAM,CAAC,EAAE,OAAO,CAAC;QAAC,SAAS,CAAC,EAAE,OAAO,CAAC;QAAC,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAA;KAAE,CAAC;CAC1E;AAED,MAAM,WAAW,eAAe;IAC9B,KAAK,EAAE;QACL,EAAE,EAAE,MAAM,CAAC;QACX;;;;WAIG;QACH,OAAO,CAAC,EAAE;YAAE,MAAM,CAAC,EAAE,oBAAoB,EAAE,CAAA;SAAE,CAAC;KAC/C,CAAC;IACF,QAAQ,EAAE,MAAM,CAAC;IACjB,uDAAuD;IACvD,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,oBAAoB;IACpB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,WAAW,CAAC;CACtB;AAID,MAAM,WAAW,yBAAyB;IACxC,UAAU,EAAE,MAAM,CAAC;IACnB,KAAK,EAAE,SAAS,CAAC;IACjB,WAAW,EAAE,WAAW,CAAC;CAC1B;AAED,MAAM,WAAW,0BAA0B;IACzC,eAAe,CAAC,SAAS,EAAE,MAAM,GAAG,yBAAyB,GAAG,SAAS,CAAC;IAC1E,gBAAgB,CAAC,KAAK,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,GAAG,yBAAyB,GAAG,SAAS,CAAC;CAC3F;AAED,MAAM,WAAW,yBAAyB;IACxC,YAAY,CAAC,MAAM,EAAE,WAAW,EAAE,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE;QAAE,QAAQ,CAAC,EAAE,OAAO,CAAA;KAAE,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;CACrG;AAED,oDAAoD;AACpD,MAAM,WAAW,sBAAsB;IACrC,EAAE,CACA,KAAK,EAAE,MAAM,EACb,OAAO,EAAE,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,OAAO,EACxC,OAAO,CAAC,EAAE,YAAY,GACrB,MAAM,OAAO,CAAC;CAClB;AA4CD,qBAAa,eAAe;IAC1B,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAsC;IAC9D,OAAO,CAAC,QAAQ,CAAC,OAAO,CAA6B;IACrD,OAAO,CAAC,QAAQ,CAAC,MAAM,CAA4B;IACnD,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAS;gBAG9B,OAAO,EAAE,0BAA0B,EACnC,MAAM,EAAE,yBAAyB,EACjC,MAAM,EAAE,MAAM;IAOhB;;;;;;;;;OASG;IACI,OAAO,CAAC,GAAG,EAAE,sBAAsB,GAAG,IAAI;IAYjD,wCAAwC;IACjC,aAAa,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI;IAQ9C,8CAA8C;IACvC,iBAAiB,CAAC,KAAK,EAAE,gBAAgB,GAAG,OAAO;IAoB1D,wCAAwC;YAC1B,IAAI;IAkClB,OAAO,CAAC,WAAW;CAKpB"}
|
|
@@ -8,7 +8,11 @@ const COMMAND_CLIP = 500;
|
|
|
8
8
|
function commandOf(req) {
|
|
9
9
|
if (req.callId === undefined)
|
|
10
10
|
return undefined;
|
|
11
|
-
|
|
11
|
+
// 审批请求可能来自没有 live session 的上下文(例如跨进程/投影后的 Agent),
|
|
12
|
+
// 此时只是拿不到命令原文,不能因此让整个审批失败。
|
|
13
|
+
const events = req.agent.session?.events;
|
|
14
|
+
if (!Array.isArray(events))
|
|
15
|
+
return undefined;
|
|
12
16
|
for (let i = events.length - 1; i >= 0; i -= 1) {
|
|
13
17
|
const event = events[i];
|
|
14
18
|
if (!event || event.type !== 'tool/call')
|
|
@@ -45,20 +49,16 @@ export class ApprovalChannel {
|
|
|
45
49
|
this.logger = logger;
|
|
46
50
|
}
|
|
47
51
|
/**
|
|
48
|
-
* 注册 approval/request waterfall answerer。
|
|
52
|
+
* 注册 approval/request waterfall answerer。
|
|
53
|
+
*
|
|
54
|
+
* 不再探测 approval 服务是否已挂载:它是 optional peer,挂载时机可能晚于
|
|
55
|
+
* 本插件的 apply,一次性探测失败会让通道永久失效。监听事件本身不依赖服务
|
|
56
|
+
* 存在——服务就绪后请求自然经过同一条瀑布,未挂载时不会有请求到达。
|
|
57
|
+
*
|
|
58
|
+
* `global` 是必需的:approval/request 按 agent 作用域派发,根作用域注册的
|
|
59
|
+
* 监听器不带 global 会被作用域过滤掉。
|
|
49
60
|
*/
|
|
50
61
|
install(ctx) {
|
|
51
|
-
let hasApproval = false;
|
|
52
|
-
try {
|
|
53
|
-
hasApproval = ctx.get('approval') !== undefined;
|
|
54
|
-
}
|
|
55
|
-
catch {
|
|
56
|
-
hasApproval = false;
|
|
57
|
-
}
|
|
58
|
-
if (!hasApproval) {
|
|
59
|
-
this.logger.debug('im-qqbot: approval service unavailable — approval channel disabled');
|
|
60
|
-
return;
|
|
61
|
-
}
|
|
62
62
|
const self = this;
|
|
63
63
|
ctx.on('approval/request', (req, next) => {
|
|
64
64
|
const request = req;
|
|
@@ -67,7 +67,7 @@ export class ApprovalChannel {
|
|
|
67
67
|
if (record)
|
|
68
68
|
return self.park(record, request);
|
|
69
69
|
return nextFn();
|
|
70
|
-
}, { prepend: true });
|
|
70
|
+
}, { global: true, prepend: true });
|
|
71
71
|
this.logger.info('im-qqbot: QQ approval channel installed');
|
|
72
72
|
}
|
|
73
73
|
/** 会话回收时清理其 pending 审批,避免 Promise 悬挂 */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"approval-channel.js","sourceRoot":"","sources":["../../src/features/approval-channel.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"approval-channel.js","sourceRoot":"","sources":["../../src/features/approval-channel.ts"],"names":[],"mappings":"AAYA,OAAO,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AACrD,OAAO,EAAE,qBAAqB,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAiElF,MAAM,YAAY,GAAG,GAAG,CAAC;AAEzB;;;GAGG;AACH,SAAS,SAAS,CAAC,GAAoB;IACrC,IAAI,GAAG,CAAC,MAAM,KAAK,SAAS;QAAE,OAAO,SAAS,CAAC;IAC/C,kDAAkD;IAClD,2BAA2B;IAC3B,MAAM,MAAM,GAAG,GAAG,CAAC,KAAK,CAAC,OAAO,EAAE,MAAM,CAAC;IACzC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC;QAAE,OAAO,SAAS,CAAC;IAC7C,KAAK,IAAI,CAAC,GAAG,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC;QAC/C,MAAM,KAAK,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC;QACxB,IAAI,CAAC,KAAK,IAAI,KAAK,CAAC,IAAI,KAAK,WAAW;YAAE,SAAS;QACnD,MAAM,IAAI,GAAG,KAAK,CAAC,IAAI,CAAC;QACxB,IAAI,MAAM,CAAC,IAAI,EAAE,MAAM,CAAC,KAAK,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC;YAAE,SAAS;QAC1D,MAAM,GAAG,GAAG,IAAI,EAAE,SAAS,CAAC;QAC5B,IAAI,OAAO,GAAG,KAAK,QAAQ;YAAE,OAAO,SAAS,CAAC;QAC9C,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAY,CAAC;YAC1C,IAAI,MAAM,KAAK,IAAI,IAAI,OAAO,MAAM,KAAK,QAAQ,IAAI,SAAS,IAAI,MAAM,EAAE,CAAC;gBACzE,MAAM,OAAO,GAAI,MAAgC,CAAC,OAAO,CAAC;gBAC1D,IAAI,OAAO,OAAO,KAAK,QAAQ;oBAAE,OAAO,OAAO,CAAC;YAClD,CAAC;QACH,CAAC;QAAC,MAAM,CAAC;YACP,kBAAkB;QACpB,CAAC;QACD,OAAO,GAAG,CAAC,MAAM,IAAI,YAAY,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,GAAG,CAAC,KAAK,CAAC,CAAC,EAAE,YAAY,CAAC,GAAG,CAAC;IAC7E,CAAC;IACD,OAAO,SAAS,CAAC;AACnB,CAAC;AAED,MAAM,OAAO,eAAe;IACT,OAAO,GAAG,IAAI,GAAG,EAA2B,CAAC;IAC7C,OAAO,CAA6B;IACpC,MAAM,CAA4B;IAClC,MAAM,CAAS;IAEhC,YACE,OAAmC,EACnC,MAAiC,EACjC,MAAc;QAEd,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC;QACvB,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;QACrB,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;IACvB,CAAC;IAED;;;;;;;;;OASG;IACI,OAAO,CAAC,GAA2B;QACxC,MAAM,IAAI,GAAG,IAAI,CAAC;QAClB,GAAG,CAAC,EAAE,CAAC,kBAAkB,EAAE,CAAC,GAAY,EAAE,IAAa,EAAE,EAAE;YACzD,MAAM,OAAO,GAAG,GAAsB,CAAC;YACvC,MAAM,MAAM,GAAG,IAAsC,CAAC;YACtD,MAAM,MAAM,GAAG,IAAI,CAAC,OAAO,CAAC,eAAe,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;YAC9D,IAAI,MAAM;gBAAE,OAAO,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;YAC9C,OAAO,MAAM,EAAE,CAAC;QAClB,CAAC,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC;QACpC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,yCAAyC,CAAC,CAAC;IAC9D,CAAC;IAED,wCAAwC;IACjC,aAAa,CAAC,UAAkB;QACrC,MAAM,KAAK,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC;QAC3C,IAAI,CAAC,KAAK;YAAE,OAAO;QACnB,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC;QAChC,IAAI,CAAC,WAAW,CAAC,KAAK,CAAC,CAAC;QACxB,KAAK,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC;IAC7B,CAAC;IAED,8CAA8C;IACvC,iBAAiB,CAAC,KAAuB;QAC9C,MAAM,MAAM,GAAG,KAAK,CAAC,YAAY,IAAI,KAAK,CAAC,WAAW,CAAC;QACvD,IAAI,CAAC,MAAM;YAAE,OAAO,KAAK,CAAC;QAC1B,MAAM,KAAK,GAAc,KAAK,CAAC,YAAY,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC;QAC9D,MAAM,MAAM,GAAG,IAAI,CAAC,OAAO,CAAC,gBAAgB,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC;QAC5D,IAAI,CAAC,MAAM;YAAE,OAAO,KAAK,CAAC;QAC1B,MAAM,KAAK,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC;QAClD,IAAI,CAAC,KAAK;YAAE,OAAO,KAAK,CAAC;QAEzB,MAAM,IAAI,GAAG,KAAK,CAAC,IAAI,EAAE,QAAQ,EAAE,WAAW,CAAC;QAC/C,IAAI,CAAC,IAAI;YAAE,OAAO,KAAK,CAAC;QACxB,MAAM,MAAM,GAAG,gBAAgB,CAAC,IAAI,CAAC,CAAC;QACtC,IAAI,CAAC,MAAM,IAAI,MAAM,CAAC,CAAC,KAAK,UAAU;YAAE,OAAO,KAAK,CAAC;QAErD,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC;QACvC,IAAI,CAAC,WAAW,CAAC,KAAK,CAAC,CAAC;QACxB,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,KAAK,OAAO,CAAC,CAAC,CAAC,cAAc,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC;QAClE,OAAO,IAAI,CAAC;IACd,CAAC;IAED,wCAAwC;IAChC,KAAK,CAAC,IAAI,CAAC,MAAiC,EAAE,OAAwB;QAC5E,MAAM,GAAG,GAAG,MAAM,CAAC,UAAU,CAAC;QAC9B,uCAAuC;QACvC,IAAI,OAAO,CAAC,MAAM,EAAE,OAAO;YAAE,OAAO,WAAW,CAAC;QAEhD,MAAM,OAAO,GAAG,SAAS,CAAC,OAAO,CAAC,CAAC;QACnC,IAAI,CAAC;YACH,MAAM,IAAI,CAAC,MAAM,CAAC,YAAY,CAC5B,MAAM,CAAC,WAAW,EAClB,iBAAiB,CAAC,OAAO,EAAE,OAAO,CAAC,EACnC,EAAE,QAAQ,EAAE,qBAAqB,EAAE,EAAE,CACtC,CAAC;QACJ,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,MAAM,GAAG,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;YAC7D,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,sCAAsC,GAAG,KAAK,GAAG,EAAE,CAAC,CAAC;YACvE,OAAO,aAAa,CAAC,CAAC,qBAAqB;QAC7C,CAAC;QAED,OAAO,IAAI,OAAO,CAAkB,CAAC,OAAO,EAAE,EAAE;YAC9C,MAAM,KAAK,GAAoB,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,EAAE,CAAC;YAC5D,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC;gBACnB,MAAM,OAAO,GAAG,GAAS,EAAE;oBACzB,IAAI,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,KAAK;wBAAE,OAAO;oBAC5C,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;oBACzB,OAAO,CAAC,WAAW,CAAC,CAAC;gBACvB,CAAC,CAAC;gBACF,KAAK,CAAC,OAAO,GAAG,OAAO,CAAC;gBACxB,OAAO,CAAC,MAAM,CAAC,gBAAgB,CAAC,OAAO,EAAE,OAAO,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;YACpE,CAAC;YACD,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;YAC7B,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,2DAA2D,GAAG,EAAE,CAAC,CAAC;QACrF,CAAC,CAAC,CAAC;IACL,CAAC;IAEO,WAAW,CAAC,KAAsB;QACxC,IAAI,KAAK,CAAC,OAAO,IAAI,KAAK,CAAC,OAAO,CAAC,MAAM,EAAE,CAAC;YAC1C,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,mBAAmB,CAAC,OAAO,EAAE,KAAK,CAAC,OAAO,CAAC,CAAC;QACnE,CAAC;IACH,CAAC;CACF"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"bootstrap.d.ts","sourceRoot":"","sources":["../../src/gateway/bootstrap.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAC;AAGnD,OAAO,EAAkB,KAAK,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;
|
|
1
|
+
{"version":3,"file":"bootstrap.d.ts","sourceRoot":"","sources":["../../src/gateway/bootstrap.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAC;AAGnD,OAAO,EAAkB,KAAK,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AAY5E,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAClD,OAAO,KAAK,EAAa,MAAM,EAAE,MAAM,aAAa,CAAC;AAqBrD,wBAAsB,gBAAgB,CACpC,GAAG,EAAE,OAAO,EACZ,MAAM,EAAE,gBAAgB,EACxB,MAAM,EAAE,aAAa,EACrB,MAAM,EAAE,MAAM,GACb,OAAO,CAAC,IAAI,CAAC,CAmJf"}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { QQBot } from '@tencent-connect/qqbot-nodejs';
|
|
2
2
|
import { SessionManager } from "../session/index.js";
|
|
3
3
|
import { handleInbound, createOutboundHandler } from "../transport/index.js";
|
|
4
|
+
import { parseStreamFrame } from "../transport/events.js";
|
|
4
5
|
import { ReplyLimiter } from "../transport/reply-limiter.js";
|
|
5
6
|
import { cacheMsgId, cacheEventId } from "../transport/msgid-cache.js";
|
|
6
7
|
import { resolveReplyTarget, sendResolvedMarkdown } from "../transport/reply-target.js";
|
|
@@ -78,9 +79,19 @@ export async function bootstrapGateway(ctx, agents, config, logger) {
|
|
|
78
79
|
},
|
|
79
80
|
}),
|
|
80
81
|
};
|
|
81
|
-
const
|
|
82
|
+
const outbound = createOutboundHandler(manager, sender, config, logger, toolsRegistry);
|
|
82
83
|
ctx
|
|
83
|
-
.on('session/event',
|
|
84
|
+
.on('session/event', outbound.routeSessionEvent);
|
|
85
|
+
// ── 出站流式:agent/assistant-stream → 流式帧路由 ──
|
|
86
|
+
// 实时流式走瞬态 agent/assistant-stream(chunk 不进 session log)。
|
|
87
|
+
// 该事件按 agent 作用域派发,根作用域监听器不带 global 会被过滤(同
|
|
88
|
+
// approval/request),帧到达后自行按 agent.id 路由,非 QQ 会话在 router 内忽略。
|
|
89
|
+
ctx
|
|
90
|
+
.on('agent/assistant-stream', (payload) => {
|
|
91
|
+
const parsed = parseStreamFrame(payload);
|
|
92
|
+
if (parsed !== undefined)
|
|
93
|
+
outbound.routeStreamFrame(parsed.agentId, parsed.delta);
|
|
94
|
+
}, { global: true });
|
|
84
95
|
// ── 问答通道(ask_user_question → QQ 文本 + 按钮) ──
|
|
85
96
|
const questionChannel = new QuestionChannel(manager, sender, config, logger);
|
|
86
97
|
manager.questionChannel = questionChannel;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"bootstrap.js","sourceRoot":"","sources":["../../src/gateway/bootstrap.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"bootstrap.js","sourceRoot":"","sources":["../../src/gateway/bootstrap.ts"],"names":[],"mappings":"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"}
|
|
@@ -77,4 +77,27 @@ export declare function extractTurnError(reason: TurnEndReason): {
|
|
|
77
77
|
code: string;
|
|
78
78
|
message: string;
|
|
79
79
|
} | undefined;
|
|
80
|
+
/**
|
|
81
|
+
* 归一化后的流式增量(`agent/assistant-stream` 瞬态帧,chunk 不进 session log)。
|
|
82
|
+
*/
|
|
83
|
+
export type StreamDelta = {
|
|
84
|
+
kind: 'attempt-start';
|
|
85
|
+
attemptId: string;
|
|
86
|
+
} | {
|
|
87
|
+
kind: 'text-delta';
|
|
88
|
+
attemptId: string;
|
|
89
|
+
text: string;
|
|
90
|
+
};
|
|
91
|
+
/**
|
|
92
|
+
* 解析 `agent/assistant-stream` 的 payload(对齐 @deepseek-ai/dsh-agent 的
|
|
93
|
+
* AssistantStreamFrame 最小契约,避免硬依赖)。
|
|
94
|
+
*
|
|
95
|
+
* 只归一化两类帧:start(新 attempt)与 chunk 的 text-delta(文本增量)。
|
|
96
|
+
* reasoning-delta / tool-call-delta 不进用户消息;end 帧不处理——收尾由 durable
|
|
97
|
+
* `assistant/message` / `turn/end` 事件负责。未知形态返回 undefined。
|
|
98
|
+
*/
|
|
99
|
+
export declare function parseStreamFrame(raw: unknown): {
|
|
100
|
+
agentId: string;
|
|
101
|
+
delta: StreamDelta;
|
|
102
|
+
} | undefined;
|
|
80
103
|
//# sourceMappingURL=events.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"events.d.ts","sourceRoot":"","sources":["../../src/transport/events.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,gDAAgD;AAChD,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAC/B;AAED,+DAA+D;AAC/D,MAAM,WAAW,aAAa;IAC5B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE;QAAE,OAAO,CAAC,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IAC5C,OAAO,CAAC,EAAE;QAAE,OAAO,CAAC,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IAC9C,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,yCAAyC;AACzC,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,iBAAiB,CAAC;IACxB,IAAI,EAAE,MAAM,CAAC;CACd;AAED,2BAA2B;AAC3B,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,mBAAmB,CAAC;IAC1B,OAAO,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CACjD;AAED,mBAAmB;AACnB,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,WAAW,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,qBAAqB;AACrB,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,aAAa,CAAC;IACpB,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC;IACvC,mCAAmC;IACnC,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAC9B;AAED,kBAAkB;AAClB,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,UAAU,CAAC;IACjB,MAAM,EAAE,aAAa,CAAC;CACvB;AAED,eAAe;AACf,MAAM,MAAM,aAAa,GACrB,UAAU,GACV,YAAY,GACZ,aAAa,GACb,eAAe,GACf,YAAY,CAAC;AAEjB;;;;GAIG;AACH,wBAAgB,UAAU,CAAC,GAAG,EAAE,eAAe,GAAG,aAAa,GAAG,SAAS,CAmC1E;AAED;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,aAAa,GAAG;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,GAAG,SAAS,CAQrG"}
|
|
1
|
+
{"version":3,"file":"events.d.ts","sourceRoot":"","sources":["../../src/transport/events.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,gDAAgD;AAChD,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAC/B;AAED,+DAA+D;AAC/D,MAAM,WAAW,aAAa;IAC5B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE;QAAE,OAAO,CAAC,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IAC5C,OAAO,CAAC,EAAE;QAAE,OAAO,CAAC,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IAC9C,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,yCAAyC;AACzC,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,iBAAiB,CAAC;IACxB,IAAI,EAAE,MAAM,CAAC;CACd;AAED,2BAA2B;AAC3B,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,mBAAmB,CAAC;IAC1B,OAAO,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CACjD;AAED,mBAAmB;AACnB,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,WAAW,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,qBAAqB;AACrB,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,aAAa,CAAC;IACpB,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC;IACvC,mCAAmC;IACnC,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAC9B;AAED,kBAAkB;AAClB,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,UAAU,CAAC;IACjB,MAAM,EAAE,aAAa,CAAC;CACvB;AAED,eAAe;AACf,MAAM,MAAM,aAAa,GACrB,UAAU,GACV,YAAY,GACZ,aAAa,GACb,eAAe,GACf,YAAY,CAAC;AAEjB;;;;GAIG;AACH,wBAAgB,UAAU,CAAC,GAAG,EAAE,eAAe,GAAG,aAAa,GAAG,SAAS,CAmC1E;AAED;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,aAAa,GAAG;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,GAAG,SAAS,CAQrG;AAID;;GAEG;AACH,MAAM,MAAM,WAAW,GACnB;IAAE,IAAI,EAAE,eAAe,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAE,GAC5C;IAAE,IAAI,EAAE,YAAY,CAAC;IAAC,SAAS,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC;AAE5D;;;;;;;GAOG;AACH,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,OAAO,GAAG;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,WAAW,CAAA;CAAE,GAAG,SAAS,CAmBlG"}
|
package/dist/transport/events.js
CHANGED
|
@@ -59,4 +59,35 @@ export function extractTurnError(reason) {
|
|
|
59
59
|
message: detail?.message ?? reason.message ?? 'unknown error',
|
|
60
60
|
};
|
|
61
61
|
}
|
|
62
|
+
/**
|
|
63
|
+
* 解析 `agent/assistant-stream` 的 payload(对齐 @deepseek-ai/dsh-agent 的
|
|
64
|
+
* AssistantStreamFrame 最小契约,避免硬依赖)。
|
|
65
|
+
*
|
|
66
|
+
* 只归一化两类帧:start(新 attempt)与 chunk 的 text-delta(文本增量)。
|
|
67
|
+
* reasoning-delta / tool-call-delta 不进用户消息;end 帧不处理——收尾由 durable
|
|
68
|
+
* `assistant/message` / `turn/end` 事件负责。未知形态返回 undefined。
|
|
69
|
+
*/
|
|
70
|
+
export function parseStreamFrame(raw) {
|
|
71
|
+
if (raw === null || typeof raw !== 'object')
|
|
72
|
+
return undefined;
|
|
73
|
+
const agentId = raw.agent?.id;
|
|
74
|
+
if (typeof agentId !== 'string' || !agentId)
|
|
75
|
+
return undefined;
|
|
76
|
+
const frame = raw.frame;
|
|
77
|
+
if (frame === null || typeof frame !== 'object')
|
|
78
|
+
return undefined;
|
|
79
|
+
const { type, attemptId } = frame;
|
|
80
|
+
if (typeof attemptId !== 'string' || !attemptId)
|
|
81
|
+
return undefined;
|
|
82
|
+
if (type === 'start') {
|
|
83
|
+
return { agentId, delta: { kind: 'attempt-start', attemptId } };
|
|
84
|
+
}
|
|
85
|
+
if (type === 'chunk') {
|
|
86
|
+
const chunk = frame.chunk;
|
|
87
|
+
if (chunk?.type !== 'text-delta' || typeof chunk.text !== 'string' || !chunk.text)
|
|
88
|
+
return undefined;
|
|
89
|
+
return { agentId, delta: { kind: 'text-delta', attemptId, text: chunk.text } };
|
|
90
|
+
}
|
|
91
|
+
return undefined;
|
|
92
|
+
}
|
|
62
93
|
//# sourceMappingURL=events.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"events.js","sourceRoot":"","sources":["../../src/transport/events.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AA4DH;;;;GAIG;AACH,MAAM,UAAU,UAAU,CAAC,GAAoB;IAC7C,QAAQ,GAAG,CAAC,IAAI,EAAE,CAAC;QACjB,KAAK,iBAAiB,CAAC,CAAC,CAAC;YACvB,MAAM,KAAK,GAAI,GAAG,CAAC,IAAqD,CAAC,KAAK,CAAC;YAC/E,IAAI,KAAK,KAAK,SAAS,IAAI,KAAK,CAAC,IAAI,KAAK,YAAY,IAAI,CAAC,KAAK,CAAC,IAAI;gBAAE,OAAO,SAAS,CAAC;YACxF,OAAO,EAAE,IAAI,EAAE,iBAAiB,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,EAAE,CAAC;QACvD,CAAC;QAED,KAAK,mBAAmB,CAAC,CAAC,CAAC;YACzB,MAAM,OAAO,GAAI,GAAG,CAAC,IAA2E,CAAC,OAAO,CAAC;YACzG,IAAI,OAAO,KAAK,SAAS,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC,OAAO,CAAC;gBAAE,OAAO,SAAS,CAAC;YAC/E,OAAO,EAAE,IAAI,EAAE,mBAAmB,EAAE,OAAO,EAAE,OAAO,CAAC,OAAO,EAAE,CAAC;QACjE,CAAC;QAED,KAAK,WAAW,CAAC,CAAC,CAAC;YACjB,MAAM,IAAI,GAAG,GAAG,CAAC,IAA8D,CAAC;YAChF,IAAI,CAAC,IAAI,CAAC,MAAM,IAAI,CAAC,IAAI,CAAC,IAAI;gBAAE,OAAO,SAAS,CAAC;YACjD,OAAO,EAAE,IAAI,EAAE,WAAW,EAAE,MAAM,EAAE,IAAI,CAAC,MAAM,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,SAAS,EAAE,IAAI,CAAC,SAAS,IAAI,EAAE,EAAE,CAAC;QACtG,CAAC;QAED,KAAK,aAAa,CAAC,CAAC,CAAC;YACnB,MAAM,IAAI,GAAG,GAAG,CAAC,IAA8F,CAAC;YAChH,MAAM,MAAM,GAAG,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,CAAC;YAC5C,IAAI,CAAC,MAAM;gBAAE,OAAO,SAAS,CAAC;YAC9B,OAAO,EAAE,IAAI,EAAE,aAAa,EAAE,MAAM,EAAE,KAAK,EAAE,IAAI,CAAC,KAAK,EAAE,GAAG,EAAE,GAAG,CAAC,IAAI,EAAE,CAAC;QAC3E,CAAC;QAED,KAAK,UAAU,CAAC,CAAC,CAAC;YAChB,MAAM,MAAM,GAAI,GAAG,CAAC,IAAmC,CAAC,MAAM,IAAI,EAAE,CAAC;YACrE,OAAO,EAAE,IAAI,EAAE,UAAU,EAAE,MAAM,EAAE,CAAC;QACtC,CAAC;QAED;YACE,OAAO,SAAS,CAAC;IACrB,CAAC;AACH,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,gBAAgB,CAAC,MAAqB;IACpD,IAAI,MAAM,CAAC,IAAI,KAAK,OAAO;QAAE,OAAO,SAAS,CAAC;IAE9C,MAAM,MAAM,GAAG,MAAM,CAAC,KAAK,IAAI,MAAM,CAAC,OAAO,CAAC;IAC9C,OAAO;QACL,IAAI,EAAE,MAAM,EAAE,IAAI,IAAI,MAAM,CAAC,IAAI,IAAI,SAAS;QAC9C,OAAO,EAAE,MAAM,EAAE,OAAO,IAAI,MAAM,CAAC,OAAO,IAAI,eAAe;KAC9D,CAAC;AACJ,CAAC"}
|
|
1
|
+
{"version":3,"file":"events.js","sourceRoot":"","sources":["../../src/transport/events.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AA4DH;;;;GAIG;AACH,MAAM,UAAU,UAAU,CAAC,GAAoB;IAC7C,QAAQ,GAAG,CAAC,IAAI,EAAE,CAAC;QACjB,KAAK,iBAAiB,CAAC,CAAC,CAAC;YACvB,MAAM,KAAK,GAAI,GAAG,CAAC,IAAqD,CAAC,KAAK,CAAC;YAC/E,IAAI,KAAK,KAAK,SAAS,IAAI,KAAK,CAAC,IAAI,KAAK,YAAY,IAAI,CAAC,KAAK,CAAC,IAAI;gBAAE,OAAO,SAAS,CAAC;YACxF,OAAO,EAAE,IAAI,EAAE,iBAAiB,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,EAAE,CAAC;QACvD,CAAC;QAED,KAAK,mBAAmB,CAAC,CAAC,CAAC;YACzB,MAAM,OAAO,GAAI,GAAG,CAAC,IAA2E,CAAC,OAAO,CAAC;YACzG,IAAI,OAAO,KAAK,SAAS,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC,OAAO,CAAC;gBAAE,OAAO,SAAS,CAAC;YAC/E,OAAO,EAAE,IAAI,EAAE,mBAAmB,EAAE,OAAO,EAAE,OAAO,CAAC,OAAO,EAAE,CAAC;QACjE,CAAC;QAED,KAAK,WAAW,CAAC,CAAC,CAAC;YACjB,MAAM,IAAI,GAAG,GAAG,CAAC,IAA8D,CAAC;YAChF,IAAI,CAAC,IAAI,CAAC,MAAM,IAAI,CAAC,IAAI,CAAC,IAAI;gBAAE,OAAO,SAAS,CAAC;YACjD,OAAO,EAAE,IAAI,EAAE,WAAW,EAAE,MAAM,EAAE,IAAI,CAAC,MAAM,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,SAAS,EAAE,IAAI,CAAC,SAAS,IAAI,EAAE,EAAE,CAAC;QACtG,CAAC;QAED,KAAK,aAAa,CAAC,CAAC,CAAC;YACnB,MAAM,IAAI,GAAG,GAAG,CAAC,IAA8F,CAAC;YAChH,MAAM,MAAM,GAAG,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,CAAC;YAC5C,IAAI,CAAC,MAAM;gBAAE,OAAO,SAAS,CAAC;YAC9B,OAAO,EAAE,IAAI,EAAE,aAAa,EAAE,MAAM,EAAE,KAAK,EAAE,IAAI,CAAC,KAAK,EAAE,GAAG,EAAE,GAAG,CAAC,IAAI,EAAE,CAAC;QAC3E,CAAC;QAED,KAAK,UAAU,CAAC,CAAC,CAAC;YAChB,MAAM,MAAM,GAAI,GAAG,CAAC,IAAmC,CAAC,MAAM,IAAI,EAAE,CAAC;YACrE,OAAO,EAAE,IAAI,EAAE,UAAU,EAAE,MAAM,EAAE,CAAC;QACtC,CAAC;QAED;YACE,OAAO,SAAS,CAAC;IACrB,CAAC;AACH,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,gBAAgB,CAAC,MAAqB;IACpD,IAAI,MAAM,CAAC,IAAI,KAAK,OAAO;QAAE,OAAO,SAAS,CAAC;IAE9C,MAAM,MAAM,GAAG,MAAM,CAAC,KAAK,IAAI,MAAM,CAAC,OAAO,CAAC;IAC9C,OAAO;QACL,IAAI,EAAE,MAAM,EAAE,IAAI,IAAI,MAAM,CAAC,IAAI,IAAI,SAAS;QAC9C,OAAO,EAAE,MAAM,EAAE,OAAO,IAAI,MAAM,CAAC,OAAO,IAAI,eAAe;KAC9D,CAAC;AACJ,CAAC;AAWD;;;;;;;GAOG;AACH,MAAM,UAAU,gBAAgB,CAAC,GAAY;IAC3C,IAAI,GAAG,KAAK,IAAI,IAAI,OAAO,GAAG,KAAK,QAAQ;QAAE,OAAO,SAAS,CAAC;IAC9D,MAAM,OAAO,GAAI,GAAoC,CAAC,KAAK,EAAE,EAAE,CAAC;IAChE,IAAI,OAAO,OAAO,KAAK,QAAQ,IAAI,CAAC,OAAO;QAAE,OAAO,SAAS,CAAC;IAE9D,MAAM,KAAK,GAAI,GAA2B,CAAC,KAAK,CAAC;IACjD,IAAI,KAAK,KAAK,IAAI,IAAI,OAAO,KAAK,KAAK,QAAQ;QAAE,OAAO,SAAS,CAAC;IAClE,MAAM,EAAE,IAAI,EAAE,SAAS,EAAE,GAAG,KAAgD,CAAC;IAC7E,IAAI,OAAO,SAAS,KAAK,QAAQ,IAAI,CAAC,SAAS;QAAE,OAAO,SAAS,CAAC;IAElE,IAAI,IAAI,KAAK,OAAO,EAAE,CAAC;QACrB,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,EAAE,IAAI,EAAE,eAAe,EAAE,SAAS,EAAE,EAAE,CAAC;IAClE,CAAC;IACD,IAAI,IAAI,KAAK,OAAO,EAAE,CAAC;QACrB,MAAM,KAAK,GAAI,KAA+D,CAAC,KAAK,CAAC;QACrF,IAAI,KAAK,EAAE,IAAI,KAAK,YAAY,IAAI,OAAO,KAAK,CAAC,IAAI,KAAK,QAAQ,IAAI,CAAC,KAAK,CAAC,IAAI;YAAE,OAAO,SAAS,CAAC;QACpG,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,EAAE,IAAI,EAAE,YAAY,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,EAAE,EAAE,CAAC;IACjF,CAAC;IACD,OAAO,SAAS,CAAC;AACnB,CAAC"}
|
|
@@ -32,6 +32,8 @@ export declare class OutboundBuffer {
|
|
|
32
32
|
append(text: string): void;
|
|
33
33
|
/** 获取当前累积文本 */
|
|
34
34
|
get text(): string;
|
|
35
|
+
/** 重置累积文本(LLM 重试的新 attempt),流式会话保留由全量 update 重写 */
|
|
36
|
+
reset(): void;
|
|
35
37
|
/** 发送所有累积文本:流式优先,降级静态 */
|
|
36
38
|
flush(): Promise<void>;
|
|
37
39
|
/** 取消(异常/丢弃),中止流式并清空缓冲 */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"outbound-buffer.d.ts","sourceRoot":"","sources":["../../src/transport/outbound-buffer.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,+BAA+B,CAAC;AACpE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACzD,OAAO,KAAK,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAOvD,6BAA6B;AAC7B,MAAM,WAAW,iBAAiB;IAChC,MAAM,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IAC1C,QAAQ,IAAI,OAAO,CAAC,OAAO,CAAC,CAAC;CAC9B;AAED,kBAAkB;AAClB,MAAM,WAAW,WAAW;IAC1B,YAAY,CAAC,MAAM,EAAE,WAAW,EAAE,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE;QAAE,QAAQ,CAAC,EAAE,cAAc,CAAA;KAAE,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IAC3G,UAAU,CAAC,MAAM,EAAE,WAAW,GAAG,iBAAiB,CAAC;CACpD;AAED,qBAAa,cAAc;IACzB,OAAO,CAAC,MAAM,CAAM;IACpB,OAAO,CAAC,QAAQ,CAAS;IACzB,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAyB;IAChD,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAgB;IACvC,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAc;IAClC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAS;IAC/B,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAS;gBAG9B,MAAM,EAAE,aAAa,EACrB,GAAG,EAAE,WAAW,EAChB,KAAK,EAAE,MAAM,EACb,MAAM,EAAE,MAAM,EACd,gBAAgB,EAAE,OAAO;IAW3B,aAAa;IACN,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI;IAKjC,eAAe;IACf,IAAW,IAAI,IAAI,MAAM,CAExB;IAED,yBAAyB;IACZ,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAwBnC,0BAA0B;IACnB,MAAM,IAAI,IAAI;CAItB"}
|
|
1
|
+
{"version":3,"file":"outbound-buffer.d.ts","sourceRoot":"","sources":["../../src/transport/outbound-buffer.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,+BAA+B,CAAC;AACpE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACzD,OAAO,KAAK,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAOvD,6BAA6B;AAC7B,MAAM,WAAW,iBAAiB;IAChC,MAAM,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IAC1C,QAAQ,IAAI,OAAO,CAAC,OAAO,CAAC,CAAC;CAC9B;AAED,kBAAkB;AAClB,MAAM,WAAW,WAAW;IAC1B,YAAY,CAAC,MAAM,EAAE,WAAW,EAAE,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE;QAAE,QAAQ,CAAC,EAAE,cAAc,CAAA;KAAE,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IAC3G,UAAU,CAAC,MAAM,EAAE,WAAW,GAAG,iBAAiB,CAAC;CACpD;AAED,qBAAa,cAAc;IACzB,OAAO,CAAC,MAAM,CAAM;IACpB,OAAO,CAAC,QAAQ,CAAS;IACzB,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAyB;IAChD,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAgB;IACvC,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAc;IAClC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAS;IAC/B,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAS;gBAG9B,MAAM,EAAE,aAAa,EACrB,GAAG,EAAE,WAAW,EAChB,KAAK,EAAE,MAAM,EACb,MAAM,EAAE,MAAM,EACd,gBAAgB,EAAE,OAAO;IAW3B,aAAa;IACN,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI;IAKjC,eAAe;IACf,IAAW,IAAI,IAAI,MAAM,CAExB;IAED,mDAAmD;IAC5C,KAAK,IAAI,IAAI;IAKpB,yBAAyB;IACZ,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAwBnC,0BAA0B;IACnB,MAAM,IAAI,IAAI;CAItB"}
|
|
@@ -28,6 +28,11 @@ export class OutboundBuffer {
|
|
|
28
28
|
get text() {
|
|
29
29
|
return this.buffer;
|
|
30
30
|
}
|
|
31
|
+
/** 重置累积文本(LLM 重试的新 attempt),流式会话保留由全量 update 重写 */
|
|
32
|
+
reset() {
|
|
33
|
+
this.buffer = '';
|
|
34
|
+
this.writer?.reset();
|
|
35
|
+
}
|
|
31
36
|
/** 发送所有累积文本:流式优先,降级静态 */
|
|
32
37
|
async flush() {
|
|
33
38
|
if (this.flushing || !this.buffer.trim())
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"outbound-buffer.js","sourceRoot":"","sources":["../../src/transport/outbound-buffer.ts"],"names":[],"mappings":"AASA,OAAO,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAC;AACjD,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAExD,wCAAwC;AACxC,MAAM,kBAAkB,GAAG,GAAG,CAAC;AAc/B,MAAM,OAAO,cAAc;IACjB,MAAM,GAAG,EAAE,CAAC;IACZ,QAAQ,GAAG,KAAK,CAAC;IACR,MAAM,CAAyB;IAC/B,MAAM,CAAgB;IACtB,GAAG,CAAc;IACjB,KAAK,CAAS;IACd,MAAM,CAAS;IAEhC,YACE,MAAqB,EACrB,GAAgB,EAChB,KAAa,EACb,MAAc,EACd,gBAAyB;QAEzB,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;QACrB,IAAI,CAAC,GAAG,GAAG,GAAG,CAAC;QACf,IAAI,CAAC,KAAK,GAAG,KAAK,CAAC;QACnB,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;QACrB,IAAI,CAAC,MAAM,GAAG,gBAAgB;YAC5B,CAAC,CAAC,IAAI,eAAe,CAAC,EAAE,GAAG,EAAE,MAAM,EAAE,MAAM,CAAC,WAAW,EAAE,MAAM,EAAE,UAAU,EAAE,kBAAkB,EAAE,CAAC;YAClG,CAAC,CAAC,IAAI,CAAC;IACX,CAAC;IAED,aAAa;IACN,MAAM,CAAC,IAAY;QACxB,IAAI,CAAC,MAAM,IAAI,IAAI,CAAC;QACpB,IAAI,CAAC,MAAM,EAAE,MAAM,CAAC,IAAI,CAAC,CAAC;IAC5B,CAAC;IAED,eAAe;IACf,IAAW,IAAI;QACb,OAAO,IAAI,CAAC,MAAM,CAAC;IACrB,CAAC;IAED,yBAAyB;IAClB,KAAK,CAAC,KAAK;QAChB,IAAI,IAAI,CAAC,QAAQ,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,EAAE;YAAE,OAAO;QACjD,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC;QAErB,IAAI,CAAC;YACH,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC;gBAChB,MAAM,IAAI,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC;gBAC3B,kBAAkB;gBAClB,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,cAAc;oBAAE,OAAO;YAC1C,CAAC;YAED,8BAA8B;YAC9B,MAAM,MAAM,GAAG,iBAAiB,CAAC,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC;YAC1D,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;gBAC3B,MAAM,IAAI,CAAC,GAAG,CAAC,YAAY,CAAC,IAAI,CAAC,MAAM,CAAC,WAAW,EAAE,KAAK,CAAC,CAAC;YAC9D,CAAC;QACH,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,2BAA2B,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QACnG,CAAC;gBAAS,CAAC;YACT,IAAI,CAAC,MAAM,GAAG,EAAE,CAAC;YACjB,IAAI,CAAC,QAAQ,GAAG,KAAK,CAAC;QACxB,CAAC;IACH,CAAC;IAED,0BAA0B;IACnB,MAAM;QACX,IAAI,CAAC,MAAM,EAAE,KAAK,EAAE,CAAC;QACrB,IAAI,CAAC,MAAM,GAAG,EAAE,CAAC;IACnB,CAAC;CACF"}
|
|
1
|
+
{"version":3,"file":"outbound-buffer.js","sourceRoot":"","sources":["../../src/transport/outbound-buffer.ts"],"names":[],"mappings":"AASA,OAAO,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAC;AACjD,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAExD,wCAAwC;AACxC,MAAM,kBAAkB,GAAG,GAAG,CAAC;AAc/B,MAAM,OAAO,cAAc;IACjB,MAAM,GAAG,EAAE,CAAC;IACZ,QAAQ,GAAG,KAAK,CAAC;IACR,MAAM,CAAyB;IAC/B,MAAM,CAAgB;IACtB,GAAG,CAAc;IACjB,KAAK,CAAS;IACd,MAAM,CAAS;IAEhC,YACE,MAAqB,EACrB,GAAgB,EAChB,KAAa,EACb,MAAc,EACd,gBAAyB;QAEzB,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;QACrB,IAAI,CAAC,GAAG,GAAG,GAAG,CAAC;QACf,IAAI,CAAC,KAAK,GAAG,KAAK,CAAC;QACnB,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;QACrB,IAAI,CAAC,MAAM,GAAG,gBAAgB;YAC5B,CAAC,CAAC,IAAI,eAAe,CAAC,EAAE,GAAG,EAAE,MAAM,EAAE,MAAM,CAAC,WAAW,EAAE,MAAM,EAAE,UAAU,EAAE,kBAAkB,EAAE,CAAC;YAClG,CAAC,CAAC,IAAI,CAAC;IACX,CAAC;IAED,aAAa;IACN,MAAM,CAAC,IAAY;QACxB,IAAI,CAAC,MAAM,IAAI,IAAI,CAAC;QACpB,IAAI,CAAC,MAAM,EAAE,MAAM,CAAC,IAAI,CAAC,CAAC;IAC5B,CAAC;IAED,eAAe;IACf,IAAW,IAAI;QACb,OAAO,IAAI,CAAC,MAAM,CAAC;IACrB,CAAC;IAED,mDAAmD;IAC5C,KAAK;QACV,IAAI,CAAC,MAAM,GAAG,EAAE,CAAC;QACjB,IAAI,CAAC,MAAM,EAAE,KAAK,EAAE,CAAC;IACvB,CAAC;IAED,yBAAyB;IAClB,KAAK,CAAC,KAAK;QAChB,IAAI,IAAI,CAAC,QAAQ,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,EAAE;YAAE,OAAO;QACjD,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC;QAErB,IAAI,CAAC;YACH,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC;gBAChB,MAAM,IAAI,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC;gBAC3B,kBAAkB;gBAClB,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,cAAc;oBAAE,OAAO;YAC1C,CAAC;YAED,8BAA8B;YAC9B,MAAM,MAAM,GAAG,iBAAiB,CAAC,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC;YAC1D,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;gBAC3B,MAAM,IAAI,CAAC,GAAG,CAAC,YAAY,CAAC,IAAI,CAAC,MAAM,CAAC,WAAW,EAAE,KAAK,CAAC,CAAC;YAC9D,CAAC;QACH,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,2BAA2B,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QACnG,CAAC;gBAAS,CAAC;YACT,IAAI,CAAC,MAAM,GAAG,EAAE,CAAC;YACjB,IAAI,CAAC,QAAQ,GAAG,KAAK,CAAC;QACxB,CAAC;IACH,CAAC;IAED,0BAA0B;IACnB,MAAM;QACX,IAAI,CAAC,MAAM,EAAE,KAAK,EAAE,CAAC;QACrB,IAAI,CAAC,MAAM,GAAG,EAAE,CAAC;IACnB,CAAC;CACF"}
|
|
@@ -9,11 +9,21 @@ import type { ImQQBotConfig } from '../config.ts';
|
|
|
9
9
|
import type { Logger } from '../types.ts';
|
|
10
10
|
import { type QQBotSender } from './outbound-buffer.ts';
|
|
11
11
|
import { type ToolsRegistryLike } from './tool-presenter.ts';
|
|
12
|
-
import { type RawSessionEvent } from './events.ts';
|
|
12
|
+
import { type RawSessionEvent, type StreamDelta } from './events.ts';
|
|
13
13
|
export type { QQBotSender } from './outbound-buffer.ts';
|
|
14
14
|
export type { ToolsRegistryLike } from './tool-presenter.ts';
|
|
15
|
+
export { parseStreamFrame } from './events.ts';
|
|
15
16
|
/** 出站处理器签名(注册到 ctx.on('session/event')) */
|
|
16
17
|
export type OutboundHandler = (session: SessionLike, event: RawSessionEvent) => void;
|
|
18
|
+
/** 出站事件入口集合:durable 事件 + 实时流式帧 */
|
|
19
|
+
export interface OutboundHandlers {
|
|
20
|
+
/** durable session 事件入口(注册到 ctx.on('session/event')) */
|
|
21
|
+
routeSessionEvent(session: SessionLike, event: RawSessionEvent): void;
|
|
22
|
+
/**
|
|
23
|
+
* 实时流式帧入口(注册到 ctx.on('agent/assistant-stream', ..., { global: true }))。
|
|
24
|
+
*/
|
|
25
|
+
routeStreamFrame(agentId: string, delta: StreamDelta): void;
|
|
26
|
+
}
|
|
17
27
|
/** dsh Session 简化类型 */
|
|
18
28
|
export interface SessionLike {
|
|
19
29
|
header: {
|
|
@@ -23,8 +33,9 @@ export interface SessionLike {
|
|
|
23
33
|
/**
|
|
24
34
|
* 创建出站事件处理器
|
|
25
35
|
*
|
|
26
|
-
*
|
|
36
|
+
* 返回 durable 事件与实时流式帧两个入口,分别注册到
|
|
37
|
+
* ctx.on('session/event') 与 ctx.on('agent/assistant-stream', ..., { global: true })。
|
|
27
38
|
* toolsRegistry 用于工具结果的结构化展示。
|
|
28
39
|
*/
|
|
29
|
-
export declare function createOutboundHandler(manager: SessionManager, bot: QQBotSender, config: ImQQBotConfig, logger: Logger, toolsRegistry?: ToolsRegistryLike):
|
|
40
|
+
export declare function createOutboundHandler(manager: SessionManager, bot: QQBotSender, config: ImQQBotConfig, logger: Logger, toolsRegistry?: ToolsRegistryLike): OutboundHandlers;
|
|
30
41
|
//# sourceMappingURL=outbound.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"outbound.d.ts","sourceRoot":"","sources":["../../src/transport/outbound.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAO,KAAK,EAAE,cAAc,EAAiB,MAAM,qBAAqB,CAAC;AACzE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAClD,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAE1C,OAAO,EAAkB,KAAK,WAAW,EAAE,MAAM,sBAAsB,CAAC;AACxE,OAAO,EAAoB,KAAK,iBAAiB,EAAuB,MAAM,qBAAqB,CAAC;AACpG,OAAO,EAQL,KAAK,eAAe,
|
|
1
|
+
{"version":3,"file":"outbound.d.ts","sourceRoot":"","sources":["../../src/transport/outbound.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAO,KAAK,EAAE,cAAc,EAAiB,MAAM,qBAAqB,CAAC;AACzE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAClD,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAE1C,OAAO,EAAkB,KAAK,WAAW,EAAE,MAAM,sBAAsB,CAAC;AACxE,OAAO,EAAoB,KAAK,iBAAiB,EAAuB,MAAM,qBAAqB,CAAC;AACpG,OAAO,EAQL,KAAK,eAAe,EACpB,KAAK,WAAW,EACjB,MAAM,aAAa,CAAC;AAErB,YAAY,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AACxD,YAAY,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AAC7D,OAAO,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAE/C,2CAA2C;AAC3C,MAAM,MAAM,eAAe,GAAG,CAAC,OAAO,EAAE,WAAW,EAAE,KAAK,EAAE,eAAe,KAAK,IAAI,CAAC;AAErF,kCAAkC;AAClC,MAAM,WAAW,gBAAgB;IAC/B,wDAAwD;IACxD,iBAAiB,CAAC,OAAO,EAAE,WAAW,EAAE,KAAK,EAAE,eAAe,GAAG,IAAI,CAAC;IACtE;;OAEG;IACH,gBAAgB,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,WAAW,GAAG,IAAI,CAAC;CAC7D;AAED,uBAAuB;AACvB,MAAM,WAAW,WAAW;IAC1B,MAAM,EAAE;QAAE,EAAE,EAAE,MAAM,CAAA;KAAE,CAAC;CACxB;AAqMD;;;;;;GAMG;AACH,wBAAgB,qBAAqB,CACnC,OAAO,EAAE,cAAc,EACvB,GAAG,EAAE,WAAW,EAChB,MAAM,EAAE,aAAa,EACrB,MAAM,EAAE,MAAM,EACd,aAAa,CAAC,EAAE,iBAAiB,GAChC,gBAAgB,CAMlB"}
|
|
@@ -2,6 +2,7 @@ import { chunkMarkdownText } from "./chunker.js";
|
|
|
2
2
|
import { OutboundBuffer } from "./outbound-buffer.js";
|
|
3
3
|
import { formatToolResult } from "./tool-presenter.js";
|
|
4
4
|
import { parseEvent, extractTurnError, } from "./events.js";
|
|
5
|
+
export { parseStreamFrame } from "./events.js";
|
|
5
6
|
/** 不展示给用户的轮次错误码(底层传输/网络错误,对用户无意义,且常被重试兜住) */
|
|
6
7
|
const SILENT_TURN_ERROR_CODES = new Set(['STREAM_CLOSED']);
|
|
7
8
|
/**
|
|
@@ -10,6 +11,8 @@ const SILENT_TURN_ERROR_CODES = new Set(['STREAM_CLOSED']);
|
|
|
10
11
|
class OutboundRouter {
|
|
11
12
|
buffers = new Map();
|
|
12
13
|
toolCalls = new Map();
|
|
14
|
+
/** 每会话当前流式 attemptId:LLM 重试会发布新 attempt,用于 reset 与迟到帧过滤 */
|
|
15
|
+
streamAttempts = new Map();
|
|
13
16
|
manager;
|
|
14
17
|
bot;
|
|
15
18
|
config;
|
|
@@ -48,14 +51,47 @@ class OutboundRouter {
|
|
|
48
51
|
break;
|
|
49
52
|
}
|
|
50
53
|
}
|
|
51
|
-
/**
|
|
54
|
+
/** durable assistant/chunk 事件的流式增量(历史格式兼容保留,当前宿主不再生产该事件) */
|
|
52
55
|
onChunk(sessionId, record, event) {
|
|
56
|
+
this.appendChunk(sessionId, record, event.text);
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* 实时流式帧入口(瞬态 agent/assistant-stream 事件)。
|
|
60
|
+
*
|
|
61
|
+
* attempt 语义:start 帧即新内容起点,无条件重置 buffer——清空旧 attempt 的
|
|
62
|
+
* 累积文本但保留流式会话(QQ 流式 update 是全量替换,用户看到同一条消息被
|
|
63
|
+
* 新内容重写)。不用 attemptId 对比判断"新 attempt":agent replacement 后
|
|
64
|
+
* attempt 计数重启、attemptId 可能与旧 agent 重叠(官方按 frame revision 的
|
|
65
|
+
* gap 检测处理同一问题)。迟到帧(attemptId 不匹配)仍直接丢弃,防止旧
|
|
66
|
+
* attempt 的尾巴混进新内容。
|
|
67
|
+
*/
|
|
68
|
+
routeStreamFrame(agentId, delta) {
|
|
69
|
+
if (delta.kind === 'attempt-start') {
|
|
70
|
+
this.streamAttempts.set(agentId, delta.attemptId);
|
|
71
|
+
this.buffers.get(agentId)?.reset();
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
74
|
+
// text-delta:首帧未见 start 时自愈记录,迟到帧丢弃
|
|
75
|
+
const current = this.streamAttempts.get(agentId);
|
|
76
|
+
if (current === undefined) {
|
|
77
|
+
this.streamAttempts.set(agentId, delta.attemptId);
|
|
78
|
+
}
|
|
79
|
+
else if (current !== delta.attemptId) {
|
|
80
|
+
return;
|
|
81
|
+
}
|
|
82
|
+
const record = this.manager.findBySessionId(agentId);
|
|
83
|
+
if (record === undefined)
|
|
84
|
+
return;
|
|
85
|
+
this.appendChunk(agentId, record, delta.text);
|
|
86
|
+
}
|
|
87
|
+
/** 获取或创建会话 buffer 并追加增量 */
|
|
88
|
+
appendChunk(sessionId, record, text) {
|
|
53
89
|
let buffer = this.buffers.get(sessionId);
|
|
54
90
|
if (buffer === undefined) {
|
|
55
91
|
buffer = new OutboundBuffer(record, this.bot, this.config.textChunkLimit, this.logger, this.shouldStream(record));
|
|
56
92
|
this.buffers.set(sessionId, buffer);
|
|
57
93
|
}
|
|
58
|
-
buffer.append(
|
|
94
|
+
buffer.append(text);
|
|
59
95
|
}
|
|
60
96
|
/** 是否启用流式:配置开启 + c2c + 有 msgId(群聊不支持流式) */
|
|
61
97
|
shouldStream(record) {
|
|
@@ -99,7 +135,7 @@ class OutboundRouter {
|
|
|
99
135
|
return;
|
|
100
136
|
void this.send(record, text, 'sendToolResult');
|
|
101
137
|
}
|
|
102
|
-
/** 轮次结束:清理 buffer
|
|
138
|
+
/** 轮次结束:清理 buffer 与 attempt 跟踪状态,异常结束时告知用户 */
|
|
103
139
|
onTurnEnd(sessionId, record, event) {
|
|
104
140
|
const buffer = this.buffers.get(sessionId);
|
|
105
141
|
if (buffer !== undefined) {
|
|
@@ -111,6 +147,7 @@ class OutboundRouter {
|
|
|
111
147
|
}
|
|
112
148
|
this.buffers.delete(sessionId);
|
|
113
149
|
}
|
|
150
|
+
this.streamAttempts.delete(sessionId);
|
|
114
151
|
const failure = extractTurnError(event.reason);
|
|
115
152
|
if (failure !== undefined && !SILENT_TURN_ERROR_CODES.has(failure.code)) {
|
|
116
153
|
void this.send(record, `⚠️ 本轮异常结束\n\`${failure.code}\`: ${failure.message}`, 'sendTurnEndError');
|
|
@@ -133,11 +170,15 @@ class OutboundRouter {
|
|
|
133
170
|
/**
|
|
134
171
|
* 创建出站事件处理器
|
|
135
172
|
*
|
|
136
|
-
*
|
|
173
|
+
* 返回 durable 事件与实时流式帧两个入口,分别注册到
|
|
174
|
+
* ctx.on('session/event') 与 ctx.on('agent/assistant-stream', ..., { global: true })。
|
|
137
175
|
* toolsRegistry 用于工具结果的结构化展示。
|
|
138
176
|
*/
|
|
139
177
|
export function createOutboundHandler(manager, bot, config, logger, toolsRegistry) {
|
|
140
178
|
const router = new OutboundRouter(manager, bot, config, logger, toolsRegistry);
|
|
141
|
-
return
|
|
179
|
+
return {
|
|
180
|
+
routeSessionEvent: (session, event) => router.route(session, event),
|
|
181
|
+
routeStreamFrame: (agentId, delta) => router.routeStreamFrame(agentId, delta),
|
|
182
|
+
};
|
|
142
183
|
}
|
|
143
184
|
//# sourceMappingURL=outbound.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"outbound.js","sourceRoot":"","sources":["../../src/transport/outbound.ts"],"names":[],"mappings":"AASA,OAAO,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAC;AACjD,OAAO,EAAE,cAAc,EAAoB,MAAM,sBAAsB,CAAC;AACxE,OAAO,EAAE,gBAAgB,EAA+C,MAAM,qBAAqB,CAAC;AACpG,OAAO,EACL,UAAU,EACV,gBAAgB,
|
|
1
|
+
{"version":3,"file":"outbound.js","sourceRoot":"","sources":["../../src/transport/outbound.ts"],"names":[],"mappings":"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"}
|
|
@@ -33,6 +33,14 @@ export declare class StreamingWriter {
|
|
|
33
33
|
get shouldFallback(): boolean;
|
|
34
34
|
/** 累积全文(降级静态发送时使用) */
|
|
35
35
|
get text(): string;
|
|
36
|
+
/**
|
|
37
|
+
* 重置累积文本(LLM 重试的新 attempt)。
|
|
38
|
+
*
|
|
39
|
+
* 保留已打开的流式会话与 sentChunkCount:QQ 流式 update 是全量替换语义,
|
|
40
|
+
* 新 attempt 的增量会把同一条消息整体重写,用户不会看到两条消息;
|
|
41
|
+
* sentChunkCount 保留则防止重试后误判"从未发送"而降级静态造成重复。
|
|
42
|
+
*/
|
|
43
|
+
reset(): void;
|
|
36
44
|
/** 追加增量文本,节流(throttle)后 update 全量 */
|
|
37
45
|
append(delta: string): void;
|
|
38
46
|
/** 结束:flush 最终文本 + complete 收尾 */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"streaming-writer.d.ts","sourceRoot":"","sources":["../../src/transport/streaming-writer.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AACH,OAAO,KAAK,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AACvD,OAAO,KAAK,EAAE,WAAW,EAAqB,MAAM,sBAAsB,CAAC;AAE3E,MAAM,WAAW,mBAAmB;IAClC,GAAG,EAAE,WAAW,CAAC;IACjB,MAAM,EAAE,WAAW,CAAC;IACpB,MAAM,EAAE,MAAM,CAAC;IACf,2CAA2C;IAC3C,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,qBAAa,eAAe;IAC1B,OAAO,CAAC,QAAQ,CAAM;IACtB,OAAO,CAAC,OAAO,CAAkC;IACjD,OAAO,CAAC,cAAc,CAAK;IAC3B,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,QAAQ,CAAS;IACzB,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,aAAa,CAA8C;IACnE,OAAO,CAAC,KAAK,CAAoC;IAEjD,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAsB;gBAExB,IAAI,EAAE,mBAAmB;IAI5C,6BAA6B;IAC7B,IAAW,cAAc,IAAI,OAAO,CAEnC;IAED,sBAAsB;IACtB,IAAW,IAAI,IAAI,MAAM,CAExB;IAED,qCAAqC;IAC9B,MAAM,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI;IAclC,kCAAkC;IACrB,MAAM,IAAI,OAAO,CAAC,IAAI,CAAC;IAyBpC,gCAAgC;IACzB,KAAK,IAAI,IAAI;IAwBpB,2BAA2B;IAC3B,OAAO,CAAC,OAAO;IAIf,0CAA0C;YAC5B,UAAU;CA2BzB"}
|
|
1
|
+
{"version":3,"file":"streaming-writer.d.ts","sourceRoot":"","sources":["../../src/transport/streaming-writer.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AACH,OAAO,KAAK,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AACvD,OAAO,KAAK,EAAE,WAAW,EAAqB,MAAM,sBAAsB,CAAC;AAE3E,MAAM,WAAW,mBAAmB;IAClC,GAAG,EAAE,WAAW,CAAC;IACjB,MAAM,EAAE,WAAW,CAAC;IACpB,MAAM,EAAE,MAAM,CAAC;IACf,2CAA2C;IAC3C,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,qBAAa,eAAe;IAC1B,OAAO,CAAC,QAAQ,CAAM;IACtB,OAAO,CAAC,OAAO,CAAkC;IACjD,OAAO,CAAC,cAAc,CAAK;IAC3B,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,QAAQ,CAAS;IACzB,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,aAAa,CAA8C;IACnE,OAAO,CAAC,KAAK,CAAoC;IAEjD,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAsB;gBAExB,IAAI,EAAE,mBAAmB;IAI5C,6BAA6B;IAC7B,IAAW,cAAc,IAAI,OAAO,CAEnC;IAED,sBAAsB;IACtB,IAAW,IAAI,IAAI,MAAM,CAExB;IAED;;;;;;OAMG;IACI,KAAK,IAAI,IAAI;IAKpB,qCAAqC;IAC9B,MAAM,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI;IAclC,kCAAkC;IACrB,MAAM,IAAI,OAAO,CAAC,IAAI,CAAC;IAyBpC,gCAAgC;IACzB,KAAK,IAAI,IAAI;IAwBpB,2BAA2B;IAC3B,OAAO,CAAC,OAAO;IAIf,0CAA0C;YAC5B,UAAU;CA2BzB"}
|
|
@@ -19,6 +19,18 @@ export class StreamingWriter {
|
|
|
19
19
|
get text() {
|
|
20
20
|
return this.fullText;
|
|
21
21
|
}
|
|
22
|
+
/**
|
|
23
|
+
* 重置累积文本(LLM 重试的新 attempt)。
|
|
24
|
+
*
|
|
25
|
+
* 保留已打开的流式会话与 sentChunkCount:QQ 流式 update 是全量替换语义,
|
|
26
|
+
* 新 attempt 的增量会把同一条消息整体重写,用户不会看到两条消息;
|
|
27
|
+
* sentChunkCount 保留则防止重试后误判"从未发送"而降级静态造成重复。
|
|
28
|
+
*/
|
|
29
|
+
reset() {
|
|
30
|
+
if (this.finished)
|
|
31
|
+
return;
|
|
32
|
+
this.fullText = '';
|
|
33
|
+
}
|
|
22
34
|
/** 追加增量文本,节流(throttle)后 update 全量 */
|
|
23
35
|
append(delta) {
|
|
24
36
|
if (this.finished)
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"streaming-writer.js","sourceRoot":"","sources":["../../src/transport/streaming-writer.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"streaming-writer.js","sourceRoot":"","sources":["../../src/transport/streaming-writer.ts"],"names":[],"mappings":"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"}
|
package/lib/client.js
CHANGED
|
@@ -659,7 +659,7 @@ window.__ModuleLoader__.load({
|
|
|
659
659
|
const MODE_OPTIONS = [
|
|
660
660
|
{
|
|
661
661
|
value: "open",
|
|
662
|
-
label: "
|
|
662
|
+
label: "所有人"
|
|
663
663
|
},
|
|
664
664
|
{
|
|
665
665
|
value: "allowlist",
|
|
@@ -667,7 +667,7 @@ window.__ModuleLoader__.load({
|
|
|
667
667
|
},
|
|
668
668
|
{
|
|
669
669
|
value: "disabled",
|
|
670
|
-
label: "
|
|
670
|
+
label: "禁用"
|
|
671
671
|
}
|
|
672
672
|
];
|
|
673
673
|
/** 深比较(表单值与初始回显值的 dirty 判断) */
|
|
@@ -715,6 +715,14 @@ window.__ModuleLoader__.load({
|
|
|
715
715
|
const changed = {};
|
|
716
716
|
for (const key of Object.keys(form)) if (!shallowEqual(form[key], initial[key])) changed[key] = form[key];
|
|
717
717
|
if (Object.keys(changed).length === 0) return;
|
|
718
|
+
if (changed.access !== void 0) {
|
|
719
|
+
const a = changed.access;
|
|
720
|
+
changed.access = {
|
|
721
|
+
...a,
|
|
722
|
+
c2cAllow: a.c2cAllow.map((s) => s.trim()).filter(Boolean),
|
|
723
|
+
groupAllow: a.groupAllow.map((s) => s.trim()).filter(Boolean)
|
|
724
|
+
};
|
|
725
|
+
}
|
|
718
726
|
setBusy(true);
|
|
719
727
|
fetch(BIND_CONFIG_PATH, {
|
|
720
728
|
method: "POST",
|
|
@@ -765,7 +773,7 @@ window.__ModuleLoader__.load({
|
|
|
765
773
|
return (0, react.createElement)("form", {
|
|
766
774
|
className: "imqb2-form",
|
|
767
775
|
onSubmit: submit
|
|
768
|
-
}, (0, react.createElement)("div", { className: "imqb2-group-title" }, "
|
|
776
|
+
}, (0, react.createElement)("div", { className: "imqb2-group-title" }, "服务范围"), (0, react.createElement)(SegmentedRow, {
|
|
769
777
|
label: "私聊",
|
|
770
778
|
value: access.c2cMode,
|
|
771
779
|
options: MODE_OPTIONS,
|
|
@@ -777,13 +785,13 @@ window.__ModuleLoader__.load({
|
|
|
777
785
|
}
|
|
778
786
|
}), access.c2cMode === "allowlist" ? (0, react.createElement)(AreaRow, {
|
|
779
787
|
label: "私聊白名单",
|
|
780
|
-
help: "
|
|
788
|
+
help: "请输入用户 openid,多个请换行输入",
|
|
781
789
|
rows: 3,
|
|
782
790
|
value: access.c2cAllow.join("\n"),
|
|
783
791
|
onChange: (v) => {
|
|
784
792
|
patch("access", {
|
|
785
793
|
...access,
|
|
786
|
-
c2cAllow: v.split("\n").map((s) => s.trim())
|
|
794
|
+
c2cAllow: v.split("\n").map((s) => s.trim())
|
|
787
795
|
});
|
|
788
796
|
}
|
|
789
797
|
}) : null, (0, react.createElement)(SegmentedRow, {
|
|
@@ -798,19 +806,19 @@ window.__ModuleLoader__.load({
|
|
|
798
806
|
}
|
|
799
807
|
}), access.groupMode === "allowlist" ? (0, react.createElement)(AreaRow, {
|
|
800
808
|
label: "群聊白名单",
|
|
801
|
-
help: "
|
|
809
|
+
help: "请输入群 openid,多个请换行输入",
|
|
802
810
|
rows: 3,
|
|
803
811
|
value: access.groupAllow.join("\n"),
|
|
804
812
|
onChange: (v) => {
|
|
805
813
|
patch("access", {
|
|
806
814
|
...access,
|
|
807
|
-
groupAllow: v.split("\n").map((s) => s.trim())
|
|
815
|
+
groupAllow: v.split("\n").map((s) => s.trim())
|
|
808
816
|
});
|
|
809
817
|
}
|
|
810
|
-
}) : null, (0, react.createElement)("div", { className: "imqb2-group-title" }, "
|
|
811
|
-
label: "
|
|
818
|
+
}) : null, (0, react.createElement)("div", { className: "imqb2-group-title" }, "基础设置"), (0, react.createElement)(SwitchRow, {
|
|
819
|
+
label: "群聊仅回复 @机器人的消息",
|
|
812
820
|
checked: form.requireMention ?? true,
|
|
813
|
-
help: "
|
|
821
|
+
help: "开启后,机器人仅可回复 @机器人的群聊消息",
|
|
814
822
|
onChange: (v) => {
|
|
815
823
|
patch("requireMention", v);
|
|
816
824
|
}
|
|
@@ -849,7 +857,7 @@ window.__ModuleLoader__.load({
|
|
|
849
857
|
onChange: (v) => {
|
|
850
858
|
patch("preset", v);
|
|
851
859
|
}
|
|
852
|
-
}), (0, react.createElement)("div", { className: "imqb2-group-title" }, "
|
|
860
|
+
}), (0, react.createElement)("div", { className: "imqb2-group-title" }, "个性化提示词"), (0, react.createElement)(AreaRow, {
|
|
853
861
|
label: "群聊额外 system prompt",
|
|
854
862
|
value: form.groupPrompt ?? "",
|
|
855
863
|
onChange: (v) => {
|
package/lib/client.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client.js","names":["STYLE_ID","useState","useRef","useCallback","createElement","createElement","useState","useCallback","createElement"],"sources":["../src/shared/bind-protocol.ts","../src/client/bind-page.ts","../src/client/config-panel.ts","../src/client/index.ts"],"sourcesContent":["/**\n * 端内绑定协议 —— 宿主路由与客户端面板的共享契约\n *\n * 类型与路径常量的唯一事实源:宿主(setup/bind-routes.ts)与浏览器\n * (client/bind-page.ts)各自 import,杜绝两端协议漂移。\n * 本模块必须保持纯类型 + 纯常量(零 node 依赖、零副作用):\n * 客户端 tsdown 构建会将其内联进 bundle。\n */\n\n/** 状态查询(绑定页轮询) */\nexport const BIND_STATE_PATH = '/qqbot/im-qqbot/bind';\n\n/** 刷新二维码(绑定页按钮) */\nexport const BIND_REFRESH_PATH = '/qqbot/im-qqbot/bind/refresh';\n\n/** 手动填写/编辑凭据(绑定页表单) */\nexport const BIND_MANUAL_PATH = '/qqbot/im-qqbot/bind/manual';\n\n/** 解绑:移除已保存凭据,回到绑定流程 */\nexport const BIND_UNBIND_PATH = '/qqbot/im-qqbot/bind/unbind';\n\n/** 配置读写(设置面板表单) */\nexport const BIND_CONFIG_PATH = '/qqbot/im-qqbot/config';\n\n/** 线上协议(HTTP 路由序列化形态) */\nexport type BindStateWire =\n | { phase: 'starting' }\n | { phase: 'waiting'; url: string; qrSvg?: string; issuedAt: number }\n | { phase: 'saving' }\n | { phase: 'failed'; reason: string }\n | { phase: 'bound'; appId: string };\n\n/** manual / unbind 操作的统一响应 */\nexport interface BindActionResponse {\n ok: boolean;\n message?: string;\n error?: string;\n}\n","/**\n * 端内绑定面板 — 扫码 / 手动填写 / 已绑定编辑\n *\n * 宿主插件注册 /qqbot/im-qqbot/bind 路由(待绑定与已绑定 fiber 均常驻):\n * - 未绑定:waiting(二维码)/ starting / saving / failed 相位 + manual 提交\n * - 已绑定:bound 相位(回显脱敏 appId,secret 不回传)+ manual 更换 + 解绑\n * 扫码成功或手动保存均写入 profile patch 并经 HMR 重载生效。\n *\n * 样式为注入式 CSS 类(imqb-* 命名空间,随面板挂载注入一次):\n * hover/过渡/focus 样式无法用 inline style 表达,统一走类;\n * 颜色尽量取 DSW 主题变量(--dsw-alias-*),缺省值兜底。\n *\n * 同一组件复用于两种展示位(侧栏绑定页 / 设置页 QQ Bot 栏目)。\n * 运行时仅依赖 react(dsh 客户端平台种子表提供);宿主通信走同源 fetch,\n * Desktop 下由壳的 IPC 桥自动附加 Host 认证转发。\n */\nimport { createElement, useCallback, useEffect, useRef, useState, type FormEvent, type ReactNode } from 'react';\nimport {\n BIND_MANUAL_PATH,\n BIND_REFRESH_PATH,\n BIND_STATE_PATH,\n BIND_UNBIND_PATH,\n type BindStateWire,\n} from '../shared/bind-protocol.ts';\n\n/** 轮询间隔(毫秒):活跃轮询 / 失败退避 */\nconst ACTIVE_POLL_MS = 2000;\nconst RETRY_POLL_MS = 3000;\n\n/** 样式注入标记(幂等) */\nconst STYLE_ID = 'im-qqbot-bind-panel-styles';\n\n/**\n * 注入面板样式(一次)。交互态(hover/active/focus)无法用 inline style\n * 表达,统一收敛到类;DSW 主题变量缺失时用中性值兜底。\n */\nfunction usePanelStyles(): void {\n useEffect(() => {\n if (typeof document === 'undefined') return;\n if (document.getElementById(STYLE_ID) !== null) return;\n const style = document.createElement('style');\n style.id = STYLE_ID;\n style.textContent = `\n.imqb-panel {\n display: flex; flex-direction: column; align-items: center; justify-content: center;\n gap: 14px; padding: 24px; min-height: 320px; text-align: center; font-size: 14px;\n}\n.imqb-title { margin: 0; font-size: 16px; font-weight: 600; }\n.imqb-hint { margin: 0; opacity: 0.75; line-height: 1.6; }\n.imqb-mono { font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-size: 13px; }\n.imqb-link { font-size: 13px; opacity: 0.85; color: var(--dsw-alias-brand, #4d6bfe); text-decoration: none; }\n.imqb-link:hover { text-decoration: underline; }\n.imqb-icon { font-size: 32px; line-height: 1; }\n.imqb-qr { border-radius: 10px; background: #fff; padding: 10px; max-width: 100%; }\n.imqb-row { display: flex; gap: 10px; justify-content: center; flex-wrap: wrap; }\n.imqb-btn, .imqb-pill {\n font: inherit; cursor: pointer; color: inherit;\n transition: background-color .15s ease, border-color .15s ease, color .15s ease, opacity .15s ease;\n}\n.imqb-btn:disabled, .imqb-pill:disabled { opacity: 0.5; cursor: default; }\n.imqb-btn {\n padding: 7px 18px; border-radius: 8px; font-size: 13px;\n border: 1px solid var(--dsw-alias-border-l2, rgba(128, 128, 128, 0.4));\n background: transparent;\n}\n.imqb-btn:hover:not(:disabled) { background: var(--dsw-alias-interactive-bg-hover, rgba(128, 128, 128, 0.12)); }\n.imqb-btn--primary {\n border-color: transparent;\n background: var(--dsw-alias-brand, #4d6bfe); color: #fff; font-weight: 500;\n}\n.imqb-btn--primary:hover:not(:disabled) { background: var(--dsw-alias-brand-strong, #3b5cf0); }\n.imqb-btn--danger { color: var(--dsw-alias-danger, #f26d6d); border-color: var(--dsw-alias-danger, rgba(242, 109, 109, 0.5)); }\n.imqb-btn--danger:hover:not(:disabled) { background: var(--dsw-alias-danger, rgba(242, 109, 109, 0.12)); }\n.imqb-ghost {\n border: none; background: transparent; opacity: 0.65; padding: 4px 8px;\n font: inherit; font-size: 13px; cursor: pointer; color: inherit;\n}\n.imqb-ghost:hover { opacity: 1; text-decoration: underline; }\n.imqb-pill {\n padding: 5px 16px; border-radius: 999px; font-size: 13px;\n border: 1px solid var(--dsw-alias-border-l2, rgba(128, 128, 128, 0.4)); background: transparent;\n}\n.imqb-pill:hover:not(:disabled) { background: var(--dsw-alias-interactive-bg-hover, rgba(128, 128, 128, 0.12)); }\n.imqb-btn:focus-visible, .imqb-pill:focus-visible, .imqb-input:focus-visible, .imqb-ghost:focus-visible {\n outline: 2px solid var(--dsw-alias-brand, #4d6bfe); outline-offset: 1px;\n}\n.imqb-form { display: flex; flex-direction: column; gap: 12px; width: min(320px, 100%); box-sizing: border-box; }\n.imqb-field { display: flex; flex-direction: column; gap: 5px; text-align: left; font-size: 13px; }\n.imqb-input {\n padding: 8px 10px; border-radius: 8px; box-sizing: border-box; width: 100%;\n border: 1px solid var(--dsw-alias-border-l2, rgba(128, 128, 128, 0.4));\n background: var(--dsw-alias-bg-input, rgba(128, 128, 128, 0.08));\n color: inherit; font: inherit; font-size: 13px; outline: none;\n}\n.imqb-input:focus { border-color: var(--dsw-alias-brand, #4d6bfe); }\n.imqb-error { margin: 0; font-size: 12px; color: var(--dsw-alias-danger, #f26d6d); }\n/* 紧凑状态视图(已绑定 / 过渡态):设置行风格,无居中大卡留白 */\n.imqb-status { display: flex; flex-direction: column; text-align: left; font-size: 14px; }\n.imqb-status-row { display: flex; align-items: center; gap: 12px; padding: 12px 0; }\n.imqb-status-icon { font-size: 24px; line-height: 1; flex: none; }\n.imqb-qqicon {\n flex: none; display: block; border-radius: 8px;\n background: #fff; /* 深色企鹅 logo 需浅底,暗色主题下保持可见 */\n}\n.imqb-status-meta { display: flex; flex-direction: column; gap: 2px; min-width: 0; flex: 1; }\n.imqb-status-title { margin: 0; font-size: 14px; font-weight: 600; line-height: 1.5; }\n.imqb-status-sub { margin: 0; font-size: 12px; line-height: 1.5; color: var(--dsw-alias-label-tertiary, inherit); opacity: .85; }\n.imqb-status-actions { display: flex; align-items: center; gap: 8px; padding: 4px 0 12px; }\n/* 扫码成功后的连接过渡:二维码模糊变暗 + 覆盖层 */\n.imqb-scanned { position: relative; display: inline-block; }\n.imqb-scanned-qr {\n display: block; border-radius: 10px; background: #fff; padding: 10px;\n filter: blur(6px) saturate(0.6); opacity: 0.55;\n}\n.imqb-scanned-veil {\n position: absolute; inset: 0; display: flex; flex-direction: column;\n align-items: center; justify-content: center; gap: 6px; text-align: center;\n}\n.imqb-scanned-title { margin: 0; font-size: 15px; font-weight: 600; }\n.imqb-scanned-sub { margin: 0; font-size: 12px; opacity: 0.75; line-height: 1.6; }\n `;\n document.head.appendChild(style);\n return () => { style.remove(); };\n }, []);\n}\n\n/**\n * 绑定状态轮询 hook。\n *\n * 404 语义分两种:从未拿到过路由 = 插件未启用(终态);\n * 曾经拿到过 = HMR 重载窗口期(manual/unbind 保存后路由短暂消失),\n * 低频等待恢复而不是判定终态——否则保存成功提示会被\n * 「插件未启用」覆盖且无法自愈。\n *\n * bound 为稳定态:轮询大幅降频(30s)。因此解绑等本地动作后必须\n * 调用 recheck() 立即重置节拍——否则视图最长停留 30s+ 才收敛到\n * 新相位(如解绑后的 waiting 二维码)。\n *\n * @returns 轮询快照与 recheck:state 为宿主相位(null = 加载中),\n * gone 表示插件未启用(从未注册过路由),recheck 废弃当前\n * 定时器并立即重新轮询(新轮询链取代旧链,不产生双计时器)。\n */\nfunction useBindState(): { state: BindStateWire | null; gone: boolean; recheck: () => void } {\n const [state, setState] = useState<BindStateWire | null>(null);\n const [gone, setGone] = useState(false);\n const recheckRef = useRef<() => void>(() => {});\n\n useEffect(() => {\n let stopped = false;\n let sawRoute = false;\n let generation = 0;\n let running = false;\n let restartAfterFlight = false;\n // recheck 后的快速收敛窗口:解绑等动作改变的是服务端状态(经\n // HMR 异步生效),动作后立即轮询拿到的可能仍是旧 fiber 的相位\n // (如 bound→30s 降频),窗口期内强制快轮询直到相位真正变化\n let urgentUntil = 0;\n let timer: ReturnType<typeof setTimeout> | undefined;\n\n const schedule = (ms: number): void => {\n timer = setTimeout(() => { void tick(); }, ms);\n };\n\n const intervalFor = (phase: BindStateWire['phase']): number => {\n const base = phase === 'saving' ? 500 : phase === 'bound' ? 30000 : ACTIVE_POLL_MS;\n return Date.now() < urgentUntil ? Math.min(base, ACTIVE_POLL_MS) : base;\n };\n\n const tick = async (): Promise<void> => {\n if (stopped || running) return;\n running = true;\n const myGeneration = generation;\n const alive = (): boolean => myGeneration === generation && !stopped;\n try {\n const res = await fetch(BIND_STATE_PATH, { cache: 'no-store' });\n if (res.status === 404) {\n if (!stopped && !sawRoute) setGone(true);\n // sawRoute:HMR 窗口期,保留当前视图等待路由恢复\n else if (alive()) schedule(Date.now() < urgentUntil ? 1000 : 3000);\n return;\n }\n if (!res.ok) {\n if (alive()) schedule(RETRY_POLL_MS);\n return;\n }\n sawRoute = true;\n const body = (await res.json()) as BindStateWire;\n if (!alive()) return;\n setState(body);\n schedule(intervalFor(body.phase));\n return;\n } catch {\n // 宿主启动窗口期不可达:退避重试\n } finally {\n running = false;\n // 在飞期间被 recheck 取代:接力启动新轮询链(否则链会断)\n if (restartAfterFlight && !stopped) {\n restartAfterFlight = false;\n void tick();\n }\n }\n if (alive()) schedule(RETRY_POLL_MS);\n };\n\n // 立即重置节拍:废弃当前计时器,旧轮询链(在飞请求)作废,\n // 新链立即发起,并进入快速收敛窗口\n recheckRef.current = (): void => {\n generation += 1;\n urgentUntil = Date.now() + 15000;\n if (timer !== undefined) clearTimeout(timer);\n if (running) {\n restartAfterFlight = true;\n return;\n }\n void tick();\n };\n\n void tick();\n return () => { stopped = true; if (timer !== undefined) clearTimeout(timer); };\n }, []);\n\n const recheck = useCallback((): void => { recheckRef.current(); }, []);\n\n return { state, gone, recheck };\n}\n\ninterface ManualResult { ok: boolean; message?: string; error?: string }\n\n/** 手动提交凭据(填写 / 更换共用) */\nasync function submitManualCredentials(appId: string, appSecret: string): Promise<ManualResult> {\n try {\n const res = await fetch(BIND_MANUAL_PATH, {\n method: 'POST',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify({ appId, appSecret }),\n });\n const body = (await res.json().catch(() => ({}))) as ManualResult;\n if (res.ok && body.ok) return { ok: true, message: body.message };\n return { ok: false, error: body.error ?? `保存失败(HTTP ${res.status})` };\n } catch (err) {\n return { ok: false, error: err instanceof Error ? err.message : String(err) };\n }\n}\n\n/**\n * 手动凭据表单(填写 / 更换共用)。\n *\n * appSecret 永不回显(占位符提示),提交成功后展示保存结果;\n * 宿主写入 profile patch 并经 HMR 重载,状态轮询随后收敛为 bound。\n */\nfunction ManualForm({ initialAppId }: { initialAppId?: string }): ReactNode {\n const [appId, setAppId] = useState(initialAppId ?? '');\n const [appSecret, setAppSecret] = useState('');\n const [busy, setBusy] = useState(false);\n const [result, setResult] = useState<ManualResult | null>(null);\n\n const submit = useCallback((event: FormEvent): void => {\n event.preventDefault();\n if (busy) return;\n const trimmedId = appId.trim();\n const trimmedSecret = appSecret.trim();\n if (trimmedId.length === 0 || trimmedSecret.length === 0) {\n setResult({ ok: false, error: 'appId 与 appSecret 均为必填' });\n return;\n }\n setBusy(true);\n void submitManualCredentials(trimmedId, trimmedSecret).then((outcome) => {\n setResult(outcome);\n setBusy(false);\n });\n }, [appId, appSecret, busy]);\n\n if (result !== null && result.ok) {\n return createElement('div', { className: 'imqb-status' },\n createElement('div', { className: 'imqb-status-row' },\n createElement('div', { className: 'imqb-status-icon' }, '✅'),\n createElement('div', { className: 'imqb-status-meta' },\n createElement('p', { className: 'imqb-status-title' }, result.message ?? '凭据已保存'),\n createElement('p', { className: 'imqb-status-sub' }, '插件将自动重载;稍后即可开始对话'),\n ),\n ),\n );\n }\n\n return createElement('form', { className: 'imqb-form', onSubmit: submit },\n createElement('label', { className: 'imqb-field' },\n 'AppID',\n createElement('input', {\n className: 'imqb-input', value: appId, placeholder: 'QQ 机器人 AppID',\n onChange: (event) => { setAppId(event.currentTarget.value); },\n autoComplete: 'off', spellCheck: false,\n }),\n ),\n createElement('label', { className: 'imqb-field' },\n 'AppSecret',\n createElement('input', {\n className: 'imqb-input', type: 'password', value: appSecret,\n placeholder: initialAppId === undefined ? 'QQ 机器人 AppSecret' : '输入新的 AppSecret(不回显)',\n onChange: (event) => { setAppSecret(event.currentTarget.value); },\n autoComplete: 'new-password',\n }),\n ),\n result !== null && !result.ok\n ? createElement('p', { className: 'imqb-error' }, result.error)\n : null,\n createElement('button', { className: 'imqb-btn imqb-btn--primary', type: 'submit', disabled: busy },\n busy ? '正在保存…' : '保存'),\n );\n}\n\n/** QQ 企鹅 logo(256×256 PNG data URI;深色图案配白底圆角,明暗主题下均可见) */\nconst QQ_BOT_ICON_PNG =\n 'data:image/png;base64,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';\n\n/** QQ 机器人图标(logo 图片,白底圆角容器内呈现) */\nfunction QqBotIcon({ size = 28 }: { size?: number }): ReactNode {\n return createElement('img', {\n src: QQ_BOT_ICON_PNG, alt: 'QQ', width: size, height: size, className: 'imqb-qqicon',\n });\n}\n\n/** 已绑定视图:回显 appId + 更换凭据 / 解绑入口 */\nfunction BoundView({ appId, recheck }: { appId: string; recheck: () => void }): ReactNode {\n const [editing, setEditing] = useState(false);\n const [unbindResult, setUnbindResult] = useState<{ ok: boolean; message: string } | null>(null);\n\n const unbind = useCallback((): void => {\n if (!window.confirm('确定解绑吗?\\n解绑后机器人立即下线,插件将重新进入扫码绑定流程。')) return;\n void fetch(BIND_UNBIND_PATH, { method: 'POST' })\n .then(async (res) => {\n const body = (await res.json().catch(() => ({}))) as { ok?: boolean; message?: string; error?: string };\n if (res.ok && body.ok === true) {\n setUnbindResult({ ok: true, message: body.message ?? '已解绑,插件将重载并重新进入绑定流程' });\n // bound 态轮询已降频到 30s:立即重置节拍,让 waiting(二维码)\n // 尽快出现而不是等下一个 30s 周期\n recheck();\n return;\n }\n setUnbindResult({ ok: false, message: body.error ?? `解绑失败(HTTP ${res.status})` });\n })\n .catch((err: unknown) => {\n setUnbindResult({ ok: false, message: err instanceof Error ? err.message : String(err) });\n });\n }, [recheck]);\n\n if (unbindResult !== null) {\n // 非终态视图:解绑成功后正常由轮询收敛到 waiting;若 HMR 未\n // 触发(状态停留 bound),用户仍有「刷新状态」出口而不是死胡同\n return createElement('div', { className: 'imqb-status' },\n createElement('div', { className: 'imqb-status-row' },\n createElement('div', { className: 'imqb-status-icon' }, unbindResult.ok ? '👋' : '⚠️'),\n createElement('div', { className: 'imqb-status-meta' },\n createElement('p', { className: 'imqb-status-title' }, unbindResult.message),\n ),\n unbindResult.ok\n ? createElement('button', { className: 'imqb-ghost', onClick: recheck }, '刷新状态')\n : createElement('button', { className: 'imqb-ghost', onClick: () => { setUnbindResult(null); } }, '返回'),\n ),\n );\n }\n\n if (editing) {\n return createElement('div', { className: 'imqb-status' },\n createElement('div', { className: 'imqb-status-row' },\n createElement('div', { className: 'imqb-status-meta' },\n createElement('p', { className: 'imqb-status-title' }, '更换凭据'),\n ),\n createElement('button', { className: 'imqb-ghost', onClick: () => { setEditing(false); } }, '返回'),\n ),\n createElement(ManualForm, { initialAppId: appId }),\n );\n }\n return createElement('div', { className: 'imqb-status' },\n createElement('div', { className: 'imqb-status-row' },\n createElement(QqBotIcon, { size: 28 }),\n createElement('div', { className: 'imqb-status-meta' },\n createElement('p', { className: 'imqb-status-title' }, '已绑定'),\n createElement('p', { className: 'imqb-status-sub imqb-mono' }, `AppID ${appId} · 私聊与群聊已接入`),\n ),\n ),\n createElement('div', { className: 'imqb-status-actions' },\n createElement('button', { className: 'imqb-btn imqb-btn--primary', onClick: () => { setEditing(true); } }, '更换凭据'),\n createElement('button', { className: 'imqb-btn imqb-btn--danger', onClick: unbind }, '解绑'),\n ),\n );\n}\n\n/** 未绑定视图:扫码 / 手动填写切换 */\nfunction UnboundView({ state }: { state: Extract<BindStateWire, { phase: 'waiting' }> }): ReactNode {\n const [mode, setMode] = useState<'qr' | 'manual'>('qr');\n const refresh = useCallback(() => { void fetch(BIND_REFRESH_PATH, { method: 'POST' }).catch(() => {}); }, []);\n\n if (mode === 'manual') {\n return createElement('div', { className: 'imqb-panel' },\n createElement('p', { className: 'imqb-title' }, '手动填写凭据'),\n createElement(ManualForm, {}),\n createElement('button', { className: 'imqb-ghost', onClick: () => { setMode('qr'); } }, '改用扫码绑定'),\n );\n }\n\n return createElement('div', { className: 'imqb-panel' },\n state.qrSvg === undefined\n ? null\n : createElement('img', { src: state.qrSvg, alt: 'QQ 扫码二维码', width: 220, height: 220, className: 'imqb-qr' }),\n createElement('p', { className: 'imqb-title' }, '扫码绑定 QQ 机器人'),\n createElement('p', { className: 'imqb-hint' }, '使用手机 QQ 扫描二维码完成绑定'),\n createElement('a', { href: state.url, target: '_blank', rel: 'noreferrer noopener', className: 'imqb-link' }, '二维码显示异常?在浏览器中打开'),\n createElement('div', { className: 'imqb-row' },\n createElement('button', { className: 'imqb-pill', onClick: refresh }, '刷新二维码'),\n createElement('button', { className: 'imqb-pill', onClick: () => { setMode('manual'); } }, '手动填写'),\n ),\n );\n}\n\n/** 依据宿主相位渲染面板主体(各展示位共用) */\nexport function BindPanelBody(): ReactNode {\n usePanelStyles();\n const { state, gone, recheck } = useBindState();\n // 扫码成功的连接过渡场景需要保留最后一帧二维码:waiting 相位持续记录,\n // bound 后清空(避免下次解绑重绑时旧码闪现)\n const [lastQr, setLastQr] = useState<string | null>(null);\n useEffect(() => {\n if (state === null) return;\n if (state.phase === 'waiting') {\n if (state.qrSvg !== undefined) setLastQr(state.qrSvg);\n } else if (state.phase === 'bound') {\n setLastQr(null);\n }\n }, [state]);\n\n if (gone) {\n return createElement('div', { className: 'imqb-panel' },\n createElement('div', { className: 'imqb-icon' }, '❔'),\n createElement('p', { className: 'imqb-hint' }, '插件未启用,或当前版本不支持端内配置'),\n );\n }\n\n if (state === null || state.phase === 'starting') {\n return createElement('div', { className: 'imqb-panel' },\n createElement('p', { className: 'imqb-hint' }, '正在获取绑定状态…'),\n );\n }\n\n if (state.phase === 'saving') {\n // 扫码路径:保留二维码做模糊过渡(手动填写路径无二维码,用紧凑态)\n if (lastQr !== null) {\n return createElement('div', { className: 'imqb-panel' },\n createElement('div', { className: 'imqb-scanned' },\n createElement('img', { src: lastQr, alt: 'QQ 扫码二维码', width: 220, height: 220, className: 'imqb-scanned-qr' }),\n createElement('div', { className: 'imqb-scanned-veil' },\n createElement('p', { className: 'imqb-scanned-title' }, '✅ 扫码成功'),\n createElement('p', { className: 'imqb-scanned-sub' }, '正在连接机器人,稍候…'),\n ),\n ),\n );\n }\n return createElement('div', { className: 'imqb-status' },\n createElement('div', { className: 'imqb-status-row' },\n createElement('div', { className: 'imqb-status-icon' }, '🎉'),\n createElement('div', { className: 'imqb-status-meta' },\n createElement('p', { className: 'imqb-status-title' }, '扫码成功'),\n createElement('p', { className: 'imqb-status-sub' }, '凭据已保存,插件正在重载,稍后即可开始对话'),\n ),\n ),\n );\n }\n\n if (state.phase === 'failed') {\n return createElement('div', { className: 'imqb-panel' },\n createElement('div', { className: 'imqb-icon' }, '⚠️'),\n createElement('p', { className: 'imqb-title' }, '绑定失败'),\n createElement('p', { className: 'imqb-hint' }, state.reason),\n createElement('div', { className: 'imqb-row' },\n createElement('button', { className: 'imqb-btn imqb-btn--primary', onClick: () => { window.location.reload(); } }, '重试'),\n ),\n );\n }\n\n if (state.phase === 'bound') {\n return createElement(BoundView, { appId: state.appId, recheck });\n }\n\n return createElement(UnboundView, { state });\n}\n","/**\n * QQ 机器人配置面板 — 必要配置的 UI 编辑\n *\n * UI 复刻 DSW 通用设置(settings-form 原语)的视觉风格:\n * 左对齐设置列、0.5px 行分隔、label 13px/500、控件右置;\n * Switch 为 36×20 aria-checked 结构(thumb translateX 动画);\n * 三值选择用分段控件(滑动指示器按段数/索引的 CSS 变量定位);\n * 保存按钮为 DSW 反色主按钮(label-primary 底 + bg-layer-3 字)。\n *\n * 数据流:GET /qqbot/im-qqbot/config 回显当前生效配置(appSecret\n * 已由宿主剔除)→ 表单编辑 → dirty diff → POST 仅提交变更键 →\n * 宿主白名单 + Schema 校验 → 最小写入 profile patch → HMR 重载生效。\n *\n * 字段策略:只开放用户必要的配置;cwd 只读展示;超时与性能调优\n * 类字段走 profile patch / 环境变量。\n */\nimport { createElement, useCallback, useEffect, useState, type CSSProperties, type ChangeEvent, type FormEvent, type ReactNode } from 'react';\nimport { BIND_CONFIG_PATH } from '../shared/bind-protocol.ts';\n\n/** 访问控制配置(与 src/config.ts 的 AccessControlConfig 对应的局部投影) */\ninterface AccessControlWire {\n c2cMode: 'open' | 'allowlist' | 'disabled';\n c2cAllow: string[];\n groupMode: 'open' | 'allowlist' | 'disabled';\n groupAllow: string[];\n}\n\n/** GET 回显的生效配置(appSecret 已剔除) */\ntype ConfigWire = {\n requireMention?: boolean;\n streaming?: boolean;\n showToolResults?: boolean;\n debug?: boolean;\n provider?: string;\n model?: string;\n preset?: string;\n groupPrompt?: string;\n directPrompt?: string;\n access?: AccessControlWire;\n cwd?: string;\n};\n\n/** 样式注入标记(幂等) */\nconst STYLE_ID = 'im-qqbot-config-panel-styles';\n\n/** DSW 通用设置风格(settings-form / Switch / SegmentedControl 原语复刻) */\nfunction useConfigPanelStyles(): void {\n useEffect(() => {\n if (typeof document === 'undefined') return;\n if (document.getElementById(STYLE_ID) !== null) return;\n const style = document.createElement('style');\n style.id = STYLE_ID;\n style.textContent = `\n.imqb2-form { display: flex; flex-direction: column; width: 100%; }\n.imqb2-group-title {\n padding: 14px 0 2px; font-size: 12px; font-weight: 600; line-height: 18px;\n color: var(--dsw-alias-label-tertiary); text-transform: uppercase; letter-spacing: .04em;\n}\n.imqb2-field { display: flex; flex-direction: column; gap: 6px; padding: 12px 0; }\n.imqb2-field + .imqb2-field { border-top: 0.5px solid var(--dsw-alias-border-l2); }\n.imqb2-head { display: flex; align-items: center; gap: 8px; min-height: 28px; }\n.imqb2-label {\n flex: 1; min-width: 0; font-size: 13px; font-weight: 500; line-height: 1.5;\n color: var(--dsw-alias-label-primary);\n}\n.imqb2-help { margin: 0; font-size: 12px; line-height: 1.6; color: var(--dsw-alias-label-secondary); }\n.imqb2-hint { margin: 0; font-size: 12px; line-height: 1.5; color: var(--dsw-alias-label-tertiary); }\n/* Switch(aria-checked 驱动,视觉态与无障碍态同源) */\n.imqb2-switch {\n box-sizing: border-box; position: relative; flex: 0 0 auto;\n width: 36px; height: 20px; padding: 2px; border: 0; border-radius: 999px;\n background: var(--dsw-alias-border-l3); cursor: pointer; font: inherit;\n}\n.imqb2-switch[aria-checked='true'] { background: var(--dsw-alias-brand-primary); }\n.imqb2-switch:disabled { cursor: default; opacity: 0.5; }\n.imqb2-switch:focus-visible {\n outline: var(--dsw-focus-ring-width, 2px) solid var(--dsw-focus-ring-color, var(--dsw-alias-state-business-primary));\n outline-offset: 2px;\n}\n.imqb2-switch-thumb {\n display: block; width: 16px; height: 16px; border-radius: 50%;\n background: var(--dsw-alias-switch-thumb, #ffffff);\n transition: transform 120ms ease;\n}\n.imqb2-switch[aria-checked='true'] .imqb2-switch-thumb {\n background: var(--dsw-alias-label-primary-foreground, #ffffff);\n transform: translateX(16px);\n}\n/* 输入(官方 fields.input 复刻) */\n.imqb2-input {\n box-sizing: border-box; width: 100%; height: 34px; padding: 0 12px;\n border: 0.5px solid var(--dsw-alias-border-l4); border-radius: var(--dsw-radius-md, 8px);\n background: var(--dsw-alias-bg-layer-3); font: inherit; font-size: 13px; line-height: 1.5;\n color: var(--dsw-alias-label-primary); outline: none;\n}\n.imqb2-input:focus { outline: none; border-color: var(--dsw-alias-state-business-primary); }\n.imqb2-input:disabled { color: var(--dsw-alias-label-tertiary); cursor: default; }\n.imqb2-textarea { height: auto; min-height: 68px; padding: 8px 12px; resize: vertical; line-height: 1.5; }\n/* 分段控件(官方 SegmentedControl 复刻:指示器按段数/索引定位) */\n.imqb2-seg {\n position: relative; display: inline-grid; grid-auto-flow: column; grid-auto-columns: 1fr;\n gap: 2px; padding: 4px; border-radius: var(--dsw-radius-md, 8px);\n background: var(--dsw-alias-interactive-bg-hover);\n}\n.imqb2-seg-indicator {\n position: absolute; top: 4px; left: 4px;\n width: calc((100% - 8px - 2px * (var(--imqb2-seg-count) - 1)) / var(--imqb2-seg-count));\n height: calc(100% - 8px);\n border: 0; border-radius: var(--dsw-radius-sm, 6px);\n background: var(--dsw-alias-bg-layer-1);\n box-shadow: var(--dsw-elevation-soft, 0 1px 3px rgba(0,0,0,.08));\n transform: translateX(calc(var(--imqb2-seg-index) * (100% + 2px)));\n transition: transform 160ms ease;\n pointer-events: none;\n}\n.imqb2-seg-tab {\n box-sizing: border-box; position: relative; z-index: 1; height: 28px; padding: 0 16px;\n border: 0; border-radius: var(--dsw-radius-sm, 6px); background: transparent;\n color: var(--dsw-alias-label-secondary); font: inherit; font-size: 13px; line-height: 20px;\n font-weight: 500; white-space: nowrap; cursor: pointer; transition: color 120ms ease;\n}\n.imqb2-seg-tab:hover, .imqb2-seg-tab[aria-selected='true'] { color: var(--dsw-alias-label-primary); }\n.imqb2-seg-tab:focus-visible {\n outline: var(--dsw-focus-ring-width, 2px) solid var(--dsw-focus-ring-color, var(--dsw-alias-state-business-primary));\n outline-offset: -2px;\n}\n/* 底栏(官方 SettingsForm.footer 复刻) */\n.imqb2-footer { display: flex; align-items: center; gap: 8px; padding-top: 16px; }\n.imqb2-note { flex: 1; min-width: 0; margin: 0; font-size: 12px; line-height: 1.5; color: var(--dsw-alias-label-tertiary); }\n.imqb2-note--error { color: var(--dsw-alias-state-error-primary, var(--dsw-alias-label-error)); }\n.imqb2-note--ok { color: var(--dsw-alias-label-secondary); }\n.imqb2-save {\n appearance: none; flex: none; border: 1px solid transparent;\n border-radius: var(--dsw-radius-md, 8px); padding: 5px 14px;\n font: inherit; font-size: 13px; line-height: 1.5; cursor: pointer;\n background: var(--dsw-alias-label-primary); color: var(--dsw-alias-bg-layer-3);\n}\n.imqb2-save:disabled { opacity: 0.4; cursor: default; }\n.imqb2-save:focus-visible {\n outline: var(--dsw-focus-ring-width, 2px) solid var(--dsw-focus-ring-color, var(--dsw-alias-state-business-primary));\n outline-offset: 1px;\n}\n/* cwd 只读行 */\n.imqb2-readonly { font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-size: 12px; color: var(--dsw-alias-label-secondary); word-break: break-all; margin: 0; }\n `;\n document.head.appendChild(style);\n return () => { style.remove(); };\n }, []);\n}\n\n/** 开关(官方 Switch 原语结构:aria-checked 驱动视觉态) */\nfunction Switch({ checked, label, onChange }: {\n checked: boolean; label: string; onChange: (next: boolean) => void;\n}): ReactNode {\n return createElement('button', {\n type: 'button', role: 'switch', 'aria-checked': checked, 'aria-label': label,\n className: 'imqb2-switch',\n onClick: () => { onChange(!checked); },\n }, createElement('span', { className: 'imqb2-switch-thumb' }));\n}\n\n/** 访问模式分段选择(官方 SegmentedControl 结构:CSS 变量定位滑动指示器) */\nfunction Segmented({ value, options, onChange, label }: {\n value: AccessMode; options: ReadonlyArray<{ value: AccessMode; label: string }>;\n onChange: (next: AccessMode) => void; label: string;\n}): ReactNode {\n const index = Math.max(0, options.findIndex((o) => o.value === value));\n const trackStyle = {\n '--imqb2-seg-count': options.length,\n '--imqb2-seg-index': index,\n } as CSSProperties;\n return createElement('div', { className: 'imqb2-seg', role: 'tablist', 'aria-label': label, style: trackStyle },\n createElement('span', { className: 'imqb2-seg-indicator' }),\n options.map((o) => createElement('button', {\n key: o.value, type: 'button', role: 'tab', 'aria-selected': o.value === value,\n className: 'imqb2-seg-tab', onClick: () => { onChange(o.value); },\n }, o.label)),\n );\n}\n\n/** 开关行(label 左 + Switch 右 + 可选 help) */\nfunction SwitchRow({ label, help, checked, onChange }: {\n label: string; help?: string; checked: boolean; onChange: (next: boolean) => void;\n}): ReactNode {\n return createElement('div', { className: 'imqb2-field' },\n createElement('div', { className: 'imqb2-head' },\n createElement('span', { className: 'imqb2-label' }, label),\n createElement(Switch, { checked, label, onChange }),\n ),\n help === undefined ? null : createElement('p', { className: 'imqb2-help' }, help),\n );\n}\n\n/** 文本行(label 上 + 输入下,与官方 fields 布局一致) */\nfunction FieldRow({ label, help, value, placeholder, onChange }: {\n label: string; help?: string; value: string; placeholder?: string; onChange: (next: string) => void;\n}): ReactNode {\n return createElement('div', { className: 'imqb2-field' },\n createElement('span', { className: 'imqb2-label' }, label),\n createElement('input', {\n className: 'imqb2-input', value, placeholder, spellCheck: false,\n onChange: (event: ChangeEvent<HTMLInputElement>) => { onChange(event.currentTarget.value); },\n }),\n help === undefined ? null : createElement('p', { className: 'imqb2-hint' }, help),\n );\n}\n\n/** 多行文本行 */\nfunction AreaRow({ label, help, value, rows, onChange }: {\n label: string; help?: string; value: string; rows?: number; onChange: (next: string) => void;\n}): ReactNode {\n return createElement('div', { className: 'imqb2-field' },\n createElement('span', { className: 'imqb2-label' }, label),\n createElement('textarea', {\n className: 'imqb2-input imqb2-textarea', value, rows: rows ?? 3,\n onChange: (event: ChangeEvent<HTMLTextAreaElement>) => { onChange(event.currentTarget.value); },\n }),\n help === undefined ? null : createElement('p', { className: 'imqb2-hint' }, help),\n );\n}\n\n/** 访问模式分段选择行 */\nfunction SegmentedRow({ label, help, value, options, onChange }: {\n label: string; help?: string; value: AccessMode;\n options: ReadonlyArray<{ value: AccessMode; label: string }>; onChange: (next: AccessMode) => void;\n}): ReactNode {\n return createElement('div', { className: 'imqb2-field' },\n createElement('div', { className: 'imqb2-head' },\n createElement('span', { className: 'imqb2-label' }, label),\n createElement(Segmented, { value, options, onChange, label }),\n ),\n help === undefined ? null : createElement('p', { className: 'imqb2-hint' }, help),\n );\n}\n\ntype AccessMode = AccessControlWire['c2cMode'];\n\nconst MODE_OPTIONS: ReadonlyArray<{ value: AccessMode; label: string }> = [\n { value: 'open', label: '开放' },\n { value: 'allowlist', label: '白名单' },\n { value: 'disabled', label: '停用' },\n];\n\n/** 深比较(表单值与初始回显值的 dirty 判断) */\nfunction shallowEqual(a: unknown, b: unknown): boolean {\n return JSON.stringify(a) === JSON.stringify(b);\n}\n\n/**\n * 配置面板主体。\n *\n * 保存仅提交变更键(服务端按白名单合并),保存成功后提示\n * HMR 重载语义(进行中的机器人会话将重置)。\n */\nexport function ConfigPanel(): ReactNode {\n useConfigPanelStyles();\n const [initial, setInitial] = useState<ConfigWire | null>(null);\n const [form, setForm] = useState<ConfigWire | null>(null);\n const [busy, setBusy] = useState(false);\n const [result, setResult] = useState<{ ok: boolean; message: string } | null>(null);\n const [loadError, setLoadError] = useState<string | null>(null);\n\n useEffect(() => {\n let stopped = false;\n void fetch(BIND_CONFIG_PATH, { cache: 'no-store' })\n .then(async (res) => {\n if (!res.ok) throw new Error(`HTTP ${res.status}`);\n const body = (await res.json()) as { config: ConfigWire };\n if (stopped) return;\n setInitial(body.config);\n setForm(body.config);\n })\n .catch((err: unknown) => {\n if (!stopped) setLoadError(err instanceof Error ? err.message : String(err));\n });\n return () => { stopped = true; };\n }, []);\n\n const patch = useCallback(<K extends keyof ConfigWire>(key: K, value: ConfigWire[K]): void => {\n setForm((current) => current === null ? current : { ...current, [key]: value });\n setResult(null);\n }, []);\n\n const submit = useCallback((event: FormEvent): void => {\n event.preventDefault();\n if (busy || initial === null || form === null) return;\n const changed: Record<string, unknown> = {};\n for (const key of Object.keys(form) as Array<keyof ConfigWire>) {\n if (!shallowEqual(form[key], initial[key])) {\n changed[key] = form[key];\n }\n }\n if (Object.keys(changed).length === 0) return;\n\n setBusy(true);\n void fetch(BIND_CONFIG_PATH, {\n method: 'POST',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify(changed),\n })\n .then(async (res) => {\n const body = (await res.json().catch(() => ({}))) as { ok?: boolean; message?: string; error?: string };\n if (res.ok && body.ok === true) {\n setResult({ ok: true, message: body.message ?? '配置已保存,插件将自动重载' });\n setInitial(form);\n return;\n }\n setResult({ ok: false, message: body.error ?? `保存失败(HTTP ${res.status})` });\n })\n .catch((err: unknown) => {\n setResult({ ok: false, message: err instanceof Error ? err.message : String(err) });\n })\n .finally(() => { setBusy(false); });\n }, [busy, form, initial]);\n\n if (loadError !== null) {\n return createElement('p', { className: 'imqb2-hint', style: { padding: '12px 0' } },\n `配置加载失败:${loadError}`);\n }\n if (initial === null || form === null) {\n return createElement('p', { className: 'imqb2-hint', style: { padding: '12px 0' } }, '正在加载配置…');\n }\n\n const dirty = (Object.keys(form) as Array<keyof ConfigWire>).some((key) => !shallowEqual(form[key], initial[key]));\n const access: AccessControlWire = form.access ?? { c2cMode: 'open', c2cAllow: [], groupMode: 'open', groupAllow: [] };\n\n return createElement('form', { className: 'imqb2-form', onSubmit: submit },\n createElement('div', { className: 'imqb2-group-title' }, '访问控制'),\n createElement(SegmentedRow, {\n label: '私聊', value: access.c2cMode, options: MODE_OPTIONS,\n onChange: (v) => { patch('access', { ...access, c2cMode: v }); },\n }),\n access.c2cMode === 'allowlist'\n ? createElement(AreaRow, {\n label: '私聊白名单', help: '每行一个 openid', rows: 3,\n value: access.c2cAllow.join('\\n'),\n onChange: (v) => { patch('access', { ...access, c2cAllow: v.split('\\n').map((s) => s.trim()).filter(Boolean) }); },\n })\n : null,\n createElement(SegmentedRow, {\n label: '群聊', value: access.groupMode, options: MODE_OPTIONS,\n onChange: (v) => { patch('access', { ...access, groupMode: v }); },\n }),\n access.groupMode === 'allowlist'\n ? createElement(AreaRow, {\n label: '群聊白名单', help: '每行一个群 openid', rows: 3,\n value: access.groupAllow.join('\\n'),\n onChange: (v) => { patch('access', { ...access, groupAllow: v.split('\\n').map((s) => s.trim()).filter(Boolean) }); },\n })\n : null,\n\n createElement('div', { className: 'imqb2-group-title' }, '基本'),\n createElement(SwitchRow, {\n label: '群聊需要 @机器人', checked: form.requireMention ?? true,\n help: '开启后群聊中只有 @机器人 的消息会触发回复',\n onChange: (v) => { patch('requireMention', v); },\n }),\n createElement(SwitchRow, {\n label: '流式输出', checked: form.streaming ?? true,\n help: '回复内容分段实时推送到聊天',\n onChange: (v) => { patch('streaming', v); },\n }),\n createElement(SwitchRow, {\n label: '显示工具调用结果', checked: form.showToolResults ?? false,\n help: '在聊天中展示 agent 工具调用的结构化结果',\n onChange: (v) => { patch('showToolResults', v); },\n }),\n\n createElement('div', { className: 'imqb2-group-title' }, '模型'),\n createElement(FieldRow, {\n label: 'Provider', value: form.provider ?? '', placeholder: '留空继承宿主默认',\n onChange: (v) => { patch('provider', v); },\n }),\n createElement(FieldRow, {\n label: 'Model', value: form.model ?? '', placeholder: '留空继承宿主默认',\n onChange: (v) => { patch('model', v); },\n }),\n createElement(FieldRow, {\n label: 'Preset', value: form.preset ?? '', placeholder: 'Agent preset id',\n onChange: (v) => { patch('preset', v); },\n }),\n\n createElement('div', { className: 'imqb2-group-title' }, '补充指令'),\n createElement(AreaRow, {\n label: '群聊额外 system prompt', value: form.groupPrompt ?? '',\n onChange: (v) => { patch('groupPrompt', v); },\n }),\n createElement(AreaRow, {\n label: '私聊额外 system prompt', value: form.directPrompt ?? '',\n onChange: (v) => { patch('directPrompt', v); },\n }),\n\n form.cwd !== undefined\n ? createElement('div', { className: 'imqb2-field' },\n createElement('div', { className: 'imqb2-head' },\n createElement('span', { className: 'imqb2-label' }, 'Agent 工作目录'),\n createElement('span', { className: 'imqb2-hint' }, '只读'),\n ),\n createElement('p', { className: 'imqb2-readonly' }, form.cwd),\n )\n : null,\n\n createElement('div', { className: 'imqb2-footer' },\n result !== null\n ? createElement('p', { className: `imqb2-note${result.ok ? ' imqb2-note--ok' : ' imqb2-note--error'}` },\n (result.ok ? '' : '⚠️ ') + result.message)\n : dirty\n ? createElement('p', { className: 'imqb2-note' }, '保存后插件将重载,进行中的机器人会话将重置')\n : createElement('p', { className: 'imqb2-note' }),\n createElement('button', { className: 'imqb2-save', type: 'submit', disabled: busy || !dirty },\n busy ? '正在保存…' : '保存'),\n ),\n );\n}\n","/**\n * im-qqbot 浏览器半边 —— QQ Bot 端内扫码绑定入口\n *\n * 宿主插件在凭据缺失时注册 /qqbot/im-qqbot/bind 状态路由;本插件在\n * Web / Desktop 提供两个展示位:\n *\n * 1. 设置页「QQ Bot」栏目(settings.section 席位)——注册即展示,\n * 无 Session surface 时序依赖,待绑定/已绑定状态常驻可见;\n * 2. 右侧栏「QQ Bot 绑定」页(sidebarRightTabs)——Start 页入口 +\n * 待绑定时自动打开(失败随轮询重试)。\n *\n * 运行时依赖仅 react(客户端平台种子表提供);宿主服务经 cordis inject\n * 声明访问(声明缺失时插件保持 inactive,不阻塞浏览器启动)。\n */\nimport type { Context } from '@deepseek-ai/cordis';\nimport { createElement, type ReactNode } from 'react';\nimport { BIND_STATE_PATH } from '../shared/bind-protocol.ts';\nimport { BindPanelBody } from './bind-page.ts';\nimport { ConfigPanel } from './config-panel.ts';\n\nexport const name = 'im-qqbot-client';\nexport const inject = ['slots', 'sidebarRight', 'sidebarRightTabs'];\n\n/** 侧栏 Tab 类型(ui-sidebar-right 契约的局部投影) */\nconst TAB_KIND = 'qqbot-bind';\n/** 席位注册 key(Tab 类型 id,席位按其分发;只需全局唯一,与包名解耦) */\nconst TAB_ID = 'im-qqbot/bind';\n\n/** ui-sidebar-right 的 Tab 注册表服务(局部投影) */\ninterface TabRegistryLike {\n register(definition: {\n id: string;\n kind: string;\n title: (address: string) => string;\n guide?: ReadonlyArray<{\n id: string;\n order: number;\n title: () => string;\n description: () => string;\n icon: unknown;\n }>;\n }): () => void;\n}\n\n/** ui-sidebar-right 的导航控制器服务(局部投影) */\ninterface SidebarRightLike {\n openTab(kind: string, options?: Record<string, unknown>): unknown;\n}\n\n/** ui-slots 的席位系统服务(局部投影) */\ninterface SlotsLike {\n inject(slotName: string, register: () => (() => void)): () => void;\n register(spec: Record<string, unknown>, component: unknown): () => void;\n}\n\n/** 绑定入口图标(QQ 机器人,跟随主题图标色变量) */\nfunction BindGuideIcon(): ReactNode {\n return createElement('svg', {\n width: 24, height: 24, viewBox: '0 0 24 24', fill: 'none', 'aria-hidden': true,\n },\n createElement('path', {\n d: 'M9.50039 11.1504C9.96983 11.1504 10.3504 11.5309 10.3504 12.0004V14.0004C10.3504 14.4698 9.96983 14.8504 9.50039 14.8504C9.03095 14.8504 8.65039 14.4698 8.65039 14.0004V12.0004C8.65039 11.5309 9.03095 11.1504 9.50039 11.1504Z',\n fill: 'var(------icon_primary, #1A1A1A)',\n }),\n createElement('path', {\n d: 'M14.5004 11.1504C14.9698 11.1504 15.3504 11.5309 15.3504 12.0004V14.0004C15.3504 14.4698 14.9698 14.8504 14.5004 14.8504C14.0309 14.8504 13.6504 14.4698 13.6504 14.0004V12.0004C13.6504 11.5309 14.0309 11.1504 14.5004 11.1504Z',\n fill: 'var(------icon_primary, #1A1A1A)',\n }),\n createElement('path', {\n fillRule: 'evenodd',\n clipRule: 'evenodd',\n d: 'M12.8504 5.3109C13.5299 4.99138 14.0004 4.30063 14.0004 3.5C14.0004 2.39543 13.1049 1.5 12.0004 1.5C10.8958 1.5 10.0004 2.39543 10.0004 3.5C10.0004 4.30065 10.4708 4.99141 11.1504 5.31092V6.18851C6.38487 6.61795 2.65039 10.6231 2.65039 15.5004V17.0004C2.65039 19.679 4.82181 21.8504 7.50039 21.8504H16.5004C19.179 21.8504 21.3504 19.679 21.3504 17.0004V15.5004C21.3504 10.6231 17.6159 6.61795 12.8504 6.18851V5.3109ZM12.0004 7.85039C7.77541 7.85039 4.35039 11.2754 4.35039 15.5004V17.0004C4.35039 18.7401 5.76069 20.1504 7.50039 20.1504H16.5004C18.2401 20.1504 19.6504 18.7401 19.6504 17.0004V15.5004C19.6504 11.2754 16.2254 7.85039 12.0004 7.85039Z',\n fill: 'var(------icon_primary, #1A1A1A)',\n }),\n );\n}\n\n/** 设置页「QQ Bot」栏目:面板常驻展示绑定状态 */\nfunction QQBotSettingsSection(): ReactNode {\n return createElement('div', null,\n createElement(BindPanelBody),\n createElement(ConfigPanel),\n );\n}\n\nexport function apply(ctx: Context): void {\n const tabs = (ctx as unknown as { sidebarRightTabs?: TabRegistryLike }).sidebarRightTabs;\n const right = (ctx as unknown as { sidebarRight?: SidebarRightLike }).sidebarRight;\n const slots = (ctx as unknown as { slots?: SlotsLike }).slots;\n\n const disposers: Array<() => void> = [];\n\n // 1. 设置页「QQ Bot」栏目(主展示位:注册即展示,无时序依赖)\n if (slots !== undefined) {\n disposers.push( slots.inject('settings.section', () => slots.register(\n { name: 'settings.section', id: 'qqbot', order: 7, label: 'QQ 机器人' },\n QQBotSettingsSection,\n )));\n }\n\n // 2. 侧栏绑定页(快捷展示位:Start 页入口 + 待绑定自动打开)\n if (tabs !== undefined && slots !== undefined) {\n disposers.push(tabs.register({\n id: TAB_ID,\n kind: TAB_KIND,\n title: () => 'QQ 机器人绑定',\n guide: [{\n id: 'bind',\n order: 90,\n title: () => 'QQ 机器人绑定',\n description: () => '扫码或手动填写,绑定 QQ 机器人',\n icon: BindGuideIcon,\n }],\n }));\n disposers.push(slots.inject('sidebar.right.pane.tab', () => slots.register(\n { name: 'sidebar.right.pane.tab', key: TAB_ID },\n BindPanelBody,\n )));\n // 待绑定检测与自动引导\n disposers.push(watchAndPrompt(right));\n }\n\n (ctx as unknown as { effect(fn: () => () => void, name?: string): void }).effect(() => () => {\n for (const dispose of disposers.reverse()) dispose();\n }, 'im-qqbot-client.binding');\n}\n\n/**\n * 轮询绑定状态:待绑定时自动打开绑定页。\n *\n * - 页面隐藏时降频轮询(可见时立即恢复节拍)\n * - 404(已绑定/未安装)时退避到 30s,保持低成本常驻探测\n * - 每次页面加载至多打开一次(用户手动关闭后不打扰);\n * 打开失败(如启动早期 Session surface 尚未挂载)不消费机会,\n * 由下一轮轮询(3s)自动重试\n */\nfunction watchAndPrompt(right: SidebarRightLike | undefined): () => void {\n let stopped = false;\n let opened = right === undefined;\n let timer: ReturnType<typeof setTimeout> | undefined;\n\n const schedule = (ms: number): void => {\n timer = setTimeout(() => { void tick(); }, ms);\n };\n\n const tick = async (): Promise<void> => {\n if (stopped) return;\n if (typeof document !== 'undefined' && document.visibilityState === 'hidden') {\n schedule(5000);\n return;\n }\n try {\n const res = await fetch(BIND_STATE_PATH, { cache: 'no-store' });\n if (res.ok) {\n const body = (await res.json()) as { phase?: string };\n if (body.phase === 'waiting' && !opened && right !== undefined) {\n try {\n right.openTab(TAB_KIND);\n opened = true;\n } catch (err) {\n // 启动早期 Session surface 可能尚未挂载:保留机会,3s 后随轮询重试\n console.error('[im-qqbot] 打开绑定页失败,稍后重试', err);\n }\n }\n schedule(3000);\n return;\n }\n // 404:已绑定或插件未启用\n schedule(30000);\n return;\n } catch {\n // 宿主暂不可达(启动窗口期):退避重试\n }\n schedule(10000);\n };\n\n void tick();\n return () => { stopped = true; if (timer !== undefined) clearTimeout(timer); };\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"client.js","names":["STYLE_ID","useState","useRef","useCallback","createElement","createElement","useState","useCallback","createElement"],"sources":["../src/shared/bind-protocol.ts","../src/client/bind-page.ts","../src/client/config-panel.ts","../src/client/index.ts"],"sourcesContent":["/**\n * 端内绑定协议 —— 宿主路由与客户端面板的共享契约\n *\n * 类型与路径常量的唯一事实源:宿主(setup/bind-routes.ts)与浏览器\n * (client/bind-page.ts)各自 import,杜绝两端协议漂移。\n * 本模块必须保持纯类型 + 纯常量(零 node 依赖、零副作用):\n * 客户端 tsdown 构建会将其内联进 bundle。\n */\n\n/** 状态查询(绑定页轮询) */\nexport const BIND_STATE_PATH = '/qqbot/im-qqbot/bind';\n\n/** 刷新二维码(绑定页按钮) */\nexport const BIND_REFRESH_PATH = '/qqbot/im-qqbot/bind/refresh';\n\n/** 手动填写/编辑凭据(绑定页表单) */\nexport const BIND_MANUAL_PATH = '/qqbot/im-qqbot/bind/manual';\n\n/** 解绑:移除已保存凭据,回到绑定流程 */\nexport const BIND_UNBIND_PATH = '/qqbot/im-qqbot/bind/unbind';\n\n/** 配置读写(设置面板表单) */\nexport const BIND_CONFIG_PATH = '/qqbot/im-qqbot/config';\n\n/** 线上协议(HTTP 路由序列化形态) */\nexport type BindStateWire =\n | { phase: 'starting' }\n | { phase: 'waiting'; url: string; qrSvg?: string; issuedAt: number }\n | { phase: 'saving' }\n | { phase: 'failed'; reason: string }\n | { phase: 'bound'; appId: string };\n\n/** manual / unbind 操作的统一响应 */\nexport interface BindActionResponse {\n ok: boolean;\n message?: string;\n error?: string;\n}\n","/**\n * 端内绑定面板 — 扫码 / 手动填写 / 已绑定编辑\n *\n * 宿主插件注册 /qqbot/im-qqbot/bind 路由(待绑定与已绑定 fiber 均常驻):\n * - 未绑定:waiting(二维码)/ starting / saving / failed 相位 + manual 提交\n * - 已绑定:bound 相位(回显脱敏 appId,secret 不回传)+ manual 更换 + 解绑\n * 扫码成功或手动保存均写入 profile patch 并经 HMR 重载生效。\n *\n * 样式为注入式 CSS 类(imqb-* 命名空间,随面板挂载注入一次):\n * hover/过渡/focus 样式无法用 inline style 表达,统一走类;\n * 颜色尽量取 DSW 主题变量(--dsw-alias-*),缺省值兜底。\n *\n * 同一组件复用于两种展示位(侧栏绑定页 / 设置页 QQ Bot 栏目)。\n * 运行时仅依赖 react(dsh 客户端平台种子表提供);宿主通信走同源 fetch,\n * Desktop 下由壳的 IPC 桥自动附加 Host 认证转发。\n */\nimport { createElement, useCallback, useEffect, useRef, useState, type FormEvent, type ReactNode } from 'react';\nimport {\n BIND_MANUAL_PATH,\n BIND_REFRESH_PATH,\n BIND_STATE_PATH,\n BIND_UNBIND_PATH,\n type BindStateWire,\n} from '../shared/bind-protocol.ts';\n\n/** 轮询间隔(毫秒):活跃轮询 / 失败退避 */\nconst ACTIVE_POLL_MS = 2000;\nconst RETRY_POLL_MS = 3000;\n\n/** 样式注入标记(幂等) */\nconst STYLE_ID = 'im-qqbot-bind-panel-styles';\n\n/**\n * 注入面板样式(一次)。交互态(hover/active/focus)无法用 inline style\n * 表达,统一收敛到类;DSW 主题变量缺失时用中性值兜底。\n */\nfunction usePanelStyles(): void {\n useEffect(() => {\n if (typeof document === 'undefined') return;\n if (document.getElementById(STYLE_ID) !== null) return;\n const style = document.createElement('style');\n style.id = STYLE_ID;\n style.textContent = `\n.imqb-panel {\n display: flex; flex-direction: column; align-items: center; justify-content: center;\n gap: 14px; padding: 24px; min-height: 320px; text-align: center; font-size: 14px;\n}\n.imqb-title { margin: 0; font-size: 16px; font-weight: 600; }\n.imqb-hint { margin: 0; opacity: 0.75; line-height: 1.6; }\n.imqb-mono { font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-size: 13px; }\n.imqb-link { font-size: 13px; opacity: 0.85; color: var(--dsw-alias-brand, #4d6bfe); text-decoration: none; }\n.imqb-link:hover { text-decoration: underline; }\n.imqb-icon { font-size: 32px; line-height: 1; }\n.imqb-qr { border-radius: 10px; background: #fff; padding: 10px; max-width: 100%; }\n.imqb-row { display: flex; gap: 10px; justify-content: center; flex-wrap: wrap; }\n.imqb-btn, .imqb-pill {\n font: inherit; cursor: pointer; color: inherit;\n transition: background-color .15s ease, border-color .15s ease, color .15s ease, opacity .15s ease;\n}\n.imqb-btn:disabled, .imqb-pill:disabled { opacity: 0.5; cursor: default; }\n.imqb-btn {\n padding: 7px 18px; border-radius: 8px; font-size: 13px;\n border: 1px solid var(--dsw-alias-border-l2, rgba(128, 128, 128, 0.4));\n background: transparent;\n}\n.imqb-btn:hover:not(:disabled) { background: var(--dsw-alias-interactive-bg-hover, rgba(128, 128, 128, 0.12)); }\n.imqb-btn--primary {\n border-color: transparent;\n background: var(--dsw-alias-brand, #4d6bfe); color: #fff; font-weight: 500;\n}\n.imqb-btn--primary:hover:not(:disabled) { background: var(--dsw-alias-brand-strong, #3b5cf0); }\n.imqb-btn--danger { color: var(--dsw-alias-danger, #f26d6d); border-color: var(--dsw-alias-danger, rgba(242, 109, 109, 0.5)); }\n.imqb-btn--danger:hover:not(:disabled) { background: var(--dsw-alias-danger, rgba(242, 109, 109, 0.12)); }\n.imqb-ghost {\n border: none; background: transparent; opacity: 0.65; padding: 4px 8px;\n font: inherit; font-size: 13px; cursor: pointer; color: inherit;\n}\n.imqb-ghost:hover { opacity: 1; text-decoration: underline; }\n.imqb-pill {\n padding: 5px 16px; border-radius: 999px; font-size: 13px;\n border: 1px solid var(--dsw-alias-border-l2, rgba(128, 128, 128, 0.4)); background: transparent;\n}\n.imqb-pill:hover:not(:disabled) { background: var(--dsw-alias-interactive-bg-hover, rgba(128, 128, 128, 0.12)); }\n.imqb-btn:focus-visible, .imqb-pill:focus-visible, .imqb-input:focus-visible, .imqb-ghost:focus-visible {\n outline: 2px solid var(--dsw-alias-brand, #4d6bfe); outline-offset: 1px;\n}\n.imqb-form { display: flex; flex-direction: column; gap: 12px; width: min(320px, 100%); box-sizing: border-box; }\n.imqb-field { display: flex; flex-direction: column; gap: 5px; text-align: left; font-size: 13px; }\n.imqb-input {\n padding: 8px 10px; border-radius: 8px; box-sizing: border-box; width: 100%;\n border: 1px solid var(--dsw-alias-border-l2, rgba(128, 128, 128, 0.4));\n background: var(--dsw-alias-bg-input, rgba(128, 128, 128, 0.08));\n color: inherit; font: inherit; font-size: 13px; outline: none;\n}\n.imqb-input:focus { border-color: var(--dsw-alias-brand, #4d6bfe); }\n.imqb-error { margin: 0; font-size: 12px; color: var(--dsw-alias-danger, #f26d6d); }\n/* 紧凑状态视图(已绑定 / 过渡态):设置行风格,无居中大卡留白 */\n.imqb-status { display: flex; flex-direction: column; text-align: left; font-size: 14px; }\n.imqb-status-row { display: flex; align-items: center; gap: 12px; padding: 12px 0; }\n.imqb-status-icon { font-size: 24px; line-height: 1; flex: none; }\n.imqb-qqicon {\n flex: none; display: block; border-radius: 8px;\n background: #fff; /* 深色企鹅 logo 需浅底,暗色主题下保持可见 */\n}\n.imqb-status-meta { display: flex; flex-direction: column; gap: 2px; min-width: 0; flex: 1; }\n.imqb-status-title { margin: 0; font-size: 14px; font-weight: 600; line-height: 1.5; }\n.imqb-status-sub { margin: 0; font-size: 12px; line-height: 1.5; color: var(--dsw-alias-label-tertiary, inherit); opacity: .85; }\n.imqb-status-actions { display: flex; align-items: center; gap: 8px; padding: 4px 0 12px; }\n/* 扫码成功后的连接过渡:二维码模糊变暗 + 覆盖层 */\n.imqb-scanned { position: relative; display: inline-block; }\n.imqb-scanned-qr {\n display: block; border-radius: 10px; background: #fff; padding: 10px;\n filter: blur(6px) saturate(0.6); opacity: 0.55;\n}\n.imqb-scanned-veil {\n position: absolute; inset: 0; display: flex; flex-direction: column;\n align-items: center; justify-content: center; gap: 6px; text-align: center;\n}\n.imqb-scanned-title { margin: 0; font-size: 15px; font-weight: 600; }\n.imqb-scanned-sub { margin: 0; font-size: 12px; opacity: 0.75; line-height: 1.6; }\n `;\n document.head.appendChild(style);\n return () => { style.remove(); };\n }, []);\n}\n\n/**\n * 绑定状态轮询 hook。\n *\n * 404 语义分两种:从未拿到过路由 = 插件未启用(终态);\n * 曾经拿到过 = HMR 重载窗口期(manual/unbind 保存后路由短暂消失),\n * 低频等待恢复而不是判定终态——否则保存成功提示会被\n * 「插件未启用」覆盖且无法自愈。\n *\n * bound 为稳定态:轮询大幅降频(30s)。因此解绑等本地动作后必须\n * 调用 recheck() 立即重置节拍——否则视图最长停留 30s+ 才收敛到\n * 新相位(如解绑后的 waiting 二维码)。\n *\n * @returns 轮询快照与 recheck:state 为宿主相位(null = 加载中),\n * gone 表示插件未启用(从未注册过路由),recheck 废弃当前\n * 定时器并立即重新轮询(新轮询链取代旧链,不产生双计时器)。\n */\nfunction useBindState(): { state: BindStateWire | null; gone: boolean; recheck: () => void } {\n const [state, setState] = useState<BindStateWire | null>(null);\n const [gone, setGone] = useState(false);\n const recheckRef = useRef<() => void>(() => {});\n\n useEffect(() => {\n let stopped = false;\n let sawRoute = false;\n let generation = 0;\n let running = false;\n let restartAfterFlight = false;\n // recheck 后的快速收敛窗口:解绑等动作改变的是服务端状态(经\n // HMR 异步生效),动作后立即轮询拿到的可能仍是旧 fiber 的相位\n // (如 bound→30s 降频),窗口期内强制快轮询直到相位真正变化\n let urgentUntil = 0;\n let timer: ReturnType<typeof setTimeout> | undefined;\n\n const schedule = (ms: number): void => {\n timer = setTimeout(() => { void tick(); }, ms);\n };\n\n const intervalFor = (phase: BindStateWire['phase']): number => {\n const base = phase === 'saving' ? 500 : phase === 'bound' ? 30000 : ACTIVE_POLL_MS;\n return Date.now() < urgentUntil ? Math.min(base, ACTIVE_POLL_MS) : base;\n };\n\n const tick = async (): Promise<void> => {\n if (stopped || running) return;\n running = true;\n const myGeneration = generation;\n const alive = (): boolean => myGeneration === generation && !stopped;\n try {\n const res = await fetch(BIND_STATE_PATH, { cache: 'no-store' });\n if (res.status === 404) {\n if (!stopped && !sawRoute) setGone(true);\n // sawRoute:HMR 窗口期,保留当前视图等待路由恢复\n else if (alive()) schedule(Date.now() < urgentUntil ? 1000 : 3000);\n return;\n }\n if (!res.ok) {\n if (alive()) schedule(RETRY_POLL_MS);\n return;\n }\n sawRoute = true;\n const body = (await res.json()) as BindStateWire;\n if (!alive()) return;\n setState(body);\n schedule(intervalFor(body.phase));\n return;\n } catch {\n // 宿主启动窗口期不可达:退避重试\n } finally {\n running = false;\n // 在飞期间被 recheck 取代:接力启动新轮询链(否则链会断)\n if (restartAfterFlight && !stopped) {\n restartAfterFlight = false;\n void tick();\n }\n }\n if (alive()) schedule(RETRY_POLL_MS);\n };\n\n // 立即重置节拍:废弃当前计时器,旧轮询链(在飞请求)作废,\n // 新链立即发起,并进入快速收敛窗口\n recheckRef.current = (): void => {\n generation += 1;\n urgentUntil = Date.now() + 15000;\n if (timer !== undefined) clearTimeout(timer);\n if (running) {\n restartAfterFlight = true;\n return;\n }\n void tick();\n };\n\n void tick();\n return () => { stopped = true; if (timer !== undefined) clearTimeout(timer); };\n }, []);\n\n const recheck = useCallback((): void => { recheckRef.current(); }, []);\n\n return { state, gone, recheck };\n}\n\ninterface ManualResult { ok: boolean; message?: string; error?: string }\n\n/** 手动提交凭据(填写 / 更换共用) */\nasync function submitManualCredentials(appId: string, appSecret: string): Promise<ManualResult> {\n try {\n const res = await fetch(BIND_MANUAL_PATH, {\n method: 'POST',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify({ appId, appSecret }),\n });\n const body = (await res.json().catch(() => ({}))) as ManualResult;\n if (res.ok && body.ok) return { ok: true, message: body.message };\n return { ok: false, error: body.error ?? `保存失败(HTTP ${res.status})` };\n } catch (err) {\n return { ok: false, error: err instanceof Error ? err.message : String(err) };\n }\n}\n\n/**\n * 手动凭据表单(填写 / 更换共用)。\n *\n * appSecret 永不回显(占位符提示),提交成功后展示保存结果;\n * 宿主写入 profile patch 并经 HMR 重载,状态轮询随后收敛为 bound。\n */\nfunction ManualForm({ initialAppId }: { initialAppId?: string }): ReactNode {\n const [appId, setAppId] = useState(initialAppId ?? '');\n const [appSecret, setAppSecret] = useState('');\n const [busy, setBusy] = useState(false);\n const [result, setResult] = useState<ManualResult | null>(null);\n\n const submit = useCallback((event: FormEvent): void => {\n event.preventDefault();\n if (busy) return;\n const trimmedId = appId.trim();\n const trimmedSecret = appSecret.trim();\n if (trimmedId.length === 0 || trimmedSecret.length === 0) {\n setResult({ ok: false, error: 'appId 与 appSecret 均为必填' });\n return;\n }\n setBusy(true);\n void submitManualCredentials(trimmedId, trimmedSecret).then((outcome) => {\n setResult(outcome);\n setBusy(false);\n });\n }, [appId, appSecret, busy]);\n\n if (result !== null && result.ok) {\n return createElement('div', { className: 'imqb-status' },\n createElement('div', { className: 'imqb-status-row' },\n createElement('div', { className: 'imqb-status-icon' }, '✅'),\n createElement('div', { className: 'imqb-status-meta' },\n createElement('p', { className: 'imqb-status-title' }, result.message ?? '凭据已保存'),\n createElement('p', { className: 'imqb-status-sub' }, '插件将自动重载;稍后即可开始对话'),\n ),\n ),\n );\n }\n\n return createElement('form', { className: 'imqb-form', onSubmit: submit },\n createElement('label', { className: 'imqb-field' },\n 'AppID',\n createElement('input', {\n className: 'imqb-input', value: appId, placeholder: 'QQ 机器人 AppID',\n onChange: (event) => { setAppId(event.currentTarget.value); },\n autoComplete: 'off', spellCheck: false,\n }),\n ),\n createElement('label', { className: 'imqb-field' },\n 'AppSecret',\n createElement('input', {\n className: 'imqb-input', type: 'password', value: appSecret,\n placeholder: initialAppId === undefined ? 'QQ 机器人 AppSecret' : '输入新的 AppSecret(不回显)',\n onChange: (event) => { setAppSecret(event.currentTarget.value); },\n autoComplete: 'new-password',\n }),\n ),\n result !== null && !result.ok\n ? createElement('p', { className: 'imqb-error' }, result.error)\n : null,\n createElement('button', { className: 'imqb-btn imqb-btn--primary', type: 'submit', disabled: busy },\n busy ? '正在保存…' : '保存'),\n );\n}\n\n/** QQ 企鹅 logo(256×256 PNG data URI;深色图案配白底圆角,明暗主题下均可见) */\nconst QQ_BOT_ICON_PNG =\n 'data:image/png;base64,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';\n\n/** QQ 机器人图标(logo 图片,白底圆角容器内呈现) */\nfunction QqBotIcon({ size = 28 }: { size?: number }): ReactNode {\n return createElement('img', {\n src: QQ_BOT_ICON_PNG, alt: 'QQ', width: size, height: size, className: 'imqb-qqicon',\n });\n}\n\n/** 已绑定视图:回显 appId + 更换凭据 / 解绑入口 */\nfunction BoundView({ appId, recheck }: { appId: string; recheck: () => void }): ReactNode {\n const [editing, setEditing] = useState(false);\n const [unbindResult, setUnbindResult] = useState<{ ok: boolean; message: string } | null>(null);\n\n const unbind = useCallback((): void => {\n if (!window.confirm('确定解绑吗?\\n解绑后机器人立即下线,插件将重新进入扫码绑定流程。')) return;\n void fetch(BIND_UNBIND_PATH, { method: 'POST' })\n .then(async (res) => {\n const body = (await res.json().catch(() => ({}))) as { ok?: boolean; message?: string; error?: string };\n if (res.ok && body.ok === true) {\n setUnbindResult({ ok: true, message: body.message ?? '已解绑,插件将重载并重新进入绑定流程' });\n // bound 态轮询已降频到 30s:立即重置节拍,让 waiting(二维码)\n // 尽快出现而不是等下一个 30s 周期\n recheck();\n return;\n }\n setUnbindResult({ ok: false, message: body.error ?? `解绑失败(HTTP ${res.status})` });\n })\n .catch((err: unknown) => {\n setUnbindResult({ ok: false, message: err instanceof Error ? err.message : String(err) });\n });\n }, [recheck]);\n\n if (unbindResult !== null) {\n // 非终态视图:解绑成功后正常由轮询收敛到 waiting;若 HMR 未\n // 触发(状态停留 bound),用户仍有「刷新状态」出口而不是死胡同\n return createElement('div', { className: 'imqb-status' },\n createElement('div', { className: 'imqb-status-row' },\n createElement('div', { className: 'imqb-status-icon' }, unbindResult.ok ? '👋' : '⚠️'),\n createElement('div', { className: 'imqb-status-meta' },\n createElement('p', { className: 'imqb-status-title' }, unbindResult.message),\n ),\n unbindResult.ok\n ? createElement('button', { className: 'imqb-ghost', onClick: recheck }, '刷新状态')\n : createElement('button', { className: 'imqb-ghost', onClick: () => { setUnbindResult(null); } }, '返回'),\n ),\n );\n }\n\n if (editing) {\n return createElement('div', { className: 'imqb-status' },\n createElement('div', { className: 'imqb-status-row' },\n createElement('div', { className: 'imqb-status-meta' },\n createElement('p', { className: 'imqb-status-title' }, '更换凭据'),\n ),\n createElement('button', { className: 'imqb-ghost', onClick: () => { setEditing(false); } }, '返回'),\n ),\n createElement(ManualForm, { initialAppId: appId }),\n );\n }\n return createElement('div', { className: 'imqb-status' },\n createElement('div', { className: 'imqb-status-row' },\n createElement(QqBotIcon, { size: 28 }),\n createElement('div', { className: 'imqb-status-meta' },\n createElement('p', { className: 'imqb-status-title' }, '已绑定'),\n createElement('p', { className: 'imqb-status-sub imqb-mono' }, `AppID ${appId} · 私聊与群聊已接入`),\n ),\n ),\n createElement('div', { className: 'imqb-status-actions' },\n createElement('button', { className: 'imqb-btn imqb-btn--primary', onClick: () => { setEditing(true); } }, '更换凭据'),\n createElement('button', { className: 'imqb-btn imqb-btn--danger', onClick: unbind }, '解绑'),\n ),\n );\n}\n\n/** 未绑定视图:扫码 / 手动填写切换 */\nfunction UnboundView({ state }: { state: Extract<BindStateWire, { phase: 'waiting' }> }): ReactNode {\n const [mode, setMode] = useState<'qr' | 'manual'>('qr');\n const refresh = useCallback(() => { void fetch(BIND_REFRESH_PATH, { method: 'POST' }).catch(() => {}); }, []);\n\n if (mode === 'manual') {\n return createElement('div', { className: 'imqb-panel' },\n createElement('p', { className: 'imqb-title' }, '手动填写凭据'),\n createElement(ManualForm, {}),\n createElement('button', { className: 'imqb-ghost', onClick: () => { setMode('qr'); } }, '改用扫码绑定'),\n );\n }\n\n return createElement('div', { className: 'imqb-panel' },\n state.qrSvg === undefined\n ? null\n : createElement('img', { src: state.qrSvg, alt: 'QQ 扫码二维码', width: 220, height: 220, className: 'imqb-qr' }),\n createElement('p', { className: 'imqb-title' }, '扫码绑定 QQ 机器人'),\n createElement('p', { className: 'imqb-hint' }, '使用手机 QQ 扫描二维码完成绑定'),\n createElement('a', { href: state.url, target: '_blank', rel: 'noreferrer noopener', className: 'imqb-link' }, '二维码显示异常?在浏览器中打开'),\n createElement('div', { className: 'imqb-row' },\n createElement('button', { className: 'imqb-pill', onClick: refresh }, '刷新二维码'),\n createElement('button', { className: 'imqb-pill', onClick: () => { setMode('manual'); } }, '手动填写'),\n ),\n );\n}\n\n/** 依据宿主相位渲染面板主体(各展示位共用) */\nexport function BindPanelBody(): ReactNode {\n usePanelStyles();\n const { state, gone, recheck } = useBindState();\n // 扫码成功的连接过渡场景需要保留最后一帧二维码:waiting 相位持续记录,\n // bound 后清空(避免下次解绑重绑时旧码闪现)\n const [lastQr, setLastQr] = useState<string | null>(null);\n useEffect(() => {\n if (state === null) return;\n if (state.phase === 'waiting') {\n if (state.qrSvg !== undefined) setLastQr(state.qrSvg);\n } else if (state.phase === 'bound') {\n setLastQr(null);\n }\n }, [state]);\n\n if (gone) {\n return createElement('div', { className: 'imqb-panel' },\n createElement('div', { className: 'imqb-icon' }, '❔'),\n createElement('p', { className: 'imqb-hint' }, '插件未启用,或当前版本不支持端内配置'),\n );\n }\n\n if (state === null || state.phase === 'starting') {\n return createElement('div', { className: 'imqb-panel' },\n createElement('p', { className: 'imqb-hint' }, '正在获取绑定状态…'),\n );\n }\n\n if (state.phase === 'saving') {\n // 扫码路径:保留二维码做模糊过渡(手动填写路径无二维码,用紧凑态)\n if (lastQr !== null) {\n return createElement('div', { className: 'imqb-panel' },\n createElement('div', { className: 'imqb-scanned' },\n createElement('img', { src: lastQr, alt: 'QQ 扫码二维码', width: 220, height: 220, className: 'imqb-scanned-qr' }),\n createElement('div', { className: 'imqb-scanned-veil' },\n createElement('p', { className: 'imqb-scanned-title' }, '✅ 扫码成功'),\n createElement('p', { className: 'imqb-scanned-sub' }, '正在连接机器人,稍候…'),\n ),\n ),\n );\n }\n return createElement('div', { className: 'imqb-status' },\n createElement('div', { className: 'imqb-status-row' },\n createElement('div', { className: 'imqb-status-icon' }, '🎉'),\n createElement('div', { className: 'imqb-status-meta' },\n createElement('p', { className: 'imqb-status-title' }, '扫码成功'),\n createElement('p', { className: 'imqb-status-sub' }, '凭据已保存,插件正在重载,稍后即可开始对话'),\n ),\n ),\n );\n }\n\n if (state.phase === 'failed') {\n return createElement('div', { className: 'imqb-panel' },\n createElement('div', { className: 'imqb-icon' }, '⚠️'),\n createElement('p', { className: 'imqb-title' }, '绑定失败'),\n createElement('p', { className: 'imqb-hint' }, state.reason),\n createElement('div', { className: 'imqb-row' },\n createElement('button', { className: 'imqb-btn imqb-btn--primary', onClick: () => { window.location.reload(); } }, '重试'),\n ),\n );\n }\n\n if (state.phase === 'bound') {\n return createElement(BoundView, { appId: state.appId, recheck });\n }\n\n return createElement(UnboundView, { state });\n}\n","/**\n * QQ 机器人配置面板 — 必要配置的 UI 编辑\n *\n * UI 复刻 DSW 通用设置(settings-form 原语)的视觉风格:\n * 左对齐设置列、0.5px 行分隔、label 13px/500、控件右置;\n * Switch 为 36×20 aria-checked 结构(thumb translateX 动画);\n * 三值选择用分段控件(滑动指示器按段数/索引的 CSS 变量定位);\n * 保存按钮为 DSW 反色主按钮(label-primary 底 + bg-layer-3 字)。\n *\n * 数据流:GET /qqbot/im-qqbot/config 回显当前生效配置(appSecret\n * 已由宿主剔除)→ 表单编辑 → dirty diff → POST 仅提交变更键 →\n * 宿主白名单 + Schema 校验 → 最小写入 profile patch → HMR 重载生效。\n *\n * 字段策略:只开放用户必要的配置;cwd 只读展示;超时与性能调优\n * 类字段走 profile patch / 环境变量。\n */\nimport { createElement, useCallback, useEffect, useState, type CSSProperties, type ChangeEvent, type FormEvent, type ReactNode } from 'react';\nimport { BIND_CONFIG_PATH } from '../shared/bind-protocol.ts';\n\n/** 访问控制配置(与 src/config.ts 的 AccessControlConfig 对应的局部投影) */\ninterface AccessControlWire {\n c2cMode: 'open' | 'allowlist' | 'disabled';\n c2cAllow: string[];\n groupMode: 'open' | 'allowlist' | 'disabled';\n groupAllow: string[];\n}\n\n/** GET 回显的生效配置(appSecret 已剔除) */\ntype ConfigWire = {\n requireMention?: boolean;\n streaming?: boolean;\n showToolResults?: boolean;\n debug?: boolean;\n provider?: string;\n model?: string;\n preset?: string;\n groupPrompt?: string;\n directPrompt?: string;\n access?: AccessControlWire;\n cwd?: string;\n};\n\n/** 样式注入标记(幂等) */\nconst STYLE_ID = 'im-qqbot-config-panel-styles';\n\n/** DSW 通用设置风格(settings-form / Switch / SegmentedControl 原语复刻) */\nfunction useConfigPanelStyles(): void {\n useEffect(() => {\n if (typeof document === 'undefined') return;\n if (document.getElementById(STYLE_ID) !== null) return;\n const style = document.createElement('style');\n style.id = STYLE_ID;\n style.textContent = `\n.imqb2-form { display: flex; flex-direction: column; width: 100%; }\n.imqb2-group-title {\n padding: 14px 0 2px; font-size: 12px; font-weight: 600; line-height: 18px;\n color: var(--dsw-alias-label-tertiary); text-transform: uppercase; letter-spacing: .04em;\n}\n.imqb2-field { display: flex; flex-direction: column; gap: 6px; padding: 12px 0; }\n.imqb2-field + .imqb2-field { border-top: 0.5px solid var(--dsw-alias-border-l2); }\n.imqb2-head { display: flex; align-items: center; gap: 8px; min-height: 28px; }\n.imqb2-label {\n flex: 1; min-width: 0; font-size: 13px; font-weight: 500; line-height: 1.5;\n color: var(--dsw-alias-label-primary);\n}\n.imqb2-help { margin: 0; font-size: 12px; line-height: 1.6; color: var(--dsw-alias-label-secondary); }\n.imqb2-hint { margin: 0; font-size: 12px; line-height: 1.5; color: var(--dsw-alias-label-tertiary); }\n/* Switch(aria-checked 驱动,视觉态与无障碍态同源) */\n.imqb2-switch {\n box-sizing: border-box; position: relative; flex: 0 0 auto;\n width: 36px; height: 20px; padding: 2px; border: 0; border-radius: 999px;\n background: var(--dsw-alias-border-l3); cursor: pointer; font: inherit;\n}\n.imqb2-switch[aria-checked='true'] { background: var(--dsw-alias-brand-primary); }\n.imqb2-switch:disabled { cursor: default; opacity: 0.5; }\n.imqb2-switch:focus-visible {\n outline: var(--dsw-focus-ring-width, 2px) solid var(--dsw-focus-ring-color, var(--dsw-alias-state-business-primary));\n outline-offset: 2px;\n}\n.imqb2-switch-thumb {\n display: block; width: 16px; height: 16px; border-radius: 50%;\n background: var(--dsw-alias-switch-thumb, #ffffff);\n transition: transform 120ms ease;\n}\n.imqb2-switch[aria-checked='true'] .imqb2-switch-thumb {\n background: var(--dsw-alias-label-primary-foreground, #ffffff);\n transform: translateX(16px);\n}\n/* 输入(官方 fields.input 复刻) */\n.imqb2-input {\n box-sizing: border-box; width: 100%; height: 34px; padding: 0 12px;\n border: 0.5px solid var(--dsw-alias-border-l4); border-radius: var(--dsw-radius-md, 8px);\n background: var(--dsw-alias-bg-layer-3); font: inherit; font-size: 13px; line-height: 1.5;\n color: var(--dsw-alias-label-primary); outline: none;\n}\n.imqb2-input:focus { outline: none; border-color: var(--dsw-alias-state-business-primary); }\n.imqb2-input:disabled { color: var(--dsw-alias-label-tertiary); cursor: default; }\n.imqb2-textarea { height: auto; min-height: 68px; padding: 8px 12px; resize: vertical; line-height: 1.5; }\n/* 分段控件(官方 SegmentedControl 复刻:指示器按段数/索引定位) */\n.imqb2-seg {\n position: relative; display: inline-grid; grid-auto-flow: column; grid-auto-columns: 1fr;\n gap: 2px; padding: 4px; border-radius: var(--dsw-radius-md, 8px);\n background: var(--dsw-alias-interactive-bg-hover);\n}\n.imqb2-seg-indicator {\n position: absolute; top: 4px; left: 4px;\n width: calc((100% - 8px - 2px * (var(--imqb2-seg-count) - 1)) / var(--imqb2-seg-count));\n height: calc(100% - 8px);\n border: 0; border-radius: var(--dsw-radius-sm, 6px);\n background: var(--dsw-alias-bg-layer-1);\n box-shadow: var(--dsw-elevation-soft, 0 1px 3px rgba(0,0,0,.08));\n transform: translateX(calc(var(--imqb2-seg-index) * (100% + 2px)));\n transition: transform 160ms ease;\n pointer-events: none;\n}\n.imqb2-seg-tab {\n box-sizing: border-box; position: relative; z-index: 1; height: 28px; padding: 0 16px;\n border: 0; border-radius: var(--dsw-radius-sm, 6px); background: transparent;\n color: var(--dsw-alias-label-secondary); font: inherit; font-size: 13px; line-height: 20px;\n font-weight: 500; white-space: nowrap; cursor: pointer; transition: color 120ms ease;\n}\n.imqb2-seg-tab:hover, .imqb2-seg-tab[aria-selected='true'] { color: var(--dsw-alias-label-primary); }\n.imqb2-seg-tab:focus-visible {\n outline: var(--dsw-focus-ring-width, 2px) solid var(--dsw-focus-ring-color, var(--dsw-alias-state-business-primary));\n outline-offset: -2px;\n}\n/* 底栏(官方 SettingsForm.footer 复刻) */\n.imqb2-footer { display: flex; align-items: center; gap: 8px; padding-top: 16px; }\n.imqb2-note { flex: 1; min-width: 0; margin: 0; font-size: 12px; line-height: 1.5; color: var(--dsw-alias-label-tertiary); }\n.imqb2-note--error { color: var(--dsw-alias-state-error-primary, var(--dsw-alias-label-error)); }\n.imqb2-note--ok { color: var(--dsw-alias-label-secondary); }\n.imqb2-save {\n appearance: none; flex: none; border: 1px solid transparent;\n border-radius: var(--dsw-radius-md, 8px); padding: 5px 14px;\n font: inherit; font-size: 13px; line-height: 1.5; cursor: pointer;\n background: var(--dsw-alias-label-primary); color: var(--dsw-alias-bg-layer-3);\n}\n.imqb2-save:disabled { opacity: 0.4; cursor: default; }\n.imqb2-save:focus-visible {\n outline: var(--dsw-focus-ring-width, 2px) solid var(--dsw-focus-ring-color, var(--dsw-alias-state-business-primary));\n outline-offset: 1px;\n}\n/* cwd 只读行 */\n.imqb2-readonly { font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-size: 12px; color: var(--dsw-alias-label-secondary); word-break: break-all; margin: 0; }\n `;\n document.head.appendChild(style);\n return () => { style.remove(); };\n }, []);\n}\n\n/** 开关(官方 Switch 原语结构:aria-checked 驱动视觉态) */\nfunction Switch({ checked, label, onChange }: {\n checked: boolean; label: string; onChange: (next: boolean) => void;\n}): ReactNode {\n return createElement('button', {\n type: 'button', role: 'switch', 'aria-checked': checked, 'aria-label': label,\n className: 'imqb2-switch',\n onClick: () => { onChange(!checked); },\n }, createElement('span', { className: 'imqb2-switch-thumb' }));\n}\n\n/** 访问模式分段选择(官方 SegmentedControl 结构:CSS 变量定位滑动指示器) */\nfunction Segmented({ value, options, onChange, label }: {\n value: AccessMode; options: ReadonlyArray<{ value: AccessMode; label: string }>;\n onChange: (next: AccessMode) => void; label: string;\n}): ReactNode {\n const index = Math.max(0, options.findIndex((o) => o.value === value));\n const trackStyle = {\n '--imqb2-seg-count': options.length,\n '--imqb2-seg-index': index,\n } as CSSProperties;\n return createElement('div', { className: 'imqb2-seg', role: 'tablist', 'aria-label': label, style: trackStyle },\n createElement('span', { className: 'imqb2-seg-indicator' }),\n options.map((o) => createElement('button', {\n key: o.value, type: 'button', role: 'tab', 'aria-selected': o.value === value,\n className: 'imqb2-seg-tab', onClick: () => { onChange(o.value); },\n }, o.label)),\n );\n}\n\n/** 开关行(label 左 + Switch 右 + 可选 help) */\nfunction SwitchRow({ label, help, checked, onChange }: {\n label: string; help?: string; checked: boolean; onChange: (next: boolean) => void;\n}): ReactNode {\n return createElement('div', { className: 'imqb2-field' },\n createElement('div', { className: 'imqb2-head' },\n createElement('span', { className: 'imqb2-label' }, label),\n createElement(Switch, { checked, label, onChange }),\n ),\n help === undefined ? null : createElement('p', { className: 'imqb2-help' }, help),\n );\n}\n\n/** 文本行(label 上 + 输入下,与官方 fields 布局一致) */\nfunction FieldRow({ label, help, value, placeholder, onChange }: {\n label: string; help?: string; value: string; placeholder?: string; onChange: (next: string) => void;\n}): ReactNode {\n return createElement('div', { className: 'imqb2-field' },\n createElement('span', { className: 'imqb2-label' }, label),\n createElement('input', {\n className: 'imqb2-input', value, placeholder, spellCheck: false,\n onChange: (event: ChangeEvent<HTMLInputElement>) => { onChange(event.currentTarget.value); },\n }),\n help === undefined ? null : createElement('p', { className: 'imqb2-hint' }, help),\n );\n}\n\n/** 多行文本行 */\nfunction AreaRow({ label, help, value, rows, onChange }: {\n label: string; help?: string; value: string; rows?: number; onChange: (next: string) => void;\n}): ReactNode {\n return createElement('div', { className: 'imqb2-field' },\n createElement('span', { className: 'imqb2-label' }, label),\n createElement('textarea', {\n className: 'imqb2-input imqb2-textarea', value, rows: rows ?? 3,\n onChange: (event: ChangeEvent<HTMLTextAreaElement>) => { onChange(event.currentTarget.value); },\n }),\n help === undefined ? null : createElement('p', { className: 'imqb2-hint' }, help),\n );\n}\n\n/** 访问模式分段选择行 */\nfunction SegmentedRow({ label, help, value, options, onChange }: {\n label: string; help?: string; value: AccessMode;\n options: ReadonlyArray<{ value: AccessMode; label: string }>; onChange: (next: AccessMode) => void;\n}): ReactNode {\n return createElement('div', { className: 'imqb2-field' },\n createElement('div', { className: 'imqb2-head' },\n createElement('span', { className: 'imqb2-label' }, label),\n createElement(Segmented, { value, options, onChange, label }),\n ),\n help === undefined ? null : createElement('p', { className: 'imqb2-hint' }, help),\n );\n}\n\ntype AccessMode = AccessControlWire['c2cMode'];\n\nconst MODE_OPTIONS: ReadonlyArray<{ value: AccessMode; label: string }> = [\n { value: 'open', label: '所有人' },\n { value: 'allowlist', label: '白名单' },\n { value: 'disabled', label: '禁用' },\n];\n\n/** 深比较(表单值与初始回显值的 dirty 判断) */\nfunction shallowEqual(a: unknown, b: unknown): boolean {\n return JSON.stringify(a) === JSON.stringify(b);\n}\n\n/**\n * 配置面板主体。\n *\n * 保存仅提交变更键(服务端按白名单合并),保存成功后提示\n * HMR 重载语义(进行中的机器人会话将重置)。\n */\nexport function ConfigPanel(): ReactNode {\n useConfigPanelStyles();\n const [initial, setInitial] = useState<ConfigWire | null>(null);\n const [form, setForm] = useState<ConfigWire | null>(null);\n const [busy, setBusy] = useState(false);\n const [result, setResult] = useState<{ ok: boolean; message: string } | null>(null);\n const [loadError, setLoadError] = useState<string | null>(null);\n\n useEffect(() => {\n let stopped = false;\n void fetch(BIND_CONFIG_PATH, { cache: 'no-store' })\n .then(async (res) => {\n if (!res.ok) throw new Error(`HTTP ${res.status}`);\n const body = (await res.json()) as { config: ConfigWire };\n if (stopped) return;\n setInitial(body.config);\n setForm(body.config);\n })\n .catch((err: unknown) => {\n if (!stopped) setLoadError(err instanceof Error ? err.message : String(err));\n });\n return () => { stopped = true; };\n }, []);\n\n const patch = useCallback(<K extends keyof ConfigWire>(key: K, value: ConfigWire[K]): void => {\n setForm((current) => current === null ? current : { ...current, [key]: value });\n setResult(null);\n }, []);\n\n const submit = useCallback((event: FormEvent): void => {\n event.preventDefault();\n if (busy || initial === null || form === null) return;\n const changed: Record<string, unknown> = {};\n for (const key of Object.keys(form) as Array<keyof ConfigWire>) {\n if (!shallowEqual(form[key], initial[key])) {\n changed[key] = form[key];\n }\n }\n if (Object.keys(changed).length === 0) return;\n\n // 白名单编辑期间保留原始换行/空行(textarea 可正常回车),提交时才规范化\n if (changed.access !== undefined) {\n const a = changed.access as AccessControlWire;\n changed.access = {\n ...a,\n c2cAllow: a.c2cAllow.map((s) => s.trim()).filter(Boolean),\n groupAllow: a.groupAllow.map((s) => s.trim()).filter(Boolean),\n };\n }\n\n setBusy(true);\n void fetch(BIND_CONFIG_PATH, {\n method: 'POST',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify(changed),\n })\n .then(async (res) => {\n const body = (await res.json().catch(() => ({}))) as { ok?: boolean; message?: string; error?: string };\n if (res.ok && body.ok === true) {\n setResult({ ok: true, message: body.message ?? '配置已保存,插件将自动重载' });\n setInitial(form);\n return;\n }\n setResult({ ok: false, message: body.error ?? `保存失败(HTTP ${res.status})` });\n })\n .catch((err: unknown) => {\n setResult({ ok: false, message: err instanceof Error ? err.message : String(err) });\n })\n .finally(() => { setBusy(false); });\n }, [busy, form, initial]);\n\n if (loadError !== null) {\n return createElement('p', { className: 'imqb2-hint', style: { padding: '12px 0' } },\n `配置加载失败:${loadError}`);\n }\n if (initial === null || form === null) {\n return createElement('p', { className: 'imqb2-hint', style: { padding: '12px 0' } }, '正在加载配置…');\n }\n\n const dirty = (Object.keys(form) as Array<keyof ConfigWire>).some((key) => !shallowEqual(form[key], initial[key]));\n const access: AccessControlWire = form.access ?? { c2cMode: 'open', c2cAllow: [], groupMode: 'open', groupAllow: [] };\n\n return createElement('form', { className: 'imqb2-form', onSubmit: submit },\n createElement('div', { className: 'imqb2-group-title' }, '服务范围'),\n createElement(SegmentedRow, {\n label: '私聊', value: access.c2cMode, options: MODE_OPTIONS,\n onChange: (v) => { patch('access', { ...access, c2cMode: v }); },\n }),\n access.c2cMode === 'allowlist'\n ? createElement(AreaRow, {\n label: '私聊白名单', help: '请输入用户 openid,多个请换行输入', rows: 3,\n value: access.c2cAllow.join('\\n'),\n onChange: (v) => { patch('access', { ...access, c2cAllow: v.split('\\n').map((s) => s.trim()) }); },\n })\n : null,\n createElement(SegmentedRow, {\n label: '群聊', value: access.groupMode, options: MODE_OPTIONS,\n onChange: (v) => { patch('access', { ...access, groupMode: v }); },\n }),\n access.groupMode === 'allowlist'\n ? createElement(AreaRow, {\n label: '群聊白名单', help: '请输入群 openid,多个请换行输入', rows: 3,\n value: access.groupAllow.join('\\n'),\n onChange: (v) => { patch('access', { ...access, groupAllow: v.split('\\n').map((s) => s.trim()) }); },\n })\n : null,\n\n createElement('div', { className: 'imqb2-group-title' }, '基础设置'),\n createElement(SwitchRow, {\n label: '群聊仅回复 @机器人的消息', checked: form.requireMention ?? true,\n help: '开启后,机器人仅可回复 @机器人的群聊消息',\n onChange: (v) => { patch('requireMention', v); },\n }),\n createElement(SwitchRow, {\n label: '流式输出', checked: form.streaming ?? true,\n help: '回复内容分段实时推送到聊天',\n onChange: (v) => { patch('streaming', v); },\n }),\n createElement(SwitchRow, {\n label: '显示工具调用结果', checked: form.showToolResults ?? false,\n help: '在聊天中展示 agent 工具调用的结构化结果',\n onChange: (v) => { patch('showToolResults', v); },\n }),\n\n createElement('div', { className: 'imqb2-group-title' }, '模型'),\n createElement(FieldRow, {\n label: 'Provider', value: form.provider ?? '', placeholder: '留空继承宿主默认',\n onChange: (v) => { patch('provider', v); },\n }),\n createElement(FieldRow, {\n label: 'Model', value: form.model ?? '', placeholder: '留空继承宿主默认',\n onChange: (v) => { patch('model', v); },\n }),\n createElement(FieldRow, {\n label: 'Preset', value: form.preset ?? '', placeholder: 'Agent preset id',\n onChange: (v) => { patch('preset', v); },\n }),\n\n createElement('div', { className: 'imqb2-group-title' }, '个性化提示词'),\n createElement(AreaRow, {\n label: '群聊额外 system prompt', value: form.groupPrompt ?? '',\n onChange: (v) => { patch('groupPrompt', v); },\n }),\n createElement(AreaRow, {\n label: '私聊额外 system prompt', value: form.directPrompt ?? '',\n onChange: (v) => { patch('directPrompt', v); },\n }),\n\n form.cwd !== undefined\n ? createElement('div', { className: 'imqb2-field' },\n createElement('div', { className: 'imqb2-head' },\n createElement('span', { className: 'imqb2-label' }, 'Agent 工作目录'),\n createElement('span', { className: 'imqb2-hint' }, '只读'),\n ),\n createElement('p', { className: 'imqb2-readonly' }, form.cwd),\n )\n : null,\n\n createElement('div', { className: 'imqb2-footer' },\n result !== null\n ? createElement('p', { className: `imqb2-note${result.ok ? ' imqb2-note--ok' : ' imqb2-note--error'}` },\n (result.ok ? '' : '⚠️ ') + result.message)\n : dirty\n ? createElement('p', { className: 'imqb2-note' }, '保存后插件将重载,进行中的机器人会话将重置')\n : createElement('p', { className: 'imqb2-note' }),\n createElement('button', { className: 'imqb2-save', type: 'submit', disabled: busy || !dirty },\n busy ? '正在保存…' : '保存'),\n ),\n );\n}\n","/**\n * im-qqbot 浏览器半边 —— QQ Bot 端内扫码绑定入口\n *\n * 宿主插件在凭据缺失时注册 /qqbot/im-qqbot/bind 状态路由;本插件在\n * Web / Desktop 提供两个展示位:\n *\n * 1. 设置页「QQ Bot」栏目(settings.section 席位)——注册即展示,\n * 无 Session surface 时序依赖,待绑定/已绑定状态常驻可见;\n * 2. 右侧栏「QQ Bot 绑定」页(sidebarRightTabs)——Start 页入口 +\n * 待绑定时自动打开(失败随轮询重试)。\n *\n * 运行时依赖仅 react(客户端平台种子表提供);宿主服务经 cordis inject\n * 声明访问(声明缺失时插件保持 inactive,不阻塞浏览器启动)。\n */\nimport type { Context } from '@deepseek-ai/cordis';\nimport { createElement, type ReactNode } from 'react';\nimport { BIND_STATE_PATH } from '../shared/bind-protocol.ts';\nimport { BindPanelBody } from './bind-page.ts';\nimport { ConfigPanel } from './config-panel.ts';\n\nexport const name = 'im-qqbot-client';\nexport const inject = ['slots', 'sidebarRight', 'sidebarRightTabs'];\n\n/** 侧栏 Tab 类型(ui-sidebar-right 契约的局部投影) */\nconst TAB_KIND = 'qqbot-bind';\n/** 席位注册 key(Tab 类型 id,席位按其分发;只需全局唯一,与包名解耦) */\nconst TAB_ID = 'im-qqbot/bind';\n\n/** ui-sidebar-right 的 Tab 注册表服务(局部投影) */\ninterface TabRegistryLike {\n register(definition: {\n id: string;\n kind: string;\n title: (address: string) => string;\n guide?: ReadonlyArray<{\n id: string;\n order: number;\n title: () => string;\n description: () => string;\n icon: unknown;\n }>;\n }): () => void;\n}\n\n/** ui-sidebar-right 的导航控制器服务(局部投影) */\ninterface SidebarRightLike {\n openTab(kind: string, options?: Record<string, unknown>): unknown;\n}\n\n/** ui-slots 的席位系统服务(局部投影) */\ninterface SlotsLike {\n inject(slotName: string, register: () => (() => void)): () => void;\n register(spec: Record<string, unknown>, component: unknown): () => void;\n}\n\n/** 绑定入口图标(QQ 机器人,跟随主题图标色变量) */\nfunction BindGuideIcon(): ReactNode {\n return createElement('svg', {\n width: 24, height: 24, viewBox: '0 0 24 24', fill: 'none', 'aria-hidden': true,\n },\n createElement('path', {\n d: 'M9.50039 11.1504C9.96983 11.1504 10.3504 11.5309 10.3504 12.0004V14.0004C10.3504 14.4698 9.96983 14.8504 9.50039 14.8504C9.03095 14.8504 8.65039 14.4698 8.65039 14.0004V12.0004C8.65039 11.5309 9.03095 11.1504 9.50039 11.1504Z',\n fill: 'var(------icon_primary, #1A1A1A)',\n }),\n createElement('path', {\n d: 'M14.5004 11.1504C14.9698 11.1504 15.3504 11.5309 15.3504 12.0004V14.0004C15.3504 14.4698 14.9698 14.8504 14.5004 14.8504C14.0309 14.8504 13.6504 14.4698 13.6504 14.0004V12.0004C13.6504 11.5309 14.0309 11.1504 14.5004 11.1504Z',\n fill: 'var(------icon_primary, #1A1A1A)',\n }),\n createElement('path', {\n fillRule: 'evenodd',\n clipRule: 'evenodd',\n d: 'M12.8504 5.3109C13.5299 4.99138 14.0004 4.30063 14.0004 3.5C14.0004 2.39543 13.1049 1.5 12.0004 1.5C10.8958 1.5 10.0004 2.39543 10.0004 3.5C10.0004 4.30065 10.4708 4.99141 11.1504 5.31092V6.18851C6.38487 6.61795 2.65039 10.6231 2.65039 15.5004V17.0004C2.65039 19.679 4.82181 21.8504 7.50039 21.8504H16.5004C19.179 21.8504 21.3504 19.679 21.3504 17.0004V15.5004C21.3504 10.6231 17.6159 6.61795 12.8504 6.18851V5.3109ZM12.0004 7.85039C7.77541 7.85039 4.35039 11.2754 4.35039 15.5004V17.0004C4.35039 18.7401 5.76069 20.1504 7.50039 20.1504H16.5004C18.2401 20.1504 19.6504 18.7401 19.6504 17.0004V15.5004C19.6504 11.2754 16.2254 7.85039 12.0004 7.85039Z',\n fill: 'var(------icon_primary, #1A1A1A)',\n }),\n );\n}\n\n/** 设置页「QQ Bot」栏目:面板常驻展示绑定状态 */\nfunction QQBotSettingsSection(): ReactNode {\n return createElement('div', null,\n createElement(BindPanelBody),\n createElement(ConfigPanel),\n );\n}\n\nexport function apply(ctx: Context): void {\n const tabs = (ctx as unknown as { sidebarRightTabs?: TabRegistryLike }).sidebarRightTabs;\n const right = (ctx as unknown as { sidebarRight?: SidebarRightLike }).sidebarRight;\n const slots = (ctx as unknown as { slots?: SlotsLike }).slots;\n\n const disposers: Array<() => void> = [];\n\n // 1. 设置页「QQ Bot」栏目(主展示位:注册即展示,无时序依赖)\n if (slots !== undefined) {\n disposers.push( slots.inject('settings.section', () => slots.register(\n { name: 'settings.section', id: 'qqbot', order: 7, label: 'QQ 机器人' },\n QQBotSettingsSection,\n )));\n }\n\n // 2. 侧栏绑定页(快捷展示位:Start 页入口 + 待绑定自动打开)\n if (tabs !== undefined && slots !== undefined) {\n disposers.push(tabs.register({\n id: TAB_ID,\n kind: TAB_KIND,\n title: () => 'QQ 机器人绑定',\n guide: [{\n id: 'bind',\n order: 90,\n title: () => 'QQ 机器人绑定',\n description: () => '扫码或手动填写,绑定 QQ 机器人',\n icon: BindGuideIcon,\n }],\n }));\n disposers.push(slots.inject('sidebar.right.pane.tab', () => slots.register(\n { name: 'sidebar.right.pane.tab', key: TAB_ID },\n BindPanelBody,\n )));\n // 待绑定检测与自动引导\n disposers.push(watchAndPrompt(right));\n }\n\n (ctx as unknown as { effect(fn: () => () => void, name?: string): void }).effect(() => () => {\n for (const dispose of disposers.reverse()) dispose();\n }, 'im-qqbot-client.binding');\n}\n\n/**\n * 轮询绑定状态:待绑定时自动打开绑定页。\n *\n * - 页面隐藏时降频轮询(可见时立即恢复节拍)\n * - 404(已绑定/未安装)时退避到 30s,保持低成本常驻探测\n * - 每次页面加载至多打开一次(用户手动关闭后不打扰);\n * 打开失败(如启动早期 Session surface 尚未挂载)不消费机会,\n * 由下一轮轮询(3s)自动重试\n */\nfunction watchAndPrompt(right: SidebarRightLike | undefined): () => void {\n let stopped = false;\n let opened = right === undefined;\n let timer: ReturnType<typeof setTimeout> | undefined;\n\n const schedule = (ms: number): void => {\n timer = setTimeout(() => { void tick(); }, ms);\n };\n\n const tick = async (): Promise<void> => {\n if (stopped) return;\n if (typeof document !== 'undefined' && document.visibilityState === 'hidden') {\n schedule(5000);\n return;\n }\n try {\n const res = await fetch(BIND_STATE_PATH, { cache: 'no-store' });\n if (res.ok) {\n const body = (await res.json()) as { phase?: string };\n if (body.phase === 'waiting' && !opened && right !== undefined) {\n try {\n right.openTab(TAB_KIND);\n opened = true;\n } catch (err) {\n // 启动早期 Session surface 可能尚未挂载:保留机会,3s 后随轮询重试\n console.error('[im-qqbot] 打开绑定页失败,稍后重试', err);\n }\n }\n schedule(3000);\n return;\n }\n // 404:已绑定或插件未启用\n schedule(30000);\n return;\n } catch {\n // 宿主暂不可达(启动窗口期):退避重试\n }\n schedule(10000);\n };\n\n void tick();\n return () => { stopped = true; if (timer !== undefined) clearTimeout(timer); };\n}\n"],"mappings":"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"}
|