# 业务模块 CLI 生成规范

使用 Skill Maker 生成或更新业务模块时，默认同步实现 `src/shortcuts/<module>`。Agent Skill 只引用已经在 CLI 中注册并通过 `schema` 暴露的 operation。

本规范借鉴飞书 CLI 的 shortcut 纪律，但按 `weaver-work-cli` 当前 TypeScript 架构落地：飞书的 `shortcuts/<domain>` 对应这里的 `src/shortcuts/<module>`；飞书的 command-level affordance 对应这里的 `docs/<module>.md` 和 Skill references；飞书的 `--dry-run` 预览在这里优先映射为 `*.preview`、`*.prepare` 或只读回查 operation，除非本模块显式实现人类友好的 dry-run 子命令。

## 生成前先定正确实现面

开始写代码前，先建立当前合约和 owner：

- 已有模块：先读 `src/shortcuts/<module>`、`docs/<module>.md`、`skills/weaver-e10-<module>`、相关 `test/business/<module>-*.test.ts`，确认现有 command、operation、schema、输出 envelope、错误 subtype 和安全边界。
- 新模块：先从源资料划分“业务友好的高层 operation”和“底层接口细节”。只有能为 Agent 或人类提供稳定流程、智能默认值、安全确认、字段收敛或结果归一化时，才新增 operation。
- 不重复命令面：同一业务动作只能有一个 canonical operation。可选的人类友好子命令只是薄包装，最终必须调用同一个 operation 执行器。
- 不绕过 owner：E10 认证、profile、HTTP client 和请求拦截链归 `src/internal/e10`；业务 API 适配归本模块 `host.ts`；operation 只组织业务输入、校验、确认链和结果。
- 不补推测能力：缺少接口路径、请求方法、关键字段、权限/认证边界、幂等键、回查方式或写入确认条件时，先确认是否只影响局部 operation；能实现的 operation 继续实现，不能实现的列入待确认清单或禁用边界。
- 不空停：如果必须暂停等用户，最终回复必须列出 `operation -> 缺少事实 -> 为什么阻断`，并提出一个明确问题。不要以“实现前需确认几个高风险接口细节”“读取关键 reference 原文”作为最终回复；仓库内已经存在的 reference 应先直接读取。

## 入口与注册

CLI 命令后缀 `<command>` 使用小写字母、数字和连字符，命令名就是 `<command>`；它独立于 Skill 后缀 `<skill>`，两者可不同。operation 前缀统一用 `<command>.<action>`：

```text
weaver-work-cli <command>
weaver-work-cli <command> schema
weaver-work-cli --json <command> run <command>.<action> --input-json '{"key":"value"}'
```

新增模块时必须更新 `src/shortcuts/index.ts`，把 `<command>Shortcut` 加入 `builtinShortcuts`。命令对象实现 `CliCommand`，`category` 使用 `shortcut`，注册方式参考 `src/shortcuts/invoice/index.ts`。命名分工：`src/shortcuts/<command>`、`docs/<command>.md`、`test/business/<command>-*.test.ts` 用 `<command>`；`skills/weaver-e10-<skill>`、`skill-template/domains/<skill>.md`、`skill-template/business-info.json` 的 key 用 `<skill>`。本规范下文的 `<module>` 均指 CLI 命令后缀 `<command>`。

## 文件结构

推荐结构：

```text
src/shortcuts/<module>/
  index.ts                  Commander 命令注册、schema/run、可选人类友好子命令。
  manifest.ts               operation 合约清单。
  operations.ts             run 入口：选择 handler、校验输入、统一执行。
  errors.ts                 模块结构化错误。
  host.ts                   业务 API 适配，复用 E10 request runtime/session。
  continuation.ts           只有 prepare/apply 写入链需要。
  operations/
    registry.ts             manifest 和 handler 一一对应校验。
    types.ts                operation handler 类型。
    shared.ts               通用输入校验、响应归一化、文件限制。
    <operation>.ts          具体 operation。
```

小模块可以合并少量文件，但不能省略 `schema`、`run`、manifest 与 registry 对齐校验。

## operation 合约

`manifest.ts` 是 Agent 和测试的 WHAT 合约，至少暴露：

