foliko 1.0.74 → 1.0.76

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 (238) hide show
  1. package/.agent/.shared/ui-ux-pro-max/data/charts.csv +26 -0
  2. package/.agent/.shared/ui-ux-pro-max/data/colors.csv +97 -0
  3. package/.agent/.shared/ui-ux-pro-max/data/icons.csv +101 -0
  4. package/.agent/.shared/ui-ux-pro-max/data/landing.csv +31 -0
  5. package/.agent/.shared/ui-ux-pro-max/data/products.csv +97 -0
  6. package/.agent/.shared/ui-ux-pro-max/data/prompts.csv +24 -0
  7. package/.agent/.shared/ui-ux-pro-max/data/react-performance.csv +45 -0
  8. package/.agent/.shared/ui-ux-pro-max/data/stacks/flutter.csv +53 -0
  9. package/.agent/.shared/ui-ux-pro-max/data/stacks/html-tailwind.csv +56 -0
  10. package/.agent/.shared/ui-ux-pro-max/data/stacks/jetpack-compose.csv +53 -0
  11. package/.agent/.shared/ui-ux-pro-max/data/stacks/nextjs.csv +53 -0
  12. package/.agent/.shared/ui-ux-pro-max/data/stacks/nuxt-ui.csv +51 -0
  13. package/.agent/.shared/ui-ux-pro-max/data/stacks/nuxtjs.csv +59 -0
  14. package/.agent/.shared/ui-ux-pro-max/data/stacks/react-native.csv +52 -0
  15. package/.agent/.shared/ui-ux-pro-max/data/stacks/react.csv +54 -0
  16. package/.agent/.shared/ui-ux-pro-max/data/stacks/shadcn.csv +61 -0
  17. package/.agent/.shared/ui-ux-pro-max/data/stacks/svelte.csv +54 -0
  18. package/.agent/.shared/ui-ux-pro-max/data/stacks/swiftui.csv +51 -0
  19. package/.agent/.shared/ui-ux-pro-max/data/stacks/vue.csv +50 -0
  20. package/.agent/.shared/ui-ux-pro-max/data/styles.csv +59 -0
  21. package/.agent/.shared/ui-ux-pro-max/data/typography.csv +58 -0
  22. package/.agent/.shared/ui-ux-pro-max/data/ui-reasoning.csv +101 -0
  23. package/.agent/.shared/ui-ux-pro-max/data/ux-guidelines.csv +100 -0
  24. package/.agent/.shared/ui-ux-pro-max/data/web-interface.csv +31 -0
  25. package/.agent/.shared/ui-ux-pro-max/scripts/__pycache__/core.cpython-313.pyc +0 -0
  26. package/.agent/.shared/ui-ux-pro-max/scripts/__pycache__/design_system.cpython-313.pyc +0 -0
  27. package/.agent/.shared/ui-ux-pro-max/scripts/core.py +258 -0
  28. package/.agent/.shared/ui-ux-pro-max/scripts/design_system.py +1067 -0
  29. package/.agent/.shared/ui-ux-pro-max/scripts/search.py +106 -0
  30. package/.agent/ARCHITECTURE.md +288 -0
  31. package/.agent/agents/ambient-agent.md +57 -0
  32. package/.agent/agents/debugger.md +55 -0
  33. package/.agent/agents/email-assistant.md +49 -0
  34. package/.agent/agents/file-manager.md +42 -0
  35. package/.agent/agents/python-developer.md +60 -0
  36. package/.agent/agents/scheduler.md +59 -0
  37. package/.agent/agents/web-developer.md +45 -0
  38. package/.agent/data/default.json +29 -0
  39. package/.agent/data/plugins-state.json +255 -0
  40. package/.agent/mcp_config.json +4 -0
  41. package/.agent/mcp_config_updated.json +12 -0
  42. package/.agent/plugins.json +5 -0
  43. package/.agent/rules/GEMINI.md +273 -0
  44. package/.agent/rules/allow-rule.md +77 -0
  45. package/.agent/rules/log-rule.md +83 -0
  46. package/.agent/rules/security-rule.md +93 -0
  47. package/.agent/scripts/auto_preview.py +148 -0
  48. package/.agent/scripts/checklist.py +217 -0
  49. package/.agent/scripts/session_manager.py +120 -0
  50. package/.agent/scripts/verify_all.py +327 -0
  51. package/.agent/skills/api-patterns/SKILL.md +81 -0
  52. package/.agent/skills/api-patterns/api-style.md +42 -0
  53. package/.agent/skills/api-patterns/auth.md +24 -0
  54. package/.agent/skills/api-patterns/documentation.md +26 -0
  55. package/.agent/skills/api-patterns/graphql.md +41 -0
  56. package/.agent/skills/api-patterns/rate-limiting.md +31 -0
  57. package/.agent/skills/api-patterns/response.md +37 -0
  58. package/.agent/skills/api-patterns/rest.md +40 -0
  59. package/.agent/skills/api-patterns/scripts/api_validator.py +211 -0
  60. package/.agent/skills/api-patterns/security-testing.md +122 -0
  61. package/.agent/skills/api-patterns/trpc.md +41 -0
  62. package/.agent/skills/api-patterns/versioning.md +22 -0
  63. package/.agent/skills/app-builder/SKILL.md +75 -0
  64. package/.agent/skills/app-builder/agent-coordination.md +71 -0
  65. package/.agent/skills/app-builder/feature-building.md +53 -0
  66. package/.agent/skills/app-builder/project-detection.md +34 -0
  67. package/.agent/skills/app-builder/scaffolding.md +118 -0
  68. package/.agent/skills/app-builder/tech-stack.md +40 -0
  69. package/.agent/skills/app-builder/templates/SKILL.md +39 -0
  70. package/.agent/skills/app-builder/templates/astro-static/TEMPLATE.md +76 -0
  71. package/.agent/skills/app-builder/templates/chrome-extension/TEMPLATE.md +92 -0
  72. package/.agent/skills/app-builder/templates/cli-tool/TEMPLATE.md +88 -0
  73. package/.agent/skills/app-builder/templates/electron-desktop/TEMPLATE.md +88 -0
  74. package/.agent/skills/app-builder/templates/express-api/TEMPLATE.md +83 -0
  75. package/.agent/skills/app-builder/templates/flutter-app/TEMPLATE.md +90 -0
  76. package/.agent/skills/app-builder/templates/monorepo-turborepo/TEMPLATE.md +90 -0
  77. package/.agent/skills/app-builder/templates/nextjs-fullstack/TEMPLATE.md +122 -0
  78. package/.agent/skills/app-builder/templates/nextjs-saas/TEMPLATE.md +122 -0
  79. package/.agent/skills/app-builder/templates/nextjs-static/TEMPLATE.md +169 -0
  80. package/.agent/skills/app-builder/templates/nuxt-app/TEMPLATE.md +134 -0
  81. package/.agent/skills/app-builder/templates/python-fastapi/TEMPLATE.md +83 -0
  82. package/.agent/skills/app-builder/templates/react-native-app/TEMPLATE.md +119 -0
  83. package/.agent/skills/architecture/SKILL.md +55 -0
  84. package/.agent/skills/architecture/context-discovery.md +43 -0
  85. package/.agent/skills/architecture/examples.md +94 -0
  86. package/.agent/skills/architecture/pattern-selection.md +68 -0
  87. package/.agent/skills/architecture/patterns-reference.md +50 -0
  88. package/.agent/skills/architecture/trade-off-analysis.md +77 -0
  89. package/.agent/skills/clean-code/SKILL.md +201 -0
  90. package/.agent/skills/doc.md +177 -0
  91. package/.agent/skills/frontend-design/SKILL.md +418 -0
  92. package/.agent/skills/frontend-design/animation-guide.md +331 -0
  93. package/.agent/skills/frontend-design/color-system.md +311 -0
  94. package/.agent/skills/frontend-design/decision-trees.md +418 -0
  95. package/.agent/skills/frontend-design/motion-graphics.md +306 -0
  96. package/.agent/skills/frontend-design/scripts/accessibility_checker.py +183 -0
  97. package/.agent/skills/frontend-design/scripts/ux_audit.py +722 -0
  98. package/.agent/skills/frontend-design/typography-system.md +345 -0
  99. package/.agent/skills/frontend-design/ux-psychology.md +1116 -0
  100. package/.agent/skills/frontend-design/visual-effects.md +383 -0
  101. package/.agent/skills/i18n-localization/SKILL.md +154 -0
  102. package/.agent/skills/i18n-localization/scripts/i18n_checker.py +241 -0
  103. package/.agent/skills/mcp-builder/SKILL.md +176 -0
  104. package/.agent/skills/web-design-guidelines/SKILL.md +57 -0
  105. package/.agent/workflows/brainstorm.md +113 -0
  106. package/.agent/workflows/create.md +59 -0
  107. package/.agent/workflows/debug.md +103 -0
  108. package/.agent/workflows/deploy.md +176 -0
  109. package/.agent/workflows/enhance.md +63 -0
  110. package/.agent/workflows/orchestrate.md +237 -0
  111. package/.agent/workflows/plan.md +89 -0
  112. package/.agent/workflows/preview.md +81 -0
  113. package/.agent/workflows/simple-test.md +42 -0
  114. package/.agent/workflows/status.md +86 -0
  115. package/.agent/workflows/structured-orchestrate.md +180 -0
  116. package/.agent/workflows/test.md +144 -0
  117. package/.agent/workflows/ui-ux-pro-max.md +296 -0
  118. package/.claude/settings.local.json +11 -1
  119. package/.editorconfig +56 -0
  120. package/.husky/pre-commit +4 -0
  121. package/.lintstagedrc +7 -0
  122. package/.prettierignore +29 -0
  123. package/.prettierrc +11 -0
  124. package/CLAUDE.md +2 -0
  125. package/README.md +64 -55
  126. package/SPEC.md +102 -61
  127. package/cli/bin/foliko.js +11 -11
  128. package/cli/src/commands/chat.js +143 -141
  129. package/cli/src/commands/list.js +93 -90
  130. package/cli/src/index.js +75 -75
  131. package/cli/src/ui/chat-ui.js +201 -199
  132. package/cli/src/utils/ansi.js +40 -40
  133. package/cli/src/utils/markdown.js +292 -296
  134. package/docker-compose.yml +1 -1
  135. package/docs/ai-sdk-optimization.md +655 -643
  136. package/docs/features.md +80 -80
  137. package/docs/quick-reference.md +49 -46
  138. package/docs/user-manual.md +411 -380
  139. package/examples/ambient-example.js +194 -196
  140. package/examples/basic.js +50 -45
  141. package/examples/bootstrap.js +121 -112
  142. package/examples/mcp-example.js +19 -16
  143. package/examples/skill-example.js +20 -20
  144. package/examples/test-chat.js +137 -135
  145. package/examples/test-mcp.js +85 -79
  146. package/examples/test-reload.js +59 -61
  147. package/examples/test-telegram.js +50 -50
  148. package/examples/test-tg-bot.js +45 -42
  149. package/examples/test-tg-simple.js +47 -46
  150. package/examples/test-tg.js +62 -62
  151. package/examples/test-think.js +43 -37
  152. package/examples/test-web-plugin.js +103 -98
  153. package/examples/test-weixin-feishu.js +103 -100
  154. package/examples/workflow.js +158 -158
  155. package/package.json +37 -3
  156. package/plugins/ai-plugin.js +102 -100
  157. package/plugins/ambient-agent/EventWatcher.js +113 -0
  158. package/plugins/ambient-agent/ExplorerLoop.js +640 -0
  159. package/plugins/ambient-agent/GoalManager.js +197 -0
  160. package/plugins/ambient-agent/Reflector.js +95 -0
  161. package/plugins/ambient-agent/StateStore.js +90 -0
  162. package/plugins/ambient-agent/constants.js +101 -0
  163. package/plugins/ambient-agent/index.js +579 -0
  164. package/plugins/audit-plugin.js +187 -187
  165. package/plugins/default-plugins.js +662 -649
  166. package/plugins/email/constants.js +64 -0
  167. package/plugins/email/handlers.js +461 -0
  168. package/plugins/email/index.js +278 -0
  169. package/plugins/email/monitor.js +269 -0
  170. package/plugins/email/parser.js +138 -0
  171. package/plugins/email/reply.js +151 -0
  172. package/plugins/email/utils.js +124 -0
  173. package/plugins/feishu-plugin.js +481 -477
  174. package/plugins/file-system-plugin.js +826 -476
  175. package/plugins/install-plugin.js +199 -197
  176. package/plugins/python-executor-plugin.js +367 -365
  177. package/plugins/python-plugin-loader.js +481 -479
  178. package/plugins/rules-plugin.js +294 -292
  179. package/plugins/scheduler-plugin.js +691 -689
  180. package/plugins/session-plugin.js +369 -367
  181. package/plugins/shell-executor-plugin.js +197 -197
  182. package/plugins/storage-plugin.js +240 -238
  183. package/plugins/subagent-plugin.js +845 -785
  184. package/plugins/telegram-plugin.js +482 -475
  185. package/plugins/think-plugin.js +345 -343
  186. package/plugins/tools-plugin.js +196 -194
  187. package/plugins/web-plugin.js +606 -604
  188. package/plugins/weixin-plugin.js +545 -538
  189. package/reports/system-health-report-20260401.md +79 -0
  190. package/skills/ambient-agent/SKILL.md +49 -39
  191. package/skills/foliko-dev/AGENTS.md +64 -61
  192. package/skills/foliko-dev/SKILL.md +125 -119
  193. package/skills/mcp-usage/SKILL.md +19 -17
  194. package/skills/python-plugin-dev/SKILL.md +16 -15
  195. package/skills/skill-guide/SKILL.md +12 -12
  196. package/skills/subagent-guide/SKILL.md +237 -0
  197. package/skills/workflow-guide/SKILL.md +90 -45
  198. package/skills/workflow-troubleshooting/DEBUGGING.md +36 -21
  199. package/skills/workflow-troubleshooting/SKILL.md +156 -79
  200. package/src/capabilities/index.js +11 -11
  201. package/src/capabilities/skill-manager.js +609 -595
  202. package/src/capabilities/workflow-engine.js +1109 -1195
  203. package/src/core/agent-chat.js +882 -735
  204. package/src/core/agent.js +892 -688
  205. package/src/core/framework.js +465 -431
  206. package/src/core/index.js +19 -19
  207. package/src/core/plugin-base.js +219 -219
  208. package/src/core/plugin-manager.js +863 -767
  209. package/src/core/provider.js +114 -111
  210. package/src/core/sub-agent-config.js +264 -0
  211. package/src/core/system-prompt-builder.js +120 -0
  212. package/src/core/tool-registry.js +517 -134
  213. package/src/core/tool-router.js +297 -216
  214. package/src/executors/executor-base.js +12 -12
  215. package/src/executors/mcp-executor.js +741 -729
  216. package/src/index.js +25 -37
  217. package/src/utils/circuit-breaker.js +301 -0
  218. package/src/utils/error-boundary.js +363 -0
  219. package/src/utils/error.js +374 -0
  220. package/src/utils/event-emitter.js +97 -97
  221. package/src/utils/id.js +133 -0
  222. package/src/utils/index.js +217 -3
  223. package/src/utils/logger.js +181 -0
  224. package/src/utils/plugin-helpers.js +90 -0
  225. package/src/utils/retry.js +122 -0
  226. package/src/utils/sandbox.js +292 -0
  227. package/test/tool-registry-validation.test.js +218 -0
  228. package/test_report.md +70 -0
  229. package/website/docs/api.html +169 -107
  230. package/website/docs/configuration.html +296 -144
  231. package/website/docs/plugin-development.html +154 -85
  232. package/website/docs/project-structure.html +110 -109
  233. package/website/docs/skill-development.html +117 -61
  234. package/website/index.html +209 -205
  235. package/website/script.js +136 -133
  236. package/website/styles.css +1 -1
  237. package/plugins/ambient-agent-plugin.js +0 -1565
  238. package/plugins/email.js +0 -1142
