@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/lib/client.js +626 -650
- package/lib/index.d.ts +0 -3
- package/lib/index.js +70 -66
- package/package.json +8 -8
- package/src/client/card.tsx +169 -52
- package/src/client/client.ts +20 -8
- package/src/client/scope.ts +25 -3
- package/src/config.ts +15 -3
- package/src/index.ts +8 -3
- package/src/mailer.ts +2 -2
- package/src/service.ts +23 -17
- package/src/triggers/builtin.ts +5 -2
- package/src/watchers/turn-end.ts +4 -7
package/src/config.ts
CHANGED
|
@@ -4,8 +4,9 @@
|
|
|
4
4
|
* 共用同一 schemastery schema。SMTP 密码标记 secret 角色,任何读取通道不得回传。
|
|
5
5
|
* @module notify-email/config
|
|
6
6
|
*/
|
|
7
|
-
|
|
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({
|
|
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,
|
|
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 {
|
|
9
|
-
import {
|
|
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
|
-
|
|
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
|
-
{
|
|
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: {
|
|
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
|
-
|
|
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
|
|
113
|
-
|
|
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
|
|
121
|
-
|
|
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
|
}
|
package/src/triggers/builtin.ts
CHANGED
|
@@ -5,8 +5,11 @@
|
|
|
5
5
|
*/
|
|
6
6
|
import type { NotifyEmailConfig } from '../config.ts'
|
|
7
7
|
import {
|
|
8
|
-
renderAbortedNotice,
|
|
9
|
-
|
|
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
|
|
package/src/watchers/turn-end.ts
CHANGED
|
@@ -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
|
-
|
|
97
|
-
|
|
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) => {
|