@zhin.js/core 1.3.1 → 1.3.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (358) hide show
  1. package/README.md +66 -11
  2. package/lib/adapter.d.ts +41 -3
  3. package/lib/adapter.js +110 -6
  4. package/lib/agent-prompt.d.ts +0 -1
  5. package/lib/agent-prompt.js +0 -1
  6. package/lib/built/adapter-process.d.ts +11 -2
  7. package/lib/built/adapter-process.js +43 -2
  8. package/lib/built/agent-preset.d.ts +0 -1
  9. package/lib/built/agent-preset.js +0 -1
  10. package/lib/built/ai-access.d.ts +36 -0
  11. package/lib/built/ai-access.js +46 -0
  12. package/lib/built/ai-outbound/adapter-access.d.ts +3 -0
  13. package/lib/built/ai-outbound/adapter-access.js +9 -0
  14. package/lib/built/ai-outbound/extensions/onebot-keyboard.d.ts +2 -0
  15. package/lib/built/ai-outbound/extensions/onebot-keyboard.js +67 -0
  16. package/lib/built/ai-outbound/extensions/qq-message.d.ts +3 -0
  17. package/lib/built/ai-outbound/extensions/qq-message.js +23 -0
  18. package/lib/built/ai-outbound/index.d.ts +9 -0
  19. package/lib/built/ai-outbound/index.js +9 -0
  20. package/lib/built/ai-outbound/parse.d.ts +13 -0
  21. package/lib/built/ai-outbound/parse.js +94 -0
  22. package/lib/built/ai-outbound/plain-mention-rewrite.d.ts +6 -0
  23. package/lib/built/ai-outbound/plain-mention-rewrite.js +37 -0
  24. package/lib/built/ai-outbound/prompt.d.ts +11 -0
  25. package/lib/built/ai-outbound/prompt.js +44 -0
  26. package/lib/built/ai-outbound/resolve.d.ts +4 -0
  27. package/lib/built/ai-outbound/resolve.js +64 -0
  28. package/lib/built/ai-outbound/structured-detect.d.ts +3 -0
  29. package/lib/built/ai-outbound/structured-detect.js +7 -0
  30. package/lib/built/ai-outbound/types.d.ts +60 -0
  31. package/lib/built/ai-outbound/types.js +5 -0
  32. package/lib/built/ai-trigger.d.ts +5 -1
  33. package/lib/built/ai-trigger.js +3 -7
  34. package/lib/built/authorization.d.ts +0 -1
  35. package/lib/built/authorization.js +0 -1
  36. package/lib/built/command.d.ts +2 -1
  37. package/lib/built/command.js +14 -4
  38. package/lib/built/common-adapter-tools.d.ts +25 -26
  39. package/lib/built/common-adapter-tools.js +48 -49
  40. package/lib/built/component.d.ts +0 -1
  41. package/lib/built/component.js +1 -3
  42. package/lib/built/config.d.ts +4 -1
  43. package/lib/built/config.js +26 -5
  44. package/lib/built/connect-endpoint-instance.d.ts +0 -1
  45. package/lib/built/connect-endpoint-instance.js +3 -2
  46. package/lib/built/database.d.ts +0 -1
  47. package/lib/built/database.js +1 -3
  48. package/lib/built/dispatcher.d.ts +6 -6
  49. package/lib/built/dispatcher.js +20 -8
  50. package/lib/built/endpoint-commands.d.ts +3 -0
  51. package/lib/built/endpoint-commands.js +99 -0
  52. package/lib/built/endpoint-lifecycle-service.d.ts +28 -0
  53. package/lib/built/endpoint-lifecycle-service.js +241 -0
  54. package/lib/built/endpoint-lifecycle.d.ts +0 -1
  55. package/lib/built/endpoint-lifecycle.js +0 -1
  56. package/lib/built/endpoint-manager.d.ts +34 -0
  57. package/lib/built/endpoint-manager.js +1 -0
  58. package/lib/built/generated-qrcode.d.ts +24 -0
  59. package/lib/built/generated-qrcode.js +45 -0
  60. package/lib/built/generic-segment-mapper.d.ts +6 -0
  61. package/lib/built/generic-segment-mapper.js +232 -0
  62. package/lib/built/html-renderer-loader.d.ts +13 -0
  63. package/lib/built/html-renderer-loader.js +33 -0
  64. package/lib/built/html-segment-fallback.d.ts +2 -2
  65. package/lib/built/html-segment-fallback.js +0 -1
  66. package/lib/built/html-to-text.d.ts +0 -1
  67. package/lib/built/html-to-text.js +0 -1
  68. package/lib/built/inbound-pipeline.d.ts +0 -1
  69. package/lib/built/inbound-pipeline.js +0 -1
  70. package/lib/built/inbound-runner.d.ts +0 -1
  71. package/lib/built/inbound-runner.js +0 -1
  72. package/lib/built/interactive-segment-contract.d.ts +6 -0
  73. package/lib/built/interactive-segment-contract.js +9 -0
  74. package/lib/built/interactive-segments/action.d.ts +17 -0
  75. package/lib/built/interactive-segments/action.js +54 -0
  76. package/lib/built/interactive-segments/button-spec.d.ts +10 -0
  77. package/lib/built/interactive-segments/button-spec.js +21 -0
  78. package/lib/built/interactive-segments/handlers.d.ts +9 -0
  79. package/lib/built/interactive-segments/handlers.js +58 -0
  80. package/lib/built/interactive-segments/index.d.ts +7 -0
  81. package/lib/built/interactive-segments/index.js +7 -0
  82. package/lib/built/interactive-segments/keyboard-segment.d.ts +12 -0
  83. package/lib/built/interactive-segments/keyboard-segment.js +13 -0
  84. package/lib/built/interactive-segments/onebot-keyboard.d.ts +10 -0
  85. package/lib/built/interactive-segments/onebot-keyboard.js +53 -0
  86. package/lib/built/interactive-segments/resolve.d.ts +9 -0
  87. package/lib/built/interactive-segments/resolve.js +84 -0
  88. package/lib/built/interactive-segments/types.d.ts +62 -0
  89. package/lib/built/interactive-segments/types.js +13 -0
  90. package/lib/built/introspection-format.d.ts +10 -0
  91. package/lib/built/introspection-format.js +28 -0
  92. package/lib/built/login-assist.d.ts +1 -2
  93. package/lib/built/login-assist.js +0 -1
  94. package/lib/built/management-command-guard.d.ts +15 -0
  95. package/lib/built/management-command-guard.js +25 -0
  96. package/lib/built/message-enrich.d.ts +0 -1
  97. package/lib/built/message-enrich.js +0 -1
  98. package/lib/built/message-filter.d.ts +0 -1
  99. package/lib/built/message-filter.js +1 -3
  100. package/lib/built/optional-peer-import.d.ts +3 -0
  101. package/lib/built/optional-peer-import.js +33 -0
  102. package/lib/built/outbound-media-contract.d.ts +22 -0
  103. package/lib/built/outbound-media-contract.js +10 -0
  104. package/lib/built/outbound-media-utils.d.ts +9 -0
  105. package/lib/built/outbound-media-utils.js +62 -0
  106. package/lib/built/permission.d.ts +0 -1
  107. package/lib/built/permission.js +1 -3
  108. package/lib/built/permit-check.d.ts +0 -1
  109. package/lib/built/permit-check.js +0 -1
  110. package/lib/built/permit-parse.d.ts +0 -1
  111. package/lib/built/permit-parse.js +0 -1
  112. package/lib/built/platform-permit.d.ts +5 -6
  113. package/lib/built/platform-permit.js +11 -12
  114. package/lib/built/prepend-quote-context.d.ts +0 -1
  115. package/lib/built/prepend-quote-context.js +0 -1
  116. package/lib/built/qrcode-segment.d.ts +18 -0
  117. package/lib/built/qrcode-segment.js +78 -0
  118. package/lib/built/queue-im-field-contract.d.ts +6 -1
  119. package/lib/built/queue-im-field-contract.js +10 -1
  120. package/lib/built/rich-segments/adapter-policies.d.ts +9 -0
  121. package/lib/built/rich-segments/adapter-policies.js +27 -0
  122. package/lib/built/rich-segments/base.d.ts +11 -0
  123. package/lib/built/rich-segments/base.js +24 -0
  124. package/lib/built/rich-segments/builtins.d.ts +4 -0
  125. package/lib/built/rich-segments/builtins.js +40 -0
  126. package/lib/built/rich-segments/capabilities.d.ts +6 -0
  127. package/lib/built/rich-segments/capabilities.js +39 -0
  128. package/lib/built/rich-segments/html-segment.d.ts +15 -0
  129. package/lib/built/rich-segments/html-segment.js +65 -0
  130. package/lib/built/rich-segments/index.d.ts +13 -0
  131. package/lib/built/rich-segments/index.js +13 -0
  132. package/lib/built/rich-segments/markdown-segment.d.ts +14 -0
  133. package/lib/built/rich-segments/markdown-segment.js +61 -0
  134. package/lib/built/rich-segments/markdown-to-text.d.ts +3 -0
  135. package/lib/built/rich-segments/markdown-to-text.js +27 -0
  136. package/lib/built/rich-segments/qrcode-segment.d.ts +18 -0
  137. package/lib/built/rich-segments/qrcode-segment.js +73 -0
  138. package/lib/built/rich-segments/registry.d.ts +16 -0
  139. package/lib/built/rich-segments/registry.js +52 -0
  140. package/lib/built/rich-segments/resolve.d.ts +5 -0
  141. package/lib/built/rich-segments/resolve.js +87 -0
  142. package/lib/built/rich-segments/tts-segment.d.ts +13 -0
  143. package/lib/built/rich-segments/tts-segment.js +51 -0
  144. package/lib/built/rich-segments/types.d.ts +84 -0
  145. package/lib/built/rich-segments/types.js +17 -0
  146. package/lib/built/roles.d.ts +0 -1
  147. package/lib/built/roles.js +0 -1
  148. package/lib/built/runtime-io.d.ts +0 -1
  149. package/lib/built/runtime-io.js +0 -1
  150. package/lib/built/schedule.d.ts +55 -0
  151. package/lib/built/schedule.js +112 -0
  152. package/lib/built/schema-endpoint-manager.d.ts +17 -0
  153. package/lib/built/schema-endpoint-manager.js +73 -0
  154. package/lib/built/schema-feature.d.ts +0 -1
  155. package/lib/built/schema-feature.js +1 -3
  156. package/lib/built/segment-contract/assert.d.ts +4 -0
  157. package/lib/built/segment-contract/assert.js +30 -0
  158. package/lib/built/segment-contract/delivery.d.ts +5 -0
  159. package/lib/built/segment-contract/delivery.js +40 -0
  160. package/lib/built/segment-contract/image.d.ts +5 -0
  161. package/lib/built/segment-contract/image.js +10 -0
  162. package/lib/built/segment-contract/index.d.ts +8 -0
  163. package/lib/built/segment-contract/index.js +7 -0
  164. package/lib/built/segment-contract/media.d.ts +8 -0
  165. package/lib/built/segment-contract/media.js +39 -0
  166. package/lib/built/segment-contract/mention.d.ts +10 -0
  167. package/lib/built/segment-contract/mention.js +26 -0
  168. package/lib/built/segment-contract/preview.d.ts +3 -0
  169. package/lib/built/segment-contract/preview.js +159 -0
  170. package/lib/built/segment-contract/types.d.ts +70 -0
  171. package/lib/built/segment-contract/types.js +5 -0
  172. package/lib/built/segment-contract/validate.d.ts +138 -0
  173. package/lib/built/segment-contract/validate.js +124 -0
  174. package/lib/built/skill.d.ts +0 -1
  175. package/lib/built/skill.js +0 -1
  176. package/lib/built/speech-loader.d.ts +14 -0
  177. package/lib/built/speech-loader.js +32 -0
  178. package/lib/built/tool.d.ts +0 -1
  179. package/lib/built/tool.js +1 -3
  180. package/lib/command.d.ts +12 -7
  181. package/lib/command.js +38 -16
  182. package/lib/component.d.ts +0 -1
  183. package/lib/component.js +0 -1
  184. package/lib/endpoint-capabilities.d.ts +3 -1
  185. package/lib/endpoint-capabilities.js +0 -1
  186. package/lib/endpoint.d.ts +0 -1
  187. package/lib/endpoint.js +0 -1
  188. package/lib/errors.d.ts +0 -1
  189. package/lib/errors.js +0 -1
  190. package/lib/host-plugin-registry.d.ts +0 -1
  191. package/lib/host-plugin-registry.js +0 -1
  192. package/lib/im-scene.d.ts +29 -0
  193. package/lib/im-scene.js +77 -0
  194. package/lib/im-session-id.d.ts +25 -12
  195. package/lib/im-session-id.js +35 -17
  196. package/lib/index.d.ts +25 -5
  197. package/lib/index.js +22 -4
  198. package/lib/jsx-dev-runtime.d.ts +0 -1
  199. package/lib/jsx-dev-runtime.js +0 -1
  200. package/lib/jsx-runtime.d.ts +0 -1
  201. package/lib/jsx-runtime.js +0 -1
  202. package/lib/jsx.d.ts +0 -1
  203. package/lib/jsx.js +0 -1
  204. package/lib/message-quote.d.ts +1 -2
  205. package/lib/message-quote.js +2 -3
  206. package/lib/message.d.ts +12 -2
  207. package/lib/message.js +16 -1
  208. package/lib/models/system-log.d.ts +0 -1
  209. package/lib/models/system-log.js +0 -1
  210. package/lib/models/user.d.ts +0 -1
  211. package/lib/models/user.js +0 -1
  212. package/lib/notice.d.ts +0 -1
  213. package/lib/notice.js +0 -1
  214. package/lib/plugin-context.d.ts +0 -1
  215. package/lib/plugin-context.js +0 -1
  216. package/lib/plugin.d.ts +11 -2
  217. package/lib/plugin.js +22 -23
  218. package/lib/prompt.d.ts +0 -1
  219. package/lib/prompt.js +1 -2
  220. package/lib/request.d.ts +0 -1
  221. package/lib/request.js +0 -1
  222. package/lib/tool-zod.d.ts +0 -1
  223. package/lib/tool-zod.js +0 -1
  224. package/lib/types-generator.d.ts +0 -1
  225. package/lib/types-generator.js +0 -1
  226. package/lib/types.d.ts +30 -11
  227. package/lib/types.js +0 -1
  228. package/lib/utils.d.ts +57 -12
  229. package/lib/utils.js +54 -19
  230. package/package.json +18 -9
  231. package/lib/adapter.d.ts.map +0 -1
  232. package/lib/adapter.js.map +0 -1
  233. package/lib/agent-prompt.d.ts.map +0 -1
  234. package/lib/agent-prompt.js.map +0 -1
  235. package/lib/built/adapter-process.d.ts.map +0 -1
  236. package/lib/built/adapter-process.js.map +0 -1
  237. package/lib/built/agent-preset.d.ts.map +0 -1
  238. package/lib/built/agent-preset.js.map +0 -1
  239. package/lib/built/ai-trigger.d.ts.map +0 -1
  240. package/lib/built/ai-trigger.js.map +0 -1
  241. package/lib/built/authorization.d.ts.map +0 -1
  242. package/lib/built/authorization.js.map +0 -1
  243. package/lib/built/command.d.ts.map +0 -1
  244. package/lib/built/command.js.map +0 -1
  245. package/lib/built/common-adapter-tools.d.ts.map +0 -1
  246. package/lib/built/common-adapter-tools.js.map +0 -1
  247. package/lib/built/component.d.ts.map +0 -1
  248. package/lib/built/component.js.map +0 -1
  249. package/lib/built/config.d.ts.map +0 -1
  250. package/lib/built/config.js.map +0 -1
  251. package/lib/built/connect-endpoint-instance.d.ts.map +0 -1
  252. package/lib/built/connect-endpoint-instance.js.map +0 -1
  253. package/lib/built/cron.d.ts +0 -75
  254. package/lib/built/cron.d.ts.map +0 -1
  255. package/lib/built/cron.js +0 -122
  256. package/lib/built/cron.js.map +0 -1
  257. package/lib/built/database.d.ts.map +0 -1
  258. package/lib/built/database.js.map +0 -1
  259. package/lib/built/dispatcher.d.ts.map +0 -1
  260. package/lib/built/dispatcher.js.map +0 -1
  261. package/lib/built/endpoint-lifecycle.d.ts.map +0 -1
  262. package/lib/built/endpoint-lifecycle.js.map +0 -1
  263. package/lib/built/html-segment-fallback.d.ts.map +0 -1
  264. package/lib/built/html-segment-fallback.js.map +0 -1
  265. package/lib/built/html-to-text.d.ts.map +0 -1
  266. package/lib/built/html-to-text.js.map +0 -1
  267. package/lib/built/inbound-pipeline.d.ts.map +0 -1
  268. package/lib/built/inbound-pipeline.js.map +0 -1
  269. package/lib/built/inbound-runner.d.ts.map +0 -1
  270. package/lib/built/inbound-runner.js.map +0 -1
  271. package/lib/built/login-assist.d.ts.map +0 -1
  272. package/lib/built/login-assist.js.map +0 -1
  273. package/lib/built/mcp-mesh-registrar.d.ts +0 -9
  274. package/lib/built/mcp-mesh-registrar.d.ts.map +0 -1
  275. package/lib/built/mcp-mesh-registrar.js +0 -17
  276. package/lib/built/mcp-mesh-registrar.js.map +0 -1
  277. package/lib/built/message-enrich.d.ts.map +0 -1
  278. package/lib/built/message-enrich.js.map +0 -1
  279. package/lib/built/message-filter.d.ts.map +0 -1
  280. package/lib/built/message-filter.js.map +0 -1
  281. package/lib/built/permission.d.ts.map +0 -1
  282. package/lib/built/permission.js.map +0 -1
  283. package/lib/built/permit-check.d.ts.map +0 -1
  284. package/lib/built/permit-check.js.map +0 -1
  285. package/lib/built/permit-parse.d.ts.map +0 -1
  286. package/lib/built/permit-parse.js.map +0 -1
  287. package/lib/built/platform-permit.d.ts.map +0 -1
  288. package/lib/built/platform-permit.js.map +0 -1
  289. package/lib/built/prepend-quote-context.d.ts.map +0 -1
  290. package/lib/built/prepend-quote-context.js.map +0 -1
  291. package/lib/built/queue-im-field-contract.d.ts.map +0 -1
  292. package/lib/built/queue-im-field-contract.js.map +0 -1
  293. package/lib/built/roles.d.ts.map +0 -1
  294. package/lib/built/roles.js.map +0 -1
  295. package/lib/built/runtime-io.d.ts.map +0 -1
  296. package/lib/built/runtime-io.js.map +0 -1
  297. package/lib/built/schema-feature.d.ts.map +0 -1
  298. package/lib/built/schema-feature.js.map +0 -1
  299. package/lib/built/skill.d.ts.map +0 -1
  300. package/lib/built/skill.js.map +0 -1
  301. package/lib/built/tool.d.ts.map +0 -1
  302. package/lib/built/tool.js.map +0 -1
  303. package/lib/command.d.ts.map +0 -1
  304. package/lib/command.js.map +0 -1
  305. package/lib/component.d.ts.map +0 -1
  306. package/lib/component.js.map +0 -1
  307. package/lib/endpoint-capabilities.d.ts.map +0 -1
  308. package/lib/endpoint-capabilities.js.map +0 -1
  309. package/lib/endpoint.d.ts.map +0 -1
  310. package/lib/endpoint.js.map +0 -1
  311. package/lib/errors.d.ts.map +0 -1
  312. package/lib/errors.js.map +0 -1
  313. package/lib/host-plugin-registry.d.ts.map +0 -1
  314. package/lib/host-plugin-registry.js.map +0 -1
  315. package/lib/im-session-id.d.ts.map +0 -1
  316. package/lib/im-session-id.js.map +0 -1
  317. package/lib/index.d.ts.map +0 -1
  318. package/lib/index.js.map +0 -1
  319. package/lib/jsx-dev-runtime.d.ts.map +0 -1
  320. package/lib/jsx-dev-runtime.js.map +0 -1
  321. package/lib/jsx-runtime.d.ts.map +0 -1
  322. package/lib/jsx-runtime.js.map +0 -1
  323. package/lib/jsx.d.ts.map +0 -1
  324. package/lib/jsx.js.map +0 -1
  325. package/lib/message-quote.d.ts.map +0 -1
  326. package/lib/message-quote.js.map +0 -1
  327. package/lib/message.d.ts.map +0 -1
  328. package/lib/message.js.map +0 -1
  329. package/lib/models/system-log.d.ts.map +0 -1
  330. package/lib/models/system-log.js.map +0 -1
  331. package/lib/models/user.d.ts.map +0 -1
  332. package/lib/models/user.js.map +0 -1
  333. package/lib/notice.d.ts.map +0 -1
  334. package/lib/notice.js.map +0 -1
  335. package/lib/plugin-context.d.ts.map +0 -1
  336. package/lib/plugin-context.js.map +0 -1
  337. package/lib/plugin.d.ts.map +0 -1
  338. package/lib/plugin.js.map +0 -1
  339. package/lib/prompt.d.ts.map +0 -1
  340. package/lib/prompt.js.map +0 -1
  341. package/lib/request.d.ts.map +0 -1
  342. package/lib/request.js.map +0 -1
  343. package/lib/scheduler/scheduler.d.ts +0 -49
  344. package/lib/scheduler/scheduler.d.ts.map +0 -1
  345. package/lib/scheduler/scheduler.js +0 -352
  346. package/lib/scheduler/scheduler.js.map +0 -1
  347. package/lib/scheduler/types.d.ts +0 -71
  348. package/lib/scheduler/types.d.ts.map +0 -1
  349. package/lib/scheduler/types.js +0 -8
  350. package/lib/scheduler/types.js.map +0 -1
  351. package/lib/tool-zod.d.ts.map +0 -1
  352. package/lib/tool-zod.js.map +0 -1
  353. package/lib/types-generator.d.ts.map +0 -1
  354. package/lib/types-generator.js.map +0 -1
  355. package/lib/types.d.ts.map +0 -1
  356. package/lib/types.js.map +0 -1
  357. package/lib/utils.d.ts.map +0 -1
  358. package/lib/utils.js.map +0 -1
