@xopcai/xopc 0.0.108 → 0.0.110

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 (275) hide show
  1. package/dist/browser-ext/manifest.json +1 -1
  2. package/dist/extensions/feishu/src/outbound/media-load.js +1 -1
  3. package/dist/extensions/feishu/src/pairing-config-resolver.d.ts +1 -0
  4. package/dist/extensions/feishu/src/pairing-config-resolver.js +30 -0
  5. package/dist/extensions/feishu/src/pairing-config-resolver.js.map +1 -0
  6. package/dist/extensions/feishu/src/plugin.d.ts +1 -0
  7. package/dist/extensions/feishu/src/plugin.js +1 -0
  8. package/dist/extensions/feishu/src/plugin.js.map +1 -1
  9. package/dist/extensions/feishu/src/workflow-progress.js +1 -1
  10. package/dist/extensions/telegram/src/access-control.d.ts +2 -1
  11. package/dist/extensions/telegram/src/access-control.js.map +1 -1
  12. package/dist/extensions/telegram/src/account-manager.d.ts +2 -1
  13. package/dist/extensions/telegram/src/account-manager.js.map +1 -1
  14. package/dist/extensions/telegram/src/adapters/gateway-setup.js +26 -26
  15. package/dist/extensions/telegram/src/adapters/gateway-setup.js.map +1 -1
  16. package/dist/extensions/telegram/src/adapters/onboard-cli.js +8 -4
  17. package/dist/extensions/telegram/src/adapters/onboard-cli.js.map +1 -1
  18. package/dist/extensions/telegram/src/adapters/streaming-adapter.js +1 -1
  19. package/dist/extensions/telegram/src/config-schema.d.ts +88 -50
  20. package/dist/extensions/telegram/src/config-schema.js +40 -32
  21. package/dist/extensions/telegram/src/config-schema.js.map +1 -1
  22. package/dist/extensions/telegram/src/config-types.d.ts +54 -0
  23. package/dist/extensions/telegram/src/config-types.js +1 -0
  24. package/dist/extensions/telegram/src/doctor.js +17 -16
  25. package/dist/extensions/telegram/src/doctor.js.map +1 -1
  26. package/dist/extensions/telegram/src/exec-approvals.js +2 -3
  27. package/dist/extensions/telegram/src/exec-approvals.js.map +1 -1
  28. package/dist/extensions/telegram/src/group-config-resolver.d.ts +1 -1
  29. package/dist/extensions/telegram/src/group-config-resolver.js.map +1 -1
  30. package/dist/extensions/telegram/src/inbound-processor.js +1 -1
  31. package/dist/extensions/telegram/src/pairing-config-resolver.d.ts +1 -0
  32. package/dist/extensions/telegram/src/pairing-config-resolver.js +56 -0
  33. package/dist/extensions/telegram/src/pairing-config-resolver.js.map +1 -0
  34. package/dist/extensions/telegram/src/plugin.d.ts +1 -0
  35. package/dist/extensions/telegram/src/plugin.js +9 -10
  36. package/dist/extensions/telegram/src/plugin.js.map +1 -1
  37. package/dist/extensions/telegram/src/routing-integration.js +2 -2
  38. package/dist/extensions/telegram/src/update-offset-store.js +1 -1
  39. package/dist/extensions/telegram/src/workflow-progress.js +1 -1
  40. package/dist/extensions/telegram/xopc.extension.json +156 -122
  41. package/dist/extensions/weixin/src/api/api.js +2 -2
  42. package/dist/extensions/weixin/src/auth/accounts.js +1 -1
  43. package/dist/extensions/weixin/src/cdn/upload.js +1 -1
  44. package/dist/extensions/weixin/src/media/data-url.js +1 -1
  45. package/dist/extensions/weixin/src/messaging/debug-mode.js +1 -1
  46. package/dist/extensions/weixin/src/messaging/inbound.js +1 -1
  47. package/dist/extensions/weixin/src/messaging/process-message.js +1 -1
  48. package/dist/extensions/weixin/src/pairing-config-resolver.d.ts +1 -0
  49. package/dist/extensions/weixin/src/pairing-config-resolver.js +54 -0
  50. package/dist/extensions/weixin/src/pairing-config-resolver.js.map +1 -0
  51. package/dist/extensions/weixin/src/plugin.d.ts +1 -0
  52. package/dist/extensions/weixin/src/plugin.js +2 -1
  53. package/dist/extensions/weixin/src/plugin.js.map +1 -1
  54. package/dist/extensions/weixin/src/storage/sync-buf.js +1 -1
  55. package/dist/extensions/weixin/src/workflow-progress.js +1 -1
  56. package/dist/gateway/static/root/assets/{agents-56kCGHdV.js → agents-CFFioJCI.js} +1 -1
  57. package/dist/gateway/static/root/assets/{apps-page-Dd88J47r.js → apps-page-BYDmkbzG.js} +1 -1
  58. package/dist/gateway/static/root/assets/{channels-settings-Ckyvnvml.js → channels-settings-CsbDaMvd.js} +1 -1
  59. package/dist/gateway/static/root/assets/{cron-page-DKo2ZdRA.js → cron-page-Apk-7p4p.js} +1 -1
  60. package/dist/gateway/static/root/assets/{dist-dmxWdtPG.js → dist-DmGDgpy2.js} +1 -1
  61. package/dist/gateway/static/root/assets/{extension-debug-page-iGpG-vpp.js → extension-debug-page-pxFC-tUa.js} +1 -1
  62. package/dist/gateway/static/root/assets/{extension-page-I7-3uHiD.js → extension-page-W1wiG38F.js} +1 -1
  63. package/dist/gateway/static/root/assets/{extension-settings-page-BisnHG7r.js → extension-settings-page-COXSv6xP.js} +1 -1
  64. package/dist/gateway/static/root/assets/{heartbeat-config-api-tbWAFPN8.js → heartbeat-config-api-DcmAMYmN.js} +1 -1
  65. package/dist/gateway/static/root/assets/{index-slwUkhxH.js → index-C_2yKRJX.js} +3 -3
  66. package/dist/gateway/static/root/assets/{logs-page-CCZiXrWu.js → logs-page-DvTWUOzd.js} +1 -1
  67. package/dist/gateway/static/root/assets/{note-detail-page-BYbw2GLl.js → note-detail-page-CZbdugWZ.js} +1 -1
  68. package/dist/gateway/static/root/assets/{note-time-Cya72Lte.js → note-time-RdyBZxj3.js} +1 -1
  69. package/dist/gateway/static/root/assets/{notes-page-DrAO7VRK.js → notes-page-mEAwy3e1.js} +1 -1
  70. package/dist/gateway/static/root/assets/{schema-form-a6UJCK55.js → schema-form-DEvdni_r.js} +1 -1
  71. package/dist/gateway/static/root/assets/{sessions-page-DNU3Ymvz.js → sessions-page-BsgffzV4.js} +1 -1
  72. package/dist/gateway/static/root/assets/{settings-advanced-gate-CyEJYTbw.js → settings-advanced-gate-t6v8Dwb8.js} +1 -1
  73. package/dist/gateway/static/root/assets/{settings-form-section-DpHo2ecA.js → settings-form-section-BoYYZmJG.js} +1 -1
  74. package/dist/gateway/static/root/assets/{settings-page-YRwe4q56.js → settings-page-ClIthYF8.js} +1 -1
  75. package/dist/gateway/static/root/assets/{share-preview-page-B7rf4QB4.js → share-preview-page-Dd9et7KD.js} +1 -1
  76. package/dist/gateway/static/root/assets/skills-page-DEXtxyfQ.js +2 -0
  77. package/dist/gateway/static/root/assets/{voice-api-key-field-Btagks_B.js → voice-api-key-field-CNrKzQrf.js} +1 -1
  78. package/dist/gateway/static/root/assets/{workflow-page.utils-DvzJKs6W.js → workflow-page.utils-EYg_xBQS.js} +1 -1
  79. package/dist/gateway/static/root/assets/{workflows-page-BgOAgCOG.js → workflows-page-EMZkzJNN.js} +1 -1
  80. package/dist/gateway/static/root/index.html +1 -1
  81. package/dist/package.js +1 -1
  82. package/dist/src/agent/agent-manager.js +7 -7
  83. package/dist/src/agent/agent-scope.js +1 -1
  84. package/dist/src/agent/bootstrap/load-bootstrap-files.js +1 -1
  85. package/dist/src/agent/context/workspace-seed.js +2 -2
  86. package/dist/src/agent/context/workspace-state.js +1 -1
  87. package/dist/src/agent/goals/goal-run-store.js +4 -4
  88. package/dist/src/agent/goals/persistent-goal-service.js +1 -1
  89. package/dist/src/agent/goals/post-turn.js +2 -2
  90. package/dist/src/agent/image/load-image-media.js +2 -2
  91. package/dist/src/agent/ipc/bus.js +1 -1
  92. package/dist/src/agent/ipc/inbox.js +2 -2
  93. package/dist/src/agent/ipc/socket.js +1 -1
  94. package/dist/src/agent/mcp/bundle-mcp-materialize.js +1 -1
  95. package/dist/src/agent/mcp/bundle-mcp-runtime.js +1 -1
  96. package/dist/src/agent/mcp/mcp-transport-config.js +1 -1
  97. package/dist/src/agent/mcp/mcp-transport.js +1 -1
  98. package/dist/src/agent/memory/builtin-memory-store.js +1 -1
  99. package/dist/src/agent/memory/dreaming/deep-promotion.js +1 -1
  100. package/dist/src/agent/memory/dreaming/events.js +1 -1
  101. package/dist/src/agent/memory/dreaming/last-run.js +1 -1
  102. package/dist/src/agent/memory/dreaming/light-sweep.js +1 -1
  103. package/dist/src/agent/memory/dreaming/preview.js +1 -1
  104. package/dist/src/agent/memory/dreaming/rem-patterns.js +1 -1
  105. package/dist/src/agent/memory/dreaming/short-term-store.js +1 -1
  106. package/dist/src/agent/memory/dreaming/utils.js +1 -1
  107. package/dist/src/agent/memory/memory-flush.js +1 -1
  108. package/dist/src/agent/memory/plugin-discovery.js +1 -1
  109. package/dist/src/agent/models/manager.js +1 -1
  110. package/dist/src/agent/prompt/service-prompt-builder.js +2 -2
  111. package/dist/src/agent/reply/post-compaction-context.js +1 -1
  112. package/dist/src/agent/reply/workspace-boundary-read.js +1 -1
  113. package/dist/src/agent/sandbox/path-policy.js +2 -2
  114. package/dist/src/agent/service.js +4 -4
  115. package/dist/src/agent/session/session-inspector.js +1 -1
  116. package/dist/src/agent/skills/config.js +1 -1
  117. package/dist/src/agent/skills/hub-hash.js +2 -2
  118. package/dist/src/agent/skills/hub-lock.js +1 -1
  119. package/dist/src/agent/skills/hub-pull.js +2 -2
  120. package/dist/src/agent/skills/index.js +1 -1
  121. package/dist/src/agent/skills/managed-store.js +1 -1
  122. package/dist/src/agent/skills/scanner.js +1 -1
  123. package/dist/src/agent/skills/skill-manage-ops.js +1 -1
  124. package/dist/src/agent/skills/skill-manager.js +1 -1
  125. package/dist/src/agent/starter-agents.js +1 -1
  126. package/dist/src/agent/tools/dreaming-tool.js +1 -1
  127. package/dist/src/agent/tools/factory.js +1 -1
  128. package/dist/src/agent/tools/image-generate-tool.js +1 -1
  129. package/dist/src/agent/tools/send-media.js +1 -1
  130. package/dist/src/agent/tools/skill-manage-tool.js +1 -1
  131. package/dist/src/agent/tools/workflow-tool.js +1 -1
  132. package/dist/src/agent/tools/write.js +1 -1
  133. package/dist/src/agent/workflow/catalog.js +1 -1
  134. package/dist/src/auth/credentials.js +3 -3
  135. package/dist/src/auth/profiles/store.js +2 -2
  136. package/dist/src/auth/sync-provider-auth.js +1 -1
  137. package/dist/src/browser/cache-dir-policy.js +1 -1
  138. package/dist/src/browser/cdp-local-launcher.js +2 -2
  139. package/dist/src/browser/providers/browser-ext-install.js +3 -3
  140. package/dist/src/browser/providers/cloakbrowser.js +4 -4
  141. package/dist/src/browser/providers/playwright-doctor.js +1 -1
  142. package/dist/src/browser/stealth.js +1 -1
  143. package/dist/src/channels/channel-domain.d.ts +1 -81
  144. package/dist/src/channels/outbound/persist-store.js +1 -1
  145. package/dist/src/channels/pairing/allow-from-file.js +1 -1
  146. package/dist/src/channels/pairing/index.d.ts +2 -2
  147. package/dist/src/channels/pairing/index.js +2 -2
  148. package/dist/src/channels/pairing/pairing-service.d.ts +13 -0
  149. package/dist/src/channels/pairing/pairing-service.js +78 -63
  150. package/dist/src/channels/pairing/pairing-service.js.map +1 -1
  151. package/dist/src/channels/pairing/pairing-store.js +2 -2
  152. package/dist/src/chat-commands/agent-edit.js +2 -2
  153. package/dist/src/chat-commands/builtins/config.js +6 -13
  154. package/dist/src/chat-commands/builtins/config.js.map +1 -1
  155. package/dist/src/chat-commands/context.js +1 -1
  156. package/dist/src/cli/commands/config.js +1 -1
  157. package/dist/src/cli/commands/doctor/checks/config-health.js +1 -1
  158. package/dist/src/cli/commands/doctor/checks/provider-auth.js +1 -1
  159. package/dist/src/cli/commands/doctor/checks/state-integrity.js +1 -1
  160. package/dist/src/cli/commands/doctor/checks/workspace-status.js +1 -1
  161. package/dist/src/cli/commands/extension-create.js +1 -1
  162. package/dist/src/cli/commands/extension-dev.js +1 -1
  163. package/dist/src/cli/commands/extension-marketplace.js +2 -2
  164. package/dist/src/cli/commands/extension-pack.js +2 -2
  165. package/dist/src/cli/commands/extension.js +2 -2
  166. package/dist/src/cli/commands/gateway/logs.js +1 -1
  167. package/dist/src/cli/commands/image.js +1 -1
  168. package/dist/src/cli/commands/init.js +3 -3
  169. package/dist/src/cli/commands/models.js +1 -1
  170. package/dist/src/cli/commands/onboard/model.js +2 -2
  171. package/dist/src/cli/utils/init-workspace-core.js +2 -2
  172. package/dist/src/config/agent-profile.js +1 -1
  173. package/dist/src/config/agent-typed-models.js +1 -1
  174. package/dist/src/config/gateway-bind.js +1 -1
  175. package/dist/src/config/index.js +5 -5
  176. package/dist/src/config/loader.js +2 -2
  177. package/dist/src/config/models-json.js +2 -2
  178. package/dist/src/config/paths-state.js +1 -1
  179. package/dist/src/config/profile.js +2 -2
  180. package/dist/src/config/schema.js +9 -14
  181. package/dist/src/config/schema.js.map +1 -1
  182. package/dist/src/config/workspace-path.js +1 -1
  183. package/dist/src/cron/executor.js +2 -2
  184. package/dist/src/cron/persistence.js +1 -1
  185. package/dist/src/daemon/constants.js +1 -1
  186. package/dist/src/daemon/install-plan.js +2 -2
  187. package/dist/src/daemon/launchd.js +2 -2
  188. package/dist/src/daemon/schtasks.js +2 -2
  189. package/dist/src/daemon/systemd.js +2 -2
  190. package/dist/src/extensions/bundle-mcp.js +1 -1
  191. package/dist/src/extensions/discover-extensions.js +1 -1
  192. package/dist/src/extensions/health.js +1 -1
  193. package/dist/src/extensions/loader.js +1 -1
  194. package/dist/src/extensions/lockfile.js +2 -2
  195. package/dist/src/extensions/update.js +1 -1
  196. package/dist/src/gateway/agents-admin.js +2 -2
  197. package/dist/src/gateway/file-path-classifier.js +2 -2
  198. package/dist/src/gateway/hono/lib/config-payload.js +1 -1
  199. package/dist/src/gateway/hono/lib/extension-store.js +2 -2
  200. package/dist/src/gateway/hono/lib/static-ui.js +2 -2
  201. package/dist/src/gateway/hono/oauth-async.js +1 -1
  202. package/dist/src/gateway/hono/oauth.js +1 -1
  203. package/dist/src/gateway/hono/routes/agents.js +1 -1
  204. package/dist/src/gateway/hono/routes/auth-registry-extensions.js +1 -1
  205. package/dist/src/gateway/hono/routes/config-patch/misc.js +1 -1
  206. package/dist/src/gateway/hono/routes/dreaming.js +1 -1
  207. package/dist/src/gateway/hono/routes/host-fs.js +2 -2
  208. package/dist/src/gateway/hono/routes/models.js +1 -1
  209. package/dist/src/gateway/hono/routes/shares.js +1 -1
  210. package/dist/src/gateway/hono/routes/workflows.js +1 -1
  211. package/dist/src/gateway/hono/routes/workspace.js +2 -2
  212. package/dist/src/gateway/lock.js +3 -3
  213. package/dist/src/gateway/ports.js +1 -1
  214. package/dist/src/gateway/service/agent-runner.js +2 -2
  215. package/dist/src/gateway/service/marketplace-service.js +2 -2
  216. package/dist/src/gateway/service.js +3 -3
  217. package/dist/src/gateway/workspace-fs-file-list.js +1 -1
  218. package/dist/src/infra/brew.js +1 -1
  219. package/dist/src/infra/package-json.js +1 -1
  220. package/dist/src/infra/package-update-steps.js +1 -1
  221. package/dist/src/infra/path-env.js +2 -2
  222. package/dist/src/infra/restart.js +2 -2
  223. package/dist/src/infra/stable-node-path.js +1 -1
  224. package/dist/src/infra/update-check.js +1 -1
  225. package/dist/src/infra/update-global.js +1 -1
  226. package/dist/src/infra/update-lock.js +3 -3
  227. package/dist/src/infra/update-runner.js +1 -1
  228. package/dist/src/infra/update-startup.js +2 -2
  229. package/dist/src/infra/write-file-atomic.js +2 -2
  230. package/dist/src/media/store.js +1 -1
  231. package/dist/src/notes/agent-context.js +1 -1
  232. package/dist/src/notes/store.js +2 -2
  233. package/dist/src/project-trust/trust-store.js +2 -2
  234. package/dist/src/providers/auth-runtime/auth-profile-store.js +1 -1
  235. package/dist/src/providers/index.js +2 -2
  236. package/dist/src/providers/model-registry.js +1 -1
  237. package/dist/src/session/init-session-turn.js +2 -2
  238. package/dist/src/session/resolve-session.js +3 -3
  239. package/dist/src/session/session-title.js +2 -2
  240. package/dist/src/session/store.js +2 -2
  241. package/dist/src/share/share-auto.js +2 -2
  242. package/dist/src/share/share-store.js +3 -3
  243. package/dist/src/share/share-thumbnail.js +2 -2
  244. package/dist/src/share/share-zip.js +1 -1
  245. package/dist/src/share/site-share-store.js +3 -3
  246. package/dist/src/share/site-static-serve.js +1 -1
  247. package/dist/src/storage/sqlite/connection.js +2 -2
  248. package/dist/src/storage/sqlite/memory-index-repository.js +2 -2
  249. package/dist/src/storage/sqlite/migrations/discover.js +1 -1
  250. package/dist/src/storage/sqlite/migrations/runner.js +1 -1
  251. package/dist/src/storage/sqlite/schema.js +1 -1
  252. package/dist/src/tui/backends/embedded-backend.js +1 -1
  253. package/dist/src/tui/clipboard-image.js +3 -3
  254. package/dist/src/tui/theme-manager.js +1 -1
  255. package/dist/src/tui/tui-command-formatters.js +3 -3
  256. package/dist/src/tui/tui-commands.js +2 -2
  257. package/dist/src/tui/tui-keybindings-file.js +1 -1
  258. package/dist/src/tui/tui-scoped-models.js +2 -2
  259. package/dist/src/tui/tui-settings.js +1 -1
  260. package/dist/src/tui/tui-startup-resources.js +1 -1
  261. package/dist/src/tui/tui.js +5 -5
  262. package/dist/src/tunnel/frpc-binary.js +3 -3
  263. package/dist/src/tunnel/frpc-config.js +1 -1
  264. package/dist/src/tunnel/frpc-extract.js +1 -1
  265. package/dist/src/tunnel/tunnel-state.js +1 -1
  266. package/dist/src/utils/logger/audit.js +1 -1
  267. package/dist/src/utils/logger/log-store.js +1 -1
  268. package/dist/src/utils/logger/rotation.js +1 -1
  269. package/dist/src/voice/tts/audio.js +1 -1
  270. package/dist/src/voice/tts/providers/edge-speech.js +2 -2
  271. package/dist/src/workflows/draft/workflow-draft-service.js +1 -1
  272. package/dist/src/workflows/store/event-store.js +1 -1
  273. package/dist/src/workflows/store/run-store.js +1 -1
  274. package/package.json +1 -1
  275. package/dist/gateway/static/root/assets/skills-page-we1NAt7u.js +0 -2