```ts
export interface <Module>OperationContract {
  name: string;
  risk: string;
  scope?: string;
  auth?: string[];
  permissions?: string[];
  conditionalAuth?: Record<string, string[]>;
  conditionalPermissions?: Record<string, string[]>;
  deprecatedInputAliases?: Record<string, string[]>;
  fixed?: Record<string, unknown>;
  inputExamples?: Array<{
    name: string;
    input: Record<string, unknown>;
    source: string;
    sourceType: 'source-provided' | 'synthetic';
    notes?: string;
  }>;
  missingExamples?: Array<{
    reason: string;
    missingFacts?: string[];
    source?: string;
  }>;
  inputSchema: Record<string, unknown>;
  outputSchema: Record<string, unknown>;
}

export const <module>Operations: <Module>OperationContract[] = [
  {
    name: '<module>.<action>',
    risk: 'read',
    inputSchema: {
      type: 'object',
      additionalProperties: false,
      properties: {}
    },
    outputSchema: {
      type: 'object',
      additionalProperties: false,
      properties: {}
    }
  }
];
```

operation 名称使用 `<module>.<action>`，多级动作可用 `<module>.<object>.<action>`。`inputSchema` 必须禁止额外字段；需要二选一、至少一个、互斥、固定值或默认值时用 JSON Schema 表达，不把规则只写在说明里。源资料给出结构化 JSON 请求体字段表时，必须把字段逐项转换进 `inputSchema.properties`，包括必填、数组元素、嵌套对象、枚举和默认值；不得只写 `{ payload: { type: "object" } }`、`requestPayload`、`body` 或 `additionalProperties: true` 来代替参数转换。若为了兼容旧版本继续接受 `payload`，只能在 handler 归一化中处理，并用测试证明 canonical 顶层字段仍是 schema/reference 的唯一推荐输入。源资料给出权限、scope、角色、身份或接口前置条件时，记录到 `auth`、`permissions`、`scope` 或 `fixed` 中；如果当前模块不需要这些字段，可以省略，但不能把已知权限事实只放在正文里。

`outputSchema` 描述 `--json run` 成功 envelope 中的 `data` 字段，不描述外层 `{schemaVersion, ok, operation, meta, warnings}`。源资料给出接口响应、出参、返回值字段表或响应示例时，必须把稳定字段逐项转换进 `outputSchema.properties`，包括字段名、类型、必填、数组元素、嵌套对象、枚举、状态码和分页/汇总字段；不得只写 `{ result: { type: "object" } }`、`raw`、`data` 或 `additionalProperties: true` 来代替返回值转换。handler 对服务端响应做过归一化时，`outputSchema` 以 CLI 实际返回的 `data` 结构为准，并在属性说明里标注原始接口字段来源；确需保留服务端原始响应时，只能把 raw 字段作为附加属性暴露，同时仍要声明 CLI 已知的稳定字段。源资料没有返回字段表但有示例时，从示例抽取稳定字段并标明 `sourceType: "synthetic"` 或在 source-manifest 记录待复核；源资料完全缺少响应事实时，写入 `missingOutputSchema` 或等价待确认项，不要编造字段。

`inputExamples` 是 Agent 入参格式的优先参考，按以下规则生成：

- 源资料、历史 Skill、测试脚本或接口文档已有入参样例时，必须迁移到 `inputExamples`，`sourceType` 为 `source-provided`，`source` 指到源文件、标题、脚本或稳定 chunk；这类样例缺失时测试失败。
- 源资料没有样例但参数事实完整时，可以生成 `sourceType: "synthetic"` 的最小样例，字段值只能用明显假值、`example.test` 或安全占位，并在 `notes` 标明由 schema 推导、需业务复核。
- 源资料没有样例且参数事实不足时，不要生成伪样例；写入 `missingExamples`，列出缺少的类型、必填、枚举、来源、绑定规则、回查或确认链事实。生成完成时必须把这些缺口报告给用户。
- 只读无入参 operation 可以省略 `inputExamples`，但要保证 `inputSchema.properties` 为空且 reference 不制造多余入参。

`inputExamples` 中每个字段必须出现在 `inputSchema.properties` 或 `deprecatedInputAliases` 中，最小样例必须覆盖 required 字段；涉及 `oneOf`/`anyOf` 时，每条样例必须能解释覆盖的是哪条输入分支。reference 里的 `--input-json` 示例应优先来自 `inputExamples`，不能与 schema 漂移。

如果某些权限、身份或接口只在特定执行路径需要，例如“勾选同步才需要写权限”“上传附件才需要文件接口”，用 `conditionalAuth` 或 `conditionalPermissions` 在 manifest 中声明触发条件，并在 handler 中按同一个条件校验。不要把条件权限只写进 `references/` 或错误提示里。

常用风险等级：

- `read`：只读查询。
- `external-read`：向外部服务查询但不写业务数据。
- `external-artifact`：上传或生成外部制品，但不落业务对象。
- `read-with-upload`：上传后只读解析或预览。
- `read-before-write`：写入前准备、预览、生成 continuation。
- `high-risk-write`：新增、编辑、删除、导入、同步等真实写入。
- `local-file-write`：写本地文件。

