@dsh-plus/notify-email 0.1.28 → 0.1.29
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 +1 -1
- package/lib/index.d.ts +77 -73
- package/lib/index.js +51 -62
- package/package.json +17 -17
- package/src/client/client.ts +2 -2
- package/src/config.ts +16 -8
- package/src/index.ts +4 -4
- package/src/service.ts +7 -16
package/lib/client.js
CHANGED
|
@@ -42,7 +42,7 @@ window.__ModuleLoader__.load({
|
|
|
42
42
|
className: `${p}-pending`,
|
|
43
43
|
children: props.dirtyLabel
|
|
44
44
|
}) : null,
|
|
45
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.
|
|
45
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconChevronDownOutlineRegular, { className: `${p}-chevron${props.open ? ` ${p}-chevronOpen` : ""}` })
|
|
46
46
|
]
|
|
47
47
|
}), props.open ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
48
48
|
className: `${p}-body`,
|
package/lib/index.d.ts
CHANGED
|
@@ -1,76 +1,80 @@
|
|
|
1
|
-
import z from "@deepseek-ai/schemastery";
|
|
2
1
|
import { Context, Service } from "@deepseek-ai/cordis";
|
|
2
|
+
import { UnwrapVolatile } from "@dsh-plus/shared";
|
|
3
|
+
import z from "@deepseek-ai/schemastery";
|
|
3
4
|
//#region src/config.d.ts
|
|
4
|
-
declare const Config: z<Schemastery.ObjectS<{
|
|
5
|
-
enabled: z<boolean, boolean>;
|
|
6
|
-
smtp: z<Schemastery.ObjectS<{
|
|
7
|
-
host: z<string, string>;
|
|
8
|
-
port: z<number, number>;
|
|
9
|
-
secure: z<boolean, boolean>;
|
|
10
|
-
user: z<string, string>;
|
|
11
|
-
pass: z<string, string>;
|
|
12
|
-
from: z<string, string>;
|
|
13
|
-
}
|
|
14
|
-
host: z<string, string>;
|
|
15
|
-
port: z<number, number>;
|
|
16
|
-
secure: z<boolean, boolean>;
|
|
17
|
-
user: z<string, string>;
|
|
18
|
-
pass: z<string, string>;
|
|
19
|
-
from: z<string, string>;
|
|
20
|
-
}
|
|
21
|
-
to: z<string[]
|
|
22
|
-
triggers: z<Schemastery.ObjectS<{
|
|
23
|
-
onComplete: z<boolean, boolean>;
|
|
24
|
-
onError: z<boolean, boolean>;
|
|
25
|
-
onAborted: z<boolean, boolean>;
|
|
26
|
-
onQuestion: z<boolean, boolean>;
|
|
27
|
-
onPlanReview: z<boolean, boolean>;
|
|
28
|
-
}
|
|
29
|
-
onComplete: z<boolean, boolean>;
|
|
30
|
-
onError: z<boolean, boolean>;
|
|
31
|
-
onAborted: z<boolean, boolean>;
|
|
32
|
-
onQuestion: z<boolean, boolean>;
|
|
33
|
-
onPlanReview: z<boolean, boolean>;
|
|
34
|
-
}
|
|
35
|
-
idleDebounceMs: z<number, number>;
|
|
36
|
-
maxBodyChars: z<number, number>;
|
|
37
|
-
dryRun: z<boolean, boolean>;
|
|
38
|
-
}
|
|
39
|
-
enabled: z<boolean, boolean>;
|
|
40
|
-
smtp: z<Schemastery.ObjectS<{
|
|
41
|
-
host: z<string, string>;
|
|
42
|
-
port: z<number, number>;
|
|
43
|
-
secure: z<boolean, boolean>;
|
|
44
|
-
user: z<string, string>;
|
|
45
|
-
pass: z<string, string>;
|
|
46
|
-
from: z<string, string>;
|
|
47
|
-
}
|
|
48
|
-
host: z<string, string>;
|
|
49
|
-
port: z<number, number>;
|
|
50
|
-
secure: z<boolean, boolean>;
|
|
51
|
-
user: z<string, string>;
|
|
52
|
-
pass: z<string, string>;
|
|
53
|
-
from: z<string, string>;
|
|
54
|
-
}
|
|
55
|
-
to: z<string[]
|
|
56
|
-
triggers: z<Schemastery.ObjectS<{
|
|
57
|
-
onComplete: z<boolean, boolean>;
|
|
58
|
-
onError: z<boolean, boolean>;
|
|
59
|
-
onAborted: z<boolean, boolean>;
|
|
60
|
-
onQuestion: z<boolean, boolean>;
|
|
61
|
-
onPlanReview: z<boolean, boolean>;
|
|
62
|
-
}
|
|
63
|
-
onComplete: z<boolean, boolean>;
|
|
64
|
-
onError: z<boolean, boolean>;
|
|
65
|
-
onAborted: z<boolean, boolean>;
|
|
66
|
-
onQuestion: z<boolean, boolean>;
|
|
67
|
-
onPlanReview: z<boolean, boolean>;
|
|
68
|
-
}
|
|
69
|
-
idleDebounceMs: z<number, number>;
|
|
70
|
-
maxBodyChars: z<number, number>;
|
|
71
|
-
dryRun: z<boolean, boolean>;
|
|
72
|
-
}
|
|
73
|
-
|
|
5
|
+
declare const Config: z<Schemastery.ObjectS<NoInfer<{
|
|
6
|
+
enabled: z<boolean, boolean, "volatile-defined">;
|
|
7
|
+
smtp: z<NoInfer<Schemastery.ObjectS<NoInfer<{
|
|
8
|
+
host: z<string, string, "defined">;
|
|
9
|
+
port: z<number, number, "defined">;
|
|
10
|
+
secure: z<boolean, boolean, "defined">;
|
|
11
|
+
user: z<string, string, "defined">;
|
|
12
|
+
pass: z<string, string, "defined">;
|
|
13
|
+
from: z<string, string, "defined">;
|
|
14
|
+
}>>>, NoInfer<Schemastery.ObjectT<NoInfer<{
|
|
15
|
+
host: z<string, string, "defined">;
|
|
16
|
+
port: z<number, number, "defined">;
|
|
17
|
+
secure: z<boolean, boolean, "defined">;
|
|
18
|
+
user: z<string, string, "defined">;
|
|
19
|
+
pass: z<string, string, "defined">;
|
|
20
|
+
from: z<string, string, "defined">;
|
|
21
|
+
}>>>, "volatile-defined">;
|
|
22
|
+
to: z<NoInfer<string[]>, NoInfer<string[]>, "volatile-defined">;
|
|
23
|
+
triggers: z<NoInfer<Schemastery.ObjectS<NoInfer<{
|
|
24
|
+
onComplete: z<boolean, boolean, "defined">;
|
|
25
|
+
onError: z<boolean, boolean, "defined">;
|
|
26
|
+
onAborted: z<boolean, boolean, "defined">;
|
|
27
|
+
onQuestion: z<boolean, boolean, "defined">;
|
|
28
|
+
onPlanReview: z<boolean, boolean, "defined">;
|
|
29
|
+
}>>>, NoInfer<Schemastery.ObjectT<NoInfer<{
|
|
30
|
+
onComplete: z<boolean, boolean, "defined">;
|
|
31
|
+
onError: z<boolean, boolean, "defined">;
|
|
32
|
+
onAborted: z<boolean, boolean, "defined">;
|
|
33
|
+
onQuestion: z<boolean, boolean, "defined">;
|
|
34
|
+
onPlanReview: z<boolean, boolean, "defined">;
|
|
35
|
+
}>>>, "volatile-defined">;
|
|
36
|
+
idleDebounceMs: z<number, number, "volatile-defined">;
|
|
37
|
+
maxBodyChars: z<number, number, "volatile-defined">;
|
|
38
|
+
dryRun: z<boolean, boolean, "volatile-defined">;
|
|
39
|
+
}>>, Schemastery.ObjectT<NoInfer<{
|
|
40
|
+
enabled: z<boolean, boolean, "volatile-defined">;
|
|
41
|
+
smtp: z<NoInfer<Schemastery.ObjectS<NoInfer<{
|
|
42
|
+
host: z<string, string, "defined">;
|
|
43
|
+
port: z<number, number, "defined">;
|
|
44
|
+
secure: z<boolean, boolean, "defined">;
|
|
45
|
+
user: z<string, string, "defined">;
|
|
46
|
+
pass: z<string, string, "defined">;
|
|
47
|
+
from: z<string, string, "defined">;
|
|
48
|
+
}>>>, NoInfer<Schemastery.ObjectT<NoInfer<{
|
|
49
|
+
host: z<string, string, "defined">;
|
|
50
|
+
port: z<number, number, "defined">;
|
|
51
|
+
secure: z<boolean, boolean, "defined">;
|
|
52
|
+
user: z<string, string, "defined">;
|
|
53
|
+
pass: z<string, string, "defined">;
|
|
54
|
+
from: z<string, string, "defined">;
|
|
55
|
+
}>>>, "volatile-defined">;
|
|
56
|
+
to: z<NoInfer<string[]>, NoInfer<string[]>, "volatile-defined">;
|
|
57
|
+
triggers: z<NoInfer<Schemastery.ObjectS<NoInfer<{
|
|
58
|
+
onComplete: z<boolean, boolean, "defined">;
|
|
59
|
+
onError: z<boolean, boolean, "defined">;
|
|
60
|
+
onAborted: z<boolean, boolean, "defined">;
|
|
61
|
+
onQuestion: z<boolean, boolean, "defined">;
|
|
62
|
+
onPlanReview: z<boolean, boolean, "defined">;
|
|
63
|
+
}>>>, NoInfer<Schemastery.ObjectT<NoInfer<{
|
|
64
|
+
onComplete: z<boolean, boolean, "defined">;
|
|
65
|
+
onError: z<boolean, boolean, "defined">;
|
|
66
|
+
onAborted: z<boolean, boolean, "defined">;
|
|
67
|
+
onQuestion: z<boolean, boolean, "defined">;
|
|
68
|
+
onPlanReview: z<boolean, boolean, "defined">;
|
|
69
|
+
}>>>, "volatile-defined">;
|
|
70
|
+
idleDebounceMs: z<number, number, "volatile-defined">;
|
|
71
|
+
maxBodyChars: z<number, number, "volatile-defined">;
|
|
72
|
+
dryRun: z<boolean, boolean, "volatile-defined">;
|
|
73
|
+
}>>, "plain">;
|
|
74
|
+
/** 活动字段形态(0.1.7 loader 解析产物:volatile 字段为活动引用)。 */
|
|
75
|
+
type NotifyEmailConfigFields = Schemastery.TypeT<typeof Config>;
|
|
76
|
+
/** 平面配置形态(消费面的读取形态,由活动引用解包得到)。 */
|
|
77
|
+
type NotifyEmailConfig = UnwrapVolatile<NotifyEmailConfigFields>;
|
|
74
78
|
//#endregion
|
|
75
79
|
//#region src/triggers/types.d.ts
|
|
76
80
|
/**
|
|
@@ -121,7 +125,7 @@ declare class NotifyEmailService extends Service {
|
|
|
121
125
|
private readonly triggers;
|
|
122
126
|
private readonly mailer;
|
|
123
127
|
private current;
|
|
124
|
-
constructor(ctx: Context, config: NotifyEmailConfig);
|
|
128
|
+
constructor(ctx: Context, config: NotifyEmailConfig | NotifyEmailConfigFields);
|
|
125
129
|
/** 注册触发器(第三方扩展接口);返回注销函数,随调用方 fiber 释放。 */
|
|
126
130
|
registerTrigger(trigger: NotifyTrigger): () => void;
|
|
127
131
|
/** 当前生效配置(settings 用户层解析结果或 cordis 行级 config)。 */
|
|
@@ -149,6 +153,6 @@ declare class NotifyEmailService extends Service {
|
|
|
149
153
|
//#region src/index.d.ts
|
|
150
154
|
declare const name = "dsh-plus-notify-email";
|
|
151
155
|
declare const inject: readonly ['agents', 'tools', 'credentials'];
|
|
152
|
-
declare function apply(ctx: Context, config: NotifyEmailConfig): void;
|
|
156
|
+
declare function apply(ctx: Context, config: NotifyEmailConfig | NotifyEmailConfigFields): void;
|
|
153
157
|
//#endregion
|
|
154
158
|
export { Config, type DecisionCall, type EmailNotice, NotifyEmailService, type NotifyTrigger, type TurnEndInfo, apply, inject, name };
|
package/lib/index.js
CHANGED
|
@@ -1,61 +1,10 @@
|
|
|
1
|
-
import z from "@deepseek-ai/schemastery";
|
|
2
1
|
import { Service } from "@deepseek-ai/cordis";
|
|
3
|
-
import { pluginDataPath } from "@dsh-plus/shared";
|
|
2
|
+
import { pluginDataPath, unwrapVolatile } from "@dsh-plus/shared";
|
|
4
3
|
import { appendFile, mkdir } from "node:fs/promises";
|
|
5
4
|
import { dirname } from "node:path";
|
|
6
5
|
import { credentialRef } from "@deepseek-ai/dsh-credentials";
|
|
7
6
|
import nodemailer from "nodemailer";
|
|
8
|
-
|
|
9
|
-
//#region src/config.ts
|
|
10
|
-
/**
|
|
11
|
-
* 配置单一事实源:cordis 行级 Config(组合默认值,dev/prod patch 层可覆盖)
|
|
12
|
-
* 与 settings namespace(用户层,经 dsh-settings-file 持久化到 $DSH_HOME/settings.yaml)
|
|
13
|
-
* 共用同一 schemastery schema。SMTP 密码走官方 credentials seam
|
|
14
|
-
* (refs/NOTIFY_EMAIL_SMTP_PASS),不进 settings.yaml(存储规范)。
|
|
15
|
-
* @module notify-email/config
|
|
16
|
-
*/
|
|
17
|
-
/** settings 命名空间(字面量即合法命名空间,0.1.2-alpha.2 起编译期校验;webui 配置卡片与插件运行期读取同一份)。 */
|
|
18
|
-
const SETTINGS_NS = "dsh-plus-notify-email";
|
|
19
|
-
/** SMTP 密码在官方 credentials seam 中的引用名。 */
|
|
20
|
-
const SMTP_PASS_REF = "NOTIFY_EMAIL_SMTP_PASS";
|
|
21
|
-
const SmtpSchema = z.object({
|
|
22
|
-
host: z.string().description("SMTP 服务器主机名").default(""),
|
|
23
|
-
port: z.natural().max(65535).description("SMTP 端口").default(465),
|
|
24
|
-
secure: z.boolean().description("使用 TLS 直连(465 端口通常为 true)").default(true),
|
|
25
|
-
user: z.string().description("SMTP 登录用户名(通常为发件邮箱)").default(""),
|
|
26
|
-
pass: z.string().role("secret").description("SMTP 密码/授权码(仅兼容行级注入;用户层请配置 credentials 引用)").default(""),
|
|
27
|
-
from: z.string().description("发件地址(From 头)").default("")
|
|
28
|
-
});
|
|
29
|
-
const TriggerSchema = z.object({
|
|
30
|
-
onComplete: z.boolean().description("任务执行完毕时通知").default(true),
|
|
31
|
-
onError: z.boolean().description("任务报错/失败停止时通知").default(true),
|
|
32
|
-
onAborted: z.boolean().description("任务被用户取消时通知").default(false),
|
|
33
|
-
onQuestion: z.boolean().description("agent 提问等待回答时通知").default(true),
|
|
34
|
-
onPlanReview: z.boolean().description("plan 待审批时通知").default(true)
|
|
35
|
-
});
|
|
36
|
-
const Config = z.object({
|
|
37
|
-
enabled: z.boolean().description("总开关").default(false),
|
|
38
|
-
smtp: SmtpSchema.default({
|
|
39
|
-
host: "",
|
|
40
|
-
port: 465,
|
|
41
|
-
secure: true,
|
|
42
|
-
user: "",
|
|
43
|
-
pass: "",
|
|
44
|
-
from: ""
|
|
45
|
-
}),
|
|
46
|
-
to: z.array(z.string()).description("收件邮箱列表").default([]),
|
|
47
|
-
triggers: TriggerSchema.default({
|
|
48
|
-
onComplete: true,
|
|
49
|
-
onError: true,
|
|
50
|
-
onAborted: false,
|
|
51
|
-
onQuestion: true,
|
|
52
|
-
onPlanReview: true
|
|
53
|
-
}),
|
|
54
|
-
idleDebounceMs: z.natural().description("turn 结束后确认无后续工作的等待毫秒数").default(3e3),
|
|
55
|
-
maxBodyChars: z.natural().min(200).description("邮件正文内容截断长度").default(4e3),
|
|
56
|
-
dryRun: z.boolean().description("仅记录日志不真实发送(开发调试用)").default(false)
|
|
57
|
-
});
|
|
58
|
-
//#endregion
|
|
7
|
+
import z from "@deepseek-ai/schemastery";
|
|
59
8
|
//#region src/audit.ts
|
|
60
9
|
/**
|
|
61
10
|
* 通知投递审计:每次发送尝试追加一行 JSONL 到
|
|
@@ -122,6 +71,54 @@ function registerTestApi(ctx, service) {
|
|
|
122
71
|
});
|
|
123
72
|
}
|
|
124
73
|
//#endregion
|
|
74
|
+
//#region src/config.ts
|
|
75
|
+
/**
|
|
76
|
+
* 配置单一事实源:cordis 行级 Config(组合默认值,dev/prod patch 层可覆盖)
|
|
77
|
+
* 与 settings namespace(用户层,经 dsh-settings-file 持久化到 $DSH_HOME/settings.yaml)
|
|
78
|
+
* 共用同一 schemastery schema。SMTP 密码走官方 credentials seam
|
|
79
|
+
* (refs/NOTIFY_EMAIL_SMTP_PASS),不进 settings.yaml(存储规范)。
|
|
80
|
+
* @module notify-email/config
|
|
81
|
+
*/
|
|
82
|
+
/** SMTP 密码在官方 credentials seam 中的引用名。 */
|
|
83
|
+
const SMTP_PASS_REF = "NOTIFY_EMAIL_SMTP_PASS";
|
|
84
|
+
const SmtpSchema = z.object({
|
|
85
|
+
host: z.string().description("SMTP 服务器主机名").default(""),
|
|
86
|
+
port: z.natural().max(65535).description("SMTP 端口").default(465),
|
|
87
|
+
secure: z.boolean().description("使用 TLS 直连(465 端口通常为 true)").default(true),
|
|
88
|
+
user: z.string().description("SMTP 登录用户名(通常为发件邮箱)").default(""),
|
|
89
|
+
pass: z.string().role("secret").description("SMTP 密码/授权码(仅兼容行级注入;用户层请配置 credentials 引用)").default(""),
|
|
90
|
+
from: z.string().description("发件地址(From 头)").default("")
|
|
91
|
+
});
|
|
92
|
+
const TriggerSchema = z.object({
|
|
93
|
+
onComplete: z.boolean().description("任务执行完毕时通知").default(true),
|
|
94
|
+
onError: z.boolean().description("任务报错/失败停止时通知").default(true),
|
|
95
|
+
onAborted: z.boolean().description("任务被用户取消时通知").default(false),
|
|
96
|
+
onQuestion: z.boolean().description("agent 提问等待回答时通知").default(true),
|
|
97
|
+
onPlanReview: z.boolean().description("plan 待审批时通知").default(true)
|
|
98
|
+
});
|
|
99
|
+
const Config = z.object({
|
|
100
|
+
enabled: z.boolean().description("总开关").default(false).volatile(),
|
|
101
|
+
smtp: SmtpSchema.default({
|
|
102
|
+
host: "",
|
|
103
|
+
port: 465,
|
|
104
|
+
secure: true,
|
|
105
|
+
user: "",
|
|
106
|
+
pass: "",
|
|
107
|
+
from: ""
|
|
108
|
+
}).volatile(),
|
|
109
|
+
to: z.array(z.string()).description("收件邮箱列表").default([]).volatile(),
|
|
110
|
+
triggers: TriggerSchema.default({
|
|
111
|
+
onComplete: true,
|
|
112
|
+
onError: true,
|
|
113
|
+
onAborted: false,
|
|
114
|
+
onQuestion: true,
|
|
115
|
+
onPlanReview: true
|
|
116
|
+
}).volatile(),
|
|
117
|
+
idleDebounceMs: z.natural().description("turn 结束后确认无后续工作的等待毫秒数").default(3e3).volatile(),
|
|
118
|
+
maxBodyChars: z.natural().min(200).description("邮件正文内容截断长度").default(4e3).volatile(),
|
|
119
|
+
dryRun: z.boolean().description("仅记录日志不真实发送(开发调试用)").default(false).volatile()
|
|
120
|
+
});
|
|
121
|
+
//#endregion
|
|
125
122
|
//#region src/mailer.ts
|
|
126
123
|
/**
|
|
127
124
|
* 邮件发送:nodemailer 封装 + dry-run 兜底。
|
|
@@ -450,15 +447,7 @@ var NotifyEmailService = class extends Service {
|
|
|
450
447
|
current;
|
|
451
448
|
constructor(ctx, config) {
|
|
452
449
|
super(ctx, "notifyEmail");
|
|
453
|
-
this.current = () => config;
|
|
454
|
-
ctx.inject(["settings"], (settingsCtx) => {
|
|
455
|
-
settingsCtx.settings.installSection(ctx, SETTINGS_NS, Config, config, {
|
|
456
|
-
setSource: (source) => {
|
|
457
|
-
this.current = source;
|
|
458
|
-
},
|
|
459
|
-
onChange: () => {}
|
|
460
|
-
});
|
|
461
|
-
});
|
|
450
|
+
this.current = () => unwrapVolatile(config);
|
|
462
451
|
const logger = ctx.logger("notify-email");
|
|
463
452
|
const audit = createJsonlAuditSink(pluginDataPath("notify-email", "audit.jsonl"), (message) => logger.warn(`audit write failed: ${message}`));
|
|
464
453
|
this.mailer = new Mailer(() => this.current(), logger, void 0, audit, credentialsOf(ctx));
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dsh-plus/notify-email",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.29",
|
|
4
4
|
"description": "dsh-plus service+ui plugin: 任务结束/等待决策/出错时向指定邮箱发送邮件通知",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "lib/index.js",
|
|
@@ -32,29 +32,29 @@
|
|
|
32
32
|
},
|
|
33
33
|
"dependencies": {
|
|
34
34
|
"nodemailer": "9.0.6",
|
|
35
|
-
"@dsh-plus/shared": "0.1.
|
|
35
|
+
"@dsh-plus/shared": "0.1.22"
|
|
36
36
|
},
|
|
37
37
|
"peerDependencies": {
|
|
38
|
-
"@deepseek-ai/cordis": "^4.0.
|
|
39
|
-
"@deepseek-ai/dsh-home-paths": "^0.1.
|
|
40
|
-
"@deepseek-ai/dsh-settings": "^0.1.
|
|
41
|
-
"@deepseek-ai/schemastery": "^3.18.
|
|
42
|
-
"@deepseek-ai/dsh-credentials": "^0.1.
|
|
38
|
+
"@deepseek-ai/cordis": "^4.0.4",
|
|
39
|
+
"@deepseek-ai/dsh-home-paths": "^0.1.7-alpha.2",
|
|
40
|
+
"@deepseek-ai/dsh-settings": "^0.1.7-alpha.2",
|
|
41
|
+
"@deepseek-ai/schemastery": "^3.18.4",
|
|
42
|
+
"@deepseek-ai/dsh-credentials": "^0.1.7-alpha.2"
|
|
43
43
|
},
|
|
44
44
|
"devDependencies": {
|
|
45
|
-
"@deepseek-ai/cordis": "4.0.
|
|
46
|
-
"@deepseek-ai/dsh-agent": "0.1.
|
|
47
|
-
"@deepseek-ai/dsh-home-paths": "0.1.
|
|
48
|
-
"@deepseek-ai/dsh-host-webserver": "0.1.
|
|
49
|
-
"@deepseek-ai/dsh-llm": "0.1.
|
|
50
|
-
"@deepseek-ai/dsh-session": "0.1.
|
|
51
|
-
"@deepseek-ai/dsh-settings": "0.1.
|
|
52
|
-
"@deepseek-ai/dsh-tools": "0.1.
|
|
53
|
-
"@deepseek-ai/schemastery": "3.18.
|
|
45
|
+
"@deepseek-ai/cordis": "4.0.4",
|
|
46
|
+
"@deepseek-ai/dsh-agent": "0.1.7-alpha.2",
|
|
47
|
+
"@deepseek-ai/dsh-home-paths": "0.1.7-alpha.2",
|
|
48
|
+
"@deepseek-ai/dsh-host-webserver": "0.1.7-alpha.2",
|
|
49
|
+
"@deepseek-ai/dsh-llm": "0.1.7-alpha.2",
|
|
50
|
+
"@deepseek-ai/dsh-session": "0.1.7-alpha.2",
|
|
51
|
+
"@deepseek-ai/dsh-settings": "0.1.7-alpha.2",
|
|
52
|
+
"@deepseek-ai/dsh-tools": "0.1.7-alpha.2",
|
|
53
|
+
"@deepseek-ai/schemastery": "3.18.4",
|
|
54
54
|
"@types/nodemailer": "8.0.1",
|
|
55
55
|
"@types/react": "~18.3.31",
|
|
56
56
|
"react": "^18.2.0",
|
|
57
|
-
"@deepseek-ai/dsh-credentials": "0.1.
|
|
57
|
+
"@deepseek-ai/dsh-credentials": "0.1.7-alpha.2"
|
|
58
58
|
},
|
|
59
59
|
"publishConfig": {
|
|
60
60
|
"access": "public"
|
package/src/client/client.ts
CHANGED
|
@@ -8,8 +8,8 @@
|
|
|
8
8
|
* 类型说明:浏览器半只用到 slots/locale/remote 的很窄一面,
|
|
9
9
|
* scope 与基础控件走 @dsh-plus/shared/client 套件(收编自本插件原实现)。
|
|
10
10
|
* 配置读写经 ctx.remote.settings 直连(0.1.2-alpha.1 起 connection.api.settings
|
|
11
|
-
*
|
|
12
|
-
*
|
|
11
|
+
* 已移除;0.1.7 起 settingsScope 服务亦删除(configForms 取代)——插件卡片自始
|
|
12
|
+
* 直连 remote.settings);自定义端点仅剩「发送测试邮件」(api.ts)。
|
|
13
13
|
* 卡片 key/rowId 约定见 @dsh-plus/shared/client/config-slots。
|
|
14
14
|
* @module @dsh-plus/notify-email/client
|
|
15
15
|
*/
|
package/src/config.ts
CHANGED
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
9
|
import z from '@deepseek-ai/schemastery'
|
|
10
|
+
import type { UnwrapVolatile } from '@dsh-plus/shared'
|
|
10
11
|
|
|
11
12
|
import { SETTINGS_NS as NS_LITERAL } from './ns.ts'
|
|
12
13
|
|
|
@@ -38,7 +39,7 @@ const TriggerSchema = z.object({
|
|
|
38
39
|
})
|
|
39
40
|
|
|
40
41
|
export const Config = z.object({
|
|
41
|
-
enabled: z.boolean().description('总开关').default(false),
|
|
42
|
+
enabled: z.boolean().description('总开关').default(false).volatile(),
|
|
42
43
|
smtp: SmtpSchema.default({
|
|
43
44
|
host: '',
|
|
44
45
|
port: 465,
|
|
@@ -46,21 +47,28 @@ export const Config = z.object({
|
|
|
46
47
|
user: '',
|
|
47
48
|
pass: '',
|
|
48
49
|
from: '',
|
|
49
|
-
}),
|
|
50
|
-
to: z.array(z.string()).description('收件邮箱列表').default([]),
|
|
50
|
+
}).volatile(),
|
|
51
|
+
to: z.array(z.string()).description('收件邮箱列表').default([]).volatile(),
|
|
51
52
|
triggers: TriggerSchema.default({
|
|
52
53
|
onComplete: true,
|
|
53
54
|
onError: true,
|
|
54
55
|
onAborted: false,
|
|
55
56
|
onQuestion: true,
|
|
56
57
|
onPlanReview: true,
|
|
57
|
-
}),
|
|
58
|
-
idleDebounceMs: z
|
|
59
|
-
|
|
60
|
-
|
|
58
|
+
}).volatile(),
|
|
59
|
+
idleDebounceMs: z
|
|
60
|
+
.natural()
|
|
61
|
+
.description('turn 结束后确认无后续工作的等待毫秒数')
|
|
62
|
+
.default(3000)
|
|
63
|
+
.volatile(),
|
|
64
|
+
maxBodyChars: z.natural().min(200).description('邮件正文内容截断长度').default(4000).volatile(),
|
|
65
|
+
dryRun: z.boolean().description('仅记录日志不真实发送(开发调试用)').default(false).volatile(),
|
|
61
66
|
})
|
|
62
67
|
|
|
63
|
-
|
|
68
|
+
/** 活动字段形态(0.1.7 loader 解析产物:volatile 字段为活动引用)。 */
|
|
69
|
+
export type NotifyEmailConfigFields = Schemastery.TypeT<typeof Config>
|
|
70
|
+
/** 平面配置形态(消费面的读取形态,由活动引用解包得到)。 */
|
|
71
|
+
export type NotifyEmailConfig = UnwrapVolatile<NotifyEmailConfigFields>
|
|
64
72
|
export type TriggerToggles = NotifyEmailConfig['triggers']
|
|
65
73
|
|
|
66
74
|
/** 是否具备发信条件(enabled 之外的最小完整性)。 */
|
package/src/index.ts
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
*/
|
|
8
8
|
import type { Context } from '@deepseek-ai/cordis'
|
|
9
9
|
|
|
10
|
-
import {
|
|
10
|
+
import type { NotifyEmailConfig, NotifyEmailConfigFields } from './config.ts'
|
|
11
11
|
import { NotifyEmailService } from './service.ts'
|
|
12
12
|
|
|
13
13
|
export const name = 'dsh-plus-notify-email'
|
|
@@ -18,16 +18,16 @@ export const name = 'dsh-plus-notify-email'
|
|
|
18
18
|
// 两处同声明互为兜底)。
|
|
19
19
|
export const inject = ['agents', 'tools', 'credentials'] as const
|
|
20
20
|
|
|
21
|
+
export { Config } from './config.ts'
|
|
21
22
|
export { NotifyEmailService } from './service.ts'
|
|
22
|
-
|
|
23
23
|
export type {
|
|
24
24
|
DecisionCall,
|
|
25
25
|
EmailNotice,
|
|
26
26
|
NotifyTrigger,
|
|
27
27
|
TurnEndInfo,
|
|
28
28
|
} from './triggers/types.ts'
|
|
29
|
-
export { Config }
|
|
30
29
|
|
|
31
|
-
|
|
30
|
+
// config 运行期为 loader 解析出的 volatile 活动字段(测试可直接传平面值)。
|
|
31
|
+
export function apply(ctx: Context, config: NotifyEmailConfig | NotifyEmailConfigFields): void {
|
|
32
32
|
ctx.plugin(NotifyEmailService, config)
|
|
33
33
|
}
|
package/src/service.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* NotifyEmailService:通知编排中枢。
|
|
3
|
-
* - 配置:
|
|
4
|
-
*
|
|
3
|
+
* - 配置:0.1.7 volatile 活动引用(loader 解析层并入用户层,GUI 写入原位提交
|
|
4
|
+
* 热生效),无 settings provider 时即 cordis 行级 config 本身;
|
|
5
5
|
* - 触发器:registerTrigger 是第三方插件的扩展接口;内置官方适配器同路径注册。
|
|
6
6
|
* - 投递:首个非空 EmailNotice 经 Mailer 发送;单个触发器抛错不影响其余。
|
|
7
7
|
* @module @dsh-plus/notify-email
|
|
@@ -9,9 +9,9 @@
|
|
|
9
9
|
import type { Context } from '@deepseek-ai/cordis'
|
|
10
10
|
import { Service } from '@deepseek-ai/cordis'
|
|
11
11
|
import type {} from '@deepseek-ai/dsh-settings'
|
|
12
|
-
import { pluginDataPath } from '@dsh-plus/shared'
|
|
12
|
+
import { pluginDataPath, unwrapVolatile } from '@dsh-plus/shared'
|
|
13
13
|
import { createJsonlAuditSink } from './audit.ts'
|
|
14
|
-
import {
|
|
14
|
+
import type { NotifyEmailConfig, NotifyEmailConfigFields } from './config.ts'
|
|
15
15
|
import { registerTestApi } from './config-api.ts'
|
|
16
16
|
import { type CredentialsSeamLike, Mailer } from './mailer.ts'
|
|
17
17
|
import { createDecisionTrigger, createTurnEndTrigger } from './triggers/builtin.ts'
|
|
@@ -42,19 +42,10 @@ export class NotifyEmailService extends Service {
|
|
|
42
42
|
private readonly mailer: Mailer
|
|
43
43
|
private current: () => NotifyEmailConfig
|
|
44
44
|
|
|
45
|
-
constructor(ctx: Context, config: NotifyEmailConfig) {
|
|
45
|
+
constructor(ctx: Context, config: NotifyEmailConfig | NotifyEmailConfigFields) {
|
|
46
46
|
super(ctx, 'notifyEmail')
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
// base 注册用户层,缺席/detach 时回落行级 config。
|
|
50
|
-
ctx.inject(['settings'], (settingsCtx) => {
|
|
51
|
-
settingsCtx.settings.installSection(ctx, SETTINGS_NS, Config, config, {
|
|
52
|
-
setSource: (source) => {
|
|
53
|
-
this.current = source
|
|
54
|
-
},
|
|
55
|
-
onChange: () => {},
|
|
56
|
-
})
|
|
57
|
-
})
|
|
47
|
+
// 0.1.7 替代 0.1.6 installSection/setSource:活动引用原位提交,现取即热。
|
|
48
|
+
this.current = () => unwrapVolatile(config)
|
|
58
49
|
const logger = ctx.logger('notify-email')
|
|
59
50
|
const audit = createJsonlAuditSink(pluginDataPath('notify-email', 'audit.jsonl'), (message) =>
|
|
60
51
|
logger.warn(`audit write failed: ${message}`),
|