@@ -2,7 +2,7 @@
2
2
  "id": "telegram",
3
3
  "name": "Telegram Channel",
4
4
  "description": "Bundled Telegram Bot channel (private workspace sources; ships inside @xopcai/xopc dist/)",
5
- "version": "0.0.108",
5
+ "version": "0.0.110",
6
6
  "kind": "channel",
7
7
  "main": "src/index.js",
8
8
  "channels": [
@@ -48,11 +48,42 @@
48
48
  "accounts": {
49
49
  "advanced": true
50
50
  },
51
- "groupPolicy": {
51
+ "defaults": {
52
52
  "advanced": true
53
53
  },
54
- "groupAllowFrom": {
55
- "advanced": true
54
+ "accounts.default.botToken": {
55
+ "tags": [
56
+ "basic"
57
+ ],
58
+ "sensitive": true,
59
+ "help": "Telegram bot token"
60
+ },
61
+ "accounts.default.dmPolicy": {
62
+ "tags": [
63
+ "basic"
64
+ ]
65
+ },
66
+ "accounts.default.allowFrom": {
67
+ "tags": [
68
+ "basic"
69
+ ],
70
+ "help": "Telegram user ids allowed for private chat when DM policy is pairing or allowlist."
71
+ },
72
+ "accounts.default.groupPolicy": {
73
+ "tags": [
74
+ "basic"
75
+ ]
76
+ },
77
+ "accounts.default.groupAllowFrom": {
78
+ "tags": [
79
+ "basic"
80
+ ],
81
+ "help": "Telegram user ids allowed in groups when group policy is allowlist."
82
+ },
83
+ "accounts.default.streaming.mode": {
84
+ "tags": [
85
+ "basic"
86
+ ]
56
87
  }
57
88
  },
58
89
  "configSchema": {
@@ -64,97 +95,11 @@
64
95
  "default": false,
65
96
  "title": "Enabled"
66
97
  },
67
- "allowFrom": {
68
- "type": "array",
69
- "items": {
70
- "type": [
71
- "string",
72
- "number"
73
- ]
74
- },
75
- "title": "DM allow list"
76
- },
77
- "groupAllowFrom": {
78
- "type": "array",
79
- "items": {
80
- "type": [
81
- "string",
82
- "number"
83
- ]
84
- },
85
- "title": "Group allow list"
86
- },
87
98
  "debug": {
88
99
  "type": "boolean",
89
100
  "default": false,
90
101
  "title": "Debug"
91
102
  },
92
- "apiRoot": {
93
- "type": "string",
94
- "title": "API root"
95
- },
96
- "proxy": {
97
- "type": "string",
98
- "title": "Proxy"
99
- },
100
- "dmPolicy": {
101
- "type": "string",
102
- "enum": [
103
- "pairing",
104
- "allowlist",
105
- "open",
106
- "disabled"
107
- ],
108
- "default": "open",
109
- "title": "DM policy"
110
- },
111
- "groupPolicy": {
112
- "type": "string",
113
- "enum": [
114
- "open",
115
- "disabled",
116
- "allowlist"
117
- ],
118
- "default": "open",
119
- "title": "Group policy"
120
- },
121
- "replyToMode": {
122
- "type": "string",
123
- "enum": [
124
- "off",
125
- "first",
126
- "all"
127
- ],
128
- "default": "off",
129
- "title": "Reply-to mode"
130
- },
131
- "streaming": {
132
- "type": "object",
133
- "title": "Streaming",
134
- "additionalProperties": true,
135
- "properties": {
136
- "mode": {
137
- "type": "string",
138
- "enum": [
139
- "off",
140
- "partial",
141
- "block"
142
- ],
143
- "default": "partial",
144
- "title": "Mode"
145
- }
146
- }
147
- },
148
- "historyLimit": {
149
- "type": "number",
150
- "default": 50,
151
- "title": "History limit"
152
- },
153
- "textChunkLimit": {
154
- "type": "number",
155
- "default": 4000,
156
- "title": "Text chunk limit"
157
- },
158
103
  "accounts": {
159
104
  "type": "object",
160
105
  "title": "Accounts",
@@ -215,7 +160,7 @@
215
160
  "open",
216
161
  "disabled"
217
162
  ],
218
- "default": "open",
163
+ "default": "pairing",
219
164
  "title": "DM policy"
220
165
  },
221
166
  "groupPolicy": {
@@ -276,6 +221,79 @@
276
221
  }
277
222
  }
