@zaofan/dsh-qqbot 0.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (227) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +308 -0
  3. package/README_EN.md +273 -0
  4. package/client/qqbot-settings.js +1463 -0
  5. package/cordis.patch.yml +36 -0
  6. package/dist/api/group-admin.d.ts +112 -0
  7. package/dist/api/group-admin.d.ts.map +1 -0
  8. package/dist/api/group-admin.js +179 -0
  9. package/dist/api/group-admin.js.map +1 -0
  10. package/dist/channel-tools.d.ts +14 -0
  11. package/dist/channel-tools.d.ts.map +1 -0
  12. package/dist/channel-tools.js +880 -0
  13. package/dist/channel-tools.js.map +1 -0
  14. package/dist/commands/help.d.ts +11 -0
  15. package/dist/commands/help.d.ts.map +1 -0
  16. package/dist/commands/help.js +21 -0
  17. package/dist/commands/help.js.map +1 -0
  18. package/dist/commands/index.d.ts +13 -0
  19. package/dist/commands/index.d.ts.map +1 -0
  20. package/dist/commands/index.js +29 -0
  21. package/dist/commands/index.js.map +1 -0
  22. package/dist/commands/misc.d.ts +14 -0
  23. package/dist/commands/misc.d.ts.map +1 -0
  24. package/dist/commands/misc.js +39 -0
  25. package/dist/commands/misc.js.map +1 -0
  26. package/dist/commands/model.d.ts +7 -0
  27. package/dist/commands/model.d.ts.map +1 -0
  28. package/dist/commands/model.js +58 -0
  29. package/dist/commands/model.js.map +1 -0
  30. package/dist/commands/session.d.ts +10 -0
  31. package/dist/commands/session.d.ts.map +1 -0
  32. package/dist/commands/session.js +26 -0
  33. package/dist/commands/session.js.map +1 -0
  34. package/dist/commands/status.d.ts +8 -0
  35. package/dist/commands/status.d.ts.map +1 -0
  36. package/dist/commands/status.js +24 -0
  37. package/dist/commands/status.js.map +1 -0
  38. package/dist/commands/types.d.ts +12 -0
  39. package/dist/commands/types.d.ts.map +1 -0
  40. package/dist/commands/types.js +2 -0
  41. package/dist/commands/types.js.map +1 -0
  42. package/dist/config.d.ts +205 -0
  43. package/dist/config.d.ts.map +1 -0
  44. package/dist/config.js +203 -0
  45. package/dist/config.js.map +1 -0
  46. package/dist/features/chat-ledger.d.ts +53 -0
  47. package/dist/features/chat-ledger.d.ts.map +1 -0
  48. package/dist/features/chat-ledger.js +185 -0
  49. package/dist/features/chat-ledger.js.map +1 -0
  50. package/dist/features/face-tags.d.ts +17 -0
  51. package/dist/features/face-tags.d.ts.map +1 -0
  52. package/dist/features/face-tags.js +79 -0
  53. package/dist/features/face-tags.js.map +1 -0
  54. package/dist/features/group-join-request.d.ts +65 -0
  55. package/dist/features/group-join-request.d.ts.map +1 -0
  56. package/dist/features/group-join-request.js +190 -0
  57. package/dist/features/group-join-request.js.map +1 -0
  58. package/dist/features/history-store.d.ts +8 -0
  59. package/dist/features/history-store.d.ts.map +1 -0
  60. package/dist/features/history-store.js +24 -0
  61. package/dist/features/history-store.js.map +1 -0
  62. package/dist/features/qq-approval.d.ts +78 -0
  63. package/dist/features/qq-approval.d.ts.map +1 -0
  64. package/dist/features/qq-approval.js +165 -0
  65. package/dist/features/qq-approval.js.map +1 -0
  66. package/dist/features/schedule-store.d.ts +62 -0
  67. package/dist/features/schedule-store.d.ts.map +1 -0
  68. package/dist/features/schedule-store.js +253 -0
  69. package/dist/features/schedule-store.js.map +1 -0
  70. package/dist/features/scheduler.d.ts +9 -0
  71. package/dist/features/scheduler.d.ts.map +1 -0
  72. package/dist/features/scheduler.js +146 -0
  73. package/dist/features/scheduler.js.map +1 -0
  74. package/dist/features/sticker-gate.d.ts +90 -0
  75. package/dist/features/sticker-gate.d.ts.map +1 -0
  76. package/dist/features/sticker-gate.js +391 -0
  77. package/dist/features/sticker-gate.js.map +1 -0
  78. package/dist/features/sticker-store.d.ts +158 -0
  79. package/dist/features/sticker-store.d.ts.map +1 -0
  80. package/dist/features/sticker-store.js +676 -0
  81. package/dist/features/sticker-store.js.map +1 -0
  82. package/dist/features/sticker-tagger.d.ts +10 -0
  83. package/dist/features/sticker-tagger.d.ts.map +1 -0
  84. package/dist/features/sticker-tagger.js +139 -0
  85. package/dist/features/sticker-tagger.js.map +1 -0
  86. package/dist/gateway/bootstrap.d.ts +12 -0
  87. package/dist/gateway/bootstrap.d.ts.map +1 -0
  88. package/dist/gateway/bootstrap.js +346 -0
  89. package/dist/gateway/bootstrap.js.map +1 -0
  90. package/dist/gateway/debounce.d.ts +40 -0
  91. package/dist/gateway/debounce.d.ts.map +1 -0
  92. package/dist/gateway/debounce.js +262 -0
  93. package/dist/gateway/debounce.js.map +1 -0
  94. package/dist/gateway/index.d.ts +3 -0
  95. package/dist/gateway/index.d.ts.map +1 -0
  96. package/dist/gateway/index.js +3 -0
  97. package/dist/gateway/index.js.map +1 -0
  98. package/dist/gateway/middleware-setup.d.ts +12 -0
  99. package/dist/gateway/middleware-setup.d.ts.map +1 -0
  100. package/dist/gateway/middleware-setup.js +156 -0
  101. package/dist/gateway/middleware-setup.js.map +1 -0
  102. package/dist/index.d.ts +14 -0
  103. package/dist/index.d.ts.map +1 -0
  104. package/dist/index.js +187 -0
  105. package/dist/index.js.map +1 -0
  106. package/dist/middleware/attachment.d.ts +11 -0
  107. package/dist/middleware/attachment.d.ts.map +1 -0
  108. package/dist/middleware/attachment.js +17 -0
  109. package/dist/middleware/attachment.js.map +1 -0
  110. package/dist/middleware/media-history.d.ts +30 -0
  111. package/dist/middleware/media-history.d.ts.map +1 -0
  112. package/dist/middleware/media-history.js +54 -0
  113. package/dist/middleware/media-history.js.map +1 -0
  114. package/dist/middleware/sticker-capture.d.ts +17 -0
  115. package/dist/middleware/sticker-capture.d.ts.map +1 -0
  116. package/dist/middleware/sticker-capture.js +97 -0
  117. package/dist/middleware/sticker-capture.js.map +1 -0
  118. package/dist/model/index.d.ts +10 -0
  119. package/dist/model/index.d.ts.map +1 -0
  120. package/dist/model/index.js +9 -0
  121. package/dist/model/index.js.map +1 -0
  122. package/dist/model/model-resolver.d.ts +88 -0
  123. package/dist/model/model-resolver.d.ts.map +1 -0
  124. package/dist/model/model-resolver.js +151 -0
  125. package/dist/model/model-resolver.js.map +1 -0
  126. package/dist/model/prefs-store.d.ts +24 -0
  127. package/dist/model/prefs-store.d.ts.map +1 -0
  128. package/dist/model/prefs-store.js +126 -0
  129. package/dist/model/prefs-store.js.map +1 -0
  130. package/dist/model/settings-reader.d.ts +19 -0
  131. package/dist/model/settings-reader.d.ts.map +1 -0
  132. package/dist/model/settings-reader.js +76 -0
  133. package/dist/model/settings-reader.js.map +1 -0
  134. package/dist/model/types.d.ts +15 -0
  135. package/dist/model/types.d.ts.map +1 -0
  136. package/dist/model/types.js +5 -0
  137. package/dist/model/types.js.map +1 -0
  138. package/dist/session/idle-evictor.d.ts +18 -0
  139. package/dist/session/idle-evictor.d.ts.map +1 -0
  140. package/dist/session/idle-evictor.js +31 -0
  141. package/dist/session/idle-evictor.js.map +1 -0
  142. package/dist/session/index.d.ts +9 -0
  143. package/dist/session/index.d.ts.map +1 -0
  144. package/dist/session/index.js +8 -0
  145. package/dist/session/index.js.map +1 -0
  146. package/dist/session/session-manager.d.ts +97 -0
  147. package/dist/session/session-manager.d.ts.map +1 -0
  148. package/dist/session/session-manager.js +624 -0
  149. package/dist/session/session-manager.js.map +1 -0
  150. package/dist/session/types.d.ts +130 -0
  151. package/dist/session/types.d.ts.map +1 -0
  152. package/dist/session/types.js +2 -0
  153. package/dist/session/types.js.map +1 -0
  154. package/dist/session/workspace-attach.d.ts +22 -0
  155. package/dist/session/workspace-attach.d.ts.map +1 -0
  156. package/dist/session/workspace-attach.js +21 -0
  157. package/dist/session/workspace-attach.js.map +1 -0
  158. package/dist/setup.d.ts +25 -0
  159. package/dist/setup.d.ts.map +1 -0
  160. package/dist/setup.js +198 -0
  161. package/dist/setup.js.map +1 -0
  162. package/dist/shared/index.d.ts +7 -0
  163. package/dist/shared/index.d.ts.map +1 -0
  164. package/dist/shared/index.js +7 -0
  165. package/dist/shared/index.js.map +1 -0
  166. package/dist/shared/scope.d.ts +14 -0
  167. package/dist/shared/scope.d.ts.map +1 -0
  168. package/dist/shared/scope.js +12 -0
  169. package/dist/shared/scope.js.map +1 -0
  170. package/dist/shared/send-helper.d.ts +11 -0
  171. package/dist/shared/send-helper.d.ts.map +1 -0
  172. package/dist/shared/send-helper.js +13 -0
  173. package/dist/shared/send-helper.js.map +1 -0
  174. package/dist/shared/utils.d.ts +28 -0
  175. package/dist/shared/utils.d.ts.map +1 -0
  176. package/dist/shared/utils.js +143 -0
  177. package/dist/shared/utils.js.map +1 -0
  178. package/dist/transport/attachment.d.ts +18 -0
  179. package/dist/transport/attachment.d.ts.map +1 -0
  180. package/dist/transport/attachment.js +106 -0
  181. package/dist/transport/attachment.js.map +1 -0
  182. package/dist/transport/chunker.d.ts +14 -0
  183. package/dist/transport/chunker.d.ts.map +1 -0
  184. package/dist/transport/chunker.js +78 -0
  185. package/dist/transport/chunker.js.map +1 -0
  186. package/dist/transport/events.d.ts +80 -0
  187. package/dist/transport/events.d.ts.map +1 -0
  188. package/dist/transport/events.js +62 -0
  189. package/dist/transport/events.js.map +1 -0
  190. package/dist/transport/inbound.d.ts +8 -0
  191. package/dist/transport/inbound.d.ts.map +1 -0
  192. package/dist/transport/inbound.js +292 -0
  193. package/dist/transport/inbound.js.map +1 -0
  194. package/dist/transport/index.d.ts +10 -0
  195. package/dist/transport/index.d.ts.map +1 -0
  196. package/dist/transport/index.js +10 -0
  197. package/dist/transport/index.js.map +1 -0
  198. package/dist/transport/inject-rules.d.ts +24 -0
  199. package/dist/transport/inject-rules.d.ts.map +1 -0
  200. package/dist/transport/inject-rules.js +72 -0
  201. package/dist/transport/inject-rules.js.map +1 -0
  202. package/dist/transport/outbound-buffer.d.ts +56 -0
  203. package/dist/transport/outbound-buffer.d.ts.map +1 -0
  204. package/dist/transport/outbound-buffer.js +131 -0
  205. package/dist/transport/outbound-buffer.js.map +1 -0
  206. package/dist/transport/outbound.d.ts +30 -0
  207. package/dist/transport/outbound.d.ts.map +1 -0
  208. package/dist/transport/outbound.js +139 -0
  209. package/dist/transport/outbound.js.map +1 -0
  210. package/dist/transport/rich-media.d.ts +41 -0
  211. package/dist/transport/rich-media.d.ts.map +1 -0
  212. package/dist/transport/rich-media.js +104 -0
  213. package/dist/transport/rich-media.js.map +1 -0
  214. package/dist/transport/streaming-writer.d.ts +47 -0
  215. package/dist/transport/streaming-writer.d.ts.map +1 -0
  216. package/dist/transport/streaming-writer.js +110 -0
  217. package/dist/transport/streaming-writer.js.map +1 -0
  218. package/dist/transport/tool-presenter.d.ts +38 -0
  219. package/dist/transport/tool-presenter.d.ts.map +1 -0
  220. package/dist/transport/tool-presenter.js +121 -0
  221. package/dist/transport/tool-presenter.js.map +1 -0
  222. package/dist/types.d.ts +45 -0
  223. package/dist/types.d.ts.map +1 -0
  224. package/dist/types.js +5 -0
  225. package/dist/types.js.map +1 -0
  226. package/package.json +106 -0
  227. package/settings-host.js +927 -0
