dsh-email 0.3.3 → 0.4.1

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/README.md CHANGED
@@ -120,7 +120,7 @@ dsh plugin --profile web add dsh-email
120
120
 
121
121
  - **授权码就是你的邮箱钥匙**。它写在本机(profile 的 `cordis.patch.yml` 或 `settings.yaml`),请勿提交到任何 Git 仓库;更推荐用环境变量 `DSH_EMAIL_PASSWORD`。
122
122
  - `email_send` 默认走 DSH 审批通道:每次发信都显示「发送邮件给 xx,主题「xx」」,你批准才发出。没有审批通道的环境(如无 UI 的 headless)会**直接拒绝发信**,这是安全默认。
123
- - 注意:会话处于 **Full Access(完全访问)** 模式时,harness 会把审批策略置为 never,`email_send` 会被**静默拒绝**(不弹框)。想发信请把访问模式切回 Read Only Write
123
+ - 会话处于 **Full Access(完全访问)** 模式时,harness 的审批策略是 never(不弹任何确认框)——`email_send` 会**被拦截并给出明确提示**。两条出路:① 把访问模式切回 Read Only / Write;② 关闭 `sendApproval`(设置页勾掉「发信前确认」),即显式声明自行承担风险。
124
124
  - 本插件不做任何联网上报,凭证只在内存中用于连接你的邮箱服务器。
125
125
 
126
126
  ## 已知限制(v0.3)
@@ -138,7 +138,7 @@ dsh plugin --profile web add dsh-email
138
138
  ```sh
139
139
  pnpm install
140
140
  pnpm run build # tsc → lib/
141
- pnpm test # 构建 + node --test(配置/解析/注册与审批门,34 个用例,无需真实邮箱)
141
+ pnpm test # 构建 + node --test(配置/解析/注册与审批门,38 个用例,无需真实邮箱)
142
142
  ```
143
143
 
144
144
  ## 协议
package/lib/index.js CHANGED
@@ -278,7 +278,7 @@ export function apply(ctx, config = {}) {
278
278
  });
279
279
  ctx.tools.register({
280
280
  name: 'email_send',
281
- description: 'Send an email from a configured account, optionally with file attachments (absolute paths, or relative to the dsh process cwd). Sending first asks the user for approval (recipient, subject and attachment count are shown) unless sendApproval is disabled; never invent recipients or content without the user\'s instruction.',
281
+ description: 'Send an email from a configured account, optionally with file attachments (absolute paths, or relative to the dsh process cwd). Sending asks the user for approval (recipient, subject and attachment count are shown) unless sendApproval is disabled; in Full Access mode the approval policy never asks, so the send is refused with an explanation instead. Never invent recipients or content without the user\'s instruction.',
282
282
  parameters: compileParameters({
283
283
  to: { type: 'string', required: true, description: 'Recipient(s), comma-separated' },
284
284
  subject: { type: 'string', required: true, description: 'Email subject' },
@@ -358,7 +358,34 @@ export function apply(ctx, config = {}) {
358
358
  const args = (exec.args ?? {});
359
359
  const attachCount = Array.isArray(args.attachments) ? args.attachments.length : 0;
360
360
  const reason = '发送邮件给 ' + args.to + ',主题「' + args.subject + '」' + (attachCount > 0 ? ',附件 ' + attachCount + ' 个' : '');
361
- return { kind: 'ask', reason };
361
+ // Gate-owned approval: we run the approval round-trip ourselves so the
362
+ // denial reason is always honest and actionable — including the Full
363
+ // Access case where the harness policy answers 'rejected' without ever
364
+ // showing a dialog.
365
+ const approval = ctx.get('approval');
366
+ if (approval === undefined) {
367
+ return {
368
+ kind: 'deny',
369
+ reason: 'email_send 需要确认,但当前环境没有审批通道(如 headless)。如确定安全,可在配置中设置 sendApproval: false 后直接发送。',
370
+ };
371
+ }
372
+ const outcome = await approval.request({
373
+ agent: exec.agent,
374
+ toolName: exec.name,
375
+ callId: exec.callId,
376
+ reason,
377
+ signal: exec.signal,
378
+ });
379
+ if (outcome === 'allowed-once')
380
+ return next();
381
+ if (outcome === 'cancelled')
382
+ return { kind: 'deny', reason: '发信确认被取消,邮件未发送。' };
383
+ if (outcome === 'unavailable')
384
+ return { kind: 'deny', reason: '发信确认不可用(没有可用的审批界面),邮件未发送。' };
385
+ return {
386
+ kind: 'deny',
387
+ reason: '发信未获批准:要么你拒绝了,要么当前会话处于 Full Access(审批策略 never,不会弹框)。若在 Full Access:切到 Read Only / Write 再发,或关闭 sendApproval(自行承担风险)。',
388
+ };
362
389
  }, { prepend: true });
363
390
  }
364
391
  export { PROVIDER_NAMES, EMAIL_PASSWORD_ENV } from './config.js';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-email",
3
- "version": "0.3.3",
3
+ "version": "0.4.1",
4
4
  "description": "IMAP/SMTP email tools for DeepSeek Harness: list, read, search and send mail, with QQ/163/126/Sina/Aliyun/Gmail/Outlook/iCloud presets.",
5
5
  "type": "module",
6
6
  "main": "lib/index.js",