@dsh-plus/notify-email 0.1.27 → 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 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.IconChevronDownOutline14, { className: `${p}-chevron${props.open ? ` ${p}-chevronOpen` : ""}` })
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
- }>, Schemastery.ObjectT<{
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[], 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
- }>, Schemastery.ObjectT<{
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
- }>, Schemastery.ObjectT<{
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
- }>, Schemastery.ObjectT<{
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[], 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
- }>, Schemastery.ObjectT<{
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
- type NotifyEmailConfig = Schemastery.TypeT<typeof Config>;
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
- //#endregion
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.27",
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.20"
35
+ "@dsh-plus/shared": "0.1.22"
36
36
  },
37
37
  "peerDependencies": {
38
- "@deepseek-ai/cordis": "^4.0.2",
39
- "@deepseek-ai/dsh-home-paths": "^0.1.6-alpha.2",
40
- "@deepseek-ai/dsh-settings": "^0.1.6-alpha.2",
41
- "@deepseek-ai/schemastery": "^3.18.2",
42
- "@deepseek-ai/dsh-credentials": "^0.1.6-alpha.2"
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.2",
46
- "@deepseek-ai/dsh-agent": "0.1.6-alpha.2",
47
- "@deepseek-ai/dsh-home-paths": "0.1.6-alpha.2",
48
- "@deepseek-ai/dsh-host-webserver": "0.1.6-alpha.2",
49
- "@deepseek-ai/dsh-llm": "0.1.6-alpha.2",
50
- "@deepseek-ai/dsh-session": "0.1.6-alpha.2",
51
- "@deepseek-ai/dsh-settings": "0.1.6-alpha.2",
52
- "@deepseek-ai/dsh-tools": "0.1.6-alpha.2",
53
- "@deepseek-ai/schemastery": "3.18.2",
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.6-alpha.2"
57
+ "@deepseek-ai/dsh-credentials": "0.1.7-alpha.2"
58
58
  },
59
59
  "publishConfig": {
60
60
  "access": "public"
@@ -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
- * 已移除;不复用 settingsScope 服务——非 loopback 页面下它固定 memory 模式无数据);
12
- * 自定义端点仅剩「发送测试邮件」(api.ts)。
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.natural().description('turn 结束后确认无后续工作的等待毫秒数').default(3000),
59
- maxBodyChars: z.natural().min(200).description('邮件正文内容截断长度').default(4000),
60
- dryRun: z.boolean().description('仅记录日志不真实发送(开发调试用)').default(false),
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
- export type NotifyEmailConfig = Schemastery.TypeT<typeof Config>
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 { Config, type NotifyEmailConfig } from './config.ts'
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
- export function apply(ctx: Context, config: NotifyEmailConfig): void {
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
- * - 配置:settings.installSection 接入 settings 用户层($DSH_HOME/settings.yaml,热生效),
4
- * 无 settings provider 时退化为 cordis 行级 config。
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 { Config, type NotifyEmailConfig, SETTINGS_NS } from './config.ts'
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
- this.current = () => config
48
- // 官方 installSection 范式(0.1.2-alpha.2):settings 在时以行级 config 为
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}`),