package/dist/index.js ADDED
@@ -0,0 +1,187 @@
1
+ import { ConfigSchema, EditableConfigSchema } from './config.js';
2
+ import { bootstrapGateway } from './gateway/index.js';
3
+ import { getProfileDir, resolveEnv } from './shared/index.js';
4
+ import { runQrSetup, persistCredentialsToProfile } from './setup.js';
5
+ // ⚠️ @deepseek-ai/dsh-settings 的"注册 Web 可视化设置"入口在 harness 各版本间有差异:
6
+ // - rc.2 及更早:模块顶层具名导出 installSettingsSection(ctx, ns, schema, entry, hooks)
7
+ // - alpha / 0.1.2 线:改为 ctx.settings 服务,方法 installSection(ctx, ns, schema, entry, hooks)
8
+ // 直接 `import { installSettingsSection } from '@deepseek-ai/dsh-settings'` 是"静态具名导入",
9
+ // 一旦运行库没有该具名导出,模块一加载就抛 SyntaxError,会拖垮整棵插件树(dsh 都起不来)。
10
+ // 因此这里不静态导入,而在运行时动态探测两条路径,缺一条也能优雅降级(见 installLiveSettings)。
11
+ // ── Cordis 插件元数据 ──
12
+ export const name = 'im-qqbot';
13
+ export const inject = ['agents'];
14
+ export const Config = ConfigSchema;
15
+ // ── 插件主体 ──
16
+ export async function apply(ctx, config) {
17
+ const agents = ctx.agents;
18
+ const logger = ctx.logger ?? console;
19
+ console.log('[im-qqbot] apply() called');
20
+ // 多账号实例身份: settingsNs 承担"实例 id"(账号页保存时写入, 默认 im-qqbot=主账号)。
21
+ const ns = (config.settingsNs ?? '').trim() || 'im-qqbot';
22
+ const isMain = ns === 'im-qqbot';
23
+ let appId = resolveEnv(config.appId, 'QQBOT_APPID');
24
+ let appSecret = resolveEnv(config.appSecret, 'QQBOT_SECRET');
25
+ // ── 凭据缺失 ──
26
+ if (!appId || !appSecret) {
27
+ // 非主实例: 绝不触发扫码/env 覆写(防把凭据写进主账号或污染全局 env)——
28
+ // 去 Web「账号与预设」用"扫码绑定"或手动填好 appId/appSecret 后保存, 重启生效。
29
+ if (!isMain) {
30
+ logger.error(`实例 ${ns}: 未配置 appId/appSecret——请在 Web「账号与预设」为该账号完成扫码绑定或填写凭据后保存(重启生效), 本实例本次不启动。`);
31
+ return;
32
+ }
33
+ logger.info('凭据未配置,尝试扫码绑定...');
34
+ const credentials = await runQrSetup();
35
+ if (!credentials) {
36
+ logger.error('无法获取 QQ Bot 凭据,插件未启动');
37
+ return;
38
+ }
39
+ // 写入环境变量(供热更新后的下次 apply 或本次直接启动读取)
40
+ process.env.QQBOT_APPID = credentials.appId;
41
+ process.env.QQBOT_SECRET = credentials.appSecret;
42
+ appId = credentials.appId;
43
+ appSecret = credentials.appSecret;
44
+ // 持久化到 profile:成功则等待热更新重载,失败则用 env 凭据直接启动
45
+ const persisted = persistCredentialsToProfile(credentials, getProfileDir() ?? undefined, logger);
46
+ if (persisted) {
47
+ // 写入 cordis.patch.yml 会触发 dsh 热更新,自动重新加载本插件。
48
+ // 直接返回,避免与热更新产生竞态。
49
+ logger.info('配置已保存,等待热更新重新加载...');
50
+ return;
51
+ }
52
+ logger.warn('凭据未能持久化,本次进程将使用环境变量凭据启动(重启后需重新绑定)');
53
+ }
54
+ const resolvedConfig = { ...config, appId, appSecret };
55
+ // ── Web 可视化设置: 注册 im-qqbot settings 命名空间(可编辑子集, live 生效) ──
56
+ // 用户层存 ~/.dsh/settings.yaml; 变更经 watch 原地覆盖 resolvedConfig 对应字段,
57
+ // 下游消费点(middleware/inbound)每次读取 config → 热生效。settings 服务缺失则跳过(纯 yml 模式)。
58
+ try {
59
+ await installLiveSettings(ctx, resolvedConfig, logger, ns);
60
+ }
61
+ catch (err) {
62
+ logger.warn?.(`im-qqbot: settings 注册跳过: ${err instanceof Error ? err.message : String(err)}`);
63
+ }
64
+ // ── 设置面板 host 桥(单包自含, 原 dsh-qqbot-settings 独立包合并而来) ──
65
+ // 桥是标准 cordis 插件(需要 settings/webServer/agentPresets 服务, 仅 web profile 有);
66
+ // 这里用 ctx.plugin 动态装载, 服务缺失时 fail-soft(纯 yml/非 web 环境跳过, 不拖垮插件树)。
67
+ try {
68
+ const bridgeUrl = new URL('../settings-host.js', import.meta.url).href;
69
+ const bridgeMod = (await import(bridgeUrl));
70
+ if (bridgeMod && typeof bridgeMod.apply === 'function') {
71
+ ctx.plugin({ name: bridgeMod.name ?? 'qqbot-settings', inject: bridgeMod.inject, apply: bridgeMod.apply });
72
+ logger.info('[im-qqbot] settings host 桥已装载(单包)');
73
+ }
74
+ else {
75
+ logger.warn('[im-qqbot] settings-host.js 缺少 apply, 桥跳过');
76
+ }
77
+ }
78
+ catch (err) {
79
+ logger.warn?.(`im-qqbot: settings host 桥装载跳过: ${err instanceof Error ? err.message : String(err)}`);
80
+ }
81
+ await bootstrapGateway(ctx, agents, resolvedConfig, logger);
82
+ }
83
+ /** 把 settings 用户层合并进 live 运行时配置(原地字段替换; schema 解析值含默认, 可整体覆盖) */
84
+ async function installLiveSettings(ctx, live, logger, nsOverride) {
85
+ const ns = nsOverride || (live.settingsNs ?? '').trim() || 'im-qqbot';
86
+ const entry = {
87
+ behavior: live.behavior,
88
+ sticker: {
89
+ gates: live.sticker.gates,
90
+ autoTagEnabled: live.sticker.autoTagEnabled,
91
+ visionCli: live.sticker.visionCli,
92
+ },
93
+ injectRules: live.injectRules,
94
+ groupPrompt: live.groupPrompt,
95
+ schedule: live.schedule,
96
+ groupAdmin: live.groupAdmin,
97
+ enableApprovals: live.enableApprovals,
98
+ approvalTimeoutMs: live.approvalTimeoutMs,
99
+ };
100
+ let source = () => entry;
101
+ const sync = () => {
102
+ try {
103
+ const next = source();
104
+ if (!next)
105
+ return;
106
+ if (next.behavior)
107
+ live.behavior = next.behavior;
108
+ if (next.sticker)
109
+ live.sticker = { ...live.sticker, ...next.sticker };
110
+ if (Array.isArray(next.injectRules))
111
+ live.injectRules = next.injectRules;
112
+ if (typeof next.groupPrompt === 'string')
113
+ live.groupPrompt = next.groupPrompt;
114
+ if (next.schedule)
115
+ live.schedule = next.schedule;
116
+ if (next.groupAdmin)
117
+ live.groupAdmin = next.groupAdmin;
118
+ if (typeof next.enableApprovals === 'boolean')
119
+ live.enableApprovals = next.enableApprovals;
120
+ if (typeof next.approvalTimeoutMs === 'number')
121
+ live.approvalTimeoutMs = next.approvalTimeoutMs;
122
+ logger.info('[im-qqbot] 设置已同步(live): behavior/sticker/injectRules/groupPrompt/schedule/groupAdmin/approvals');
123
+ }
124
+ catch (err) {
125
+ logger.warn?.(`im-qqbot: 设置同步失败: ${err instanceof Error ? err.message : String(err)}`);
126
+ }
127
+ };
128
+ const hooks = {
129
+ setSource: (s) => { source = s; sync(); },
130
+ onChange: () => sync(),
131
+ };
132
+ const installed = await registerSettingsSection(ctx, ns, EditableConfigSchema, entry, hooks, logger);
133
+ if (installed) {
134
+ logger.info(`[im-qqbot:${ns}] settings 命名空间已注册 (${ns})`);
135
+ }
136
+ }
137
+ /**
138
+ * 版本自适应注册。两条路径语义等价:
139
+ * 1) 新版(alpha / dsh-settings 0.1.2 线): ctx.inject(['settings'], sc => sc.settings.installSection(ctx, ns, schema, entry, hooks))
140
+ * —— 官方样板(dsh-bash-local 等): 服务经 cordis 声明式注入, 直读 ctx.settings / ctx.get 拿不到!
141
+ * 2) 旧版(rc.2): @deepseek-ai/dsh-settings 的 installSettingsSection(ctx, ns, schema, entry, hooks)
142
+ * 优先新版(harness 自带服务);旧版包在时兜底;都不可用则返回 false(纯 yml 模式, 不中断插件)。
143
+ */
144
+ async function registerSettingsSection(ctx, ns, schema, entry, hooks, logger) {
145
+ // 1) 新版: ctx.inject(['settings'], …) 声明式注入(官方用法)
146
+ const injectable = ctx;
147
+ if (typeof injectable.inject === 'function') {
148
+ try {
149
+ injectable.inject(['settings'], (settingsCtx) => {
150
+ try {
151
+ const svc = settingsCtx.settings;
152
+ if (svc && typeof svc.installSection === 'function') {
153
+ svc.installSection(ctx, ns, schema, entry, hooks);
154
+ logger.info(`[im-qqbot:${ns}] settings 命名空间已注册 (${ns})`);
155
+ return;
156
+ }
157
+ }
158
+ catch (err) {
159
+ logger.warn?.(`im-qqbot: settings 注入注册失败: ${err instanceof Error ? err.message : String(err)}`);
160
+ }
161
+ void legacyRegister(ctx, ns, schema, entry, hooks, logger);
162
+ });
163
+ // inject 回调若为同步执行且已尝试, 视为已处理; 无法探测是否成功, 交由回调日志确认。
164
+ return true;
165
+ }
166
+ catch { /* inject 不可用则走下方 legacy */ }
167
+ }
168
+ return legacyRegister(ctx, ns, schema, entry, hooks, logger);
169
+ }
170
+ /** 旧版 @deepseek-ai/dsh-settings 具名导出(运行时动态探测, 避免静态导入拖垮启动) */
171
+ async function legacyRegister(ctx, ns, schema, entry, hooks, logger) {
172
+ try {
173
+ const mod = (await import('@deepseek-ai/dsh-settings'));
174
+ if (typeof mod.installSettingsSection === 'function') {
175
+ const brandedNs = typeof mod.settingsNamespace === 'function' ? mod.settingsNamespace(ns) : ns;
176
+ mod.installSettingsSection(ctx, brandedNs, schema, entry, hooks);
177
+ logger.info(`[im-qqbot:${ns}] settings 命名空间已注册(legacy) (${String(brandedNs)})`);
178
+ return true;
179
+ }
180
+ }
181
+ catch (err) {
182
+ logger.warn?.(`im-qqbot: 旧版 dsh-settings 探测失败: ${err instanceof Error ? err.message : String(err)}`);
183
+ }
184
+ logger.warn?.('im-qqbot: 当前 harness 未暴露可用的 settings 注册 API,跳过可视化设置(仍可用纯 yml/补丁配置)。');
185
+ return false;
186
+ }
187
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,11 @@
1
+ /**
2
+ * 附件下载中间件 — 在中间件链中下载 file 附件
3
+ *
4
+ * 结果写入 ctx.state.downloadedFiles,供 handleInbound 读取。
5
+ * 下载失败不阻断消息(记录告警后放行),确保附件异常不影响正常文本处理。
6
+ */
7
+ import type { MiddlewareContext } from '@tencent-connect/qqbot-nodejs';
8
+ import type { ImQQBotConfig } from '../config.js';
9
+ import type { Logger } from '../types.js';
10
+ export declare function attachmentProcessor(config: ImQQBotConfig, logger: Logger): (ctx: MiddlewareContext, next: () => Promise<void>) => Promise<void>;
11
+ //# sourceMappingURL=attachment.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"attachment.d.ts","sourceRoot":"","sources":["../../src/middleware/attachment.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,+BAA+B,CAAC;AAEvE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAClD,OAAO,KAAK,EAAE,MAAM,EAAiB,MAAM,aAAa,CAAC;AAEzD,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,aAAa,EAAE,MAAM,EAAE,MAAM,IACzD,KAAK,iBAAiB,EAAE,MAAM,MAAM,OAAO,CAAC,IAAI,CAAC,KAAG,OAAO,CAAC,IAAI,CAAC,CAchF"}
@@ -0,0 +1,17 @@
1
+ import { downloadFileAttachments } from '../transport/attachment.js';
2
+ export function attachmentProcessor(config, logger) {
3
+ return async (ctx, next) => {
4
+ const msg = ctx.message;
5
+ const cwd = config.cwd || process.cwd();
6
+ const messageId = msg.messageId ?? 'unknown';
7
+ try {
8
+ const downloaded = await downloadFileAttachments(msg.attachments, cwd, messageId, logger);
9
+ ctx.state.downloadedFiles = downloaded;
10
+ }
11
+ catch (err) {
12
+ logger.warn(`im-qqbot: attachment download failed: ${err instanceof Error ? err.message : String(err)}`);
13
+ }
14
+ await next();
15
+ };
16
+ }
17
+ //# sourceMappingURL=attachment.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"attachment.js","sourceRoot":"","sources":["../../src/middleware/attachment.ts"],"names":[],"mappings":"AAOA,OAAO,EAAE,uBAAuB,EAAE,MAAM,4BAA4B,CAAC;AAIrE,MAAM,UAAU,mBAAmB,CAAC,MAAqB,EAAE,MAAc;IACvE,OAAO,KAAK,EAAE,GAAsB,EAAE,IAAyB,EAAiB,EAAE;QAChF,MAAM,GAAG,GAAG,GAAG,CAAC,OAAgE,CAAC;QACjF,MAAM,GAAG,GAAG,MAAM,CAAC,GAAG,IAAI,OAAO,CAAC,GAAG,EAAE,CAAC;QACxC,MAAM,SAAS,GAAG,GAAG,CAAC,SAAS,IAAI,SAAS,CAAC;QAE7C,IAAI,CAAC;YACH,MAAM,UAAU,GAAG,MAAM,uBAAuB,CAAC,GAAG,CAAC,WAAW,EAAE,GAAG,EAAE,SAAS,EAAE,MAAM,CAAC,CAAC;YAC1F,GAAG,CAAC,KAAK,CAAC,eAAe,GAAG,UAAU,CAAC;QACzC,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,MAAM,CAAC,IAAI,CAAC,yCAAyC,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QAC3G,CAAC;QAED,MAAM,IAAI,EAAE,CAAC;IACf,CAAC,CAAC;AACJ,CAAC"}
@@ -0,0 +1,30 @@
1
+ /**
2
+ * media-history.ts — 增强版群历史缓冲(媒体 URL 可见)
3
+ *
4
+ * 替换 SDK 的 historyBuffer:SDK 版记历史时只存文本 content,
5
+ * 图片消息 content 为空 → 历史里的图对 AI 不可见(看不到图片链接)。
6
+ * 本中间件在记录时把带 URL 的附件折叠成 "[图片: <url>]" 等文本并入 content,
7
+ * 让冷却派发 / 下次 @ 打包群历史时,图片/媒体链接也进 AI 上下文。
8
+ *
9
+ * ⚠️ 本地手改功能(SDK 无此能力,重编译/换回 SDK 原版会丢):
10
+ * 维护清单见工作区根《插件改动维护注意事项.md》。
11
+ */
12
+ import type { Middleware, MiddlewareContext } from '@tencent-connect/qqbot-nodejs';
13
+ import type { HistoryStore } from '@tencent-connect/qqbot-nodejs';
14
+ export interface MediaHistoryOptions {
15
+ /** 每群保留的最大条数 */
16
+ limit: number;
17
+ /** 存储后端(共享单例,供回复后清空) */
18
+ store: HistoryStore;
19
+ /** 上游 stop 后仍记录(捕获未 @ 的闲聊) */
20
+ recordOnSkip: boolean;
21
+ /** 群 key 推导(带 appId 前缀) */
22
+ groupKey: (ctx: MiddlewareContext) => string | undefined;
23
+ }
24
+ /**
25
+ * 构建增强版群历史缓冲中间件(API 对齐 SDK historyBuffer):
26
+ * 1. 把当前群消息(媒体 URL 折叠进 content)记入 store(去重按 messageId);
27
+ * 2. 向下游暴露 ctx.state.history = 已缓冲历史(不含当前消息,旧→新)。
28
+ */
29
+ export declare function mediaHistoryBuffer(options: MediaHistoryOptions): Middleware;
30
+ //# sourceMappingURL=media-history.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"media-history.d.ts","sourceRoot":"","sources":["../../src/middleware/media-history.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AACH,OAAO,KAAK,EAAE,UAAU,EAAE,iBAAiB,EAAE,MAAM,+BAA+B,CAAC;AACnF,OAAO,KAAK,EAAgB,YAAY,EAAE,MAAM,+BAA+B,CAAC;AAEhF,MAAM,WAAW,mBAAmB;IAClC,gBAAgB;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,wBAAwB;IACxB,KAAK,EAAE,YAAY,CAAC;IACpB,8BAA8B;IAC9B,YAAY,EAAE,OAAO,CAAC;IACtB,2BAA2B;IAC3B,QAAQ,EAAE,CAAC,GAAG,EAAE,iBAAiB,KAAK,MAAM,GAAG,SAAS,CAAC;CAC1D;AAwBD;;;;GAIG;AACH,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,mBAAmB,GAAG,UAAU,CA4B3E"}
@@ -0,0 +1,54 @@
1
+ /** 文本 + 带 URL 附件折叠为一行段(语音 URL 对纯文本模型无意义,跳过) */
2
+ function foldMedia(msg) {
3
+ const parts = [];
4
+ const text = (msg.content ?? '').trim();
5
+ if (text)
6
+ parts.push(text);
7
+ for (const att of msg.attachments ?? []) {
8
+ if (!att.url)
9
+ continue;
10
+ if (att.content_type === 'voice')
11
+ continue; // 无 ASR 时链接无意义,避免刷屏
12
+ const label = att.content_type === 'image' ? '图片'
13
+ : att.content_type === 'video' ? '视频'
14
+ : att.content_type === 'file' ? '文件' : '附件';
15
+ parts.push(`[${label}: ${att.url}]`);
16
+ }
17
+ return parts.join('\n');
18
+ }
19
+ /**
20
+ * 构建增强版群历史缓冲中间件(API 对齐 SDK historyBuffer):
21
+ * 1. 把当前群消息(媒体 URL 折叠进 content)记入 store(去重按 messageId);
22
+ * 2. 向下游暴露 ctx.state.history = 已缓冲历史(不含当前消息,旧→新)。
23
+ */
24
+ export function mediaHistoryBuffer(options) {
25
+ const { limit, store, recordOnSkip, groupKey } = options;
26
+ return async (ctx, next) => {
27
+ const key = groupKey(ctx);
28
+ if (!key) {
29
+ await next();
30
+ return;
31
+ }
32
+ const buffered = await store.list(key, limit);
33
+ ctx.state.history = buffered;
34
+ const raw = ctx.message;
35
+ const entry = {
36
+ senderId: ctx.message.senderId,
37
+ senderName: ctx.message.senderName,
38
+ content: foldMedia(raw),
39
+ timestamp: Date.parse(ctx.message.timestamp) || Date.now(),
40
+ messageId: ctx.message.messageId,
41
+ };
42
+ try {
43
+ await store.append(key, entry, limit);
44
+ }
45
+ catch (err) {
46
+ ctx.log.error?.(`[media-history] append failed: ${err instanceof Error ? err.message : String(err)}`);
47
+ }
48
+ if (ctx.stopped && !recordOnSkip) {
49
+ return;
50
+ }
51
+ await next();
52
+ };
53
+ }
54
+ //# sourceMappingURL=media-history.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"media-history.js","sourceRoot":"","sources":["../../src/middleware/media-history.ts"],"names":[],"mappings":"AA+BA,+CAA+C;AAC/C,SAAS,SAAS,CAAC,GAAgB;IACjC,MAAM,KAAK,GAAa,EAAE,CAAC;IAC3B,MAAM,IAAI,GAAG,CAAC,GAAG,CAAC,OAAO,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC;IACxC,IAAI,IAAI;QAAE,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC3B,KAAK,MAAM,GAAG,IAAI,GAAG,CAAC,WAAW,IAAI,EAAE,EAAE,CAAC;QACxC,IAAI,CAAC,GAAG,CAAC,GAAG;YAAE,SAAS;QACvB,IAAI,GAAG,CAAC,YAAY,KAAK,OAAO;YAAE,SAAS,CAAC,oBAAoB;QAChE,MAAM,KAAK,GAAG,GAAG,CAAC,YAAY,KAAK,OAAO,CAAC,CAAC,CAAC,IAAI;YAC/C,CAAC,CAAC,GAAG,CAAC,YAAY,KAAK,OAAO,CAAC,CAAC,CAAC,IAAI;gBACnC,CAAC,CAAC,GAAG,CAAC,YAAY,KAAK,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC;QAChD,KAAK,CAAC,IAAI,CAAC,IAAI,KAAK,KAAK,GAAG,CAAC,GAAG,GAAG,CAAC,CAAC;IACvC,CAAC;IACD,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAC1B,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,kBAAkB,CAAC,OAA4B;IAC7D,MAAM,EAAE,KAAK,EAAE,KAAK,EAAE,YAAY,EAAE,QAAQ,EAAE,GAAG,OAAO,CAAC;IACzD,OAAO,KAAK,EAAE,GAAsB,EAAE,IAAyB,EAAE,EAAE;QACjE,MAAM,GAAG,GAAG,QAAQ,CAAC,GAAG,CAAC,CAAC;QAC1B,IAAI,CAAC,GAAG,EAAE,CAAC;YACT,MAAM,IAAI,EAAE,CAAC;YACb,OAAO;QACT,CAAC;QACD,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,IAAI,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;QAC9C,GAAG,CAAC,KAAK,CAAC,OAAO,GAAG,QAAQ,CAAC;QAC7B,MAAM,GAAG,GAAG,GAAG,CAAC,OAAiC,CAAC;QAClD,MAAM,KAAK,GAAiB;YAC1B,QAAQ,EAAE,GAAG,CAAC,OAAO,CAAC,QAAQ;YAC9B,UAAU,EAAE,GAAG,CAAC,OAAO,CAAC,UAAU;YAClC,OAAO,EAAE,SAAS,CAAC,GAAG,CAAC;YACvB,SAAS,EAAE,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,OAAO,CAAC,SAAS,CAAC,IAAI,IAAI,CAAC,GAAG,EAAE;YAC1D,SAAS,EAAE,GAAG,CAAC,OAAO,CAAC,SAAS;SACjC,CAAC;QACF,IAAI,CAAC;YACH,MAAM,KAAK,CAAC,MAAM,CAAC,GAAG,EAAE,KAAK,EAAE,KAAK,CAAC,CAAC;QACxC,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,GAAG,CAAC,GAAG,CAAC,KAAK,EAAE,CAAC,kCAAkC,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QACxG,CAAC;QACD,IAAI,GAAG,CAAC,OAAO,IAAI,CAAC,YAAY,EAAE,CAAC;YACjC,OAAO;QACT,CAAC;QACD,MAAM,IAAI,EAAE,CAAC;IACf,CAAC,CAAC;AACJ,CAAC"}
@@ -0,0 +1,17 @@
1
+ /**
2
+ * sticker-capture.ts — 表情包自动收藏中间件(P0)
3
+ *
4
+ * 群消息里的图片 → fire-and-forget 收藏进本地表情包库(下载/去重/落盘在 sticker-store)。
5
+ *
6
+ * ⚠️ 时机关键:收藏调度必须放在 `await next()` 之前——
7
+ * 未@机器人的群消息会在下游被 mentionGate 截断(链不走到结尾),
8
+ * 若收藏放在 next() 之后(finally)就永远不触发(线上已踩坑)。
9
+ * 下载本身 fire-and-forget 不 await,不拖慢主链。
10
+ *
11
+ * ⚠️ 本地手改功能(fork 新增):维护清单见工作区根《插件改动维护注意事项.md》。
12
+ */
13
+ import type { MiddlewareContext } from '@tencent-connect/qqbot-nodejs';
14
+ import type { ImQQBotConfig } from '../config.js';
15
+ import type { Logger } from '../types.js';
16
+ export declare function stickerCapture(config: ImQQBotConfig, logger: Logger): (ctx: MiddlewareContext, next: () => Promise<void>) => Promise<void>;
17
+ //# sourceMappingURL=sticker-capture.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sticker-capture.d.ts","sourceRoot":"","sources":["../../src/middleware/sticker-capture.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AACH,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,+BAA+B,CAAC;AACvE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAClD,OAAO,KAAK,EAAE,MAAM,EAAiB,MAAM,aAAa,CAAC;AA6EzD,wBAAgB,cAAc,CAAC,MAAM,EAAE,aAAa,EAAE,MAAM,EAAE,MAAM,IACpD,KAAK,iBAAiB,EAAE,MAAM,MAAM,OAAO,CAAC,IAAI,CAAC,KAAG,OAAO,CAAC,IAAI,CAAC,CAiBhF"}
@@ -0,0 +1,97 @@
1
+ import { join } from 'node:path';
2
+ import { getStickerStore } from '../features/sticker-store.js';
3
+ import { autoTagImage } from '../features/sticker-tagger.js';
4
+ /** 同进程并发下载上限,防止群图轰炸时打爆连接 */
5
+ let inflight = 0;
6
+ const MAX_INFLIGHT = 2;
7
+ /** 图片 URL 是否可收藏(仅 https + 看似 QQ 图片下载链接) */
8
+ function isCollectableImage(url) {
9
+ return !!url && /^https:\/\//i.test(url) && /multimedia|qq\.com|download/i.test(url);
10
+ }
11
+ /**
12
+ * 类型粗筛:SDK 的 content_type 是 MIME(如 image/jpeg —— 已实测不是 'image')。
13
+ * 明确非图片(音/视频)的排除;未知/缺失交给 store 的魔数校验兜底(非图不入库)。
14
+ */
15
+ function isNonImageContentType(ct) {
16
+ if (!ct)
17
+ return false;
18
+ const t = ct.toLowerCase();
19
+ return t.startsWith('audio/') || t.startsWith('video/') || t === 'voice';
20
+ }
21
+ /** 调度一次收藏(fire-and-forget,不阻塞调用方) */
22
+ function scheduleCapture(url, contentType, ctx, config, logger) {
23
+ if (inflight >= MAX_INFLIGHT)
24
+ return;
25
+ inflight += 1;
26
+ const msg = ctx.message;
27
+ const dataDir = config.sticker.dataDir || join(config.cwd || process.cwd(), '表情包');
28
+ const store = getStickerStore(dataDir, logger);
29
+ const senderId = msg.senderId;
30
+ const senderName = msg.senderName;
31
+ const sourceGroup = ctx.message.kind === 'group' ? msg.groupOpenid : undefined;
32
+ const msgText = (msg.content ?? '').trim().slice(0, 120) || undefined;
33
+ void (async () => {
34
+ try {
35
+ const r = await store.capture(url, { sourceGroup, senderId, senderName, msgText, sourceUrl: url }, contentType);
36
+ if (r.status === 'new' && r.id) {
37
+ logger.info(`[sticker] captured #${r.id} (${url.slice(0, 60)}…)`);
38
+ // 候选区软上限: 超 300 张时最久未用的滚进回收站(防膨胀; 数值后续可设置化)
39
+ try {
40
+ store.cleanupCandidates(300);
41
+ }
42
+ catch { /* ignore */ }
43
+ // 顺带物理清掉超 30 天的回收站条目
44
+ try {
45
+ store.purgeTrashed();
46
+ }
47
+ catch { /* ignore */ }
48
+ // 后台自动打标(可配视觉CLI 生成 tags+desc; 无可用引擎则保持 needsDescribe 待 agent 视觉补)
49
+ try {
50
+ if (config.sticker.autoTagEnabled !== false) {
51
+ const p = store.pathOf(r.id);
52
+ if (p) {
53
+ const tag = await autoTagImage(p, config.sticker.visionCli ?? '', logger);
54
+ if (tag) {
55
+ store.setDescTags(r.id, tag.tags, tag.desc);
56
+ logger.info(`[sticker] 自动打标 #${r.id}: tags=${tag.tags.join('/') || '(启发)'} desc=${tag.desc.slice(0, 40)}…`);
57
+ }
58
+ }
59
+ }
60
+ }
61
+ catch (err) {
62
+ logger.debug(`[sticker] autotag error: ${err instanceof Error ? err.message : String(err)}`);
63
+ }
64
+ }
65
+ else if (r.status === 'error') {
66
+ logger.debug(`[sticker] capture failed: ${r.error}`);
67
+ }
68
+ }
69
+ catch (err) {
70
+ logger.debug(`[sticker] capture error: ${err instanceof Error ? err.message : String(err)}`);
71
+ }
72
+ finally {
73
+ inflight -= 1;
74
+ }
75
+ })();
76
+ }
77
+ export function stickerCapture(config, logger) {
78
+ return async (ctx, next) => {
79
+ // 先调度收藏(不等待下载),再走主链 —— 保证被后续截断(未@被门控吞)也照样收藏
80
+ if (config.sticker.collectEnabled) {
81
+ try {
82
+ const msg = ctx.message;
83
+ // content_type 是 MIME(image/jpeg 等),不能 == 'image'(踩坑修正)
84
+ const images = (msg.attachments ?? [])
85
+ .filter(a => isCollectableImage(a.url) && !isNonImageContentType(a.content_type));
86
+ for (const img of images.slice(0, 3)) {
87
+ scheduleCapture(img.url, img.content_type, ctx, config, logger);
88
+ }
89
+ }
90
+ catch {
91
+ // 收藏调度失败不影响主链
92
+ }
93
+ }
94
+ await next();
95
+ };
96
+ }
97
+ //# sourceMappingURL=sticker-capture.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sticker-capture.js","sourceRoot":"","sources":["../../src/middleware/sticker-capture.ts"],"names":[],"mappings":"AAeA,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,eAAe,EAAE,MAAM,8BAA8B,CAAC;AAC/D,OAAO,EAAE,YAAY,EAAE,MAAM,+BAA+B,CAAC;AAE7D,4BAA4B;AAC5B,IAAI,QAAQ,GAAG,CAAC,CAAC;AACjB,MAAM,YAAY,GAAG,CAAC,CAAC;AAEvB,2CAA2C;AAC3C,SAAS,kBAAkB,CAAC,GAAuB;IACjD,OAAO,CAAC,CAAC,GAAG,IAAI,cAAc,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,8BAA8B,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AACvF,CAAC;AAED;;;GAGG;AACH,SAAS,qBAAqB,CAAC,EAAsB;IACnD,IAAI,CAAC,EAAE;QAAE,OAAO,KAAK,CAAC;IACtB,MAAM,CAAC,GAAG,EAAE,CAAC,WAAW,EAAE,CAAC;IAC3B,OAAO,CAAC,CAAC,UAAU,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,UAAU,CAAC,QAAQ,CAAC,IAAI,CAAC,KAAK,OAAO,CAAC;AAC3E,CAAC;AAED,qCAAqC;AACrC,SAAS,eAAe,CACtB,GAAW,EACX,WAA+B,EAC/B,GAAsB,EACtB,MAAqB,EACrB,MAAc;IAEd,IAAI,QAAQ,IAAI,YAAY;QAAE,OAAO;IACrC,QAAQ,IAAI,CAAC,CAAC;IACd,MAAM,GAAG,GAAG,GAAG,CAAC,OAA4H,CAAC;IAC7I,MAAM,OAAO,GAAG,MAAM,CAAC,OAAO,CAAC,OAAO,IAAI,IAAI,CAAC,MAAM,CAAC,GAAG,IAAI,OAAO,CAAC,GAAG,EAAE,EAAE,KAAK,CAAC,CAAC;IACnF,MAAM,KAAK,GAAG,eAAe,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;IAC/C,MAAM,QAAQ,GAAG,GAAG,CAAC,QAAQ,CAAC;IAC9B,MAAM,UAAU,GAAG,GAAG,CAAC,UAAU,CAAC;IAClC,MAAM,WAAW,GAAG,GAAG,CAAC,OAAO,CAAC,IAAI,KAAK,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC,CAAC,SAAS,CAAC;IAC/E,MAAM,OAAO,GAAG,CAAC,GAAG,CAAC,OAAO,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,IAAI,SAAS,CAAC;IAEtE,KAAK,CAAC,KAAK,IAAI,EAAE;QACf,IAAI,CAAC;YACH,MAAM,CAAC,GAAG,MAAM,KAAK,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,WAAW,EAAE,QAAQ,EAAE,UAAU,EAAE,OAAO,EAAE,SAAS,EAAE,GAAG,EAAE,EAAE,WAAW,CAAC,CAAC;YAChH,IAAI,CAAC,CAAC,MAAM,KAAK,KAAK,IAAI,CAAC,CAAC,EAAE,EAAE,CAAC;gBAC/B,MAAM,CAAC,IAAI,CAAC,uBAAuB,CAAC,CAAC,EAAE,KAAK,GAAG,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,CAAC;gBAClE,4CAA4C;gBAC5C,IAAI,CAAC;oBAAC,KAAK,CAAC,iBAAiB,CAAC,GAAG,CAAC,CAAC;gBAAC,CAAC;gBAAC,MAAM,CAAC,CAAC,YAAY,CAAC,CAAC;gBAC5D,qBAAqB;gBACrB,IAAI,CAAC;oBAAC,KAAK,CAAC,YAAY,EAAE,CAAC;gBAAC,CAAC;gBAAC,MAAM,CAAC,CAAC,YAAY,CAAC,CAAC;gBACpD,mEAAmE;gBACnE,IAAI,CAAC;oBACH,IAAI,MAAM,CAAC,OAAO,CAAC,cAAc,KAAK,KAAK,EAAE,CAAC;wBAC5C,MAAM,CAAC,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;wBAC7B,IAAI,CAAC,EAAE,CAAC;4BACN,MAAM,GAAG,GAAG,MAAM,YAAY,CAAC,CAAC,EAAE,MAAM,CAAC,OAAO,CAAC,SAAS,IAAI,EAAE,EAAE,MAAM,CAAC,CAAC;4BAC1E,IAAI,GAAG,EAAE,CAAC;gCACR,KAAK,CAAC,WAAW,CAAC,CAAC,CAAC,EAAE,EAAE,GAAG,CAAC,IAAI,EAAE,GAAG,CAAC,IAAI,CAAC,CAAC;gCAC5C,MAAM,CAAC,IAAI,CAAC,mBAAmB,CAAC,CAAC,EAAE,UAAU,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,MAAM,SAAS,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,CAAC,CAAC;4BAC9G,CAAC;wBACH,CAAC;oBACH,CAAC;gBACH,CAAC;gBAAC,OAAO,GAAG,EAAE,CAAC;oBACb,MAAM,CAAC,KAAK,CAAC,4BAA4B,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;gBAC/F,CAAC;YACH,CAAC;iBAAM,IAAI,CAAC,CAAC,MAAM,KAAK,OAAO,EAAE,CAAC;gBAChC,MAAM,CAAC,KAAK,CAAC,6BAA6B,CAAC,CAAC,KAAK,EAAE,CAAC,CAAC;YACvD,CAAC;QACH,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,MAAM,CAAC,KAAK,CAAC,4BAA4B,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QAC/F,CAAC;gBAAS,CAAC;YACT,QAAQ,IAAI,CAAC,CAAC;QAChB,CAAC;IACH,CAAC,CAAC,EAAE,CAAC;AACP,CAAC;AAED,MAAM,UAAU,cAAc,CAAC,MAAqB,EAAE,MAAc;IAClE,OAAO,KAAK,EAAE,GAAsB,EAAE,IAAyB,EAAiB,EAAE;QAChF,4CAA4C;QAC5C,IAAI,MAAM,CAAC,OAAO,CAAC,cAAc,EAAE,CAAC;YAClC,IAAI,CAAC;gBACH,MAAM,GAAG,GAAG,GAAG,CAAC,OAA4C,CAAC;gBAC7D,wDAAwD;gBACxD,MAAM,MAAM,GAAG,CAAC,GAAG,CAAC,WAAW,IAAI,EAAE,CAAC;qBACnC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,kBAAkB,CAAC,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,qBAAqB,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC;gBACpF,KAAK,MAAM,GAAG,IAAI,MAAM,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC;oBACrC,eAAe,CAAC,GAAG,CAAC,GAAG,EAAE,GAAG,CAAC,YAAY,EAAE,GAAG,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC;gBAClE,CAAC;YACH,CAAC;YAAC,MAAM,CAAC;gBACP,cAAc;YAChB,CAAC;QACH,CAAC;QACD,MAAM,IAAI,EAAE,CAAC;IACf,CAAC,CAAC;AACJ,CAAC"}
@@ -0,0 +1,10 @@
1
+ /**
2
+ * 模型路由层
3
+ *
4
+ * 统一的模型发现、路由解析、per-peer 偏好管理。
5
+ */
6
+ export { ModelResolver } from './model-resolver.js';
7
+ export { PrefsStore } from './prefs-store.js';
8
+ export { SettingsReader } from './settings-reader.js';
9
+ export type { ModelRoute, ModelEntry } from './types.js';
10
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/model/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACpD,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAC9C,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AACtD,YAAY,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC"}
@@ -0,0 +1,9 @@
1
+ /**
2
+ * 模型路由层
3
+ *
4
+ * 统一的模型发现、路由解析、per-peer 偏好管理。
5
+ */
6
+ export { ModelResolver } from './model-resolver.js';
7
+ export { PrefsStore } from './prefs-store.js';
8
+ export { SettingsReader } from './settings-reader.js';
9
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/model/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACpD,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAC9C,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC"}
@@ -0,0 +1,88 @@
1
+ /**
2
+ * ModelResolver — 统一的模型发现与路由解析
3
+ *
4
+ * 职责:
5
+ * 1. 解析当前生效的默认模型路由
6
+ * 2. 列出可用 providers 和模型
7
+ * 3. 管理 per-peer 的模型偏好(委托 PrefsStore)
8
+ *
9
+ * 优先级(从高到低):
10
+ * per-peer 偏好(~/.dsh-qqbot/model-prefs.json)
11
+ * > config 显式指定(cordis.yml 的 provider/model)
12
+ * > settings.yaml 的 agent-default-model(只读,作为默认兜底)
13
+ * > 宿主 agentDefaultModel 服务
14
+ */
15
+ import type { Context } from '@deepseek-ai/cordis';
16
+ import type { ImQQBotConfig } from '../config.js';
17
+ import type { Logger } from '../types.js';
18
+ import type { ModelRoute, ModelEntry } from './types.js';
19
+ export declare class ModelResolver {
20
+ private readonly ctx;
21
+ private readonly config;
22
+ private readonly logger?;
23
+ private readonly prefs;
24
+ private readonly settings;
25
+ constructor(ctx: Context, config: ImQQBotConfig, logger?: Logger | undefined);
26
+ /**
27
+ * 获取指定 sessionKey 的有效模型路由(create 用)
28
+ *
29
+ * 优先级:per-peer 偏好 > config 显式指定 > settings.yaml > 宿主服务
30
+ */
31
+ getEffectiveRoute(sessionKey: string): ModelRoute | undefined;
32
+ /**
33
+ * 获取 resume 时覆盖 session 的模型路由
34
+ *
35
+ * 优先级:per-peer 偏好 > cordis.yml 显式配置 > 默认链(settings.yaml > host)
36
+ *
37
+ * 注意:不能像 dsh-TUI 那样返回 undefined 让 session 沿用 requestHeader。
38
+ * dsh-TUI 靠 installModelSelection 从 session.requestHeader 恢复 {{model}},
39
+ * 而我们未装 installModelSelection,system-prompt 的 {{model}} 变量直接读
40
+ * agent.options.model(agent-loop index.ts:352)——若无值会抛
41
+ * "prompt variable {{model}} has no value for this assembly"。
42
+ * 因此这里兜底到默认链,确保 agent.options.model 始终有值。
43
+ */
44
+ getResumeRoute(sessionKey: string): ModelRoute | undefined;
45
+ /**
46
+ * 设置 per-peer 模型偏好并持久化到隔离文件
47
+ */
48
+ setOverride(sessionKey: string, route: ModelRoute): void;
49
+ /**
50
+ * 清除 per-peer 模型偏好并持久化
51
+ */
52
+ clearOverride(sessionKey: string): void;
53
+ /**
54
+ * 是否存在指定 session 的模型偏好
55
+ */
56
+ hasOverride(sessionKey: string): boolean;
57
+ /**
58
+ * 获取指定 sessionKey 的最新 sessionId(fork 后记录,重启恢复用)
59
+ */
60
+ getSessionId(sessionKey: string): string | undefined;
61
+ /**
62
+ * 记录指定 sessionKey 的最新 sessionId(fork 后调用)并持久化
63
+ */
64
+ setSessionId(sessionKey: string, sessionId: string): void;
65
+ /**
66
+ * 清除指定 sessionKey 的 sessionId 记录
67
+ */
68
+ clearSessionId(sessionKey: string): void;
69
+ /**
70
+ * 解析默认模型路由(不含 per-peer 偏好)
71
+ *
72
+ * 优先级:config 显式指定 > settings.yaml(只读) > 宿主 agentDefaultModel
73
+ * 最终兜底 deepseek-official/deepseek-v4-flash,确保 {{model}} 变量始终有值。
74
+ */
75
+ resolveDefault(): ModelRoute;
76
+ /**
77
+ * 列出所有可用模型
78
+ */
79
+ listModels(): ModelEntry[];
80
+ /**
81
+ * 列出可用 provider 名称
82
+ */
83
+ listProviders(): string[];
84
+ private readFromHost;
85
+ /** 统一的 Cordis 服务访问 */
86
+ private getService;
87
+ }
88
+ //# sourceMappingURL=model-resolver.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"model-resolver.d.ts","sourceRoot":"","sources":["../../src/model/model-resolver.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AACH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAC;AACnD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAClD,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAC1C,OAAO,KAAK,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAIzD,qBAAa,aAAa;IAKtB,OAAO,CAAC,QAAQ,CAAC,GAAG;IACpB,OAAO,CAAC,QAAQ,CAAC,MAAM;IACvB,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAC;IAN1B,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAa;IACnC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAiB;gBAGvB,GAAG,EAAE,OAAO,EACZ,MAAM,EAAE,aAAa,EACrB,MAAM,CAAC,EAAE,MAAM,YAAA;IAQlC;;;;OAIG;IACH,iBAAiB,CAAC,UAAU,EAAE,MAAM,GAAG,UAAU,GAAG,SAAS;IAI7D;;;;;;;;;;;OAWG;IACH,cAAc,CAAC,UAAU,EAAE,MAAM,GAAG,UAAU,GAAG,SAAS;IAW1D;;OAEG;IACH,WAAW,CAAC,UAAU,EAAE,MAAM,EAAE,KAAK,EAAE,UAAU,GAAG,IAAI;IAIxD;;OAEG;IACH,aAAa,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI;IAIvC;;OAEG;IACH,WAAW,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO;IAIxC;;OAEG;IACH,YAAY,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS;IAIpD;;OAEG;IACH,YAAY,CAAC,UAAU,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,IAAI;IAIzD;;OAEG;IACH,cAAc,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI;IAIxC;;;;;OAKG;IACH,cAAc,IAAI,UAAU;IAc5B;;OAEG;IACH,UAAU,IAAI,UAAU,EAAE;IAI1B;;OAEG;IACH,aAAa,IAAI,MAAM,EAAE;IAuBzB,OAAO,CAAC,YAAY;IAoBpB,sBAAsB;IACtB,OAAO,CAAC,UAAU;CAKnB"}