278
223
  }
224
+ },
225
+ "defaults": {
226
+ "type": "object",
227
+ "title": "Account defaults",
228
+ "additionalProperties": false,
229
+ "properties": {
230
+ "dmPolicy": {
231
+ "type": "string",
232
+ "enum": [
233
+ "pairing",
234
+ "allowlist",
235
+ "open",
236
+ "disabled"
237
+ ],
238
+ "default": "pairing",
239
+ "title": "DM policy"
240
+ },
241
+ "groupPolicy": {
242
+ "type": "string",
243
+ "enum": [
244
+ "open",
245
+ "disabled",
246
+ "allowlist"
247
+ ],
248
+ "default": "open",
249
+ "title": "Group policy"
250
+ },
251
+ "replyToMode": {
252
+ "type": "string",
253
+ "enum": [
254
+ "off",
255
+ "first",
256
+ "all"
257
+ ],
258
+ "default": "off",
259
+ "title": "Reply-to mode"
260
+ },
261
+ "streaming": {
262
+ "type": "object",
263
+ "title": "Streaming",
264
+ "additionalProperties": true,
265
+ "properties": {
266
+ "mode": {
267
+ "type": "string",
268
+ "enum": [
269
+ "off",
270
+ "partial",
271
+ "block"
272
+ ],
273
+ "default": "partial",
274
+ "title": "Mode"
275
+ }
276
+ }
277
+ },
278
+ "historyLimit": {
279
+ "type": "number",
280
+ "default": 50,
281
+ "title": "History limit"
282
+ },
283
+ "textChunkLimit": {
284
+ "type": "number",
285
+ "default": 4000,
286
+ "title": "Text chunk limit"
287
+ },
288
+ "proxy": {
289
+ "type": "string",
290
+ "title": "Proxy"
291
+ },
292
+ "apiRoot": {
293
+ "type": "string",
294
+ "title": "API root"
295
+ }
296
+ }
279
297
  }