@@ -0,0 +1,241 @@
1
+ import { Adapter } from '../adapter.js';
2
+ import { segment } from '../utils.js';
3
+ import { connectEndpointInstance, disconnectEndpointInstance } from './connect-endpoint-instance.js';
4
+ import { adapterSupportsProvision, resolveEndpointManager } from './schema-endpoint-manager.js';
5
+ function getConfigService(root) {
6
+ const configService = root.inject('config');
7
+ if (!configService?.primaryFile) {
8
+ throw new Error('配置服务不可用');
9
+ }
10
+ const loader = configService.configs.get(configService.primaryFile);
11
+ if (!loader) {
12
+ throw new Error('配置文件未加载');
13
+ }
14
+ return configService;
15
+ }
16
+ function readAllEndpoints(root) {
17
+ const configService = getConfigService(root);
18
+ const raw = configService.getRaw(configService.primaryFile);
19
+ return [...(raw?.endpoints ?? [])];
20
+ }
21
+ function assertUniqueName(endpoints, context, name, replaceIndex) {
22
+ const conflict = endpoints.findIndex((e) => e.context === context && e.name === name);
23
+ if (conflict >= 0 && conflict !== replaceIndex) {
24
+ throw new Error(`zhin.config 中已存在 ${context}/${name}`);
25
+ }
26
+ }
27
+ function buildProvisionContext(root, message) {
28
+ return {
29
+ message,
30
+ root,
31
+ onStatusUpdate: async (status, extra) => {
32
+ if (message.$reply) {
33
+ let content = status;
34
+ if (extra?.qrcode && typeof extra.qrcode === 'string') {
35
+ content = [segment.qrcode(extra.qrcode), segment.text(status)];
36
+ }
37
+ await message.$reply(content);
38
+ }
39
+ },
40
+ };
41
+ }
42
+ export class EndpointLifecycleService {
43
+ root;
44
+ constructor(root) {
45
+ this.root = root;
46
+ }
47
+ resolveAdapter(adapterKey) {
48
+ const adapter = this.root.inject(adapterKey);
49
+ if (!(adapter instanceof Adapter)) {
50
+ throw new Error(`适配器 ${adapterKey} 未安装或未就绪`);
51
+ }
52
+ return adapter;
53
+ }
54
+ resolveManager(adapterKey) {
55
+ const adapter = this.resolveAdapter(adapterKey);
56
+ const manager = resolveEndpointManager(adapter);
57
+ if (!manager) {
58
+ throw new Error(`适配器 ${adapterKey} 不支持运行时 Endpoint 管理(无 EndpointManager 且未声明 endpointConfigSchema)`);
59
+ }
60
+ return manager;
61
+ }
62
+ listProvisionableAdapters() {
63
+ return this.root.adapters.filter((name) => {
64
+ try {
65
+ const adapter = this.resolveAdapter(String(name));
66
+ return adapterSupportsProvision(adapter);
67
+ }
68
+ catch {
69
+ return false;
70
+ }
71
+ });
72
+ }
73
+ async persistEndpoints(endpoints) {
74
+ const configService = getConfigService(this.root);
75
+ const loader = configService.configs.get(configService.primaryFile);
76
+ loader.patchKey('endpoints', endpoints);
77
+ }
78
+ /** 将内存中的 endpoints 写回 zhin.config(修复运行时与磁盘不一致) */
79
+ async syncToDisk() {
80
+ const configService = getConfigService(this.root);
81
+ const loader = configService.configs.get(configService.primaryFile);
82
+ const endpoints = readAllEndpoints(this.root);
83
+ await this.persistEndpoints(endpoints);
84
+ const configPath = loader.resolvedPath;
85
+ const names = endpoints.map((e) => `${e.context}/${e.name}`).join(', ') || '(无)';
86
+ return {
87
+ message: `✅ 已将 ${endpoints.length} 个 endpoint 写入 \`${configPath}\`:${names}`,
88
+ };
89
+ }
90
+ async connectConfig(adapter, config) {
91
+ const name = config.name;
92
+ if (adapter.endpoints.has(name)) {
93
+ throw new Error(`Endpoint ${name} 已在线,请先 /endpoint stop ${String(adapter.name)} ${name}`);
94
+ }
95
+ const endpoint = await connectEndpointInstance({
96
+ plugin: this.root,
97
+ adapter,
98
+ config: config,
99
+ });
100
+ adapter.endpoints.set(endpoint.$id, endpoint);
101
+ return endpoint;
102
+ }
103
+ async disconnectRuntime(adapter, name) {
104
+ const endpoint = adapter.endpoints.get(name);
105
+ if (!endpoint)
106
+ return false;
107
+ if (endpoint.$connected) {
108
+ await disconnectEndpointInstance(this.root, adapter, endpoint);
109
+ }
110
+ adapter.endpoints.delete(name);
111
+ return true;
112
+ }
113
+ async add(adapterKey, message, initialReply) {
114
+ const adapter = this.resolveAdapter(adapterKey);
115
+ const manager = this.resolveManager(adapterKey);
116
+ const ctx = buildProvisionContext(this.root, message);
117
+ const config = await manager.addEndpoint(ctx);
118
+ if (!config.context)
119
+ config.context = adapterKey;
120
+ if (!config.name?.trim()) {
121
+ throw new Error('Endpoint 名称不能为空');
122
+ }
123
+ const endpoints = readAllEndpoints(this.root);
124
+ try {
125
+ assertUniqueName(endpoints, config.context, config.name);
126
+ }
127
+ catch (err) {
128
+ if (err instanceof Error && err.message.includes('已存在')) {
129
+ const online = adapter.endpoints.has(config.name);
130
+ const hint = online
131
+ ? '该 Endpoint 已在运行时注册,无需重复扫码;可发 /endpoints 确认。若 zhin.config.yml 未更新,请 /endpoint sync。'
132
+ : '可用 /endpoint start 重试连接,或 /endpoint remove 后重新添加。';
133
+ throw new Error(`${err.message}。${hint}`);
134
+ }
135
+ throw err;
136
+ }
137
+ endpoints.push(config);
138
+ await this.persistEndpoints(endpoints);
139
+ try {
140
+ await this.connectConfig(adapter, config);
141
+ }
142
+ catch (err) {
143
+ const needsRestart = adapter.getEndpointNeedsRestart?.() ??
144
+ adapter.constructor.endpointNeedsRestart;
145
+ const hint = needsRestart
146
+ ? '配置已写入,请重启进程后连接。'
147
+ : `配置已写入,可用 /endpoint start ${adapterKey} ${config.name} 重试。`;
148
+ throw new Error(`${err instanceof Error ? err.message : String(err)}(${hint})`);
149
+ }
150
+ const prefix = initialReply ? `${initialReply}\n` : '';
151
+ return {
152
+ message: `${prefix}✅ 已添加并连接 endpoint \`${config.name}\`(${adapterKey}),已写入 zhin.config。`,
153
+ config,
154
+ };
155
+ }
156
+ async edit(adapterKey, name, message) {
157
+ const adapter = this.resolveAdapter(adapterKey);
158
+ const manager = this.resolveManager(adapterKey);
159
+ const endpoints = readAllEndpoints(this.root);
160
+ const index = endpoints.findIndex((e) => e.context === adapterKey && e.name === name);
161
+ if (index < 0) {
162
+ throw new Error(`zhin.config 中不存在 ${adapterKey}/${name}`);
163
+ }
164
+ if (adapter.endpoints.has(name)) {
165
+ await this.disconnectRuntime(adapter, name);
166
+ }
167
+ const ctx = buildProvisionContext(this.root, message);
168
+ const updated = await manager.editEndpoint(name, ctx);
169
+ updated.context = adapterKey;
170
+ updated.name = name;
171
+ endpoints[index] = updated;
172
+ await this.persistEndpoints(endpoints);
173
+ try {
174
+ await this.connectConfig(adapter, updated);
175
+ }
176
+ catch (err) {
177
+ throw new Error(`配置已更新,但连接失败:${err instanceof Error ? err.message : String(err)}。` +
178
+ `可用 /endpoint start ${adapterKey} ${name} 重试。`);
179
+ }
180
+ return {
181
+ message: `✅ 已更新并连接 endpoint \`${name}\`(${adapterKey})。`,
182
+ config: updated,
183
+ };
184
+ }
185
+ async remove(adapterKey, name) {
186
+ const adapter = this.resolveAdapter(adapterKey);
187
+ const manager = this.resolveManager(adapterKey);
188
+ await this.stop(adapterKey, name);
189
+ const ok = await manager.removeEndpoint(name);
190
+ if (!ok) {
191
+ throw new Error(`无法移除 ${adapterKey}/${name}`);
192
+ }
193
+ const endpoints = readAllEndpoints(this.root);
194
+ const next = endpoints.filter((e) => !(e.context === adapterKey && e.name === name));
195
+ if (next.length === endpoints.length) {
196
+ throw new Error(`zhin.config 中不存在 ${adapterKey}/${name}`);
197
+ }
198
+ await this.persistEndpoints(next);
199
+ return { message: `✅ 已从配置移除 endpoint \`${name}\`(${adapterKey})。` };
200
+ }
201
+ async start(adapterKey, name, message) {
202
+ const adapter = this.resolveAdapter(adapterKey);
203
+ const manager = this.resolveManager(adapterKey);
204
+ const endpoints = readAllEndpoints(this.root);
205
+ const config = endpoints.find((e) => e.context === adapterKey && e.name === name);
206
+ if (!config) {
207
+ throw new Error(`zhin.config 中不存在 ${adapterKey}/${name}`);
208
+ }
209
+ if (adapter.endpoints.has(name)) {
210
+ return { message: `Endpoint ${adapterKey}/${name} 已在线。` };
211
+ }
212
+ const ctx = buildProvisionContext(this.root, message);
213
+ await manager.startEndpoint(name, ctx);
214
+ await this.connectConfig(adapter, config);
215
+ return { message: `✅ 已连接 endpoint \`${name}\`(${adapterKey})。`, config };
216
+ }
217
+ async stop(adapterKey, name) {
218
+ const adapter = this.resolveAdapter(adapterKey);
219
+ const manager = this.resolveManager(adapterKey);
220
+ const stopped = await this.disconnectRuntime(adapter, name);
221
+ await manager.stopEndpoint(name);
222
+ if (!stopped) {
223
+ return { message: `Endpoint ${adapterKey}/${name} 当前未在线。` };
224
+ }
225
+ return { message: `✅ 已断开 endpoint \`${name}\`(${adapterKey}),配置仍保留。` };
226
+ }
227
+ cancelProvision() {
228
+ for (const adapterName of this.root.adapters) {
229
+ const adapter = this.root.inject(adapterName);
230
+ if (!(adapter instanceof Adapter))
231
+ continue;
232
+ const manager = resolveEndpointManager(adapter);
233
+ if (manager?.cancelProvision?.())
234
+ return true;
235
+ }
236
+ return false;
237
+ }
238
+ }
239
+ export function createEndpointLifecycleService(root) {
240
+ return new EndpointLifecycleService(root);
241
+ }
@@ -25,4 +25,3 @@ export declare function emitEndpointLifecycle(plugin: Plugin, adapter: Adapter,
25
25
  phase?: string;
26
26
  detail?: Record<string, unknown>;
27
27
  }): Promise<void>;