@@ -0,0 +1,151 @@
1
+ /**
2
+ * Email 插件 - 自动回复
3
+ */
4
+
5
+ const { EMAIL_DEFAULTS } = require('./constants')
6
+
7
+ /**
8
+ * 处理自动回复
9
+ * @param {Object} emailPlugin - EmailPlugin 实例
10
+ * @param {Object} args - 回复参数
11
+ * @returns {Promise<Object>} 回复结果
12
+ */
13
+ async function handleAutoReply(emailPlugin, args) {
14
+ let { to, subject, body, from, _event, prompt, messageId, inReplyTo } = args
15
+
16
+ // 如果没有直接参数,尝试从 _event 提取
17
+ // 支持多种事件结构:{ email, timestamp } 或 { data: { email } } 或 { data: { ... } }
18
+ if (!to && !subject && !body && _event) {
19
+ // 兼容多种事件结构
20
+ const email = _event.email || _event.data?.email || _event.data || {}
21
+ from = email.from?.text || email.from || ''
22
+ to = email.to?.text || email.to || ''
23
+ subject = email.subject || ''
24
+ body = email.text || email.body || ''
25
+ // 优先使用 _event 中的 uid/messageId
26
+ if (!messageId) {
27
+ messageId = email.messageId || email.uid || _event.data?.messageId || _event.data?.uid
28
+ }
29
+ }
30
+
31
+ // 如果 _event 没有有效数据,不允许自动读取所有邮件
32
+ if (!_event || (!_event.email && !_event.data)) {
33
+ return {
34
+ success: false,
35
+ error: '缺少邮件数据:_event 中没有有效的邮件信息,无法自动回复。请确认是否在收到新邮件事件时调用此工具。'
36
+ }
37
+ }
38
+
39
+ // 优先使用传入的 inReplyTo,否则用 messageId
40
+ const replyTo = inReplyTo || messageId
41
+
42
+ // 检查必要参数
43
+ if (!from && !to) {
44
+ return { success: false, error: '缺少收件人地址' }
45
+ }
46
+ if (!body) {
47
+ return { success: false, error: '缺少邮件内容' }
48
+ }
49
+
50
+ try {
51
+ // 使用子 Agent 生成回复
52
+ const replyAgent = emailPlugin._framework.createSubAgent({
53
+ name: 'email_replier',
54
+ role: '邮件自动回复助手,专注于生成专业、礼貌、简洁的邮件回复',
55
+ parentTools: []
56
+ })
57
+
58
+ // 构建提示让 LLM 生成回复
59
+ const finalPrompt = prompt || `你是一封邮件自动回复助手。请根据以下邮件内容,生成一封专业的回复邮件。
60
+
61
+ 【原始邮件】
62
+ 发件人: ${from || to}
63
+ 主题: ${subject}
64
+ 内容:
65
+ ${body}
66
+
67
+ 【要求】
68
+ 1. 回复内容要针对邮件中的问题或内容进行回复
69
+ 2. 语言要专业、礼貌、简洁
70
+ 3. 只输出邮件正文内容,不要额外解释
71
+ 4. 回复语言应与原邮件一致(如果原邮件是中文,则用中文回复)`
72
+
73
+ // 等待 Agent 生成回复(带超时保护)
74
+ const timeoutMs = args.timeout || EMAIL_DEFAULTS.timeout
75
+ const timeoutPromise = new Promise((_, reject) => {
76
+ setTimeout(() => reject(new Error(`AI回复生成超时(${timeoutMs / 1000}秒)`)), timeoutMs)
77
+ })
78
+
79
+ const replyPromise = replyAgent.chat(finalPrompt, { maxSteps: 3 })
80
+ const replyResult = await Promise.race([replyPromise, timeoutPromise])
81
+
82
+ // 提取回复内容
83
+ let replyContent = ''
84
+ if (typeof replyResult === 'string') {
85
+ replyContent = replyResult.trim()
86
+ } else if (replyResult && replyResult.content) {
87
+ replyContent = replyResult.content.trim()
88
+ } else if (replyResult && replyResult.message) {
89
+ replyContent = replyResult.message.trim()
90
+ } else {
91
+ replyContent = JSON.stringify(replyResult).trim()
92
+ }
93
+
94
+ // 去掉思考过程标签
95
+ replyContent = replyContent.replace(/<think>[\s\S]*?<\/think>/g, '').trim()
96
+
97
+ if (!replyContent || replyContent.length < 5) {
98
+ return { success: false, error: 'AI未能生成有效的回复内容' }
99
+ }
100
+
101
+ // 发送回复邮件
102
+ const { sendEmail } = require('./handlers')
103
+ const sendResult = await sendEmail(emailPlugin, {
104
+ to: from || to,
105
+ subject: `Re: ${subject}`,
106
+ body: replyContent,
107
+ inReplyTo: replyTo,
108
+ references: replyTo ? [replyTo] : undefined
109
+ })
110
+
111
+ if (sendResult.success) {
112
+ // 发送成功后,标记为已处理
113
+ const emailData = _event?.email || _event?.data?.email || _event?.data || {}
114
+ const msgId = messageId || emailData.messageId || emailData.uid
115
+ if (msgId) {
116
+ emailPlugin._processedEmails.add(msgId)
117
+ emailPlugin._log.info(`邮件已处理: ${msgId}`)
118
+
119
+ // 24小时后从已处理列表中移除
120
+ setTimeout(() => {
121
+ emailPlugin._processedEmails.delete(msgId)
122
+ }, EMAIL_DEFAULTS.processedEmailTTL)
123
+ }
124
+
125
+ // 自动标记原邮件为已读
126
+ const uid = emailData.uid || msgId
127
+ if (uid) {
128
+ try {
129
+ const { markAsRead } = require('./handlers')
130
+ await markAsRead(emailPlugin, { uid: uid }) // 使用 uid 而非 messageId
131
+ } catch (err) {
132
+ emailPlugin._log.warn(`自动标记已读失败: ${err.message}`)
133
+ }
134
+ }
135
+
136
+ return {
137
+ success: true,
138
+ message: `自动回复已发送至 ${from || to}`,
139
+ replyContent
140
+ }
141
+ } else {
142
+ return { success: false, error: sendResult.error || '发送失败' }
143
+ }
144
+ } catch (err) {
145
+ return { success: false, error: err.message }
146
+ }
147
+ }
148
+
149
+ module.exports = {
150
+ handleAutoReply
151
+ }
@@ -0,0 +1,124 @@
1
+ /**
2
+ * Email 插件 - 工具函数
3
+ */
4
+
5
+ const https = require('https')
6
+ const http = require('http')
7
+ const fs = require('fs')
8
+
9
+ /**
10
+ * 验证邮箱地址格式
11
+ * @param {string} email - 邮箱地址
12
+ * @returns {boolean}
13
+ */
14
+ function isValidEmail(email) {
15
+ if (!email) return false
16
+ const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/
17
+ return emailRegex.test(email)
18
+ }
19
+
20
+ /**
21
+ * 从邮件地址提取显示名称和邮箱
22
+ * @param {string} from - 邮件地址文本
23
+ * @returns {{name: string, email: string}}
24
+ */
25
+ function parseEmailAddress(from) {
26
+ if (!from) return { name: '', email: '' }
27
+
28
+ // 格式: "Display Name <email@example.com>"
29
+ const match = from.match(/^(.+?)\s*<(.+)>$/)
30
+ if (match) {
31
+ return { name: match[1].trim(), email: match[2].trim() }
32
+ }
33
+
34
+ // 格式: email@example.com
35
+ return { name: '', email: from.trim() }
36
+ }
37
+
38
+ /**
39
+ * 获取环境变量配置
40
+ * @param {Object} args - 参数对象
41
+ * @returns {Object} 合并后的配置
42
+ */
43
+ function getConfig(args) {
44
+ return {
45
+ host: args.host || process.env.IMAP_HOST,
46
+ port: args.port || parseInt(process.env.IMAP_PORT) || 993,
47
+ user: args.user || process.env.IMAP_USER,
48
+ password: args.password || process.env.IMAP_PASS
49
+ }
50
+ }
51
+
52
+ /**
53
+ * 从 URL 获取内容
54
+ * @param {string} url - 文件 URL
55
+ * @returns {Promise<Buffer>}
56
+ */
57
+ function fetchUrl(url) {
58
+ return new Promise((resolve, reject) => {
59
+ const lib = url.startsWith('https') ? https : http
60
+
61
+ const request = lib.get(url, (response) => {
62
+ // 处理重定向
63
+ if (response.statusCode === 301 || response.statusCode === 302) {
64
+ fetchUrl(response.headers.location).then(resolve).catch(reject)
65
+ return
66
+ }
67
+
68
+ const chunks = []
69
+ response.on('data', (chunk) => chunks.push(chunk))
70
+ response.on('end', () => resolve(Buffer.concat(chunks)))
71
+ response.on('error', reject)
72
+ })
73
+
74
+ request.on('error', reject)
75
+ request.setTimeout(10000, () => {
76
+ request.destroy()
77
+ reject(new Error('下载超时'))
78
+ })
79
+ })
80
+ }
81
+
82
+ /**
83
+ * 处理附件
84
+ * @param {Object} att - 附件定义
85
+ * @returns {Promise<Object>} 处理后的附件
86
+ */
87
+ async function processAttachment(att) {
88
+ const attachment = { filename: att.filename }
89
+
90
+ if (att.path) {
91
+ // 本地文件
92
+ attachment.content = fs.createReadStream(att.path)
93
+ } else if (att.url) {
94
+ // 远程 URL
95
+ attachment.content = await fetchUrl(att.url)
96
+ } else if (att.content) {
97
+ // Base64 内容
98
+ const base64Data = att.content.replace(/^data:[^;]+;base64,/, '')
99
+ attachment.content = Buffer.from(base64Data, 'base64')
100
+ }
101
+
102
+ if (att.cid) {
103
+ attachment.cid = att.cid
104
+ }
105
+
106
+ return attachment
107
+ }
108
+
109
+ /**
110
+ * 生成唯一调用 ID
111
+ * @returns {string}
112
+ */
113
+ function generateCallId() {
114
+ return `${Date.now()}_${Math.random().toString(36).substr(2, 5)}`
115
+ }
116
+
117
+ module.exports = {
118
+ isValidEmail,
119
+ parseEmailAddress,
120
+ getConfig,
121
+ fetchUrl,
122
+ processAttachment,
123
+ generateCallId
124
+ }