280
298
  }
281
299
  },
@@ -288,21 +306,9 @@
288
306
  "enabled": {
289
307
  "title": "启用"
290
308
  },
291
- "allowFrom": {
292
- "title": "私聊允许列表"
293
- },
294
- "groupAllowFrom": {
295
- "title": "群聊允许列表"
296
- },
297
309
  "debug": {
298
310
  "title": "调试"
299
311
  },
300
- "apiRoot": {
301
- "title": "API 根地址"
302
- },
303
- "proxy": {
304
- "title": "代理"
305
- },
306
312
  "accounts": {
307
313
  "title": "账号",
308
314
  "properties": {
@@ -363,34 +369,54 @@
363
369
  }
364
370
  }
365
371
  },
366
- "dmPolicy": {
367
- "title": "私聊策略"
368
- },
369
- "groupPolicy": {
370
- "title": "群聊策略"
371
- },
372
- "replyToMode": {
373
- "title": "回复模式"
374
- },
375
- "streaming": {
376
- "title": "流式输出",
372
+ "defaults": {
373
+ "title": "账号默认值",
377
374
  "properties": {
378
- "mode": {
379
- "title": "模式"
375
+ "dmPolicy": {
376
+ "title": "私聊策略"
377
+ },
378
+ "groupPolicy": {
379
+ "title": "群聊策略"
380
+ },
381
+ "replyToMode": {
382
+ "title": "回复模式"
383
+ },
384
+ "streaming": {
385
+ "title": "流式输出",
386
+ "properties": {
387
+ "mode": {
388
+ "title": "模式"
389
+ }
390
+ }
391
+ },
392
+ "historyLimit": {
393
+ "title": "历史条数"
394
+ },
395
+ "textChunkLimit": {
396
+ "title": "文本分块上限"
397
+ },
398
+ "proxy": {
399
+ "title": "代理"
400
+ },
401
+ "apiRoot": {
402
+ "title": "API 根地址"
380
403
  }
381
404
  }
382
- },
383
- "historyLimit": {
384
- "title": "历史条数"
385
- },
386
- "textChunkLimit": {
387
- "title": "文本分块上限"
388
405
  }
389
406
  }
390
407
  },
391
408
  "uiHints": {
392
409
  "accounts.*.botToken": {
393
410
  "help": "Telegram Bot Token"
411
+ },
412
+ "accounts.default.botToken": {
413
+ "help": "Telegram Bot Token"
414
+ },
415
+ "accounts.default.allowFrom": {
416
+ "help": "私聊策略为 pairing 或 allowlist 时允许的 Telegram 用户 ID。"
417
+ },
418
+ "accounts.default.groupAllowFrom": {
419
+ "help": "群聊策略为 allowlist 时允许的 Telegram 用户 ID。"
394
420
  }
395
421
  },
396
422
  "actions": {
@@ -404,6 +430,14 @@
404
430
  }
405
431
  }
406
432
  }
433
+ },
434
+ "ui": {
435
+ "card": {
436
+ "summaryFields": [
437
+ "accounts.default.dmPolicy",
438
+ "accounts.default.streaming.mode"
439
+ ]
440
+ }
407
441
  }
408
442
  }
409
443
  },
@@ -1,9 +1,9 @@
1
1
  import { hasProxyEnv } from "../../../../src/infra/http-proxy-env.js";
2
2
  import { logger } from "../util/logger.js";
3
3
  import { redactBody, redactUrl } from "../util/redact.js";
4
- import crypto from "node:crypto";
5
- import fs from "node:fs";
6
4
  import path from "node:path";
5
+ import fs from "node:fs";
6
+ import crypto from "node:crypto";
7
7
  import { fileURLToPath } from "node:url";
8
8
  import { Agent, EnvHttpProxyAgent, fetch as fetch$1 } from "undici";
9
9
  //#region extensions/weixin/src/api/api.ts
@@ -1,8 +1,8 @@
1
1
  import { logger } from "../util/logger.js";
2
2
  import { normalizeWeixinAccountId } from "./weixin-account-id.js";
3
3
  import { resolveWeixinRootDir } from "../storage/state-dir.js";
4
- import fs from "node:fs";
5
4
  import path from "node:path";
5
+ import fs from "node:fs";
6
6
  //#region extensions/weixin/src/auth/accounts.ts
7
7
  const DEFAULT_BASE_URL = "https://ilinkai.weixin.qq.com";
8
8
  const CDN_BASE_URL = "https://novac2c.cdn.weixin.qq.com/c2c";
@@ -6,9 +6,9 @@ import { getUploadUrl } from "../api/api.js";
6
6
  import { getExtensionFromContentTypeOrUrl } from "../media/mime.js";
7
7
  import { aesEcbPaddedSize } from "./aes-ecb.js";
8
8
  import { uploadBufferToCdn } from "./cdn-upload.js";
9
+ import path from "node:path";
9
10
  import crypto from "node:crypto";
10
11
  import fs from "node:fs/promises";
11
- import path from "node:path";
12
12
  //#region extensions/weixin/src/cdn/upload.ts