28
- //# sourceMappingURL=endpoint-lifecycle.d.ts.map
@@ -33,4 +33,3 @@ export async function emitEndpointLifecycle(plugin, adapter, endpoint, kind, det
33
33
  });
34
34
  adapter.emit('notice.receive', notice);
35
35
  }
36
- //# sourceMappingURL=endpoint-lifecycle.js.map
@@ -0,0 +1,34 @@
1
+ import type { Schema } from '@zhin.js/schema';
2
+ import type { Message } from '../message.js';
3
+ import type { Plugin } from '../plugin.js';
4
+ /** zhin.config.endpoints[] 单条记录 */
5
+ export type EndpointConfigRecord = Record<string, unknown> & {
6
+ context: string;
7
+ name: string;
8
+ };
9
+ export type EndpointStatusExtra = Record<string, unknown>;
10
+ export interface ProvisionContext {
11
+ message: Message;
12
+ root: Plugin;
13
+ /** 长连接 / 扫码 / 登录进度回调(由 core 转发到 message.$reply) */
14
+ onStatusUpdate: (status: string, extra?: EndpointStatusExtra) => void | Promise<void>;
15
+ }
16
+ export interface EndpointManager {
17
+ /** 是否支持运行时 add(含 schema 通用或自定义) */
18
+ supportsProvision(): boolean;
19
+ listEndpoints(): EndpointConfigRecord[];
20
+ addEndpoint(ctx: ProvisionContext): Promise<EndpointConfigRecord>;
21
+ editEndpoint(name: string, ctx: ProvisionContext): Promise<EndpointConfigRecord>;
22
+ removeEndpoint(name: string): Promise<boolean>;
23
+ startEndpoint(name: string, ctx: ProvisionContext): Promise<void>;
24
+ stopEndpoint(name: string): Promise<boolean>;
25
+ /** 取消进行中的 add/edit 交互(如 QQ 扫码);无则返回 false */
26
+ cancelProvision?(): boolean;
27
+ }
28
+ export interface EndpointManagerClass {
29
+ new (adapter: import('../adapter.js').Adapter): EndpointManager;
30
+ /** 热连接失败时是否建议重启进程 */
31
+ readonly needsRestart?: boolean;
32
+ /** 通用 schema 驱动 add/edit 时使用 */
33
+ readonly endpointConfigSchema?: Schema;
34
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,24 @@
1
+ export interface GenerateQrCodeOptions {
2
+ width?: number;
3
+ margin?: number;
4
+ errorCorrectionLevel?: 'L' | 'M' | 'Q' | 'H';
5
+ }
6
+ export interface PrintQrCodeTerminalOptions {
7
+ small?: boolean;
8
+ }
9
+ /** 二维码实例:一次 generate,多种输出 */
10
+ export declare class GeneratedQrCode {
11
+ #private;
12
+ private constructor();
13
+ static generate(text: string, options?: GenerateQrCodeOptions): Promise<GeneratedQrCode>;
14
+ /** data URL,含 `data:image/png;base64,...` 前缀 */
15
+ toDataUrl(): string;
16
+ /**
17
+ * encoding === 'base64' → 纯 base64 载荷(无 data: 前缀)
18
+ */
19
+ toString(encoding: 'base64'): string;
20
+ /** 输出 ASCII 二维码到 process.stdout */
21
+ printToTerminal(options?: PrintQrCodeTerminalOptions): Promise<void>;
22
+ }
23
+ /** 便捷别名 */
24
+ export declare const generateQrCode: typeof GeneratedQrCode.generate;
@@ -0,0 +1,45 @@
1
+ import QRCode from 'qrcode';
2
+ /** 二维码实例:一次 generate,多种输出 */
3
+ export class GeneratedQrCode {
4
+ #text;
5
+ #dataUrl;
6
+ constructor(text, dataUrl) {
7
+ this.#text = text;
8
+ this.#dataUrl = dataUrl;
9
+ }
10
+ static async generate(text, options = {}) {
11
+ const dataUrl = await QRCode.toDataURL(text, {
12
+ width: options.width ?? 280,
13
+ margin: options.margin ?? 2,
14
+ errorCorrectionLevel: options.errorCorrectionLevel ?? 'M',
15
+ });
16
+ return new GeneratedQrCode(text, dataUrl);
17
+ }
18
+ /** data URL,含 `data:image/png;base64,...` 前缀 */
19
+ toDataUrl() {
20
+ return this.#dataUrl;
21
+ }
22
+ /**
23
+ * encoding === 'base64' → 纯 base64 载荷(无 data: 前缀)
24
+ */
25
+ toString(encoding) {
26
+ if (encoding !== 'base64') {
27
+ throw new Error(`GeneratedQrCode.toString: unsupported encoding "${encoding}"`);
28
+ }
29
+ const prefix = 'data:image/png;base64,';
30
+ if (!this.#dataUrl.startsWith(prefix)) {
31
+ throw new Error('GeneratedQrCode.toString: unexpected data URL format');
32
+ }
33
+ return this.#dataUrl.slice(prefix.length);
34
+ }
35
+ /** 输出 ASCII 二维码到 process.stdout */
36
+ async printToTerminal(options = {}) {
37
+ const terminalText = await QRCode.toString(this.#text, {
38
+ type: 'terminal',
39
+ small: options.small ?? true,
40
+ });
41
+ process.stdout.write(`${terminalText}\n`);
42
+ }
43
+ }
44
+ /** 便捷别名 */
45
+ export const generateQrCode = GeneratedQrCode.generate.bind(GeneratedQrCode);
@@ -0,0 +1,6 @@
1
+ import type { MessageElement, SendContent } from '../types.js';
2
+ import type { Segment } from './segment-contract/types.js';
3
+ /** 通用 IM adapter:legacy wire → canonical Segment[] */
4
+ export declare function toCanonicalSegments(content: readonly MessageElement[] | readonly unknown[]): Segment[];
5
+ /** canonical → wire(mention→at;image MediaRef→legacy 字段) */
6
+ export declare function fromCanonicalSegments(content: SendContent): MessageElement[];
@@ -0,0 +1,232 @@
1
+ import { createImageSegment, isMediaRef, mediaRefFromLegacyData, mediaRefToLegacyFields, readMentionTarget, } from './segment-contract/index.js';
2
+ function isRecord(value) {
3
+ return typeof value === 'object' && value !== null && !Array.isArray(value);
4
+ }
5
+ function readPlatform(seg) {
6
+ const platform = seg.platform;
7
+ return platform && typeof platform === 'object' ? platform : undefined;
8
+ }
9
+ function normalizeMention(seg) {
10
+ const data = seg.data;
11
+ const target = readMentionTarget(data);
12
+ const name = typeof data.name === 'string' && data.name ? data.name : undefined;
13
+ const platform = readPlatform(seg);
14
+ return {
15
+ type: 'mention',
16
+ data: name ? { target, name } : { target },
17
+ ...(platform ? { platform } : {}),
18
+ };
19
+ }
20
+ function normalizeImage(seg) {
21
+ const data = seg.data;
22
+ const platform = readPlatform(seg);
23
+ if (isMediaRef(data.media)) {
24
+ return {
25
+ type: 'image',
26
+ data: {
27
+ media: data.media,
28
+ ...(typeof data.alt === 'string' ? { alt: data.alt } : {}),
29
+ },
30
+ ...(platform ? { platform } : {}),
31
+ };
32
+ }
33
+ const media = mediaRefFromLegacyData(data);
34
+ if (media) {
35
+ const mergedPlatform = { ...(platform ?? {}) };
36
+ for (const key of ['url', 'file', 'src', 'file_id']) {
37
+ if (typeof data[key] === 'string' && data[key])
38
+ mergedPlatform[key] = data[key];
39
+ }
40
+ const platformKeys = Object.keys(mergedPlatform);
41
+ const legacyPlatform = platformKeys.length === 0
42
+ ? undefined
43
+ : platformKeys.length === 1 && mergedPlatform[platformKeys[0]] === media.value
44
+ ? undefined
45
+ : mergedPlatform;
46
+ return createImageSegment(media, {
47
+ alt: typeof data.alt === 'string' ? data.alt : undefined,
48
+ platform: legacyPlatform,
49
+ });
50
+ }
51
+ return seg;
52
+ }
53
+ function normalizeReply(seg) {
54
+ const data = seg.data;
55
+ const messageId = String(data.message_id ?? data.id ?? '').trim();
56
+ if (!messageId)
57
+ return seg;
58
+ return { type: 'reply', data: { message_id: messageId } };
59
+ }
60
+ function normalizeLink(seg) {
61
+ const data = seg.data;
62
+ const url = String(data.url ?? data.href ?? '').trim();
63
+ if (!url)
64
+ return seg;
65
+ const text = typeof data.text === 'string' && data.text ? data.text : undefined;
66
+ const platform = readPlatform(seg);
67
+ return {
68
+ type: 'link',
69
+ data: text ? { url, text } : { url },
70
+ ...(platform ? { platform } : {}),
71
+ };
72
+ }
73
+ function normalizeForward(seg) {
74
+ const data = seg.data;
75
+ const forwardId = String(data.forward_id ?? data.id ?? data.resid ?? '').trim();
76
+ if (!forwardId)
77
+ return seg;
78
+ const title = typeof data.title === 'string' ? data.title : undefined;
79
+ const messages = Array.isArray(data.messages) ? data.messages : undefined;
80
+ const platform = { ...(readPlatform(seg) ?? {}) };
81
+ if (data.resid != null)
82
+ platform.resid = String(data.resid);
83
+ return {
84
+ type: 'forward',
85
+ data: {
86
+ forward_id: forwardId,
87
+ ...(title ? { title } : {}),
88
+ ...(messages ? { messages: messages } : {}),
89
+ },
90
+ ...(Object.keys(platform).length ? { platform } : {}),
91
+ };
92
+ }
93
+ function isPlatformSticker(seg) {
94
+ if (seg.type !== 'sticker')
95
+ return false;
96
+ const data = seg.data;
97
+ return data.package_id != null
98
+ || data.sticker_id != null
99
+ || data.packageId != null
100
+ || data.stickerId != null;
101
+ }
102
+ function normalizeFace(seg) {
103
+ if (isPlatformSticker(seg))
104
+ return seg;
105
+ const data = seg.data;
106
+ const rawId = data.id ?? data.face_id;
107
+ const name = typeof data.name === 'string'
108
+ ? data.name
109
+ : typeof data.text === 'string'
110
+ ? data.text
111
+ : undefined;
112
+ const platform = readPlatform(seg);
113
+ return {
114
+ type: 'face',
115
+ data: {
116
+ ...(rawId != null ? { id: rawId } : {}),
117
+ ...(name ? { name } : {}),
118
+ },
119
+ ...(platform ? { platform } : {}),
120
+ };
121
+ }
122
+ function normalizeMarkdown(seg) {
123
+ const data = seg.data;
124
+ const content = typeof data.content === 'string'
125
+ ? data.content
126
+ : typeof data.text === 'string'
127
+ ? data.text
128
+ : '';
129
+ return { type: 'markdown', data: { content } };
130
+ }
131
+ function normalizeSegment(seg) {
132
+ if (seg.type === 'at' || seg.type === 'mention')
133
+ return normalizeMention(seg);
134
+ if (seg.type === 'image')
135
+ return normalizeImage(seg);
136
+ if (seg.type === 'reply')
137
+ return normalizeReply(seg);
138
+ if (seg.type === 'forward')
139
+ return normalizeForward(seg);
140
+ if (seg.type === 'sticker' && isPlatformSticker(seg))
141
+ return seg;
142
+ if (seg.type === 'face' || seg.type === 'sticker' || seg.type === 'emoji')
143
+ return normalizeFace(seg);
144
+ if (seg.type === 'link')
145
+ return normalizeLink(seg);
146
+ if (seg.type === 'markdown')
147
+ return normalizeMarkdown(seg);
148
+ return seg;
149
+ }
150
+ function asMessageSegments(content) {
151
+ return content.map((item) => {
152
+ if (typeof item === 'string')
153
+ return { type: 'text', data: { text: item } };
154
+ return item;
155
+ });
156
+ }
157
+ function asCanonicalSegments(content) {
158
+ if (typeof content === 'string') {
159
+ return [{ type: 'text', data: { text: content } }];
160
+ }
161
+ const items = Array.isArray(content) ? content : [content];
162
+ return items.map((item) => {
163
+ if (typeof item === 'string')
164
+ return { type: 'text', data: { text: item } };
165
+ return item;
166
+ });
167
+ }
168
+ /** 通用 IM adapter:legacy wire → canonical Segment[] */
169
+ export function toCanonicalSegments(content) {
170
+ return asMessageSegments(content).map((seg) => normalizeSegment(seg));
171
+ }
172
+ function mapCanonicalToWire(seg) {
173
+ if (seg.type === 'image' && isRecord(seg.data) && seg.data.media) {
174
+ const media = seg.data.media;
175
+ const legacy = mediaRefToLegacyFields(media);
176
+ return {
177
+ type: 'image',
178
+ data: {
179
+ ...legacy,
180
+ media,
181
+ ...(typeof seg.data.alt === 'string' ? { alt: seg.data.alt } : {}),
182
+ },
183
+ ...(seg.platform ? { platform: seg.platform } : {}),
184
+ };
185
+ }
186
+ if (seg.type === 'mention') {
187
+ const data = seg.data;
188
+ return {
189
+ type: 'at',
190
+ data: {
191
+ id: data.target,
192
+ ...(data.name ? { name: data.name } : {}),
193
+ },
194
+ ...(seg.platform ? { platform: seg.platform } : {}),
195
+ };
196
+ }
197
+ if (seg.type === 'reply') {
198
+ const messageId = String(seg.data.message_id);
199
+ return {
200
+ type: 'reply',
201
+ data: { id: messageId, message_id: messageId },
202
+ ...(seg.platform ? { platform: seg.platform } : {}),
203
+ };
204
+ }
205
+ if (seg.type === 'forward') {
206
+ const data = seg.data;
207
+ const resid = seg.platform?.resid ?? data.forward_id;
208
+ return {
209
+ type: 'forward',
210
+ data: {
211
+ id: data.forward_id,
212
+ resid,
213
+ ...(data.title ? { title: data.title } : {}),
214
+ ...(data.messages ? { messages: data.messages } : {}),
215
+ },
216
+ ...(seg.platform ? { platform: seg.platform } : {}),
217
+ };
218
+ }
219
+ if (seg.type === 'link') {
220
+ const data = seg.data;
221
+ return {
222
+ type: 'link',
223
+ data: { url: data.url, ...(data.text ? { text: data.text } : {}) },
224
+ ...(seg.platform ? { platform: seg.platform } : {}),
225
+ };
226
+ }
227
+ return seg;
228
+ }
229
+ /** canonical → wire(mention→at;image MediaRef→legacy 字段) */
230
+ export function fromCanonicalSegments(content) {
231
+ return asCanonicalSegments(content).map((seg) => mapCanonicalToWire(seg));
232
+ }
@@ -0,0 +1,13 @@
1
+ import type { HtmlRendererForRichSegment } from './rich-segments/types.js';
2
+ /** 动态 import 时使用的包名(与 @zhin.js/html-renderer package.json 一致) */
3
+ export declare const HTML_RENDERER_PACKAGE = "@zhin.js/html-renderer";
4
+ export interface LoadHtmlRendererOptions {
5
+ getConfig?: () => Record<string, unknown> | undefined;
6
+ warn?: (message: string) => void;
7
+ }
8
+ /** zhin 启动时已创建 renderer 时注入,避免 core 目录下 peer 解析失败 */
9
+ export declare function seedHtmlRenderer(renderer: HtmlRendererForRichSegment): void;
10
+ /** 动态加载 @zhin.js/html-renderer;未安装时 warn 一次并返回 undefined */
11
+ export declare function loadHtmlRenderer(opts?: LoadHtmlRendererOptions): Promise<HtmlRendererForRichSegment | undefined>;
12
+ /** 测试用:重置加载缓存 */
13
+ export declare function resetHtmlRendererLoaderForTests(): void;
@@ -0,0 +1,33 @@
1
+ import { importOptionalPeerPackage } from './optional-peer-import.js';
2
+ /** 动态 import 时使用的包名(与 @zhin.js/html-renderer package.json 一致) */
3
+ export const HTML_RENDERER_PACKAGE = '@zhin.js/html-renderer';
4
+ let cached;
5
+ let warned = false;
6
+ /** zhin 启动时已创建 renderer 时注入,避免 core 目录下 peer 解析失败 */
7
+ export function seedHtmlRenderer(renderer) {
8
+ cached = renderer;
9
+ }
10
+ /** 动态加载 @zhin.js/html-renderer;未安装时 warn 一次并返回 undefined */
11
+ export async function loadHtmlRenderer(opts) {
12
+ if (cached !== undefined) {
13
+ return cached ?? undefined;
14
+ }
15
+ try {
16
+ const mod = await importOptionalPeerPackage(HTML_RENDERER_PACKAGE);
17
+ cached = mod.createHtmlRenderer(opts?.getConfig?.() ?? {});
18
+ return cached;
19
+ }
20
+ catch {
21
+ if (!warned) {
22
+ warned = true;
23
+ opts?.warn?.(`未安装 ${HTML_RENDERER_PACKAGE},html/markdown=>image 已降级为 text。安装: pnpm add ${HTML_RENDERER_PACKAGE}`);
24
+ }
25
+ cached = null;
26
+ return undefined;
27
+ }
28
+ }
29
+ /** 测试用:重置加载缓存 */
30
+ export function resetHtmlRendererLoaderForTests() {
31
+ cached = undefined;
32
+ warned = false;
33
+ }
@@ -1,9 +1,9 @@
1
1
  /**
2
- * 出站 `html` 消息段兜底:未装 html-renderer 或转图失败时,自动剥离为 text 段。
2
+ * 出站 `html` 消息段兜底:等价于 Adapter policy `html:'text'`。
3
+ * 出站渲染首选 `resolveRichSegments`(renderSendMessage 首步)。
3
4
  */
