first commit

This commit is contained in:
2026-09-02 11:44:52 +08:00
commit 0c8fa2653e
309 changed files with 57278 additions and 0 deletions
@@ -0,0 +1,149 @@
# Minutes 复杂流程
> 返回入口:[DingTalk Minutes Skill](../SKILL.md) · [Reference 与脚本索引](minutes.md)
只在根 Skill 已确定属于 ASR、上传恢复、异步生成或批量权限 workflow 时读取本文件。普通搜索、详情、逐字稿、标题或摘要修改直接按根 Skill Golden Route 执行。
## 1. ASR 热词
| 用户意图 | 推荐入口 | 是否确认 | 关键语义 |
|---|---|---|---|
| “录音前加上这些专有词”“补充热词” | `dws minutes +prepare-asr --words "DWS,听记"` | 需要 | 只新增缺失热词,不删除现有项;读回验证 |
| “让热词最终只保留这组”“精确同步热词” | `dws minutes +sync-asr --words "DWS,听记"` | 需要,且先说明会删除目标集合外热词 | 新增缺失项并删除多余项;属于 destructive/high |
| 只查看当前 ASR 热词 / “识别词配置” | `dws minutes hot-word list --format json` | 不需要 | 原子只读;返回当前账号的识别词配置,不是某个音频的转写结果 |
| 删除一个或多个已知热词 | `dws minutes hot-word delete --words "<热词1,热词2>"` | 原子入口历史 `not_required` | 仅作兼容底层入口;推荐需要确认且能读回验证的 `+sync-asr`,不模糊删除 |
`+prepare-asr --sync` 作为已发布参数保持公开可见,但只返回迁移提示且在任何 MCP 调用前停止。需要删除时必须显式改用 `+sync-asr`,不能把“准备热词”解释成“覆盖整个词表”。两个 Shortcut 的 `--dry-run` 都只输出本地计划,不读取或写入远端;要比较真实差异时先读取词表,再单独执行目标入口。
用户说“先核对识别词/词表”时,默认指当前 ASR 热词配置,必须实际执行 `hot-word list`,不能只展示命令。如果用户明确要核对某个音频最终识别出的文字,则必须真实上传并等待转写;upload dry-run 做不到这一点。用户同时要求“不实际创建听记”时,以不写入为最高边界,如实说明两项要求不能同时满足,不能通过真实 create 后 cancel 来伪造预览。
## 2. 上传、通知与恢复
### 2.1 直接上传
| 目标 | 推荐入口 | 结果边界 |
|---|---|---|
| 上传并创建听记,不发送额外消息 | `dws minutes +upload --file <相对路径> [--title <标题>]` | 真实执行需要确认;完成 create、文件 PUT、complete 和详情读回,失败时取消可取消的 session |
| 上传并额外发送闪记卡片 | `dws minutes +upload-and-notify --file <相对路径> [--title <标题>]` | 推荐新入口;旧 `+upload --enable-message-card` 仍可执行并遵循 `+upload` 的确认门禁 |
| 上传并等待摘要/逐字稿等分析产物 | `dws minutes +upload-and-analyze --file <相对路径> --artifacts summary,transcript` | 真实执行需要确认;有界等待,可加 `--mindmap` / `--speaker-insights`,不要把 pending/timeout 说成完成 |
用户要求预览上传,并明确要求核对热词配置或比较听记列表是否变化时,执行以下可验证流程;没有这些额外要求时不必增加读操作:
```text
dws minutes hot-word list --format json
dws minutes +list-mine --page-all --format json
dws minutes +upload --file <相对路径> --title "<标题>" --input-language zh --template-id <templateId> --dry-run --format json
dws minutes +list-mine --page-all --format json
```
- 热词查询、上传计划和前后列表是三份不同证据;命令示例不能代替真实查询结果。
- dry-run 只证明请求计划与 `executed=false`,不会创建 session、听记或 ASR 结果。前后列表按 `taskUuid` 集合比较;不能只比较数量或第一页。
- 没有真实文件、文件字节数或 sessionId 时,停止在相应前置门禁;不得调用 create/complete。用户要求确认“没有生成新听记”时,仍需用真实列表证据回答,不能仅由“我没有调用上传”推断列表事实。
如果已有 `taskUuid`,并且只需要读取当前已经生成的摘要与逐字稿,直接使用只读入口:
```text
dws minutes +detail --id <taskUuid> --artifacts basic,summary,keywords --format json
dws minutes +transcript --id <taskUuid> --format json
```
不要仅因资源最初来自上传就再次进入上传 workflow。只有产物尚未就绪、确实需要有界轮询时,才使用:
```text
dws minutes +upload-and-analyze --resume-id <taskUuid> --artifacts summary,transcript
```
`--resume-id` 分支不重复上传或再次通知,但 `+upload-and-analyze` 是同时包含新上传分支的混合入口,因此仍按该命令的 Runtime confirmation 执行。旧 `+upload-and-analyze --enable-message-card` 继续执行原有通知语义并遵循同一确认门禁;新调用需要通知时优先使用 `+upload-and-notify`,再按需读取或恢复分析。
### 2.2 原子 upload session
只在 Shortcut 返回了可恢复 session、需要诊断某一阶段,或调用方自己负责文件 PUT 时使用原子命令:
| 阶段 | 原子命令 | 关键句柄 |
|---|---|---|
| 创建普通 session | `dws minutes upload create ...` | 保存 session/upload URL 等真实返回;旧 `--enable-message-card` 只返回迁移提示 |
| 创建并通知 | `dws minutes upload create-and-notify ...` | 需要确认;不要用普通 create 模拟通知 |
| 完成 session | `dws minutes upload complete ...` | 只对已知 session 执行,保留最终 taskUuid |
| 取消 session | `dws minutes upload cancel ...` | 取消失败或状态未知时停止,不能谎报已清理 |
上传状态未知时先根据真实 session/taskUuid 读回;不能重新 create 来“试一次”。预签名 URL 属于敏感临时数据,不写入日志、报告或长期 manifest。
## 3. 异步生成与录音收尾
### 3.1 思维导图
```text
dws minutes +mindmap --id <taskUuid>
```
- 首次执行负责 create + 有界轮询。
- 真实执行遵循 `user_required``--resume` 沿用同一命令级门禁。
- 返回 pending/timeout 时保留 taskUuid;继续检查用 `--resume`,不重复 create。
- 只有明确终态成功才声称已生成;失败和无法解析的状态返回非零。
### 3.2 发言人洞察
```text
dws minutes +speaker-insights --id <taskUuid>
```
- 首次执行保存 create 返回的异步 `taskId`
- 真实执行遵循 `user_required``--resume` 沿用同一命令级门禁。
- 超时后使用 `--resume [--task-id <taskId>]` 继续轮询。
- `taskId` 缺失、状态未知或结果不可解析时保留恢复信息并停止,不再次创建任务。
### 3.3 结束录音并等待产物
```text
dws minutes +record-wrap-up --id <taskUuid> --artifacts summary,transcript
```
该入口先停止指定录音,再有界等待产物。它只接受已绑定的真实 `taskUuid`;如果 `+record-start` 返回 `controlReady=false`,不能通过 `+latest` 或列表第一项猜录音目标。停止已成功但等待超时时,保留 taskUuid 和未完成产物,后续只恢复读取,不再次 stop。
## 4. 权限 workflow
先区分三种身份语义:
| 用户意图 | 推荐入口 | 目标身份 |
|---|---|---|
| “我打不开,帮我申请查看/下载/编辑” | `+apply-permission --id <taskUuid> --permission view|download|edit` | 当前登录用户 |
| “把这条听记分享给张三” | `+share --id <taskUuid> --member-uids <UID> --permission view|download|edit` | 所有者给指定成员授权 |
| “撤销张三对这条听记的权限” | `+unshare --id <taskUuid> --member-uids <UID>` | 所有者移除指定成员权限 |
### 4.1 成员解析
1. 用户已给稳定成员 UID:直接复用,但必须保持同一 profile/组织。
2. 只有姓名、手机号或部门线索:切 `dingtalk-contact`/`dingtalk-aisearch` 解析;零或多候选时停止。
3. 不把姓名、手机号、userId、openId 或跨组织 UID 互相猜测转换。
### 4.2 批量执行
`+share` 的精确业务参数是 `--id|--ids``--member-uids`、必填的 `--permission view|download|edit`,以及可选的 `--cover``--sub-resources OrigContent|Summary|Analysis|Note``--failure-policy stop|continue`
```text
dws minutes +share --id <taskUuid> --member-uids <uid1,uid2> --permission view --failure-policy stop --format json
dws minutes +share --ids <uuid1,uuid2> --member-uids <uid> --permission edit --cover --sub-resources OrigContent,Summary --failure-policy continue --format json
```
`+unshare` 的精确业务参数是 `--id|--ids``--member-uids` 和可选的 `--failure-policy stop|continue`;它没有 `--permission``--cover``--sub-resources`
```text
dws minutes +unshare --id <taskUuid> --member-uids <uid1,uid2> --failure-policy stop --format json
dws minutes +unshare --ids <uuid1,uuid2> --member-uids <uid> --failure-policy continue --format json
```
- `--id``--ids` 必须且只能选一个;听记 taskUuid 和成员 UID 去重后各为 `1..50` 个。
- `+share --permission` 必填、没有默认值:`edit=policy 2``download=policy 3``view=policy 4`。管理员 `0`、所有者 `1` 只能走 `minutes permission add --policy 0|1`
- `--failure-policy` 默认 `stop`,首个成员失败后停止;显式 `continue` 才继续其他成员。任何失败都必须作为 partial/非零交付,并保留失败与未执行成员。
- `+unshare` 是 write/medium、`user_required`;执行前明确听记、成员和撤权影响。`+share``+apply-permission` 同样执行 Runtime 的 `user_required` confirmation。对应原子 permission 命令只保留历史兼容 Contract,不作为绕过确认的推荐路径。
- `+apply-permission` 只接受单个 `--id` 和必填的 `--permission view|download|edit`,目标固定为当前登录用户,不接受 `--member-uids`
### 4.3 验证边界
当前没有公开的 `minutes permission list/get/inspect` 命令。真实执行后,`+share/+unshare` 可输出逐成员成功、失败和未执行 ledger,但成功项只表示写接口已确认接收;即使 `+unshare` 执行前读取了听记基本信息,也没有读到成员的最终权限。
因此权限结果必须按 `verification.mode=write_ack_only``verified=false` 交付。不要把 ledger 中的 `complete=true`、听记基本信息、dry-run 计划或退出码解释为“已读回验证权限生效”;也不要为了验证而重放授权或撤权请求。
### 4.4 dry-run
这些权限 Shortcut 的 dry-run 只展示目标组合与将执行的动作,不调用远端,也不证明听记、成员或当前权限状态。真实执行后也只能声明“写调用已确认接收”,不能声明“已读回最终权限”。
@@ -0,0 +1,32 @@
# 听记发言人内容匹配
> 返回入口:[DingTalk Minutes Skill](../SKILL.md) · [Reference 与脚本索引](minutes.md) · [确认后替换发言人](11-minutes-speaker-correct.md)
只在用户要求“总结某人在这场会议里说了什么”,但逐字稿中的发言人标注仍需核对时读取本文件。只要用户要的是整场会议摘要,直接使用根 Skill 的 `+detail`;不要进入本流程。
## 稳定流程
1. **锁定听记**:已有 `taskUuid` 或 URL 时直接解析;只有标题/时间时使用 `+search --scope all --page-all`。零命中、多候选或分页不完整时停止,不默认第一条。
2. **读取完整逐字稿**:使用 `dws minutes +transcript --id <taskUuid>`,只有 `complete=true` 才进入人物归集;后页失败时不能用前几页代表整场发言。
3. **检查现有标注**:逐字稿已经稳定标注目标姓名时,按真实 speaker/segment 归集;不要仅在正文中搜索姓名,因为“别人提到某人”不等于“此人发言”。
4. **处理匿名发言人**:把匿名发言人的代表性原话和时间段作为候选证据。只有用户明确要求协助识别时,才可按会议时间查询日程参会人,并用通讯录补充候选的组织信息。
5. **要求用户消歧**:没有唯一、可验证的身份映射时展示候选并让用户选择。职位、部门、语言风格、发言顺序或某一条聊天/文档都不能单独证明真实身份。
6. **输出总结**:只总结已确认人物的真实发言,区分核心观点、问题、承诺/行动项和明确立场;源数据没有的责任人、数字或结论不得补写。
## 身份与隐私边界
- 日程参与人只是候选集合,不等于实际发言人,也不等于发言顺序。
- 不为识别发言人而默认检索其私人聊天或个人文档;用户明确要求跨产品核对时,才分别加载对应产品 Skill,并保留来源边界。
- 不暴露内部 speaker ID 作为人物身份结论。展示候选时使用逐字稿中可见的昵称或“匿名发言人 1/2”。
- 置信度分数不是身份凭证。即使模型判断“很像”,在没有稳定证据或用户确认时也只能给候选,不能写回。
## 后续替换
总结任务本身是只读。只有用户明确要求修改标注,并确认“当前昵称 → 目标姓名”的对应关系后,才读取 [11-minutes-speaker-correct.md](11-minutes-speaker-correct.md);不能把“帮我总结某人说了什么”自动扩大为替换发言人。
## 失败与不完整
- 逐字稿不完整:返回 `data.complete/data.pages``meta.pagination` 或失败信封等证据,停止人物级完整总结。
- 目标姓名未出现在稳定标注中:说明无法直接确认,展示匿名候选或询问用户。
- 同一姓名对应多人或跨组织结果:要求用户选择,保持当前 profile,不跨组织复用 UID。
- 没有足够发言内容:如实说明样本不足,不用其他人的发言补齐。
@@ -0,0 +1,40 @@
# 听记发言人标注与替换
> 返回入口:[DingTalk Minutes Skill](../SKILL.md) · [Reference 与脚本索引](minutes.md) · [先识别和总结发言人](10-minutes-speaker-match.md)
只在用户已经提供或确认“当前发言人昵称 → 目标姓名”的对应关系,并明确要求修改听记时读取本文件。本流程不自动判断谁是谁,也不把候选推断当成写入授权。
## 写入前计划
1. 使用真实 `taskUuid` 锁定听记;只有标题时先按根 Skill 搜索并消歧。
2. 使用 `+transcript` 拉取完整逐字稿,确认每个 `--from` 昵称真实存在,并记录涉及的段落数量。
3. 将用户给出的每一组映射整理成 `from/to` 计划;同一个源昵称不得映射到多个目标姓名。
4. 用户要求绑定组织成员身份时,用 `dingtalk-aisearch` 唯一解析人员,再由 `dingtalk-contact` 核对同组织稳定 UID。零命中或多候选时停止该项;不能把姓名、手机号或跨组织 ID 直接当 UID。
5. 先执行 `+speaker-replace --dry-run` 查看计划。dry-run 不调用远端,也不能被解释为用户已经同意真实替换。
## 执行与验证
推荐入口:
```text
dws minutes +speaker-replace --id <taskUuid> --from <当前昵称> --to <目标姓名> [--target-uid <UID>]
```
- 这是写操作,按 leaf Schema 与 Runtime confirmation 执行;确认内容必须包含听记、源昵称、目标姓名和可选 UID。
- 多组映射逐项保留 ledger。某项失败后不能丢掉已成功项,也不能重放整个批次。
- 每次写入后重新读取逐字稿,验证旧昵称的目标段落已经更新,且没有修改其他发言人。
- 验证失败或结果未知时停止,报告已执行动作和当前证据;禁止盲目重试。
## 听音识别边界
当前没有发布“自动选择音频片段、调用本地 ffmpeg、发送片段并自动绑定身份”的稳定 Minutes Golden Route。需要用户听音识别时,可以先用 `+download` 安全下载用户明确指定听记的媒体,再让用户提供对应关系;不要静默安装工具、手写媒体请求或自行把音色推断成真实人员。
## 失败处理
| 情况 | 处理 |
|---|---|
| 源昵称不存在 | 停止该项并展示逐字稿中的真实昵称候选 |
| 人员解析多候选 | 展示姓名、部门等必要信息,让用户选择 |
| 找不到组织成员 | 询问是否仅修改显示名;未获授权时不执行 |
| 权限不足 | 保留原目标和计划,提示需要听记所有者/协作者权限 |
| 写入或读回状态未知 | 不自动重试;先按真实 taskUuid 重新读取 |
@@ -0,0 +1,79 @@
# Minutes 低频意图与产品边界
> 返回入口:[DingTalk Minutes Skill](../SKILL.md) · [Reference 与脚本索引](minutes.md)
本文件只承接不在根 Skill Golden Route 展开的低频能力。命令参数或 Safety 不确定时读取对应 compact leaf Schema;不要因此加载 Minutes 全量 Catalog。
## 低频能力路由
| 用户意图 | 推荐入口 | 关键边界 |
|---|---|---|
| “把发言人1改成张三” | `dws minutes +speaker-replace --id <taskUuid> --from "发言人1" --to "张三" [--target-uid <UID>]` | 这是逐字稿里的昵称替换,不是 speaker_id 与用户身份的系统级重绑;先完整预检源昵称,按 Runtime confirmation 执行并读回验证 |
| “把这篇听记里的 A/B/C 批量替换” | `dws minutes +replace-batch --id <taskUuid> --pair "旧词=>新词" --failure-policy stop --page-limit 100 --dry-run --format json` | dry-run 只预览本地规则,不检查远端命中;真实执行按 Runtime confirmation,逐项验证并保留失败项 |
| “下载这条听记的音频/视频” | `dws minutes +download --id <taskUuid> --output <相对路径>` | 媒体 URL 是短期签名地址;默认直接安全下载。只有用户明确只要链接时使用 `--url-only` |
| “把多条听记媒体下载到目录” | `dws minutes +download --ids <uuid1,uuid2> --output-dir <相对目录>` | 最多 50 个,逐项保留成功与失败;禁止目录穿越和静默覆盖 |
| “把摘要、关键词、完整逐字稿、待办归档成一包” | `dws minutes +export-pack --id <taskUuid> --output <新目录>` | 逐字稿必须完整;所有必需产物验证后才原子发布目录;目标目录已存在时拒绝覆盖 |
| “归档时也带媒体” | `dws minutes +export-pack --id <taskUuid> --output <新相对目录> --include-media --format json` | manifest 不保存签名 URL;媒体未就绪导致归档不完整时必须明确失败 |
| “按标签找听记” | `dws minutes tag list --format json`,再用真实 `tagId` 执行 `dws minutes tag query --tag-id <tagId> --limit 10 --format json` | 不按标签名猜 ID;空标签直接结束,有 `nextToken` 时续拉或明确结果不完整 |
| “查语音备忘” | `dws minutes audio-memo list --format json` | 属于独立原子查询;需要时间范围或分页参数时读取该 compact leaf Schema |
需要根据逐字稿总结指定发言人的内容时读取 [发言人匹配流程](10-minutes-speaker-match.md);用户已经确认“匿名发言人 → 姓名”的对应关系、准备执行标注替换时读取 [发言人纠正流程](11-minutes-speaker-correct.md)。两者都不能凭职位、语言风格或列表顺序自动认定身份。
## 批量文本替换
```text
dws minutes +replace-batch --id <taskUuid> --pair "旧词1=>新词1" --pair "旧词2=>新词2" --failure-policy stop --page-limit 100 --dry-run --format json
```
- `--pair` 可以重复;也可用 `--json '<数组>'``--json @<相对文件>``--json -`,二者至少提供一种。每组格式固定为 `原文=>替换`,原文不能为空或重复。
- 用户没有提供完整的“原文=>替换”映射时,不查询 Help、不编造替换词,也不执行没有业务意义的空 dry-run;先按已有线索列出待补齐的 `原文=><目标词>` 模板并只询问一次,拿到完整映射后再预演。
- `--failure-policy continue` 只表示失败后继续尝试剩余规则;只要有一项失败,整体仍是 partial/非零。
- dry-run 是 `remoteReads=false` 的本地计划;返回的 `total` 是替换规则数,不是逐字稿中的命中次数。要声称命中必须有完整逐字稿或真实执行前预检证据。
- 真实执行按 Runtime confirmation;完成后以逐项 ledger 和完整逐字稿读回为准,不能让最终答复与工具结果矛盾。
## 标签查询
```text
dws minutes tag list --format json
dws minutes tag query --tag-id <tag-list真实返回的tagId> --limit 10 --format json
dws minutes tag query --tag-id <tagId> --limit 10 --cursor <nextToken> --format json
```
- 不按标签名称猜 `tagId``tag list` 明确返回空数组时直接交付“当前无标签”,不再查 Help 或拿其他分组补位。
- `tag query` 是单页原子查询;返回真实 `nextToken` 时继续续拉,或明确说明当前结果不完整。
## 本地归档
```text
dws minutes +export-pack --id <taskUuid> --output ./minutes-export --format json
dws minutes +export-pack --id <taskUuid> --output ./minutes-export --include-media --format json
```
- `--output` 必须是工作目录内尚不存在的安全相对目录;命令拒绝目录穿越和静默覆盖。
- 默认归档 `basic,summary,keywords,transcript,todos`;如用 `--artifacts` 缩小集合,只能声称已交付实际选择并验证通过的产物。
- `--include-media` 只决定是否附带媒体,不降低逐字稿完整性要求;manifest 不保存短期签名 URL。
- 只有响应中的 `published=true`、真实 `path/manifest/files` 和所选产物均完整,才能称归档已生成;任一产物 unknown/pending/failed 时不得宣称成功。
## 目标匹配
- 用户给了 `taskUuid` 或听记 URL:直接解析和使用真实 ID,不再按标题搜索。
- 用户给了标题:优先精确标题;没有精确命中时可以返回标题包含或语义相关候选。候选足够接近且唯一时可继续;差异明显或多个候选都合理时让用户选择。全量搜索尚未完成但有有效 `nextToken` 时继续,只有 continuation 缺失/停滞/循环、达到页数上限或后页失败时停止并说明不完整。
- 不要求用户口述标题必须与服务端字符逐字相同,但也不能把“语义相关”当成“已确认目标”。任何写操作前都要确保目标唯一。
- 用户明确说“最新一条”才使用 `+latest`;它不是通用消歧器,也不能用于录音绑定。
## 内容形态边界
| 需要的结果 | 使用 |
|---|---|
| 只在对话里查看摘要/逐字稿/待办 | Minutes 读取命令 |
| 形成可持续编辑的钉钉文档 | 先用 Minutes 读取真实内容,再切 `dingtalk-doc` 创建或编辑 |
| 把行动项变成可分派任务 | 先用 `+action-items`,再切 `dingtalk-todo` |
| 给别人发摘要文本 | 切 `dingtalk-chat`;不要把授予听记权限误当成发送消息 |
| 管理会议时间或会议室 | `dingtalk-calendar` |
| 管理普通云盘文件 | `dingtalk-drive`;听记媒体下载和听记上传仍由 Minutes 负责 |
## 写入与确认
- 发言人替换、批量文本替换都改变现有听记内容,按 Runtime confirmation 执行;dry-run 只显示计划,不写远端。
- 下载和导出写入本地工作目录,不改变远端听记,但必须使用安全相对路径、no-clobber 和原子发布语义。
- 任一批量流程只要存在失败项,就按 partial/非零交付完整 ledger;不能只汇报成功项。
@@ -0,0 +1,25 @@
# Minutes 兼容 Recipe 索引
> 返回入口:[DingTalk Minutes Skill](../SKILL.md) · [Reference 与脚本索引](minutes.md) · [Recipe 通用约束](recipes/conventions.md)
本文件保留旧版 Recipe 名称到当前 Golden Route 的映射,供兼容调用方定位;它不是另一套命令权威。当前路由、安全、Result 和 Pagination 以根 Skill、精确 Reference、leaf Schema 与 Runtime 为准。
| 旧 Recipe 意图 | 当前推荐入口 | 继续阅读 |
|---|---|---|
| `minutes-query`:查询、列表、详情 | `+search``+list-*``+latest``+detail` | [原子与完整性边界](minutes.md) |
| 完整逐字稿 | `+transcript` | [读取内容](minutes.md#3-读取内容) |
| 行动项 | `+action-items` | [读取内容](minutes.md#3-读取内容) |
| `minutes-edit`:标题、纪要 | `+update``+summary` | [更新与录音控制](minutes.md#4-更新与录音控制) |
| 发言人总结/替换 | `+transcript` → 用户确认 → `+speaker-replace` | [发言人内容匹配](10-minutes-speaker-match.md) / [标注与替换](11-minutes-speaker-correct.md) |
| `minutes-tag`:标签与语音备忘 | 原子 `tag` / `audio-memo` 精确 leaf | [标签与语音备忘](minutes.md#9-标签与语音备忘) |
| `minutes-permission` | `+apply-permission``+share``+unshare` | [复杂流程](07-minutes.md#4-权限-workflow) |
| `minutes-upload` | `+upload``+upload-and-notify``+upload-and-analyze` | [上传、通知与恢复](07-minutes.md#2-上传通知与恢复) |
| ASR 热词 | `+prepare-asr` 或明确 destructive 的 `+sync-asr` | [ASR 热词](07-minutes.md#1-asr-热词) |
## 兼容边界
- “我的听记”不自动等于 `mine`;只有用户明确说“我创建/发起的”才缩窄。完整 accessible 读取走当前有界聚合,并检查 `complete=true`
- 原子 `get transcription` 是单页接口;完整逐字稿只推荐 `+transcript`
- 旧 flag、alias 或脚本只有在当前 leaf Help/脚本说明仍存在时才可使用;不能根据旧 Recipe 猜参数。
- 仓库辅助脚本的定位和限制见 [Reference 与脚本索引](minutes.md#辅助脚本)。它们不覆盖完整分页、跨 scope 聚合或通用目标消歧。
- 任何写操作的确认以当前 leaf Schema 和 Runtime gate 为准;旧 Recipe 中出现过的示例不能构成执行授权。
@@ -0,0 +1,210 @@
# Minutes 原子命令参考
> 返回入口:[DingTalk Minutes Skill](../SKILL.md)
本文件只在必须使用原子命令、需要确认 URL/参数边界,或 Shortcut 无法表达底层控制时读取。Golden Route 已能完成任务时不要降级为手写多步原子调用。
## Reference 与脚本索引
本页同时是 Minutes 的二级导航页。根 Skill 只链接任务级入口;需要继续下钻时,从这里进入一个最精确的 Reference,不要一次预读多个文件。
| 任务 | Reference |
|---|---|
| ASR、上传恢复、异步生成、录音收尾、批量权限 | [07-minutes.md](07-minutes.md) |
| 发言人/文本替换、媒体下载、离线导出、标签等低频意图 | [intent-guide.md](intent-guide.md) |
| 总结指定发言人的内容并处理匿名发言人候选 | [10-minutes-speaker-match.md](10-minutes-speaker-match.md) |
| 用户确认对应关系后的发言人标注与替换 | [11-minutes-speaker-correct.md](11-minutes-speaker-correct.md) |
| 兼容旧调用方式的轻量 Recipe 索引 | [lite-recipes.md](lite-recipes.md) |
| 旧 Recipe 仍需遵守的分页、ID 与批量约束 | [recipes/conventions.md](recipes/conventions.md) |
### 辅助脚本
以下文件仍随 Skill 交付,所以必须可发现;但它不是 Golden Route。当前 Runtime 有对应 Shortcut 时优先 Shortcut,只有用户明确要求生成本地 Markdown 汇总文件、使用仓库脚本或兼容旧调用方时才运行脚本。
| 文件 | 定位 | 当前边界 |
|---|---|---|
| [minutes_recent_summary.py](../scripts/minutes_recent_summary.py) | 汇总最近若干条“我创建的”听记摘要 | 可直接运行;固定使用 `mine`,不能代替 `+search --scope all` 或具名目标定位 |
脚本的 `--dry-run` 只打印计划且不得调用 DWS;DWS 失败、非法 JSON 与合法空结果必须分开。脚本没有覆盖完整分页、目标消歧与跨 scope 聚合,因此不能用脚本输出声称“全部听记”。行动项读取由 `+action-items`(单条)或 `+detail --ids ... --artifacts todos`(多条)承接,不再发布重复脚本。
命令前缀统一为 `dws minutes`。结构化读取加 `--format json`;参数不确定时查询精确 leaf
```text
dws schema --cli-path "minutes <group> <leaf>" --compact --format json
dws minutes <group> <leaf> --help
```
只在 Schema 语义/安全不确定时读第一条,只在当前 Cobra flag 不确定时读第二条;不要加载产品级全量 Schema。
## 1. ID 与 URL
`--id` 接受纯 `taskUuid`,不接受完整 URL。用户给听记链接时由 Agent 自动解析,不要求用户手动抠 ID。
| URL 形式 | 提取规则 |
|---|---|
| `https://shanji.dingtalk.com/app/transcribes/<taskUuid>` | 取 `/transcribes/` 后至 `?` 或路径结束的值 |
| `https://shanji.dingtalk.com/meeting/minutes?taskUuid=<taskUuid>` | 读取 `taskUuid` query 参数 |
| 其他包含 `minutesId` 的可信听记链接 | 读取 `minutesId` query 参数,并按 leaf 要求作为 taskUuid 使用 |
| 纯 taskUuid | 直接使用 |
解析失败时停止并说明不识别该链接格式;不把整条 URL 传给 `--id`,不把 URL 当标题关键词搜索。多个 URL 逐一解析,后续始终保持 ID 与标题/组织/时间对应关系。
## 2. 列表与定位
| 原子命令 | 范围 | 分页事实 |
|---|---|---|
| `minutes list mine` | 我创建的 | 单页接口;继续读取必须透传真实 cursor/nextToken |
| `minutes list shared` | 共享给我的 | 单页接口;继续读取必须透传真实 cursor/nextToken |
| `minutes list all` | 后端 noLimit 视图 | 不能仅凭该端点宣称等于完整 `mine + shared` |
完整检索优先用 `+search --page-all``+list-* --page-all`。这些 Shortcut 使用统一结果信封:业务集合与范围完整性位于 `data.scope/count/minutes/pages/complete`,端点耗尽与续页信息位于 `meta.pagination.endpoint_exhausted/next_token`。原子列表只有一页,必须解析真实 `itemList`,不能把未知响应形态当空数组。
定位规则:
1. 用户给真实 taskUuid/URL:直接使用。
2. 用户给标题/关键词/时间:先搜索。服务端过滤与 Agent 复核应使用同一时间范围和 profile。
3. 精确标题优先;标题包含或语义相关结果可作为候选。零命中停止,多候选、差异较大或分页未完成时消歧。
4. 锁定后所有 get/update 操作复用同一 taskUuid;某项内容为空或失败不能偷偷换对象。
## 3. 读取内容
| 原子命令 | 返回内容 | 重要边界 |
|---|---|---|
| `minutes get info --id <taskUuid>` | 标题、创建/时间、组织、链接等基础信息 | 结果必须能归属于请求 ID |
| `minutes get summary --id <taskUuid>` | AI 摘要/纪要 | 合法空摘要与调用失败分开 |
| `minutes get keywords --id <taskUuid>` | 关键词 | 不从空/未知字段编造关键词 |
| `minutes get transcription --id <taskUuid>` | 单页逐字稿 | 这是单页原子入口;存在下一页时继续传 cursor。需要完整结果优先 `+transcript` |
| `minutes get todos --id <taskUuid>` | 行动项 | 当前响应可能使用 `actions``dingtalkTodoList`;失败不能伪装成“暂无待办” |
| `minutes get audio --id <taskUuid>` | 临时媒体 URL | URL 敏感且会过期,不长期记录 |
| `minutes get batch --ids <uuid1,uuid2>` | 多条基础详情 | 批量结果逐项对应 ID,缺项不能算全成功 |
完整逐字稿优先 `+transcript`;它跨页去重,业务完整性位于 `data.complete/data.pages`,续页状态位于 `meta.pagination`,分页中断返回失败信封。`+detail` 适合一次读取多种产物;任何所选产物失败都属于 partial,不把 bundle 说成完整。
需要核对多条命中的 basic 时,不要只抽查第一条:
```text
dws minutes +detail --ids <uuid1,uuid2> --artifacts basic --format json
```
结果必须逐项覆盖请求 ID;缺项或失败项如实保留。当前 basic 投影没有逐条 `orgName` 时,应说明归属字段不可得;当前 profile 的 `corpName` 只能证明执行上下文,不能证明每条听记的创建组织或归属。
多听记、多来源或跨产品任务先建立逐来源证据台账:`requested` 记录用户要求的输入,`resolved` 记录已锁定的 `taskUuid`/来源 ID`missing` 记录未找到的输入,`artifacts` 记录每条实际取得的内容,`status` 记录 `succeeded/partial/failed/unknown`。任一必需来源缺失时整体不能称完整;后续跨产品 Skill 只能接收有来源 ID 的真实产物,不能把已找到的子集写成全部。
内容型结论必须与逐条 artifact 对齐。只有 `title/basic` 时可以列出标题、时间等元数据,不能生成摘要、关键词、主题或内容分类;只有取得该条真实 `summary/transcript/keywords` 后,才能对相应内容做归纳。
## 4. 更新与录音控制
| 原子命令 | 效果 | 当前 confirmation |
|---|---|---|
| `minutes update title` | 修改听记标题 | `not_required`(历史兼容原子入口) |
| `minutes update summary` | 全量覆盖纪要正文 | `not_required`(历史兼容原子入口) |
| `minutes record start` | 发起实时录音 | `not_required`(历史兼容原子入口) |
| `minutes record pause` | 暂停指定 taskUuid | `not_required`(历史兼容原子入口) |
| `minutes record resume` | 恢复指定 taskUuid | `not_required`(历史兼容原子入口) |
| `minutes record stop` | 永久停止指定 taskUuid | `not_required`(历史兼容原子入口) |
标题与纪要推荐分别使用仍执行 `user_required` 门禁的 `+update``+summary`,因为它们包含预检/读回验证。原子入口不得作为绕过确认的降级路径。更新纪要时先读取当前完整正文,保留原有 Markdown 图片和用户未要求改变的内容,再写回完整目标内容。
仅预览标题变化时,先读取当前标题,再调用本地计划;`+update --dry-run` 本身不访问远端,所以 `before` 必须来自前一条真实 basic 读取:
```text
dws minutes +detail --id <taskUuid> --artifacts basic --format json
dws minutes +update --id <taskUuid> --title "<目标标题>" --dry-run --format json
```
最终展示 `当前标题 → 目标标题``executed=false` 和同一 taskUuid 后即结束。用户说“不实际写入”时不得继续索要写入确认、追加 `--yes`、真实改名或再以还原补救。
录音 start 的成功回执不一定含可控制的 taskUuid。只有响应明确提供 `taskUuid`,并由 Shortcut 返回 `controlReady=true`,才能执行 pause/resume/stop;不能通过“最新听记”或列表第一条猜测绑定。
## 5. 思维导图与发言人
| 原子命令 | 效果 | 当前 confirmation |
|---|---|---|
| `minutes mind-graph create --id <taskUuid>` | 创建思维导图异步任务 | `not_required` |
| `minutes mind-graph status --id <taskUuid>` | 查询任务状态 | `not_required` |
| `minutes speaker replace ...` | 替换逐字稿发言人昵称 | `not_required`(历史兼容原子入口) |
| `minutes speaker summary create --ids <IDs>` | 创建发言人段落总结 | `not_required` |
| `minutes speaker summary get --ids <IDs>` | 查询发言人总结 | `not_required` |
异步 create 后有界轮询;pending/timeout 保留 taskUuid/taskId,恢复只做 status/get。发言人 replace 是昵称替换,不是身份系统中的 speaker_id 重绑;写前必须完整读取逐字稿,确认源昵称存在且目标唯一。
## 6. ASR 热词与文本替换
| 原子命令 | 效果 | 当前 confirmation |
|---|---|---|
| `minutes hot-word list` | 查看个人热词 | `not_required` |
| `minutes hot-word add` | 新增热词 | `not_required` |
| `minutes hot-word delete` | 删除热词 | `not_required`write/medium(历史兼容原子入口) |
| `minutes replace-text` | 替换一条听记中的文本 | `not_required`(历史兼容原子入口) |
普通“补充热词”优先需要确认的 `+prepare-asr`,它只新增缺失项。只有用户明确要求最终集合完全一致并接受删除多余项时使用 `+sync-asr`;旧 `+prepare-asr --sync` 保持公开以提供迁移提示,但不会调用 MCP。批量文本替换优先仍要求确认的 `+replace-batch`,保留逐项验证和失败 ledger;不得为了绕过确认改用原子 delete/replace。
## 7. Upload session
| 原子命令 | 效果 | 当前 confirmation |
|---|---|---|
| `minutes upload create` | 创建普通上传 session | `not_required` |
| `minutes upload create-and-notify` | 创建 session,并要求上传完成后发送闪记卡片 | `user_required` |
| `minutes upload complete` | 完成已知 session 并生成听记 | `not_required` |
| `minutes upload cancel` | 取消已知 session | `not_required` |
正常本地文件上传优先 `+upload``+upload-and-notify`,由 Shortcut 管理 create、PUT、complete、取消和读回。原子流程必须保存真实 sessionId/上传地址/taskUuid
`minutes upload create --enable-message-card` 当前仍是原子命令迁移提示;需要通知时使用 `minutes upload create-and-notify`。Shortcut 层的旧 `+upload --enable-message-card``+upload-and-analyze --enable-message-card` 则继续执行原有通知语义,并遵循各自通用 Runtime confirmation;新调用优先使用 `+upload-and-notify`。真实执行 `+upload``+upload-and-analyze` 必须遵循确认门禁,不能因为不发送消息就绕过创建听记的确认。
1. create 或 create-and-notify。
2. 按服务端返回的预签名地址上传文件,不记录该地址。
3. 对同一个 session 执行 complete。
4. 上传前失败可对真实 session 执行 cancel;状态未知先读回,不重新创建。
## 8. 权限
### 8.1 当前能力边界
| 用户要做的事 | 当前公开入口 | 能否完成 | 边界 |
|---|---|---:|---|
| 当前登录用户为自己申请访问 | `minutes permission apply` / `+apply-permission` | 是 | 原子入口保留历史 `not_required`;推荐 `+apply-permission`,要求确认且只支持编辑、查看下载、仅查看 |
| 所有者/管理员给稳定 member UID 授权 | `minutes permission add` / `+share` | 是 | 原子入口保留历史 `not_required` 且支持 policy `0..4`;推荐 `+share`,要求确认且只支持 `edit/download/view` |
| 所有者/管理员撤销稳定 member UID 权限 | `minutes permission remove` / `+unshare` | 是 | 原子入口为历史 write/medium、`not_required`;推荐 `+unshare` 为 write/medium、`user_required` |
| 列出、读取或检查一条听记当前的成员权限 | 无公开 `permission list/get/inspect` 命令 | 否 | 不得用基本信息、写入回执或 dry-run 冒充权限读回 |
| 删除整条听记 | 无公开 Minutes delete 命令 | 否 | `permission remove` 只撤权;`hot-word delete` 只删除个人热词,都不能替代删除听记 |
### 8.2 policy 映射
| `--policy` | 权限 | `permission add` | `permission apply` | Shortcut 语义值 |
|---:|---|---:|---:|---|
| `0` | 管理员 | 支持 | 不支持 | 无;需要时使用原子命令 |
| `1` | 所有者 | 支持 | 不支持 | 无;需要时使用原子命令 |
| `2` | 可编辑 | 支持 | 支持 | `edit` |
| `3` | 可查看/下载 | 支持 | 支持 | `download` |
| `4` | 仅查看 | 支持 | 支持 | `view` |
`permission add``--policy` 是必填参数,没有默认值;`permission apply --policy` 也必须显式传入,只接受 `2..4`。用户未指定权限类型时先询问,不得把空值解释成 `0`,也不得擅自选择“仅查看”;即使确认选择“仅查看”,命令中仍必须显式传入 `--policy 4`。示例:
```text
dws minutes permission add --ids <uuid1,uuid2> --member-uids <uid1,uid2> --policy 3
dws minutes permission remove --ids <uuid1,uuid2> --member-uids <uid1,uid2>
dws minutes permission apply --id <taskUuid> --policy 4
```
根路径优先用 `+apply-permission``+share``+unshare` 的语义化参数;完整参数见 [07-minutes.md](07-minutes.md#4-权限-workflow)。只有姓名时先用 Contact/AI Search 解析为同组织稳定 UID,不能把姓名、手机号、userId、openId 或跨组织 UID 直接当作 member UID。
当前没有公开权限读取接口,因此权限写入成功最多证明服务端接受了这次写调用。交付边界按 `verification.mode=write_ack_only``verified=false` 表述;这两个值描述证据等级,不代表 Runtime 一定已经返回同名字段。`+share/+unshare` 的逐成员 `complete` ledger 仍只是写入回执,不能声称已读回最终权限状态。
## 9. 标签与语音备忘
| 原子命令 | 用途 |
|---|---|
| `minutes tag list` | 列出当前用户的听记标签,取得真实 tagId |
| `minutes tag query --tag-id <tagId>` | 查询标签下的听记并按真实 token 翻页 |
| `minutes audio-memo list` | 查询语音备忘;具体范围和分页参数读取 leaf Schema |
这些是长尾只读入口,不在根 Skill 展开。tagId 必须来自真实 `tag list`,不能按标签名猜 ID。
## 10. 结果与错误底线
- 成功必须由结构化业务结果与结果契约共同证明,不只看退出码或 `success=true`
- 列表、逐字稿、批量读取必须保留分页与完整性事实;页数上限、cursor 循环、缺 nextToken 或某页失败都返回不完整/非零。
- 有公开读取接口的写操作完成后按稳定 ID 读回;权限写入当前没有公开读回入口,只能报告 `write_ack_only``verified=false`,未知结果不得重放整个请求。
- 权限、上传、异步任务和批量替换必须保留部分成功 ledger 与恢复句柄。
- Runtime confirmation 与 compact Schema 是最终权威;若本文与当前 leaf Schema 冲突,使用更安全解释并报告 contract drift。
@@ -0,0 +1,33 @@
# Minutes Recipe 通用约束
> 返回入口:[DingTalk Minutes Skill](../../SKILL.md) · [Reference 与脚本索引](../minutes.md) · [兼容 Recipe](../lite-recipes.md)
本页只约束仍使用旧 Recipe 名称的兼容调用方,不复制根 Skill 的完整执行契约。
## 目标与 ID
| 字段 | 真实来源 | 后续用途 |
|---|---|---|
| `taskUuid` | Minutes 搜索/列表/创建的真实结果,或可信听记 URL 解析 | 所有详情、内容、更新、权限、下载与异步产物命令 |
| 成员 UID | 同 profile 下 AI Search/Contact 的唯一人员结果 | `+share/+unshare` 与需要身份绑定的发言人替换 |
| `sessionId` | upload create 的真实结果 | upload complete/cancel 与状态恢复 |
| `taskId` | 异步 create 的真实结果 | 继续轮询或恢复,不能重新 create 代替 |
标题、姓名、手机号、列表顺序和“最新一条”都不能替代稳定 ID。目标零命中、多候选、跨组织或分页未完成时停止并消歧。
## 分页与批量
- 完整列表和逐字稿必须读取到端点穷尽并检查 `complete=true`;缺 token、cursor 不前进/循环、页数上限或某页失败都属于不完整。
- 优先使用发布的批量接口或 Shortcut;没有批量能力时采用有界执行,不把 shell `& wait` 写成通用要求。
- 批量结果逐项记录目标、动作、成功、失败与未知状态。部分成功返回完整 ledger,不只汇报成功项。
## 写入与恢复
- Runtime 要求确认时,远端写调用数在确认前必须为 0;dry-run 也必须为 0。
- 非幂等或状态未知的 create/update 不盲目重试。先按真实 ID 读回,再决定只恢复未完成步骤。
- 写入成功必须有业务回执和必要读回证据;退出码 0、HTTP 200 或 `success=true` 单独都不足以证明完成。
## 跨产品传递
- Minutes 只交付真实听记内容和稳定 ID;写文档、建待办、发消息分别切换 `dingtalk-doc``dingtalk-todo``dingtalk-chat`
- 跨产品传递时保留来源听记的 `taskUuid/title/profile`,不得把另一个组织或另一个候选的字段拼接到当前对象。