## 命令行为

每个业务命令必须提供：

- `schema`：输出 manifest，供 Agent 判断 operation、字段和风险等级。
- `run <operation> --input-json <json>`：从命令参数读取简单 JSON 对象并执行 operation，优先用于 Agent 示例和 Windows PowerShell。
- `run <operation> --input <path>`：从 JSON 文件读取对象；传 `-` 时从标准输入读取，只在当前 shell 能稳定传管道时使用。
- 可选的人类友好子命令：只作为薄包装，最终仍调用同一个 operation 执行器。
- 可选本地 introspection：复杂 JSON 输入可以提供 schema 示例或 reference，但不能为了查看 schema 要求填写业务参数。

命令示例和生成出的 Markdown 必须同时兼容 Windows 和 macOS/Linux。凡涉及 JSON 输入、用户目录、路径分隔符、Python 启动器、文件删除、目录查看或文件比对，必须同时给 Windows PowerShell 与 macOS/Linux（bash/zsh）两套示例；Agent 先根据当前系统和 shell 选择对应示例，不确定时用 `node -p "process.platform"` 判断。简单 JSON 示例优先使用 `--input-json '<json>'`；复杂或多行 JSON 使用临时 UTF-8 文件和 `--input <path>`。Windows/PowerShell 下不要使用 `printf`、`$HOME/...`、`~/...`、bash 反斜杠续行、`rm/ls/diff/python3` 等 Unix-only 写法，不要把任一平台专属命令写成唯一默认步骤。

`--json` 成功输出统一 envelope：

```json
{
  "schemaVersion": 1,
  "ok": true,
  "operation": "<module>.<action>",
  "data": {},
  "meta": { "status": "COMPLETE" },
  "warnings": []
}
```

失败输出统一 envelope：

```json
{
  "schemaVersion": 1,
  "ok": false,
  "error": {
    "type": "validation",
    "subtype": "input_invalid",
    "message": "输入不合法",
    "retryable": false
  }
}
```

结构化错误要能被 `toErrorEnvelope` 转换。校验失败用 usage exit code；认证、网络、策略、需要确认、写入不确定分别使用现有 `ExitCode` 语义。

把这些视为公共兼容合约：operation 名称、字段名、默认值、固定业务参数、输出 envelope、错误 type/subtype、exit code、文件落点和覆盖策略。修改时必须同步更新测试、Skill reference 和 docs；不要为了兼容旧输入静默替换语义。确需兼容别名或旧字段时，在输入归一化阶段显式处理，并测试“新旧同时出现”的冲突规则。

## 输入兼容与归一化

字段名以 `manifest.ts` 的 `inputSchema` 为准。源资料、历史脚本或旧 Skill 里出现多个同义字段时，先选一个 canonical 字段；只有用户明确要求兼容旧输入，或已发布版本已经接受旧字段，才在 manifest 中记录 `deprecatedInputAliases`。源接口请求体本身是 JSON 对象时，canonical 输入通常就是该请求体的业务字段；不要为了实现方便新增通用 `payload` 层。

缺少参数事实必须结构化登记，不要散落在自然语言里。为每个 operation 维护参数覆盖矩阵（通常写入 `source-manifest.json` 的 `operationImpact[operation].parameterCoverage`），逐项记录源参数到 manifest/schema/handler 的落点和状态：`converted`、`fixed`、`derived`、`deprecatedAlias`、`withheld`、`needs-confirmation`、`not-applicable`。凡是源资料出现但没有进入 `inputSchema` 的参数，都必须有 `fixed`、`derived`、`withheld`、`needs-confirmation` 或 `not-applicable` 原因；不得静默丢弃。最终报告需要单独列出 `needs-confirmation` 参数，例如 `operation.field -> 缺少事实 -> 为什么影响调用`。

归一化只能发生在 `operations/shared.ts` 或清晰命名的 `normalizeInput()` 阶段，且必须早于业务 host 调用。不要在 `host.ts`、HTTP body 拼装或结果处理里偷偷接受旧字段。旧字段和新字段同时出现时必须报结构化校验错误，不能让任一方静默覆盖另一方。

归一化测试至少断言：旧字段能映射到 canonical 字段；canonical 字段保持原样；新旧字段同时出现会失败；错误的别名值不会绕过 `inputSchema` 的枚举、格式、互斥或固定值约束。

## E10 与业务 API

### 登录与凭证契约（生成产物必须遵循）

生成的 E10 业务 Skill 必须遵守登录与凭证红线：