4
5
  import type { Plugin } from '../plugin.js';
5
6
  import type { SendContent } from '../types.js';
6
7
  export declare function coerceHtmlSegmentsToText(content: SendContent): SendContent;
7
8
  /** 注册链尾 before.sendMessage:将未转换的 html 段降级为 text */
8
9
  export declare function registerHtmlSegmentFallback(plugin: Plugin): () => void;
9
- //# sourceMappingURL=html-segment-fallback.d.ts.map
@@ -47,4 +47,3 @@ export function registerHtmlSegmentFallback(plugin) {
47
47
  plugin.root.on('before.sendMessage', handler);
48
48
  return () => plugin.root.off('before.sendMessage', handler);
49
49
  }
50
- //# sourceMappingURL=html-segment-fallback.js.map
@@ -14,4 +14,3 @@ export declare function htmlToPlainTextWithBlockBreaks(html: string, options?: H
14
14
  * HTML 卡片出站回退:块级换行 + 语义标题轻量 markdown 前缀。
15
15
  */
16
16
  export declare function htmlToFallbackText(html: string, options?: HtmlToPlainTextOptions): string;
17
- //# sourceMappingURL=html-to-text.d.ts.map
@@ -163,4 +163,3 @@ export function htmlToFallbackText(html, options) {
163
163
  .replace(/\n{3,}/g, '\n\n')
164
164
  .trim();
165
165
  }
166
- //# sourceMappingURL=html-to-text.js.map