13
13
  /**
14
14
  * Download a remote media URL (image, video, file) to a local temp file in destDir.
@@ -1,7 +1,7 @@
1
1
  import { getExtensionFromMime } from "./mime.js";
2
+ import path from "node:path";
2
3
  import { randomBytes } from "node:crypto";
3
4
  import fs from "node:fs/promises";
4
- import path from "node:path";
5
5
  //#region extensions/weixin/src/media/data-url.ts
6
6
  /**
7
7
  * Parse `data:mime;base64,...` into buffer (aligned with Telegram `parseDataUrl`).
@@ -1,7 +1,7 @@
1
1
  import { logger } from "../util/logger.js";
2
2
  import { resolveWeixinRootDir } from "../storage/state-dir.js";
3
- import fs from "node:fs";
4
3
  import path from "node:path";
4
+ import fs from "node:fs";
5
5
  //#region extensions/weixin/src/messaging/debug-mode.ts
6
6
  /**
7
7
  * Per-bot debug mode toggle, persisted to disk so it survives gateway restarts.
@@ -3,8 +3,8 @@ import { generateId } from "../util/random.js";
3
3
  import { MessageItemType } from "../api/types.js";
4
4
  import { canonicalWeixinPeerId, normalizeWeixinAccountId } from "../auth/weixin-account-id.js";
5
5
  import { resolveWeixinRootDir } from "../storage/state-dir.js";
6
- import fs from "node:fs";
7
6
  import path from "node:path";
7
+ import fs from "node:fs";
8
8
  //#region extensions/weixin/src/messaging/inbound.ts
9
9
  /**
10
10
  * contextToken is issued per-message by the Weixin getupdates API and must
@@ -11,9 +11,9 @@ import { downloadMediaFromItem } from "../media/media-download.js";
11
11
  import { isDebugMode } from "./debug-mode.js";
12
12
  import { sendMessageWeixin } from "./send.js";
13
13
  import { handleSlashCommand } from "./slash-commands.js";
14
+ import path from "node:path";
14
15
  import { randomBytes } from "node:crypto";
15
16
  import { mkdir, readFile, writeFile } from "node:fs/promises";
16
- import path from "node:path";
17
17
  //#region extensions/weixin/src/messaging/process-message.ts
18
18
  function extractTextBody(itemList) {
19
19
  if (!itemList?.length) return "";
@@ -0,0 +1,54 @@
1
+ import { resolveDmPolicy } from "../../../src/channels/security.js";
2
+ import { resolveWeixinAllowFromPath, resolveWeixinPairingPath } from "../../../src/channels/pairing/paths.js";
3
+ import { registerPairingChannelResolver } from "../../../src/channels/pairing/pairing-service.js";
4
+ //#region extensions/weixin/src/pairing-config-resolver.ts
5
+ function weixinBlock(config) {
6
+ const ch = config?.channels?.weixin;
7
+ return ch && typeof ch === "object" && !Array.isArray(ch) ? ch : null;
8
+ }
9
+ function account(block, accountId) {
10
+ const accounts = block?.accounts;
11
+ if (!accounts || typeof accounts !== "object" || Array.isArray(accounts)) return null;
12
+ const acc = accounts[accountId];
13
+ return acc && typeof acc === "object" && !Array.isArray(acc) ? acc : null;
14
+ }
15
+ registerPairingChannelResolver("weixin", {
16
+ resolvePaths(accountId) {
17
+ return {
18
+ pairingPath: resolveWeixinPairingPath(accountId),
19
+ allowPath: resolveWeixinAllowFromPath(accountId)
20
+ };
21
+ },
22
+ resolveAllowFromConfig(config, _channel, accountId) {
23
+ const block = weixinBlock(config);
24
+ const top = Array.isArray(block?.allowFrom) ? block.allowFrom.map(String).filter(Boolean) : [];
25
+ const accAllow = account(block, accountId)?.allowFrom;
26
+ const fromAcc = Array.isArray(accAllow) ? accAllow.map(String).filter(Boolean) : [];
27
+ return [...new Set([...top, ...fromAcc])];
28
+ },
29
+ resolveChannelEnabled(config) {
30
+ return weixinBlock(config)?.enabled === true;
31
+ },
32
+ resolveAccountEnabled(config, _channel, accountId) {
33
+ const block = weixinBlock(config);
34
+ if (block?.enabled !== true) return false;
35
+ return account(block, accountId)?.enabled !== false;
36
+ },
37
+ resolveDmPolicy(config, _channel, accountId) {
38
+ const block = weixinBlock(config);
39
+ const accPolicy = account(block, accountId)?.dmPolicy;
40
+ return resolveDmPolicy(accPolicy ?? block?.dmPolicy, "open");
41
+ },
42
+ resolveAccountIds(config) {
43
+ const accounts = weixinBlock(config)?.accounts;
44
+ if (accounts && typeof accounts === "object" && !Array.isArray(accounts)) {
45
+ const keys = Object.keys(accounts).sort();
46
+ if (keys.length > 0) return keys;
47
+ }
48
+ return ["default"];
49
+ }
50
+ });
51
+ //#endregion
52
+ export {};
53
+
54
+ //# sourceMappingURL=pairing-config-resolver.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pairing-config-resolver.js","names":[],"sources":["../../../../extensions/weixin/src/pairing-config-resolver.ts"],"sourcesContent":["import type { Config } from '@xopcai/xopc/config/schema.js';\nimport type { DmPolicy } from '@xopcai/xopc/channels/channel-domain.js';\nimport {\n registerPairingChannelResolver,\n resolveWeixinAllowFromPath,\n resolveWeixinPairingPath,\n} from '@xopcai/xopc/channels/pairing/index.js';\nimport { resolveDmPolicy } from '@xopcai/xopc/channels/security.js';\n\nfunction weixinBlock(config: Config | undefined): Record<string, unknown> | null {\n const ch = config?.channels?.weixin;\n return ch && typeof ch === 'object' && !Array.isArray(ch) ? (ch as Record<string, unknown>) : null;\n}\n\nfunction account(block: Record<string, unknown> | null, accountId: string): Record<string, unknown> | null {\n const accounts = block?.accounts;\n if (!accounts || typeof accounts !== 'object' || Array.isArray(accounts)) return null;\n const acc = (accounts as Record<string, unknown>)[accountId];\n return acc && typeof acc === 'object' && !Array.isArray(acc) ? (acc as Record<string, unknown>) : null;\n}\n\nregisterPairingChannelResolver('weixin', {\n resolvePaths(accountId) {\n return {\n pairingPath: resolveWeixinPairingPath(accountId),\n allowPath: resolveWeixinAllowFromPath(accountId),\n };\n },\n resolveAllowFromConfig(config, _channel, accountId) {\n const block = weixinBlock(config);\n const top = Array.isArray(block?.allowFrom) ? block.allowFrom.map(String).filter(Boolean) : [];\n const accAllow = account(block, accountId)?.allowFrom;\n const fromAcc = Array.isArray(accAllow) ? accAllow.map(String).filter(Boolean) : [];\n return [...new Set([...top, ...fromAcc])];\n },\n resolveChannelEnabled(config) {\n return weixinBlock(config)?.enabled === true;\n },\n resolveAccountEnabled(config, _channel, accountId) {\n const block = weixinBlock(config);\n if (block?.enabled !== true) return false;\n return account(block, accountId)?.enabled !== false;\n },\n resolveDmPolicy(config, _channel, accountId) {\n const block = weixinBlock(config);\n const accPolicy = account(block, accountId)?.dmPolicy as DmPolicy | undefined;\n return resolveDmPolicy(accPolicy ?? (block?.dmPolicy as DmPolicy | undefined), 'open');\n },\n resolveAccountIds(config) {\n const accounts = weixinBlock(config)?.accounts;\n if (accounts && typeof accounts === 'object' && !Array.isArray(accounts)) {\n const keys = Object.keys(accounts as Record<string, unknown>).sort();\n if (keys.length > 0) return keys;\n }\n return ['default'];\n },\n});\n"],"mappings":";;;;AASA,SAAS,YAAY,QAA4D;CAC/E,MAAM,KAAK,QAAQ,UAAU;AAC7B,QAAO,MAAM,OAAO,OAAO,YAAY,CAAC,MAAM,QAAQ,GAAG,GAAI,KAAiC;;AAGhG,SAAS,QAAQ,OAAuC,WAAmD;CACzG,MAAM,WAAW,OAAO;AACxB,KAAI,CAAC,YAAY,OAAO,aAAa,YAAY,MAAM,QAAQ,SAAS,CAAE,QAAO;CACjF,MAAM,MAAO,SAAqC;AAClD,QAAO,OAAO,OAAO,QAAQ,YAAY,CAAC,MAAM,QAAQ,IAAI,GAAI,MAAkC;;AAGpG,+BAA+B,UAAU;CACvC,aAAa,WAAW;AACtB,SAAO;GACL,aAAa,yBAAyB,UAAU;GAChD,WAAW,2BAA2B,UAAU;GACjD;;CAEH,uBAAuB,QAAQ,UAAU,WAAW;EAClD,MAAM,QAAQ,YAAY,OAAO;EACjC,MAAM,MAAM,MAAM,QAAQ,OAAO,UAAU,GAAG,MAAM,UAAU,IAAI,OAAO,CAAC,OAAO,QAAQ,GAAG,EAAE;EAC9F,MAAM,WAAW,QAAQ,OAAO,UAAU,EAAE;EAC5C,MAAM,UAAU,MAAM,QAAQ,SAAS,GAAG,SAAS,IAAI,OAAO,CAAC,OAAO,QAAQ,GAAG,EAAE;AACnF,SAAO,CAAC,GAAG,IAAI,IAAI,CAAC,GAAG,KAAK,GAAG,QAAQ,CAAC,CAAC;;CAE3C,sBAAsB,QAAQ;AAC5B,SAAO,YAAY,OAAO,EAAE,YAAY;;CAE1C,sBAAsB,QAAQ,UAAU,WAAW;EACjD,MAAM,QAAQ,YAAY,OAAO;AACjC,MAAI,OAAO,YAAY,KAAM,QAAO;AACpC,SAAO,QAAQ,OAAO,UAAU,EAAE,YAAY;;CAEhD,gBAAgB,QAAQ,UAAU,WAAW;EAC3C,MAAM,QAAQ,YAAY,OAAO;EACjC,MAAM,YAAY,QAAQ,OAAO,UAAU,EAAE;AAC7C,SAAO,gBAAgB,aAAc,OAAO,UAAmC,OAAO;;CAExF,kBAAkB,QAAQ;EACxB,MAAM,WAAW,YAAY,OAAO,EAAE;AACtC,MAAI,YAAY,OAAO,aAAa,YAAY,CAAC,MAAM,QAAQ,SAAS,EAAE;GACxE,MAAM,OAAO,OAAO,KAAK,SAAoC,CAAC,MAAM;AACpE,OAAI,KAAK,SAAS,EAAG,QAAO;;AAE9B,SAAO,CAAC,UAAU;;CAErB,CAAC"}
@@ -1,6 +1,7 @@
1
1
  /**
2
2
  * Weixin (WeChat ilink) channel — long-poll getUpdates, QR login, direct messages only.
3
3
  */
4
+ import './pairing-config-resolver.js';
4
5
  import type { Config } from '@xopcai/xopc/config/schema.js';
5
6
  import type { MessageBus } from '@xopcai/xopc/infra/bus/index.js';
6
7
  import type { ChannelCapabilities, ChannelPlugin, ChannelPluginDefaults, ChannelPluginInitOptions, ChannelPluginReloadMeta, ChannelPluginStartOptions, ChannelSecurityContext, ChannelStreamingAdapter } from '@xopcai/xopc/channels/plugin-types.js';
@@ -1,10 +1,11 @@
1
+ import { WeixinConfigSchema, init_config_schema } from "./config-schema.js";
1
2
  import { createLogger } from "../../../src/utils/logger/index.js";
2
3
  import { init_logger } from "../../../src/utils/logger.js";
3
- import { WeixinConfigSchema, init_config_schema } from "./config-schema.js";
4
4
  import { evaluateAccess, resolveDmPolicy } from "../../../src/channels/security.js";
5
5
  import { createStandardPairingAdapter } from "../../../src/channels/pairing/pairing-store-adapter.js";
6
6
  import { weixinConfigSurface } from "./config-surface.js";
7
7
  import { normalizeWeixinCronDeliveryToResolved } from "./delivery-to.js";
8
+ import "./pairing-config-resolver.js";
8
9
  import { restoreContextTokens } from "./messaging/inbound.js";
9
10
  import { listWeixinAccountIds, resolveWeixinAccount } from "./auth/accounts.js";
10
11
  import { readFrameworkAllowFromList } from "./auth/pairing.js";