- 登录与会话统一由 `weaver-e10-shared` 共享规则和 `weaver-work-cli auth ...` 命令体系托管，业务 Skill 不得自行实现任何登录流程。
- 生成的 SKILL.md frontmatter 必须声明 `dependencies:\n  - weaver-e10-shared`。
- 每个请求的请求头三件套（Cookie 完整原始串 / `eteamsid` / `User-Agent`）由 `weaver-work-cli` 统一注入，业务侧不得手工拼装或覆盖；唯一权威声明见 [`../../weaver-e10-shared/SKILL.md`](../../weaver-e10-shared/SKILL.md) 的「请求头契约」章节。
- Skill 与 reference 文档中若描述了接口请求，只需一行指针引用 `weaver-e10-shared` 的「请求头契约」，不要复制完整代码块。

E10 业务模块必须复用 `src/internal/e10` 的 session、profile 和 request runtime，不直接读取认证文件、Cookie、Keychain 或 legacy auth 目录，也不在业务 `host.ts` 中直接调用 `fetch`。业务 host 只封装本模块需要的请求方法，负责：

- 统一 base URL、headers 和 session 失效处理。
- 把源资料里的接口路径映射为明确方法。
- 归一化业务成功、业务错误、登录超时和网络异常。
- 对上传、下载、本地文件读取设置大小、类型和覆盖保护。

公共 E10 request runtime 提供统一拦截能力：`beforeRequest` 可在安全校验内调整 query、body、form、普通 header 和 timeout；不得修改 path，不得写入 Cookie、ETEAMSID、token、Authorization 等保留凭据头。`afterResponse` 默认只用于观察、记录和抛出结构化错误，不作为业务成功语义的任意改写入口。模块特有 token、业务成功码、重试和响应归一化仍留在模块 `host.ts`，不要放进全局 runtime。

如果源资料没有说明接口路径、请求方法、必要字段、分页语义、返回结构或错误码，不要猜；先把已确认 operation 继续落地，再向用户列出剩余缺口并等待补充。

用户或工作区文件访问必须在模块内集中校验。读取、上传、下载和写本地文件前，operation 要限制文件类型、大小、父目录存在性、路径逃逸和覆盖行为；Skill 层的风险提醒不能替代 CLI 层校验。

## guidance 分工

参考飞书 CLI 的 affordance/Skill 分层，weaver 中按以下边界维护：

- `manifest.ts` / `schema` 拥有 WHAT：operation、字段、风险、固定参数、权限或身份事实。
- `docs/<module>.md` 拥有维护者和命令级 WHEN：模块来源、命令结构、operation 表、何时用哪个 operation、已知限制。
- `skills/weaver-e10-<module>/SKILL.md` 拥有领域路由、共享规则入口、跨 operation 工作流和安全边界。
- `references/*.md` 拥有条件化 HOW：具体命令示例、输入摘要、输出处理、失败处理和回查策略。

不要在 docs 或 Skill 中重复整份 schema；需要字段细节时让 Agent 读取 `weaver-work-cli <module> schema` 或对应 reference。所有 shipped reference 路径必须真实存在，入口里不要链接不会随包发布的源码文件。

## 高风险写入

新增、编辑、删除、导入、同步等写操作必须优先设计为 `prepare -> apply`。这相当于飞书 shortcut 的 high-risk `--yes` 与 `--dry-run` 纪律，但 weaver 的确认必须沉到 CLI operation 中：

1. `prepare` 做只读回查、输入归一化、差异摘要和 continuation 签发，不真实写入。
2. Agent 把目标、差异、风险和确认条件摘要给用户。
3. 用户明确确认后，`apply` 必须要求 `confirm: true` 和有效 continuation。
4. `apply` 校验 session、目标 ID、文件 sha256 或业务对象指纹没有变化。
5. 写请求已发送后，如遇网络中断、部分成功或回查失败，返回 `partial/write_uncertain`，禁止自动重复提交。

写操作不能只有 Skill 层确认；CLI 必须强制确认链。

只读预览、外部查询、上传后解析等非写入风险，优先命名为 `*.preview` 或 `*.validate.preview`，并在 `risk` 中标明 `external-read`、`external-artifact` 或 `read-with-upload`。能本地预览请求形状但不触网的模块，可额外提供 dry-run，但它不能替代 `prepare -> apply`。

## 测试与文档

新增或更新业务 CLI 时同步维护：

- `test/business/<module>-*.test.ts`：覆盖 manifest、固定字段、输入校验、核心 operation、写入确认和不确定结果。
- `docs/<module>.md`：说明模块来源、CLI 结构、operation 表、常见命令和安全边界。
- `skills/weaver-e10-<module>`：只引用已实现 operation，并与 `weaver-work-cli <module> schema` 保持一致。

