@dsh-plus/notify-email 0.1.6 → 0.1.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/src/config.ts CHANGED
@@ -4,8 +4,9 @@
4
4
  * 共用同一 schemastery schema。SMTP 密码标记 secret 角色,任何读取通道不得回传。
5
5
  * @module notify-email/config
6
6
  */
7
- import z from '@deepseek-ai/schemastery'
7
+
8
8
  import { settingsNamespace } from '@deepseek-ai/dsh-settings'
9
+ import z from '@deepseek-ai/schemastery'
9
10
 
10
11
  import { SETTINGS_NS as NS_LITERAL } from './ns.ts'
11
12
 
@@ -31,10 +32,21 @@ const TriggerSchema = z.object({
31
32
 
32
33
  export const Config = z.object({
33
34
  enabled: z.boolean().description('总开关').default(false),
34
- smtp: SmtpSchema.default({ host: '', port: 465, secure: true, user: '', pass: '', from: '' }),
35
+ smtp: SmtpSchema.default({
36
+ host: '',
37
+ port: 465,
38
+ secure: true,
39
+ user: '',
40
+ pass: '',
41
+ from: '',
42
+ }),
35
43
  to: z.array(z.string()).description('收件邮箱列表').default([]),
36
44
  triggers: TriggerSchema.default({
37
- onComplete: true, onError: true, onAborted: false, onQuestion: true, onPlanReview: true,
45
+ onComplete: true,
46
+ onError: true,
47
+ onAborted: false,
48
+ onQuestion: true,
49
+ onPlanReview: true,
38
50
  }),
39
51
  idleDebounceMs: z.natural().description('turn 结束后确认无后续工作的等待毫秒数').default(3000),
40
52
  maxBodyChars: z.natural().min(200).description('邮件正文内容截断长度').default(4000),
package/src/index.ts CHANGED
@@ -14,11 +14,16 @@ export const name = 'dsh-plus-notify-email'
14
14
 
15
15
  export const inject = ['agents', 'tools'] as const
16
16
 
17
- export { Config }
18
-
19
- export type { EmailNotice, DecisionCall, TurnEndInfo, NotifyTrigger } from './triggers/types.ts'
20
17
  export { NotifyEmailService } from './service.ts'
21
18
 
19
+ export type {
20
+ DecisionCall,
21
+ EmailNotice,
22
+ NotifyTrigger,
23
+ TurnEndInfo,
24
+ } from './triggers/types.ts'
25
+ export { Config }
26
+
22
27
  export function apply(ctx: Context, config: NotifyEmailConfig): void {
23
28
  ctx.plugin(NotifyEmailService, config)
24
29
  }
package/src/mailer.ts CHANGED
@@ -5,8 +5,8 @@
5
5
  */
6
6
  import nodemailer from 'nodemailer'
7
7
 
8
- import { buildAuditRecord, type AuditSink } from './audit.ts'
9
- import { isDeliverable, type NotifyEmailConfig } from './config.ts'
8
+ import { type AuditSink, buildAuditRecord } from './audit.ts'
9
+ import type { NotifyEmailConfig } from './config.ts'
10
10
 
11
11
  /** 一封待发邮件(触发器产物的最小契约)。 */
12
12
  export interface MailMessage {
package/src/service.ts CHANGED
@@ -8,12 +8,11 @@
8
8
  */
9
9
  import { Context, Service } from '@deepseek-ai/cordis'
10
10
  import { dshHomePath } from '@deepseek-ai/dsh-home-paths'
11
-
12
- import { createJsonlAuditSink } from './audit.ts'
13
- import { Config, SETTINGS_NS, type NotifyEmailConfig } from './config.ts'
14
- import { Mailer } from './mailer.ts'
15
11
  import { installSettingsSection } from '@deepseek-ai/dsh-settings'
12
+ import { createJsonlAuditSink } from './audit.ts'
13
+ import { Config, type NotifyEmailConfig, SETTINGS_NS } from './config.ts'
16
14
  import { registerTestApi } from './config-api.ts'
15
+ import { Mailer } from './mailer.ts'
17
16
  import { createDecisionTrigger, createTurnEndTrigger } from './triggers/builtin.ts'
18
17
  import type { DecisionCall, NotifyTrigger, TurnEndInfo } from './triggers/types.ts'
19
18
  import { installDecisionWatcher } from './watchers/decision.ts'
@@ -42,9 +41,8 @@ export class NotifyEmailService extends Service {
42
41
  onChange: () => {},
43
42
  })
44
43
  const logger = ctx.logger('notify-email')
45
- const audit = createJsonlAuditSink(
46
- dshHomePath('logs', 'notify-email.jsonl'),
47
- (message) => logger.warn(`audit write failed: ${message}`),
44
+ const audit = createJsonlAuditSink(dshHomePath('logs', 'notify-email.jsonl'), (message) =>
45
+ logger.warn(`audit write failed: ${message}`),
48
46
  )
49
47
  this.mailer = new Mailer(() => this.current(), logger, undefined, audit)
50
48
  this.registerTrigger(createDecisionTrigger(() => this.current()))
@@ -89,37 +87,45 @@ export class NotifyEmailService extends Service {
89
87
  /** 配置卡片「发送测试邮件」:绕过 enabled 门禁,仍需 SMTP 完整。 */
90
88
  async sendTest(): Promise<{ ok: boolean; detail: string }> {
91
89
  return this.mailer.send(
92
- { subject: '[DSH] 邮件通知测试', text: '这是一封来自 dsh notify-email 插件的测试邮件。' },
90
+ {
91
+ subject: '[DSH] 邮件通知测试',
92
+ text: '这是一封来自 dsh notify-email 插件的测试邮件。',
93
+ },
93
94
  true,
94
95
  )
95
96
  }
96
97
 
97
98
  /** 通用直发接口(如 lifeboat 故障告警):走正常 enabled/完整性门禁。 */
98
- async sendNotice(notice: { subject: string; text: string }): Promise<{ ok: boolean; detail: string }> {
99
+ async sendNotice(notice: {
100
+ subject: string
101
+ text: string
102
+ }): Promise<{ ok: boolean; detail: string }> {
99
103
  return this.mailer.send(notice)
100
104
  }
101
105
 
102
106
  private async dispatch<T>(
103
107
  kind: string,
104
- payload: T,
108
+ _payload: T,
105
109
  produce: (t: NotifyTrigger) => { subject: string; text: string; html?: string } | undefined,
106
110
  ): Promise<void> {
107
111
  for (const trigger of [...this.triggers]) {
108
- let notice
112
+ let notice: ReturnType<typeof produce>
109
113
  try {
110
114
  notice = produce(trigger)
111
115
  } catch (error) {
112
- this.ctx.logger('notify-email').warn(
113
- `trigger ${trigger.id} failed on ${kind}: ${error instanceof Error ? error.message : String(error)}`,
114
- )
116
+ this.ctx
117
+ .logger('notify-email')
118
+ .warn(
119
+ `trigger ${trigger.id} failed on ${kind}: ${error instanceof Error ? error.message : String(error)}`,
120
+ )
115
121
  continue
116
122
  }
117
123
  if (notice === undefined) continue
118
124
  const result = await this.mailer.send(notice)
119
125
  if (!result.ok && result.detail !== 'disabled' && result.detail !== 'incomplete') {
120
- this.ctx.logger('notify-email').warn(
121
- `deliver failed via trigger ${trigger.id}: ${result.detail}`,
122
- )
126
+ this.ctx
127
+ .logger('notify-email')
128
+ .warn(`deliver failed via trigger ${trigger.id}: ${result.detail}`)
123
129
  }
124
130
  return
125
131
  }
@@ -5,8 +5,11 @@
5
5
  */
6
6
  import type { NotifyEmailConfig } from '../config.ts'
7
7
  import {
8
- renderAbortedNotice, renderCompletionNotice, renderErrorNotice,
9
- renderPlanNotice, renderQuestionNotice,
8
+ renderAbortedNotice,
9
+ renderCompletionNotice,
10
+ renderErrorNotice,
11
+ renderPlanNotice,
12
+ renderQuestionNotice,
10
13
  } from './render.ts'
11
14
  import type { NotifyTrigger } from './types.ts'
12
15
 
@@ -91,13 +91,10 @@ export function installTurnEndWatcher(
91
91
  const watch = watchOf(session.id)
92
92
  if (watch.timer !== undefined) clearTimeout(watch.timer)
93
93
  const errorMessage = extractErrorMessage(reason)
94
- watch.timer = setTimeout(
95
- () => {
96
- watch.timer = undefined
97
- fire(session, turn, reason.kind, errorMessage)
98
- },
99
- resolveConfig().idleDebounceMs,
100
- )
94
+ watch.timer = setTimeout(() => {
95
+ watch.timer = undefined
96
+ fire(session, turn, reason.kind, errorMessage)
97
+ }, resolveConfig().idleDebounceMs)
101
98
  }
102
99
 
103
100
  ctx.on('session/event', (session, event) => {