@@ -1 +1 @@
1
- {"version":3,"file":"plugin.js","names":[],"sources":["../../../../extensions/weixin/src/plugin.ts"],"sourcesContent":["/**\n * Weixin (WeChat ilink) channel — long-poll getUpdates, QR login, direct messages only.\n */\n\nimport { isDeepStrictEqual } from 'node:util';\n\nimport type { Config } from '@xopcai/xopc/config/schema.js';\nimport type { MessageBus } from '@xopcai/xopc/infra/bus/index.js';\nimport type {\n ChannelCapabilities,\n ChannelPlugin,\n ChannelPluginDefaults,\n ChannelPluginInitOptions,\n ChannelPluginReloadMeta,\n ChannelPluginStartOptions,\n ChannelSecurityContext,\n ChannelStreamingAdapter,\n ChatType,\n} from '@xopcai/xopc/channels/plugin-types.js';\nimport { evaluateAccess, resolveDmPolicy } from '@xopcai/xopc/channels/security.js';\nimport { createStandardPairingAdapter } from '@xopcai/xopc/channels/pairing/pairing-store-adapter.js';\nimport { createLogger } from '@xopcai/xopc/utils/logger.js';\n\nimport { restoreContextTokens } from './messaging/inbound.js';\nimport { monitorWeixinProvider } from './monitor/monitor.js';\nimport type {\n ChannelCliLoginAdapter,\n ChannelCronDeliveryAdapter,\n ChannelRuntimeActionAdapter,\n} from '@xopcai/xopc/channels/plugins/types.adapters.js';\nimport {\n listWeixinAccountIds,\n resolveWeixinAccount,\n type ResolvedWeixinAccount,\n} from './auth/accounts.js';\nimport { readFrameworkAllowFromList } from './auth/pairing.js';\nimport { createWeixinOutboundHandlers, weixinTextChunker } from './outbound-send.js';\nimport { normalizeWeixinCronDeliveryToResolved } from './delivery-to.js';\nimport { weixinConfigSurface } from './config-surface.js';\nimport { WeixinConfigSchema } from './config-schema.js';\nimport { weixinOnboardAdapter } from './adapters/onboard-cli.js';\n\nconst log = createLogger('WeixinPlugin');\n\nexport class WeixinChannelPlugin implements ChannelPlugin<ResolvedWeixinAccount> {\n readonly id = 'weixin' as const;\n\n readonly reload: ChannelPluginReloadMeta = {\n configPrefixes: ['channels.weixin'],\n };\n\n readonly meta = {\n id: 'weixin',\n label: 'Weixin',\n selectionLabel: 'Weixin (ilink)',\n docsPath: '/channels/weixin',\n blurb: 'WeChat via Tencent ilink bot API (QR login, direct chat).',\n order: 3,\n deferConnectUntilAfterListen: true,\n } as const;\n\n readonly capabilities: ChannelCapabilities = {\n chatTypes: ['direct'] as ChatType[],\n reactions: false,\n threads: false,\n media: true,\n polls: false,\n nativeCommands: false,\n blockStreaming: true,\n };\n\n readonly configSchema = {\n schema: {},\n validate: (raw: unknown) => {\n const r = WeixinConfigSchema.safeParse(raw);\n return r.success ? { ok: true as const } : { ok: false as const, errors: [r.error.message] };\n },\n };\n\n readonly cronDelivery: ChannelCronDeliveryAdapter = {\n async normalizeDeliveryTarget(to, sessionStore) {\n const { chatId, accountId } = await normalizeWeixinCronDeliveryToResolved(to, sessionStore);\n return { chatId, accountId };\n },\n };\n\n readonly onboard = weixinOnboardAdapter;\n\n readonly cliLogin: ChannelCliLoginAdapter = {\n async runLogin(params) {\n const { runWeixinQrLoginCli } = await import('./cli/qr-login.js');\n return runWeixinQrLoginCli({\n configPath: params.configPath,\n verbose: params.verbose,\n timeoutMs: params.timeoutMs,\n account: params.accountId,\n writeConfig: params.writeConfig,\n });\n },\n };\n\n readonly runtimeActions: ChannelRuntimeActionAdapter = {\n runAction: async ({ actionId, accountId, input, locale }) => {\n const zh = locale?.toLowerCase().startsWith('zh') === true;\n if (actionId === 'login.start') {\n const { startWeixinGatewayQrLogin } = await import('./cli/gateway-qr-login.js');\n const inputRecord =\n input && typeof input === 'object' && !Array.isArray(input)\n ? (input as Record<string, unknown>)\n : {};\n const timeoutMs = typeof inputRecord.timeoutMs === 'number' ? inputRecord.timeoutMs : 480_000;\n const start = await startWeixinGatewayQrLogin({\n account: accountId,\n timeoutMs,\n initialConfig: this.cfg,\n onPersisted: async (result) => {\n if (!result.ok) return;\n await this.reloadMonitorsWithConfig(result.config ?? this.cfg, this.bus);\n },\n });\n if (start.ok === false) {\n return { ok: false, message: start.message };\n }\n return {\n ok: true,\n payload: {\n type: 'qr',\n sessionKey: start.sessionKey,\n qrcodeUrl: start.qrcodeUrl,\n statusAction: 'login.status',\n pollIntervalMs: 2500,\n message: zh ? '请使用微信扫描二维码。' : 'Scan the QR code with WeChat.',\n },\n };\n }\n\n if (actionId === 'login.status') {\n const inputRecord =\n input && typeof input === 'object' && !Array.isArray(input)\n ? (input as Record<string, unknown>)\n : {};\n const sessionKey = typeof inputRecord.sessionKey === 'string' ? inputRecord.sessionKey : '';\n if (!sessionKey) return { ok: false, message: zh ? '缺少登录 sessionKey' : 'Missing login sessionKey' };\n const { getWeixinGatewayQrLoginStatus } = await import('./cli/gateway-qr-login.js');\n const status = getWeixinGatewayQrLoginStatus(sessionKey);\n if (status.phase === 'polling') {\n return {\n ok: true,\n payload: {\n type: 'poll',\n phase: 'pending',\n qrcodeUrl: status.qrcodeUrl,\n qrStatus: status.qrStatus,\n message: status.qrStatus,\n },\n };\n }\n if (status.phase === 'done') {\n return {\n ok: true,\n payload: {\n type: 'poll',\n phase: 'done',\n ok: status.ok,\n accountId: status.ok ? status.accountId : undefined,\n message: status.ok === true ? (zh ? '微信登录完成。' : 'Weixin login complete.') : status.message,\n configChanged: status.ok,\n },\n };\n }\n return {\n ok: true,\n payload: {\n type: 'poll',\n phase: 'unknown',\n ok: false,\n message: status.message,\n },\n };\n }\n\n return { ok: false, message: `Unsupported Weixin action: ${actionId}` };\n },\n };\n\n readonly configSurface = weixinConfigSurface;\n\n readonly pairing = createStandardPairingAdapter('weixin');\n\n readonly defaults: ChannelPluginDefaults = {\n queue: { debounceMs: 0 },\n outbound: { textChunkLimit: 4000 },\n streaming: {\n blockStreamingCoalesce: {\n minChars: 200,\n idleMs: 3000,\n },\n },\n };\n\n private bus!: ChannelPluginInitOptions['bus'];\n private cfg!: Config;\n private abortControllers = new Map<string, AbortController>();\n /** Unregister fn for the workflow-progress capability registered against the global broker. */\n private workflowProgressUnregister: (() => void) | null = null;\n\n config = {\n listAccountIds: (cfg: Config) => listWeixinAccountIds(cfg),\n resolveAccount: (cfg: Config, accountId?: string | null) => resolveWeixinAccount(cfg, accountId),\n isConfigured: async (account: ResolvedWeixinAccount) => account.configured,\n describeAccount: (account: ResolvedWeixinAccount, _cfg: Config) => ({\n accountId: account.accountId,\n channelId: 'weixin',\n name: account.name,\n enabled: account.enabled,\n configured: account.configured,\n status: undefined,\n }),\n };\n\n security = {\n resolveDmPolicy: ({ account }: { account: ResolvedWeixinAccount }) =>\n resolveDmPolicy(account.dmPolicy, 'open'),\n checkAccess: (ctx: ChannelSecurityContext, account: ResolvedWeixinAccount, _cfg: Config) => {\n const allowFrom = [...(account.allowFrom ?? []), ...readFrameworkAllowFromList(account.accountId)];\n return evaluateAccess({\n context: {\n channel: 'weixin',\n accountId: account.accountId,\n chatId: ctx.chatId,\n senderId: ctx.senderId,\n senderName: ctx.senderName,\n isGroup: false,\n isDm: true,\n },\n dmPolicy: account.dmPolicy,\n allowFrom,\n });\n },\n };\n\n outbound = {\n deliveryMode: 'direct' as const,\n chunker: weixinTextChunker,\n chunkerMode: 'text' as const,\n textChunkLimit: 4000,\n ...createWeixinOutboundHandlers(),\n };\n\n streaming: ChannelStreamingAdapter = {\n startStream: () => null,\n };\n\n /** Channel plugin hints (cron targets, media paths). */\n agentPrompt = {\n augmentSystemPrompt: (): string =>\n [\n 'Weixin (ilink): direct chat only. To send an image or file, use the message tool with action send and set media to a local absolute path or an HTTPS URL; relative paths may fail.',\n 'For cron or scheduled delivery to a Weixin contact, set delivery.to to the user Weixin id (ending in @im.wechat) and delivery.accountId to the bot account id, or outbound may pick the wrong account.',\n 'When using MEDIA: to attach a file, put the MEDIA: line alone on its own line, not inline with other text.',\n ].join('\\n'),\n };\n\n async init(options: ChannelPluginInitOptions): Promise<void> {\n this.bus = options.bus;\n this.cfg = options.config;\n\n await this.registerWorkflowProgressCapability();\n\n log.debug('Weixin plugin initialized');\n }\n\n private async registerWorkflowProgressCapability(): Promise<void> {\n // Lazy-load workflow progress so Weixin runtime startup does not pull the\n // agent/workflow/provider graph into Electron's dynamic extension path.\n const [{ getWorkflowProgressBroker }, { createWeixinWorkflowProgressCapability }] = await Promise.all([\n import('@xopcai/xopc/agent/workflow/progress-broker.js'),\n import('./workflow-progress.js'),\n ]);\n this.workflowProgressUnregister = getWorkflowProgressBroker().registerChannel(\n createWeixinWorkflowProgressCapability({ getConfig: () => this.cfg }),\n );\n }\n\n async start(options?: ChannelPluginStartOptions): Promise<void> {\n const ids = options?.accountId\n ? [options.accountId]\n : listWeixinAccountIds(this.cfg);\n\n for (const accountId of ids) {\n const account = resolveWeixinAccount(this.cfg, accountId);\n if (!account.enabled || !account.configured || !account.token) continue;\n\n if (this.abortControllers.has(accountId)) continue;\n\n restoreContextTokens(account.accountId);\n\n const ac = new AbortController();\n this.abortControllers.set(accountId, ac);\n\n void monitorWeixinProvider({\n account,\n config: this.cfg,\n bus: this.bus,\n abortSignal: ac.signal,\n }).catch((err) => {\n if ((err as { name?: string; message?: string } | undefined)?.name === 'AbortError') {\n log.debug({ accountId }, 'Weixin monitor stopped');\n return;\n }\n log.error({ err, accountId }, 'Weixin monitor exited with error');\n });\n\n log.info({ accountId }, 'Weixin monitor started');\n }\n }\n\n async stop(accountId?: string): Promise<void> {\n const ids = accountId ? [accountId] : [...this.abortControllers.keys()];\n for (const id of ids) {\n const ac = this.abortControllers.get(id);\n if (ac) {\n ac.abort();\n this.abortControllers.delete(id);\n }\n }\n // Only unregister the broker capability on a full stop. Per-account stops\n // still leave the cap usable for other accounts.\n if (!accountId) {\n this.workflowProgressUnregister?.();\n this.workflowProgressUnregister = null;\n }\n }\n\n channelIsRunning(cfg: Config): boolean {\n return listWeixinAccountIds(cfg).some((id) => {\n const a = resolveWeixinAccount(cfg, id);\n return a.configured && a.enabled !== false && this.abortControllers.has(id);\n });\n }\n\n async onConfigUpdated(cfg: Config): Promise<void> {\n const prevWx = this.cfg.channels?.weixin as unknown;\n const nextWx = cfg.channels?.weixin as { enabled?: boolean } | undefined;\n const channelOff = !nextWx || nextWx.enabled !== true;\n\n if (channelOff) {\n this.cfg = cfg;\n await this.stop();\n return;\n }\n\n this.cfg = cfg;\n\n if (isDeepStrictEqual(prevWx, nextWx) && this.channelIsRunning(cfg)) {\n return;\n }\n\n await this.stop();\n await this.start();\n }\n\n /**\n * Restart long-poll monitors after credentials were written to disk without a `channels.weixin` JSON\n * delta (e.g. only token files / account index updated). Gateway calls this after QR login completes.\n *\n * Pass `bus` explicitly: if Weixin was disabled at gateway boot, `init()` was skipped and `this.bus` was never set.\n */\n async reloadMonitorsWithConfig(cfg: Config, bus: MessageBus): Promise<void> {\n this.bus = bus;\n this.cfg = cfg;\n await this.stop();\n await this.start();\n }\n}\n\nexport const weixinPlugin = new WeixinChannelPlugin();\n"],"mappings":"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"}
1
+ {"version":3,"file":"plugin.js","names":[],"sources":["../../../../extensions/weixin/src/plugin.ts"],"sourcesContent":["/**\n * Weixin (WeChat ilink) channel — long-poll getUpdates, QR login, direct messages only.\n */\n\nimport { isDeepStrictEqual } from 'node:util';\n\nimport './pairing-config-resolver.js';\n\nimport type { Config } from '@xopcai/xopc/config/schema.js';\nimport type { MessageBus } from '@xopcai/xopc/infra/bus/index.js';\nimport type {\n ChannelCapabilities,\n ChannelPlugin,\n ChannelPluginDefaults,\n ChannelPluginInitOptions,\n ChannelPluginReloadMeta,\n ChannelPluginStartOptions,\n ChannelSecurityContext,\n ChannelStreamingAdapter,\n ChatType,\n} from '@xopcai/xopc/channels/plugin-types.js';\nimport { evaluateAccess, resolveDmPolicy } from '@xopcai/xopc/channels/security.js';\nimport { createStandardPairingAdapter } from '@xopcai/xopc/channels/pairing/pairing-store-adapter.js';\nimport { createLogger } from '@xopcai/xopc/utils/logger.js';\n\nimport { restoreContextTokens } from './messaging/inbound.js';\nimport { monitorWeixinProvider } from './monitor/monitor.js';\nimport type {\n ChannelCliLoginAdapter,\n ChannelCronDeliveryAdapter,\n ChannelRuntimeActionAdapter,\n} from '@xopcai/xopc/channels/plugins/types.adapters.js';\nimport {\n listWeixinAccountIds,\n resolveWeixinAccount,\n type ResolvedWeixinAccount,\n} from './auth/accounts.js';\nimport { readFrameworkAllowFromList } from './auth/pairing.js';\nimport { createWeixinOutboundHandlers, weixinTextChunker } from './outbound-send.js';\nimport { normalizeWeixinCronDeliveryToResolved } from './delivery-to.js';\nimport { weixinConfigSurface } from './config-surface.js';\nimport { WeixinConfigSchema } from './config-schema.js';\nimport { weixinOnboardAdapter } from './adapters/onboard-cli.js';\n\nconst log = createLogger('WeixinPlugin');\n\nexport class WeixinChannelPlugin implements ChannelPlugin<ResolvedWeixinAccount> {\n readonly id = 'weixin' as const;\n\n readonly reload: ChannelPluginReloadMeta = {\n configPrefixes: ['channels.weixin'],\n };\n\n readonly meta = {\n id: 'weixin',\n label: 'Weixin',\n selectionLabel: 'Weixin (ilink)',\n docsPath: '/channels/weixin',\n blurb: 'WeChat via Tencent ilink bot API (QR login, direct chat).',\n order: 3,\n deferConnectUntilAfterListen: true,\n } as const;\n\n readonly capabilities: ChannelCapabilities = {\n chatTypes: ['direct'] as ChatType[],\n reactions: false,\n threads: false,\n media: true,\n polls: false,\n nativeCommands: false,\n blockStreaming: true,\n };\n\n readonly configSchema = {\n schema: {},\n validate: (raw: unknown) => {\n const r = WeixinConfigSchema.safeParse(raw);\n return r.success ? { ok: true as const } : { ok: false as const, errors: [r.error.message] };\n },\n };\n\n readonly cronDelivery: ChannelCronDeliveryAdapter = {\n async normalizeDeliveryTarget(to, sessionStore) {\n const { chatId, accountId } = await normalizeWeixinCronDeliveryToResolved(to, sessionStore);\n return { chatId, accountId };\n },\n };\n\n readonly onboard = weixinOnboardAdapter;\n\n readonly cliLogin: ChannelCliLoginAdapter = {\n async runLogin(params) {\n const { runWeixinQrLoginCli } = await import('./cli/qr-login.js');\n return runWeixinQrLoginCli({\n configPath: params.configPath,\n verbose: params.verbose,\n timeoutMs: params.timeoutMs,\n account: params.accountId,\n writeConfig: params.writeConfig,\n });\n },\n };\n\n readonly runtimeActions: ChannelRuntimeActionAdapter = {\n runAction: async ({ actionId, accountId, input, locale }) => {\n const zh = locale?.toLowerCase().startsWith('zh') === true;\n if (actionId === 'login.start') {\n const { startWeixinGatewayQrLogin } = await import('./cli/gateway-qr-login.js');\n const inputRecord =\n input && typeof input === 'object' && !Array.isArray(input)\n ? (input as Record<string, unknown>)\n : {};\n const timeoutMs = typeof inputRecord.timeoutMs === 'number' ? inputRecord.timeoutMs : 480_000;\n const start = await startWeixinGatewayQrLogin({\n account: accountId,\n timeoutMs,\n initialConfig: this.cfg,\n onPersisted: async (result) => {\n if (!result.ok) return;\n await this.reloadMonitorsWithConfig(result.config ?? this.cfg, this.bus);\n },\n });\n if (start.ok === false) {\n return { ok: false, message: start.message };\n }\n return {\n ok: true,\n payload: {\n type: 'qr',\n sessionKey: start.sessionKey,\n qrcodeUrl: start.qrcodeUrl,\n statusAction: 'login.status',\n pollIntervalMs: 2500,\n message: zh ? '请使用微信扫描二维码。' : 'Scan the QR code with WeChat.',\n },\n };\n }\n\n if (actionId === 'login.status') {\n const inputRecord =\n input && typeof input === 'object' && !Array.isArray(input)\n ? (input as Record<string, unknown>)\n : {};\n const sessionKey = typeof inputRecord.sessionKey === 'string' ? inputRecord.sessionKey : '';\n if (!sessionKey) return { ok: false, message: zh ? '缺少登录 sessionKey' : 'Missing login sessionKey' };\n const { getWeixinGatewayQrLoginStatus } = await import('./cli/gateway-qr-login.js');\n const status = getWeixinGatewayQrLoginStatus(sessionKey);\n if (status.phase === 'polling') {\n return {\n ok: true,\n payload: {\n type: 'poll',\n phase: 'pending',\n qrcodeUrl: status.qrcodeUrl,\n qrStatus: status.qrStatus,\n message: status.qrStatus,\n },\n };\n }\n if (status.phase === 'done') {\n return {\n ok: true,\n payload: {\n type: 'poll',\n phase: 'done',\n ok: status.ok,\n accountId: status.ok ? status.accountId : undefined,\n message: status.ok === true ? (zh ? '微信登录完成。' : 'Weixin login complete.') : status.message,\n configChanged: status.ok,\n },\n };\n }\n return {\n ok: true,\n payload: {\n type: 'poll',\n phase: 'unknown',\n ok: false,\n message: status.message,\n },\n };\n }\n\n return { ok: false, message: `Unsupported Weixin action: ${actionId}` };\n },\n };\n\n readonly configSurface = weixinConfigSurface;\n\n readonly pairing = createStandardPairingAdapter('weixin');\n\n readonly defaults: ChannelPluginDefaults = {\n queue: { debounceMs: 0 },\n outbound: { textChunkLimit: 4000 },\n streaming: {\n blockStreamingCoalesce: {\n minChars: 200,\n idleMs: 3000,\n },\n },\n };\n\n private bus!: ChannelPluginInitOptions['bus'];\n private cfg!: Config;\n private abortControllers = new Map<string, AbortController>();\n /** Unregister fn for the workflow-progress capability registered against the global broker. */\n private workflowProgressUnregister: (() => void) | null = null;\n\n config = {\n listAccountIds: (cfg: Config) => listWeixinAccountIds(cfg),\n resolveAccount: (cfg: Config, accountId?: string | null) => resolveWeixinAccount(cfg, accountId),\n isConfigured: async (account: ResolvedWeixinAccount) => account.configured,\n describeAccount: (account: ResolvedWeixinAccount, _cfg: Config) => ({\n accountId: account.accountId,\n channelId: 'weixin',\n name: account.name,\n enabled: account.enabled,\n configured: account.configured,\n status: undefined,\n }),\n };\n\n security = {\n resolveDmPolicy: ({ account }: { account: ResolvedWeixinAccount }) =>\n resolveDmPolicy(account.dmPolicy, 'open'),\n checkAccess: (ctx: ChannelSecurityContext, account: ResolvedWeixinAccount, _cfg: Config) => {\n const allowFrom = [...(account.allowFrom ?? []), ...readFrameworkAllowFromList(account.accountId)];\n return evaluateAccess({\n context: {\n channel: 'weixin',\n accountId: account.accountId,\n chatId: ctx.chatId,\n senderId: ctx.senderId,\n senderName: ctx.senderName,\n isGroup: false,\n isDm: true,\n },\n dmPolicy: account.dmPolicy,\n allowFrom,\n });\n },\n };\n\n outbound = {\n deliveryMode: 'direct' as const,\n chunker: weixinTextChunker,\n chunkerMode: 'text' as const,\n textChunkLimit: 4000,\n ...createWeixinOutboundHandlers(),\n };\n\n streaming: ChannelStreamingAdapter = {\n startStream: () => null,\n };\n\n /** Channel plugin hints (cron targets, media paths). */\n agentPrompt = {\n augmentSystemPrompt: (): string =>\n [\n 'Weixin (ilink): direct chat only. To send an image or file, use the message tool with action send and set media to a local absolute path or an HTTPS URL; relative paths may fail.',\n 'For cron or scheduled delivery to a Weixin contact, set delivery.to to the user Weixin id (ending in @im.wechat) and delivery.accountId to the bot account id, or outbound may pick the wrong account.',\n 'When using MEDIA: to attach a file, put the MEDIA: line alone on its own line, not inline with other text.',\n ].join('\\n'),\n };\n\n async init(options: ChannelPluginInitOptions): Promise<void> {\n this.bus = options.bus;\n this.cfg = options.config;\n\n await this.registerWorkflowProgressCapability();\n\n log.debug('Weixin plugin initialized');\n }\n\n private async registerWorkflowProgressCapability(): Promise<void> {\n // Lazy-load workflow progress so Weixin runtime startup does not pull the\n // agent/workflow/provider graph into Electron's dynamic extension path.\n const [{ getWorkflowProgressBroker }, { createWeixinWorkflowProgressCapability }] = await Promise.all([\n import('@xopcai/xopc/agent/workflow/progress-broker.js'),\n import('./workflow-progress.js'),\n ]);\n this.workflowProgressUnregister = getWorkflowProgressBroker().registerChannel(\n createWeixinWorkflowProgressCapability({ getConfig: () => this.cfg }),\n );\n }\n\n async start(options?: ChannelPluginStartOptions): Promise<void> {\n const ids = options?.accountId\n ? [options.accountId]\n : listWeixinAccountIds(this.cfg);\n\n for (const accountId of ids) {\n const account = resolveWeixinAccount(this.cfg, accountId);\n if (!account.enabled || !account.configured || !account.token) continue;\n\n if (this.abortControllers.has(accountId)) continue;\n\n restoreContextTokens(account.accountId);\n\n const ac = new AbortController();\n this.abortControllers.set(accountId, ac);\n\n void monitorWeixinProvider({\n account,\n config: this.cfg,\n bus: this.bus,\n abortSignal: ac.signal,\n }).catch((err) => {\n if ((err as { name?: string; message?: string } | undefined)?.name === 'AbortError') {\n log.debug({ accountId }, 'Weixin monitor stopped');\n return;\n }\n log.error({ err, accountId }, 'Weixin monitor exited with error');\n });\n\n log.info({ accountId }, 'Weixin monitor started');\n }\n }\n\n async stop(accountId?: string): Promise<void> {\n const ids = accountId ? [accountId] : [...this.abortControllers.keys()];\n for (const id of ids) {\n const ac = this.abortControllers.get(id);\n if (ac) {\n ac.abort();\n this.abortControllers.delete(id);\n }\n }\n // Only unregister the broker capability on a full stop. Per-account stops\n // still leave the cap usable for other accounts.\n if (!accountId) {\n this.workflowProgressUnregister?.();\n this.workflowProgressUnregister = null;\n }\n }\n\n channelIsRunning(cfg: Config): boolean {\n return listWeixinAccountIds(cfg).some((id) => {\n const a = resolveWeixinAccount(cfg, id);\n return a.configured && a.enabled !== false && this.abortControllers.has(id);\n });\n }\n\n async onConfigUpdated(cfg: Config): Promise<void> {\n const prevWx = this.cfg.channels?.weixin as unknown;\n const nextWx = cfg.channels?.weixin as { enabled?: boolean } | undefined;\n const channelOff = !nextWx || nextWx.enabled !== true;\n\n if (channelOff) {\n this.cfg = cfg;\n await this.stop();\n return;\n }\n\n this.cfg = cfg;\n\n if (isDeepStrictEqual(prevWx, nextWx) && this.channelIsRunning(cfg)) {\n return;\n }\n\n await this.stop();\n await this.start();\n }\n\n /**\n * Restart long-poll monitors after credentials were written to disk without a `channels.weixin` JSON\n * delta (e.g. only token files / account index updated). Gateway calls this after QR login completes.\n *\n * Pass `bus` explicitly: if Weixin was disabled at gateway boot, `init()` was skipped and `this.bus` was never set.\n */\n async reloadMonitorsWithConfig(cfg: Config, bus: MessageBus): Promise<void> {\n this.bus = bus;\n this.cfg = cfg;\n await this.stop();\n await this.start();\n }\n}\n\nexport const weixinPlugin = new WeixinChannelPlugin();\n"],"mappings":"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"}
@@ -1,6 +1,6 @@
1
1
  import { resolveWeixinRootDir } from "./state-dir.js";
2
- import fs from "node:fs";
3
2
  import path from "node:path";
3
+ import fs from "node:fs";
4
4
  //#region extensions/weixin/src/storage/sync-buf.ts
5
5
  function resolveAccountsDir() {
6
6
  return path.join(resolveWeixinRootDir(), "accounts");
@@ -1,6 +1,6 @@
1
+ import { init_session_key, parseSessionKey } from "../../../src/routing/session-key.js";
1
2
  import { createLogger } from "../../../src/utils/logger/index.js";
2
3
  import { init_logger } from "../../../src/utils/logger.js";
3
- import { init_session_key, parseSessionKey } from "../../../src/routing/session-key.js";
4
4
  import { getContextToken } from "./messaging/inbound.js";
5
5
  import { resolveWeixinAccount } from "./auth/accounts.js";
6
6
  import { sendMessageWeixin } from "./messaging/send.js";