测试断言至少覆盖：

- manifest 和 registry 一一对应：每个 operation 有 handler，每个 handler 在 schema 中暴露。
- schema 合约：operation 名称、risk、scope/auth/permissions、`additionalProperties: false`、required/oneOf/const/default 等关键字段。
- 请求形状：用 fake host 断言 method、path、query、body、固定业务参数和分页默认值，避免只测返回文本。
- 错误形状：校验失败、认证失败、业务失败、网络失败、结果不确定都返回稳定 type/subtype 和 exit code。
- 高风险写入：`prepare` 不写入；`apply` 缺少 `confirm: true` 或 continuation 必失败；目标、session、文件 sha256 或业务指纹变化必须失败；写请求发出后的不确定结果不能自动重试。
- 文件操作：本地输入文件存在、类型、大小、路径逃逸；下载或导出拒绝覆盖已存在文件。
- 命令输入：`--input-json`、`--input <path>` 和 `--input -` 的解析行为一致；`--input-json` 与 `--input` 同时出现时报结构化校验错误；UTF-8 BOM 文件能正常读取。
- Skill/CLI 一致性：抽取 Skill 和 reference 中的 `run <operation>` 示例，断言 operation 在 manifest 中存在；示例使用的字段必须在 schema 中存在，并优先与 manifest `inputExamples` 对齐。
- 入参 example 回归：源资料已有 example 时，断言对应 operation manifest 存在 `source-provided` 样例；`inputExamples` 必须是可解析 JSON，对应字段在 `inputSchema.properties` 或 `deprecatedInputAliases` 中，最小样例覆盖 required 字段；仅源资料没有 example 不失败，但必须在 `missingExamples` 或参数覆盖矩阵中形成 WARN/needs-confirmation。
- 源资料保真：从源 MD 或机器契约中抽取关键字段表、枚举/状态、固定参数、分页口径、错误码、写入确认条件和禁用能力，断言它们分别出现在 `manifest.ts`、handler 请求形状、reference、withheld/disabled 清单或 golden tests 中；不要只测生成产物存在。
- sourceCoverage 回归：`source-manifest.json` 中业务源文件不能全部落成一条笼统说明；每个 `api-doc`、`existing-skill` 或 `code` 源文件应有 `converted`、`withheld`、`external-only`、`not-applicable` 或 `needs-confirmation` 状态，并能追到 operation/reference 或明确原因。
- 参数覆盖回归：每个源资料参数都要映射到 `converted`、`fixed`、`derived`、`deprecatedAlias`、`withheld`、`needs-confirmation` 或 `not-applicable`；源资料中存在但产物中没有解释的参数视为失败，参数事实不完整但已登记为 `needs-confirmation` 只作为待用户补充项。
- 示例安全：docs、tips、reference 示例只用 `PLACEHOLDER_VALUE`、`example.test` 或明显假 ID，不出现真实 IP、内网域名、Cookie、Token、手机号、邮箱或个人路径；PowerShell 命令块里不要使用会被解释为重定向的裸尖括号占位符。
- 更新路径：源资料变化时，测试或文档要证明 CLI、Skill、manifest、business-info 和 domain 同步更新；如果 manifest 存在 `operationImpact`，要优先覆盖受影响 operation、schema 字段、reference 和写入确认链。
- Git 更新语义回归：基于 `OLD_REF..NEW_REF` 更新时，不只检查生成产物存在；还要为受影响 operation 补充或更新 golden tests，断言用户意图会路由到正确 operation、字段 canonical 化与旧字段兼容策略、固定参数/默认值/枚举、写入确认链和错误 envelope。`major` 兼容性变化必须有测试覆盖迁移或拒绝策略。

验证命令：

每次创建或更新 Skill 后，泛微技能检测是必需步骤；运行 detector 前必须先询问用户是否现在进行 Skill 质检。用户拒绝、未回复或检测器不可用时，不得安装、发布或把生成结果声明为完成。

Windows PowerShell：

```powershell
npm test -- "test/business/MODULE_NAME-*.test.ts"
npm test -- test/skills/layout.test.ts
npm run build
weaver-work-cli MODULE_NAME schema
weaver-work-cli skills validate skills\weaver-e10-MODULE_NAME --json --no-html
```

macOS/Linux（bash/zsh）：

```bash
npm test -- "test/business/MODULE_NAME-*.test.ts"
npm test -- test/skills/layout.test.ts
npm run build
weaver-work-cli MODULE_NAME schema
weaver-work-cli skills validate skills/weaver-e10-MODULE_NAME --json --no-html
```
