refactor(cmdcore): split Safety into its own enum tier with Risk default
Risk (runtime confirmation) and Safety (schema metadata) are two independent enums composed at embed time: explicit SafetyDecl fields > CommandSpec.Safety tier > Risk.SafetyDefault(). The tier fill now also covers idempotency, so an enum-only declaration is self-sufficient and validateSchemaDecl no longer needs safety completeness checks. devapp reclassifies its write leaves by reversibility: reversible mutations declare LeafSafetyWrite (risk high->medium), create/robot submit/version create declare LeafSafetyHighWrite, and delete/version publish declare LeafSafetyDestructive (publish effect write->destructive). Shared hand-written safety constants are deleted. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
co-authored by
Claude Opus 4.6
Cursor
parent
da93fbcc47
commit
ce0501b93e
@@ -1146,7 +1146,7 @@ cmd.RunE = func(cmd *cobra.Command, args []string) error {
|
||||
| 非 Shortcut 受管定义的 Cobra 命令 Hidden | 可执行 Contract | 挂载的命令可见性与声明匹配 |
|
||||
| Shortcut 列表成员资格与语义 disposition | 经评审的 Shortcut 可见性解析器 | public/all 列表成员资格与经评审决策匹配 |
|
||||
| Runtime Schema / Agent 暴露 | 经评审的 CommandRegistry 加精确排除 | 每个暴露叶子解析到活 Contract;排除显式且不重叠 |
|
||||
| 运行时 Risk 与确认 | 可执行 Contract(非空 `Risk`)或显式 annotate(如 `runtime_gate`);见 §5.0 | 不得靠推断;空 Risk 不嵌入 schema risk;写命令须 Risk 或 gate;Safety 组装优先级 **`Schema.Safety`(Final)> `Risk` > `runtime_gate`**,高优先命中即忽略低优先 |
|
||||
| 运行时 Risk 与确认 | 可执行 Contract(非空 `Risk`)或显式 annotate(如 `runtime_gate`);见 §5.0 | 不得靠推断;空 Risk 不嵌入 schema risk;写命令须 Risk 或 gate;Safety 组装优先级 **`Schema.Safety`(Final 显式字段)> `CommandSpec.Safety` 枚举 tier > `Risk.SafetyDefault()` > `runtime_gate`**,高优先命中即忽略低优先;tier 填充含 idempotency(读 idempotent / 写 unknown),故仅声明 Risk/Safety 枚举即自足 |
|
||||
| 后端 product/tool/载荷绑定 | mcpbind + 后端元数据 | 每个绑定引用真实的 flag/属性 |
|
||||
| Agent 选择文案(`use_when`、`avoid_when`、摘要) | 经评审的 hints/catalog | 身份解析到活契约 |
|
||||
|
||||
|
||||
@@ -957,13 +957,13 @@
|
||||
]
|
||||
},
|
||||
"risk": {
|
||||
"value": "high",
|
||||
"value": "medium",
|
||||
"source": "cmdcore.contract",
|
||||
"precedence": "contract_final",
|
||||
"resolution": "highest_precedence",
|
||||
"candidates": [
|
||||
{
|
||||
"value": "high",
|
||||
"value": "medium",
|
||||
"source": "cmdcore.contract",
|
||||
"precedence": "contract_final",
|
||||
"selected": true
|
||||
@@ -999,7 +999,7 @@
|
||||
"interface_mode": "composite",
|
||||
"interface_reason": "Reviewed unpinned remote adapter: this executable CLI wrapper calls a remote helper that is absent from the pinned MCP metadata snapshot; no single pinned semantically equivalent interface_ref can represent the command.",
|
||||
"reviewed": true,
|
||||
"risk": "high",
|
||||
"risk": "medium",
|
||||
"source_refs": [
|
||||
"cmdcore.SchemaDecl",
|
||||
"skills/mono/references/products/dev.md"
|
||||
@@ -1205,13 +1205,13 @@
|
||||
]
|
||||
},
|
||||
"risk": {
|
||||
"value": "high",
|
||||
"value": "medium",
|
||||
"source": "cmdcore.contract",
|
||||
"precedence": "contract_final",
|
||||
"resolution": "highest_precedence",
|
||||
"candidates": [
|
||||
{
|
||||
"value": "high",
|
||||
"value": "medium",
|
||||
"source": "cmdcore.contract",
|
||||
"precedence": "contract_final",
|
||||
"selected": true
|
||||
@@ -1247,7 +1247,7 @@
|
||||
"interface_mode": "composite",
|
||||
"interface_reason": "Reviewed unpinned remote adapter: this executable CLI wrapper calls a remote helper that is absent from the pinned MCP metadata snapshot; no single pinned semantically equivalent interface_ref can represent the command.",
|
||||
"reviewed": true,
|
||||
"risk": "high",
|
||||
"risk": "medium",
|
||||
"source_refs": [
|
||||
"cmdcore.SchemaDecl",
|
||||
"skills/mono/references/products/dev.md"
|
||||
@@ -1701,13 +1701,13 @@
|
||||
]
|
||||
},
|
||||
"risk": {
|
||||
"value": "high",
|
||||
"value": "medium",
|
||||
"source": "cmdcore.contract",
|
||||
"precedence": "contract_final",
|
||||
"resolution": "highest_precedence",
|
||||
"candidates": [
|
||||
{
|
||||
"value": "high",
|
||||
"value": "medium",
|
||||
"source": "cmdcore.contract",
|
||||
"precedence": "contract_final",
|
||||
"selected": true
|
||||
@@ -1743,7 +1743,7 @@
|
||||
"interface_mode": "composite",
|
||||
"interface_reason": "Reviewed unpinned remote adapter: this executable CLI wrapper calls a remote helper that is absent from the pinned MCP metadata snapshot; no single pinned semantically equivalent interface_ref can represent the command.",
|
||||
"reviewed": true,
|
||||
"risk": "high",
|
||||
"risk": "medium",
|
||||
"source_refs": [
|
||||
"cmdcore.SchemaDecl",
|
||||
"skills/mono/references/products/dev.md"
|
||||
@@ -1949,13 +1949,13 @@
|
||||
]
|
||||
},
|
||||
"risk": {
|
||||
"value": "high",
|
||||
"value": "medium",
|
||||
"source": "cmdcore.contract",
|
||||
"precedence": "contract_final",
|
||||
"resolution": "highest_precedence",
|
||||
"candidates": [
|
||||
{
|
||||
"value": "high",
|
||||
"value": "medium",
|
||||
"source": "cmdcore.contract",
|
||||
"precedence": "contract_final",
|
||||
"selected": true
|
||||
@@ -1991,7 +1991,7 @@
|
||||
"interface_mode": "composite",
|
||||
"interface_reason": "Reviewed unpinned remote adapter: this executable CLI wrapper calls a remote helper that is absent from the pinned MCP metadata snapshot; no single pinned semantically equivalent interface_ref can represent the command.",
|
||||
"reviewed": true,
|
||||
"risk": "high",
|
||||
"risk": "medium",
|
||||
"source_refs": [
|
||||
"cmdcore.SchemaDecl",
|
||||
"skills/mono/references/products/dev.md"
|
||||
@@ -2678,13 +2678,13 @@
|
||||
]
|
||||
},
|
||||
"risk": {
|
||||
"value": "high",
|
||||
"value": "medium",
|
||||
"source": "cmdcore.contract",
|
||||
"precedence": "contract_final",
|
||||
"resolution": "highest_precedence",
|
||||
"candidates": [
|
||||
{
|
||||
"value": "high",
|
||||
"value": "medium",
|
||||
"source": "cmdcore.contract",
|
||||
"precedence": "contract_final",
|
||||
"selected": true
|
||||
@@ -2714,7 +2714,7 @@
|
||||
"interface_mode": "composite",
|
||||
"interface_reason": "Reviewed unpinned remote adapter: this executable CLI wrapper calls a remote helper that is absent from the pinned MCP metadata snapshot; no single pinned semantically equivalent interface_ref can represent the command.",
|
||||
"reviewed": true,
|
||||
"risk": "high",
|
||||
"risk": "medium",
|
||||
"source_refs": [
|
||||
"cmdcore.SchemaDecl"
|
||||
],
|
||||
@@ -3124,13 +3124,13 @@
|
||||
]
|
||||
},
|
||||
"risk": {
|
||||
"value": "high",
|
||||
"value": "medium",
|
||||
"source": "cmdcore.contract",
|
||||
"precedence": "contract_final",
|
||||
"resolution": "highest_precedence",
|
||||
"candidates": [
|
||||
{
|
||||
"value": "high",
|
||||
"value": "medium",
|
||||
"source": "cmdcore.contract",
|
||||
"precedence": "contract_final",
|
||||
"selected": true
|
||||
@@ -3160,7 +3160,7 @@
|
||||
"interface_mode": "composite",
|
||||
"interface_reason": "Reviewed unpinned remote adapter: this executable CLI wrapper calls a remote helper that is absent from the pinned MCP metadata snapshot; no single pinned semantically equivalent interface_ref can represent the command.",
|
||||
"reviewed": true,
|
||||
"risk": "high",
|
||||
"risk": "medium",
|
||||
"source_refs": [
|
||||
"cmdcore.SchemaDecl"
|
||||
],
|
||||
@@ -3365,13 +3365,13 @@
|
||||
]
|
||||
},
|
||||
"risk": {
|
||||
"value": "high",
|
||||
"value": "medium",
|
||||
"source": "cmdcore.contract",
|
||||
"precedence": "contract_final",
|
||||
"resolution": "highest_precedence",
|
||||
"candidates": [
|
||||
{
|
||||
"value": "high",
|
||||
"value": "medium",
|
||||
"source": "cmdcore.contract",
|
||||
"precedence": "contract_final",
|
||||
"selected": true
|
||||
@@ -3407,7 +3407,7 @@
|
||||
"interface_mode": "composite",
|
||||
"interface_reason": "Reviewed unpinned remote adapter: this executable CLI wrapper calls a remote helper that is absent from the pinned MCP metadata snapshot; no single pinned semantically equivalent interface_ref can represent the command.",
|
||||
"reviewed": true,
|
||||
"risk": "high",
|
||||
"risk": "medium",
|
||||
"source_refs": [
|
||||
"cmdcore.SchemaDecl",
|
||||
"skills/mono/references/products/dev.md"
|
||||
@@ -3861,13 +3861,13 @@
|
||||
]
|
||||
},
|
||||
"risk": {
|
||||
"value": "high",
|
||||
"value": "medium",
|
||||
"source": "cmdcore.contract",
|
||||
"precedence": "contract_final",
|
||||
"resolution": "highest_precedence",
|
||||
"candidates": [
|
||||
{
|
||||
"value": "high",
|
||||
"value": "medium",
|
||||
"source": "cmdcore.contract",
|
||||
"precedence": "contract_final",
|
||||
"selected": true
|
||||
@@ -3903,7 +3903,7 @@
|
||||
"interface_mode": "composite",
|
||||
"interface_reason": "Reviewed unpinned remote adapter: this executable CLI wrapper calls a remote helper that is absent from the pinned MCP metadata snapshot; no single pinned semantically equivalent interface_ref can represent the command.",
|
||||
"reviewed": true,
|
||||
"risk": "high",
|
||||
"risk": "medium",
|
||||
"source_refs": [
|
||||
"cmdcore.SchemaDecl",
|
||||
"skills/mono/references/products/dev.md"
|
||||
@@ -4109,13 +4109,13 @@
|
||||
]
|
||||
},
|
||||
"risk": {
|
||||
"value": "high",
|
||||
"value": "medium",
|
||||
"source": "cmdcore.contract",
|
||||
"precedence": "contract_final",
|
||||
"resolution": "highest_precedence",
|
||||
"candidates": [
|
||||
{
|
||||
"value": "high",
|
||||
"value": "medium",
|
||||
"source": "cmdcore.contract",
|
||||
"precedence": "contract_final",
|
||||
"selected": true
|
||||
@@ -4151,7 +4151,7 @@
|
||||
"interface_mode": "composite",
|
||||
"interface_reason": "Reviewed unpinned remote adapter: this executable CLI wrapper calls a remote helper that is absent from the pinned MCP metadata snapshot; no single pinned semantically equivalent interface_ref can represent the command.",
|
||||
"reviewed": true,
|
||||
"risk": "high",
|
||||
"risk": "medium",
|
||||
"source_refs": [
|
||||
"cmdcore.SchemaDecl",
|
||||
"skills/mono/references/products/dev.md"
|
||||
@@ -4357,13 +4357,13 @@
|
||||
]
|
||||
},
|
||||
"risk": {
|
||||
"value": "high",
|
||||
"value": "medium",
|
||||
"source": "cmdcore.contract",
|
||||
"precedence": "contract_final",
|
||||
"resolution": "highest_precedence",
|
||||
"candidates": [
|
||||
{
|
||||
"value": "high",
|
||||
"value": "medium",
|
||||
"source": "cmdcore.contract",
|
||||
"precedence": "contract_final",
|
||||
"selected": true
|
||||
@@ -4399,7 +4399,7 @@
|
||||
"interface_mode": "composite",
|
||||
"interface_reason": "Reviewed unpinned remote adapter: this executable CLI wrapper calls a remote helper that is absent from the pinned MCP metadata snapshot; no single pinned semantically equivalent interface_ref can represent the command.",
|
||||
"reviewed": true,
|
||||
"risk": "high",
|
||||
"risk": "medium",
|
||||
"source_refs": [
|
||||
"cmdcore.SchemaDecl",
|
||||
"skills/mono/references/products/dev.md"
|
||||
@@ -4605,13 +4605,13 @@
|
||||
]
|
||||
},
|
||||
"risk": {
|
||||
"value": "high",
|
||||
"value": "medium",
|
||||
"source": "cmdcore.contract",
|
||||
"precedence": "contract_final",
|
||||
"resolution": "highest_precedence",
|
||||
"candidates": [
|
||||
{
|
||||
"value": "high",
|
||||
"value": "medium",
|
||||
"source": "cmdcore.contract",
|
||||
"precedence": "contract_final",
|
||||
"selected": true
|
||||
@@ -4647,7 +4647,7 @@
|
||||
"interface_mode": "composite",
|
||||
"interface_reason": "Reviewed unpinned remote adapter: this executable CLI wrapper calls a remote helper that is absent from the pinned MCP metadata snapshot; no single pinned semantically equivalent interface_ref can represent the command.",
|
||||
"reviewed": true,
|
||||
"risk": "high",
|
||||
"risk": "medium",
|
||||
"source_refs": [
|
||||
"cmdcore.SchemaDecl",
|
||||
"skills/mono/references/products/dev.md"
|
||||
@@ -5579,13 +5579,13 @@
|
||||
]
|
||||
},
|
||||
"risk": {
|
||||
"value": "high",
|
||||
"value": "medium",
|
||||
"source": "cmdcore.contract",
|
||||
"precedence": "contract_final",
|
||||
"resolution": "highest_precedence",
|
||||
"candidates": [
|
||||
{
|
||||
"value": "high",
|
||||
"value": "medium",
|
||||
"source": "cmdcore.contract",
|
||||
"precedence": "contract_final",
|
||||
"selected": true
|
||||
@@ -5615,7 +5615,7 @@
|
||||
"interface_mode": "composite",
|
||||
"interface_reason": "Reviewed unpinned remote adapter: this executable CLI wrapper calls a remote helper that is absent from the pinned MCP metadata snapshot; no single pinned semantically equivalent interface_ref can represent the command.",
|
||||
"reviewed": true,
|
||||
"risk": "high",
|
||||
"risk": "medium",
|
||||
"source_refs": [
|
||||
"cmdcore.SchemaDecl"
|
||||
],
|
||||
@@ -5820,13 +5820,13 @@
|
||||
]
|
||||
},
|
||||
"risk": {
|
||||
"value": "high",
|
||||
"value": "medium",
|
||||
"source": "cmdcore.contract",
|
||||
"precedence": "contract_final",
|
||||
"resolution": "highest_precedence",
|
||||
"candidates": [
|
||||
{
|
||||
"value": "high",
|
||||
"value": "medium",
|
||||
"source": "cmdcore.contract",
|
||||
"precedence": "contract_final",
|
||||
"selected": true
|
||||
@@ -5862,7 +5862,7 @@
|
||||
"interface_mode": "composite",
|
||||
"interface_reason": "Reviewed unpinned remote adapter: this executable CLI wrapper calls a remote helper that is absent from the pinned MCP metadata snapshot; no single pinned semantically equivalent interface_ref can represent the command.",
|
||||
"reviewed": true,
|
||||
"risk": "high",
|
||||
"risk": "medium",
|
||||
"source_refs": [
|
||||
"cmdcore.SchemaDecl",
|
||||
"skills/mono/references/products/dev.md"
|
||||
@@ -6574,7 +6574,7 @@
|
||||
"含高敏权限但尚未确认时不要正式发布"
|
||||
],
|
||||
"confirmation": "user_required",
|
||||
"effect": "write",
|
||||
"effect": "destructive",
|
||||
"effect_source": "cmdcore.contract",
|
||||
"examples": [
|
||||
"dws dev app version publish --unified-app-id \u003cunifiedAppId\u003e --version-id \u003cversionId\u003e --dry-run --format json"
|
||||
@@ -6649,13 +6649,13 @@
|
||||
]
|
||||
},
|
||||
"effect": {
|
||||
"value": "write",
|
||||
"value": "destructive",
|
||||
"source": "cmdcore.contract",
|
||||
"precedence": "contract_final",
|
||||
"resolution": "highest_precedence",
|
||||
"candidates": [
|
||||
{
|
||||
"value": "write",
|
||||
"value": "destructive",
|
||||
"source": "cmdcore.contract",
|
||||
"precedence": "contract_final",
|
||||
"selected": true
|
||||
@@ -7243,13 +7243,13 @@
|
||||
]
|
||||
},
|
||||
"risk": {
|
||||
"value": "high",
|
||||
"value": "medium",
|
||||
"source": "cmdcore.contract",
|
||||
"precedence": "contract_final",
|
||||
"resolution": "highest_precedence",
|
||||
"candidates": [
|
||||
{
|
||||
"value": "high",
|
||||
"value": "medium",
|
||||
"source": "cmdcore.contract",
|
||||
"precedence": "contract_final",
|
||||
"selected": true
|
||||
@@ -7279,7 +7279,7 @@
|
||||
"interface_mode": "composite",
|
||||
"interface_reason": "Reviewed unpinned remote adapter: this executable CLI wrapper calls a remote helper that is absent from the pinned MCP metadata snapshot; no single pinned semantically equivalent interface_ref can represent the command.",
|
||||
"reviewed": true,
|
||||
"risk": "high",
|
||||
"risk": "medium",
|
||||
"source_refs": [
|
||||
"cmdcore.SchemaDecl"
|
||||
],
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"version": 1,
|
||||
"surface_hash": "sha256:29d4f5f43688cc01bc2277a4528b597de4fbab89a7b2f13fe2e56df85d1c66c4",
|
||||
"source_hash": "sha256:26c7461cde3019fd9ec7378606e59a5725ca78a3d465ac8a865f9f70ecc28c3a",
|
||||
"source_hash": "sha256:3ab6ab1717cdfaa6f115487c838ecd422f9a931bab28725e7af1cedd3d31a366",
|
||||
"catalog": {
|
||||
"agent_metadata": {
|
||||
"products_with_metadata": 26,
|
||||
@@ -12441,7 +12441,7 @@
|
||||
"name": "add_dev_app_members",
|
||||
"primary_cli_path": "dev app member add",
|
||||
"reviewed": true,
|
||||
"risk": "high",
|
||||
"risk": "medium",
|
||||
"title": "添加开放平台应用成员",
|
||||
"use_when": [
|
||||
"需要授予指定用户应用协作角色时"
|
||||
@@ -12472,7 +12472,7 @@
|
||||
"name": "apply_dev_app_permissions",
|
||||
"primary_cli_path": "dev app permission add",
|
||||
"reviewed": true,
|
||||
"risk": "high",
|
||||
"risk": "medium",
|
||||
"title": "申请开放平台应用权限点",
|
||||
"use_when": [
|
||||
"已确认 scopeValue 并需要新增权限时"
|
||||
@@ -12652,7 +12652,7 @@
|
||||
"name": "disable_dev_app",
|
||||
"primary_cli_path": "dev app disable",
|
||||
"reviewed": true,
|
||||
"risk": "high",
|
||||
"risk": "medium",
|
||||
"title": "停用开放平台企业内部应用",
|
||||
"use_when": [
|
||||
"需要让应用暂时不可用但保留配置时"
|
||||
@@ -12683,7 +12683,7 @@
|
||||
"name": "disable_dev_app_robot",
|
||||
"primary_cli_path": "dev app robot disable",
|
||||
"reviewed": true,
|
||||
"risk": "high",
|
||||
"risk": "medium",
|
||||
"title": "停用现有应用的机器人能力",
|
||||
"use_when": [
|
||||
"需要暂时让应用机器人离线时"
|
||||
@@ -12714,7 +12714,7 @@
|
||||
"name": "enable_dev_app",
|
||||
"primary_cli_path": "dev app enable",
|
||||
"reviewed": true,
|
||||
"risk": "high",
|
||||
"risk": "medium",
|
||||
"title": "启用开放平台企业内部应用",
|
||||
"use_when": [
|
||||
"需要恢复一个已停用应用时"
|
||||
@@ -12745,7 +12745,7 @@
|
||||
"name": "enable_dev_app_robot",
|
||||
"primary_cli_path": "dev app robot enable",
|
||||
"reviewed": true,
|
||||
"risk": "high",
|
||||
"risk": "medium",
|
||||
"title": "启用现有应用机器人能力(纯启用,无需配置字段)",
|
||||
"use_when": [
|
||||
"机器人配置存在但处于 OFFLINE 时"
|
||||
@@ -13109,7 +13109,7 @@
|
||||
"dry_run": {
|
||||
"preview_kind": "invocation"
|
||||
},
|
||||
"effect": "write",
|
||||
"effect": "destructive",
|
||||
"group": "app.version",
|
||||
"idempotency": "unknown",
|
||||
"interface_mode": "composite",
|
||||
@@ -13180,7 +13180,7 @@
|
||||
"name": "remove_dev_app_members",
|
||||
"primary_cli_path": "dev app member remove",
|
||||
"reviewed": true,
|
||||
"risk": "high",
|
||||
"risk": "medium",
|
||||
"title": "移除开放平台应用成员",
|
||||
"use_when": [
|
||||
"需要撤销指定用户的应用协作角色时"
|
||||
@@ -13211,7 +13211,7 @@
|
||||
"name": "remove_dev_app_permissions",
|
||||
"primary_cli_path": "dev app permission remove",
|
||||
"reviewed": true,
|
||||
"risk": "high",
|
||||
"risk": "medium",
|
||||
"title": "取消开放平台应用权限点",
|
||||
"use_when": [
|
||||
"需要撤销已知 scopeValue 的权限时"
|
||||
@@ -13273,7 +13273,7 @@
|
||||
"name": "set_extension_robot_config",
|
||||
"primary_cli_path": "dev app robot config",
|
||||
"reviewed": true,
|
||||
"risk": "high",
|
||||
"risk": "medium",
|
||||
"title": "创建或更新现有应用的机器人配置(upsert)",
|
||||
"use_when": [
|
||||
"已有 unifiedAppId 并需要配置机器人名称、回调或技能时"
|
||||
@@ -13304,7 +13304,7 @@
|
||||
"name": "set_extension_webapp_config",
|
||||
"primary_cli_path": "dev app webapp config",
|
||||
"reviewed": true,
|
||||
"risk": "high",
|
||||
"risk": "medium",
|
||||
"title": "配置网页应用能力",
|
||||
"use_when": [
|
||||
"需要设置 H5、PC 首页或 OMP 地址时"
|
||||
@@ -13366,7 +13366,7 @@
|
||||
"name": "subscribe_dev_app_events",
|
||||
"primary_cli_path": "dev app event subscribe",
|
||||
"reviewed": true,
|
||||
"risk": "high",
|
||||
"risk": "medium",
|
||||
"title": "订阅应用事件回调",
|
||||
"use_when": [
|
||||
"已确认事件码并需要新增事件订阅时"
|
||||
@@ -13397,7 +13397,7 @@
|
||||
"name": "unsubscribe_dev_app_events",
|
||||
"primary_cli_path": "dev app event unsubscribe",
|
||||
"reviewed": true,
|
||||
"risk": "high",
|
||||
"risk": "medium",
|
||||
"title": "取消订阅应用事件",
|
||||
"use_when": [
|
||||
"需要停止接收一个或多个已订阅事件时"
|
||||
@@ -13428,7 +13428,7 @@
|
||||
"name": "update_dev_app",
|
||||
"primary_cli_path": "dev app update",
|
||||
"reviewed": true,
|
||||
"risk": "high",
|
||||
"risk": "medium",
|
||||
"title": "修改开放平台企业内部应用基础信息",
|
||||
"use_when": [
|
||||
"已有 unifiedAppId,需要修改应用基础信息"
|
||||
@@ -13459,7 +13459,7 @@
|
||||
"name": "update_dev_app_security_config",
|
||||
"primary_cli_path": "dev app security config",
|
||||
"reviewed": true,
|
||||
"risk": "high",
|
||||
"risk": "medium",
|
||||
"title": "更新开放平台应用安全配置",
|
||||
"use_when": [
|
||||
"需要调整应用安全相关 URL 或白名单时"
|
||||
|
||||
@@ -317,7 +317,7 @@
|
||||
"selected": true,
|
||||
"source": "cmdcore.contract",
|
||||
"source_ref": "cmdcore.SchemaDecl",
|
||||
"value": "high"
|
||||
"value": "medium"
|
||||
}
|
||||
],
|
||||
"precedence": "contract_final",
|
||||
@@ -325,7 +325,7 @@
|
||||
"review_reason": "Contract final Schema pass-through",
|
||||
"source": "cmdcore.contract",
|
||||
"source_ref": "cmdcore.SchemaDecl",
|
||||
"value": "high"
|
||||
"value": "medium"
|
||||
},
|
||||
"title": {
|
||||
"candidates": [
|
||||
@@ -728,7 +728,7 @@
|
||||
"primary_cli_path": "dev app member add",
|
||||
"product_id": "dev",
|
||||
"reviewed": true,
|
||||
"risk": "high",
|
||||
"risk": "medium",
|
||||
"source": "reviewed_command_registry",
|
||||
"title": "添加开放平台应用成员",
|
||||
"use_when": [
|
||||
@@ -1051,7 +1051,7 @@
|
||||
"selected": true,
|
||||
"source": "cmdcore.contract",
|
||||
"source_ref": "cmdcore.SchemaDecl",
|
||||
"value": "high"
|
||||
"value": "medium"
|
||||
}
|
||||
],
|
||||
"precedence": "contract_final",
|
||||
@@ -1059,7 +1059,7 @@
|
||||
"review_reason": "Contract final Schema pass-through",
|
||||
"source": "cmdcore.contract",
|
||||
"source_ref": "cmdcore.SchemaDecl",
|
||||
"value": "high"
|
||||
"value": "medium"
|
||||
},
|
||||
"title": {
|
||||
"candidates": [
|
||||
@@ -1347,7 +1347,7 @@
|
||||
"primary_cli_path": "dev app permission add",
|
||||
"product_id": "dev",
|
||||
"reviewed": true,
|
||||
"risk": "high",
|
||||
"risk": "medium",
|
||||
"source": "reviewed_command_registry",
|
||||
"title": "申请开放平台应用权限点",
|
||||
"use_when": [
|
||||
@@ -4843,7 +4843,7 @@
|
||||
"selected": true,
|
||||
"source": "cmdcore.contract",
|
||||
"source_ref": "cmdcore.SchemaDecl",
|
||||
"value": "high"
|
||||
"value": "medium"
|
||||
}
|
||||
],
|
||||
"precedence": "contract_final",
|
||||
@@ -4851,7 +4851,7 @@
|
||||
"review_reason": "Contract final Schema pass-through",
|
||||
"source": "cmdcore.contract",
|
||||
"source_ref": "cmdcore.SchemaDecl",
|
||||
"value": "high"
|
||||
"value": "medium"
|
||||
},
|
||||
"title": {
|
||||
"candidates": [
|
||||
@@ -5024,7 +5024,7 @@
|
||||
"primary_cli_path": "dev app disable",
|
||||
"product_id": "dev",
|
||||
"reviewed": true,
|
||||
"risk": "high",
|
||||
"risk": "medium",
|
||||
"source": "reviewed_command_registry",
|
||||
"title": "停用开放平台企业内部应用",
|
||||
"use_when": [
|
||||
@@ -5347,7 +5347,7 @@
|
||||
"selected": true,
|
||||
"source": "cmdcore.contract",
|
||||
"source_ref": "cmdcore.SchemaDecl",
|
||||
"value": "high"
|
||||
"value": "medium"
|
||||
}
|
||||
],
|
||||
"precedence": "contract_final",
|
||||
@@ -5355,7 +5355,7 @@
|
||||
"review_reason": "Contract final Schema pass-through",
|
||||
"source": "cmdcore.contract",
|
||||
"source_ref": "cmdcore.SchemaDecl",
|
||||
"value": "high"
|
||||
"value": "medium"
|
||||
},
|
||||
"title": {
|
||||
"candidates": [
|
||||
@@ -5528,7 +5528,7 @@
|
||||
"primary_cli_path": "dev app robot disable",
|
||||
"product_id": "dev",
|
||||
"reviewed": true,
|
||||
"risk": "high",
|
||||
"risk": "medium",
|
||||
"source": "reviewed_command_registry",
|
||||
"title": "停用现有应用的机器人能力",
|
||||
"use_when": [
|
||||
@@ -5851,7 +5851,7 @@
|
||||
"selected": true,
|
||||
"source": "cmdcore.contract",
|
||||
"source_ref": "cmdcore.SchemaDecl",
|
||||
"value": "high"
|
||||
"value": "medium"
|
||||
}
|
||||
],
|
||||
"precedence": "contract_final",
|
||||
@@ -5859,7 +5859,7 @@
|
||||
"review_reason": "Contract final Schema pass-through",
|
||||
"source": "cmdcore.contract",
|
||||
"source_ref": "cmdcore.SchemaDecl",
|
||||
"value": "high"
|
||||
"value": "medium"
|
||||
},
|
||||
"title": {
|
||||
"candidates": [
|
||||
@@ -6032,7 +6032,7 @@
|
||||
"primary_cli_path": "dev app enable",
|
||||
"product_id": "dev",
|
||||
"reviewed": true,
|
||||
"risk": "high",
|
||||
"risk": "medium",
|
||||
"source": "reviewed_command_registry",
|
||||
"title": "启用开放平台企业内部应用",
|
||||
"use_when": [
|
||||
@@ -6355,7 +6355,7 @@
|
||||
"selected": true,
|
||||
"source": "cmdcore.contract",
|
||||
"source_ref": "cmdcore.SchemaDecl",
|
||||
"value": "high"
|
||||
"value": "medium"
|
||||
}
|
||||
],
|
||||
"precedence": "contract_final",
|
||||
@@ -6363,7 +6363,7 @@
|
||||
"review_reason": "Contract final Schema pass-through",
|
||||
"source": "cmdcore.contract",
|
||||
"source_ref": "cmdcore.SchemaDecl",
|
||||
"value": "high"
|
||||
"value": "medium"
|
||||
},
|
||||
"title": {
|
||||
"candidates": [
|
||||
@@ -6536,7 +6536,7 @@
|
||||
"primary_cli_path": "dev app robot enable",
|
||||
"product_id": "dev",
|
||||
"reviewed": true,
|
||||
"risk": "high",
|
||||
"risk": "medium",
|
||||
"source": "reviewed_command_registry",
|
||||
"title": "启用现有应用机器人能力(纯启用,无需配置字段)",
|
||||
"use_when": [
|
||||
@@ -14747,7 +14747,7 @@
|
||||
"dry_run": {
|
||||
"preview_kind": "invocation"
|
||||
},
|
||||
"effect": "write",
|
||||
"effect": "destructive",
|
||||
"effect_source": "cmdcore.contract",
|
||||
"examples": [
|
||||
"dws dev app version publish --unified-app-id \u003cunifiedAppId\u003e --version-id \u003cversionId\u003e --dry-run --format json"
|
||||
@@ -14897,7 +14897,7 @@
|
||||
"selected": true,
|
||||
"source": "cmdcore.contract",
|
||||
"source_ref": "cmdcore.SchemaDecl",
|
||||
"value": "write"
|
||||
"value": "destructive"
|
||||
}
|
||||
],
|
||||
"precedence": "contract_final",
|
||||
@@ -14905,7 +14905,7 @@
|
||||
"review_reason": "Contract final Schema pass-through",
|
||||
"source": "cmdcore.contract",
|
||||
"source_ref": "cmdcore.SchemaDecl",
|
||||
"value": "write"
|
||||
"value": "destructive"
|
||||
},
|
||||
"examples": {
|
||||
"candidates": [
|
||||
@@ -16386,7 +16386,7 @@
|
||||
"selected": true,
|
||||
"source": "cmdcore.contract",
|
||||
"source_ref": "cmdcore.SchemaDecl",
|
||||
"value": "high"
|
||||
"value": "medium"
|
||||
}
|
||||
],
|
||||
"precedence": "contract_final",
|
||||
@@ -16394,7 +16394,7 @@
|
||||
"review_reason": "Contract final Schema pass-through",
|
||||
"source": "cmdcore.contract",
|
||||
"source_ref": "cmdcore.SchemaDecl",
|
||||
"value": "high"
|
||||
"value": "medium"
|
||||
},
|
||||
"title": {
|
||||
"candidates": [
|
||||
@@ -16797,7 +16797,7 @@
|
||||
"primary_cli_path": "dev app member remove",
|
||||
"product_id": "dev",
|
||||
"reviewed": true,
|
||||
"risk": "high",
|
||||
"risk": "medium",
|
||||
"source": "reviewed_command_registry",
|
||||
"title": "移除开放平台应用成员",
|
||||
"use_when": [
|
||||
@@ -17120,7 +17120,7 @@
|
||||
"selected": true,
|
||||
"source": "cmdcore.contract",
|
||||
"source_ref": "cmdcore.SchemaDecl",
|
||||
"value": "high"
|
||||
"value": "medium"
|
||||
}
|
||||
],
|
||||
"precedence": "contract_final",
|
||||
@@ -17128,7 +17128,7 @@
|
||||
"review_reason": "Contract final Schema pass-through",
|
||||
"source": "cmdcore.contract",
|
||||
"source_ref": "cmdcore.SchemaDecl",
|
||||
"value": "high"
|
||||
"value": "medium"
|
||||
},
|
||||
"title": {
|
||||
"candidates": [
|
||||
@@ -17416,7 +17416,7 @@
|
||||
"primary_cli_path": "dev app permission remove",
|
||||
"product_id": "dev",
|
||||
"reviewed": true,
|
||||
"risk": "high",
|
||||
"risk": "medium",
|
||||
"source": "reviewed_command_registry",
|
||||
"title": "取消开放平台应用权限点",
|
||||
"use_when": [
|
||||
@@ -18442,7 +18442,7 @@
|
||||
"selected": true,
|
||||
"source": "cmdcore.contract",
|
||||
"source_ref": "cmdcore.SchemaDecl",
|
||||
"value": "high"
|
||||
"value": "medium"
|
||||
}
|
||||
],
|
||||
"precedence": "contract_final",
|
||||
@@ -18450,7 +18450,7 @@
|
||||
"review_reason": "Contract final Schema pass-through",
|
||||
"source": "cmdcore.contract",
|
||||
"source_ref": "cmdcore.SchemaDecl",
|
||||
"value": "high"
|
||||
"value": "medium"
|
||||
},
|
||||
"title": {
|
||||
"candidates": [
|
||||
@@ -20040,7 +20040,7 @@
|
||||
"primary_cli_path": "dev app robot config",
|
||||
"product_id": "dev",
|
||||
"reviewed": true,
|
||||
"risk": "high",
|
||||
"risk": "medium",
|
||||
"source": "reviewed_command_registry",
|
||||
"title": "创建或更新现有应用的机器人配置(upsert)",
|
||||
"use_when": [
|
||||
@@ -20373,7 +20373,7 @@
|
||||
"selected": true,
|
||||
"source": "cmdcore.contract",
|
||||
"source_ref": "cmdcore.SchemaDecl",
|
||||
"value": "high"
|
||||
"value": "medium"
|
||||
}
|
||||
],
|
||||
"precedence": "contract_final",
|
||||
@@ -20381,7 +20381,7 @@
|
||||
"review_reason": "Contract final Schema pass-through",
|
||||
"source": "cmdcore.contract",
|
||||
"source_ref": "cmdcore.SchemaDecl",
|
||||
"value": "high"
|
||||
"value": "medium"
|
||||
},
|
||||
"title": {
|
||||
"candidates": [
|
||||
@@ -21014,7 +21014,7 @@
|
||||
"primary_cli_path": "dev app webapp config",
|
||||
"product_id": "dev",
|
||||
"reviewed": true,
|
||||
"risk": "high",
|
||||
"risk": "medium",
|
||||
"source": "reviewed_command_registry",
|
||||
"title": "配置网页应用能力",
|
||||
"use_when": [
|
||||
@@ -22404,7 +22404,7 @@
|
||||
"selected": true,
|
||||
"source": "cmdcore.contract",
|
||||
"source_ref": "cmdcore.SchemaDecl",
|
||||
"value": "high"
|
||||
"value": "medium"
|
||||
}
|
||||
],
|
||||
"precedence": "contract_final",
|
||||
@@ -22412,7 +22412,7 @@
|
||||
"review_reason": "Contract final Schema pass-through",
|
||||
"source": "cmdcore.contract",
|
||||
"source_ref": "cmdcore.SchemaDecl",
|
||||
"value": "high"
|
||||
"value": "medium"
|
||||
},
|
||||
"title": {
|
||||
"candidates": [
|
||||
@@ -22700,7 +22700,7 @@
|
||||
"primary_cli_path": "dev app event subscribe",
|
||||
"product_id": "dev",
|
||||
"reviewed": true,
|
||||
"risk": "high",
|
||||
"risk": "medium",
|
||||
"source": "reviewed_command_registry",
|
||||
"title": "订阅应用事件回调",
|
||||
"use_when": [
|
||||
@@ -23023,7 +23023,7 @@
|
||||
"selected": true,
|
||||
"source": "cmdcore.contract",
|
||||
"source_ref": "cmdcore.SchemaDecl",
|
||||
"value": "high"
|
||||
"value": "medium"
|
||||
}
|
||||
],
|
||||
"precedence": "contract_final",
|
||||
@@ -23031,7 +23031,7 @@
|
||||
"review_reason": "Contract final Schema pass-through",
|
||||
"source": "cmdcore.contract",
|
||||
"source_ref": "cmdcore.SchemaDecl",
|
||||
"value": "high"
|
||||
"value": "medium"
|
||||
},
|
||||
"title": {
|
||||
"candidates": [
|
||||
@@ -23319,7 +23319,7 @@
|
||||
"primary_cli_path": "dev app event unsubscribe",
|
||||
"product_id": "dev",
|
||||
"reviewed": true,
|
||||
"risk": "high",
|
||||
"risk": "medium",
|
||||
"source": "reviewed_command_registry",
|
||||
"title": "取消订阅应用事件",
|
||||
"use_when": [
|
||||
@@ -23651,7 +23651,7 @@
|
||||
"selected": true,
|
||||
"source": "cmdcore.contract",
|
||||
"source_ref": "cmdcore.SchemaDecl",
|
||||
"value": "high"
|
||||
"value": "medium"
|
||||
}
|
||||
],
|
||||
"precedence": "contract_final",
|
||||
@@ -23659,7 +23659,7 @@
|
||||
"review_reason": "Contract final Schema pass-through",
|
||||
"source": "cmdcore.contract",
|
||||
"source_ref": "cmdcore.SchemaDecl",
|
||||
"value": "high"
|
||||
"value": "medium"
|
||||
},
|
||||
"title": {
|
||||
"candidates": [
|
||||
@@ -24177,7 +24177,7 @@
|
||||
"primary_cli_path": "dev app update",
|
||||
"product_id": "dev",
|
||||
"reviewed": true,
|
||||
"risk": "high",
|
||||
"risk": "medium",
|
||||
"source": "reviewed_command_registry",
|
||||
"title": "修改开放平台企业内部应用基础信息",
|
||||
"use_when": [
|
||||
@@ -24509,7 +24509,7 @@
|
||||
"selected": true,
|
||||
"source": "cmdcore.contract",
|
||||
"source_ref": "cmdcore.SchemaDecl",
|
||||
"value": "high"
|
||||
"value": "medium"
|
||||
}
|
||||
],
|
||||
"precedence": "contract_final",
|
||||
@@ -24517,7 +24517,7 @@
|
||||
"review_reason": "Contract final Schema pass-through",
|
||||
"source": "cmdcore.contract",
|
||||
"source_ref": "cmdcore.SchemaDecl",
|
||||
"value": "high"
|
||||
"value": "medium"
|
||||
},
|
||||
"title": {
|
||||
"candidates": [
|
||||
@@ -25035,7 +25035,7 @@
|
||||
"primary_cli_path": "dev app security config",
|
||||
"product_id": "dev",
|
||||
"reviewed": true,
|
||||
"risk": "high",
|
||||
"risk": "medium",
|
||||
"source": "reviewed_command_registry",
|
||||
"title": "更新开放平台应用安全配置",
|
||||
"use_when": [
|
||||
|
||||
+105
-34
@@ -155,6 +155,44 @@ func (r Risk) Effective() Risk {
|
||||
return r
|
||||
}
|
||||
|
||||
// SafetyDefault returns the Safety tier this Risk level implies when no
|
||||
// explicit Safety is declared. It is the composition seam: Risk drives
|
||||
// runtime confirmation, Safety drives Schema metadata, and SafetyDefault
|
||||
// bridges the two when only Risk is declared.
|
||||
func (r Risk) SafetyDefault() Safety {
|
||||
switch r.Effective() {
|
||||
case RiskWrite:
|
||||
return SafetyWrite
|
||||
case RiskHighWrite:
|
||||
return SafetyDestructive
|
||||
default:
|
||||
return SafetyRead
|
||||
}
|
||||
}
|
||||
|
||||
// Safety declares the Schema safety metadata tier, projected into
|
||||
// agent-facing Schema independently of the runtime Risk. Empty == SafetyRead.
|
||||
type Safety string
|
||||
|
||||
const (
|
||||
// SafetyRead is a read-only operation: read/low/not_required/idempotent.
|
||||
SafetyRead Safety = "read"
|
||||
// SafetyWrite is a reversible mutation: write/medium/user_required/unknown.
|
||||
SafetyWrite Safety = "write"
|
||||
// SafetyHighWrite is a hard-to-reverse mutation: write/high/user_required/unknown.
|
||||
SafetyHighWrite Safety = "high-write"
|
||||
// SafetyDestructive is a destructive operation: destructive/high/user_required/unknown.
|
||||
SafetyDestructive Safety = "destructive"
|
||||
)
|
||||
|
||||
// Effective returns the effective safety tier, defaulting empty to read.
|
||||
func (s Safety) Effective() Safety {
|
||||
if s == "" {
|
||||
return SafetyRead
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
// ConstraintKind is the type of a cross-flag relationship constraint. Values
|
||||
// match the shortcut framework's ConstraintKind verbatim.
|
||||
type ConstraintKind string
|
||||
@@ -218,6 +256,10 @@ type CommandSpec struct {
|
||||
Flags []FlagSpec
|
||||
Constraints []Constraint
|
||||
Risk Risk
|
||||
// Safety declares the Schema safety tier independently of the runtime
|
||||
// Risk. Empty falls back to Risk.SafetyDefault(); explicit SafetyDecl
|
||||
// string fields always win over the tier fill.
|
||||
Safety Safety
|
||||
// ConfirmFirst runs the Risk write-confirmation before required/constraint/
|
||||
// Validate checks instead of after them. Use it where the legacy semantics
|
||||
// were guard-first (a write without --yes fails fast with
|
||||
@@ -898,7 +940,7 @@ func embedSchemaDecl(cmd *cobra.Command, spec CommandSpec) {
|
||||
payload := cli.ContractFinalPayload{
|
||||
Title: firstNonEmpty(schema.Title, spec.Short),
|
||||
Description: firstNonEmpty(schema.Description, spec.Long),
|
||||
Safety: schemaSafetyFromDecl(spec.Risk, schema.Safety),
|
||||
Safety: schemaSafetyFromDecl(spec.Risk, spec.Safety, schema.Safety),
|
||||
}
|
||||
if n := len(schema.Positionals); n > 0 {
|
||||
payload.Positionals = make([]cli.RuntimeSchemaPositional, n)
|
||||
@@ -959,45 +1001,74 @@ func firstNonEmpty(values ...string) string {
|
||||
return ""
|
||||
}
|
||||
|
||||
func schemaSafetyFromDecl(risk Risk, decl SafetyDecl) *cli.SafetySpec {
|
||||
// schemaSafetyFromDecl composes the Schema safety metadata from three
|
||||
// sources, in precedence order: explicit SafetyDecl string fields (highest)
|
||||
// > the declared Safety tier enum > Risk.SafetyDefault() (lowest). The tier
|
||||
// fill also covers Idempotency (idempotent for reads, unknown for writes),
|
||||
// so a plain Risk/Safety enum declaration is self-sufficient.
|
||||
func schemaSafetyFromDecl(risk Risk, safety Safety, decl SafetyDecl) *cli.SafetySpec {
|
||||
out := cli.SafetySpec{
|
||||
Effect: strings.TrimSpace(decl.Effect),
|
||||
Risk: strings.TrimSpace(decl.Risk),
|
||||
Confirmation: strings.TrimSpace(decl.Confirmation),
|
||||
Idempotency: strings.TrimSpace(decl.Idempotency),
|
||||
}
|
||||
if strings.TrimSpace(string(risk)) != "" {
|
||||
switch risk.Effective() {
|
||||
case RiskWrite:
|
||||
if out.Effect == "" {
|
||||
out.Effect = "write"
|
||||
}
|
||||
if out.Risk == "" {
|
||||
out.Risk = "medium"
|
||||
}
|
||||
if out.Confirmation == "" {
|
||||
out.Confirmation = "user_required"
|
||||
}
|
||||
case RiskHighWrite:
|
||||
if out.Effect == "" {
|
||||
out.Effect = "destructive"
|
||||
}
|
||||
if out.Risk == "" {
|
||||
out.Risk = "high"
|
||||
}
|
||||
if out.Confirmation == "" {
|
||||
out.Confirmation = "user_required"
|
||||
}
|
||||
case RiskRead:
|
||||
if out.Effect == "" {
|
||||
out.Effect = "read"
|
||||
}
|
||||
if out.Risk == "" {
|
||||
out.Risk = "low"
|
||||
}
|
||||
if out.Confirmation == "" {
|
||||
out.Confirmation = "not_required"
|
||||
}
|
||||
tier := safety
|
||||
if tier == "" {
|
||||
tier = risk.SafetyDefault()
|
||||
}
|
||||
switch tier.Effective() {
|
||||
case SafetyWrite:
|
||||
if out.Effect == "" {
|
||||
out.Effect = "write"
|
||||
}
|
||||
if out.Risk == "" {
|
||||
out.Risk = "medium"
|
||||
}
|
||||
if out.Confirmation == "" {
|
||||
out.Confirmation = "user_required"
|
||||
}
|
||||
if out.Idempotency == "" {
|
||||
out.Idempotency = "unknown"
|
||||
}
|
||||
case SafetyHighWrite:
|
||||
if out.Effect == "" {
|
||||
out.Effect = "write"
|
||||
}
|
||||
if out.Risk == "" {
|
||||
out.Risk = "high"
|
||||
}
|
||||
if out.Confirmation == "" {
|
||||
out.Confirmation = "user_required"
|
||||
}
|
||||
if out.Idempotency == "" {
|
||||
out.Idempotency = "unknown"
|
||||
}
|
||||
case SafetyDestructive:
|
||||
if out.Effect == "" {
|
||||
out.Effect = "destructive"
|
||||
}
|
||||
if out.Risk == "" {
|
||||
out.Risk = "high"
|
||||
}
|
||||
if out.Confirmation == "" {
|
||||
out.Confirmation = "user_required"
|
||||
}
|
||||
if out.Idempotency == "" {
|
||||
out.Idempotency = "unknown"
|
||||
}
|
||||
default: // SafetyRead
|
||||
if out.Effect == "" {
|
||||
out.Effect = "read"
|
||||
}
|
||||
if out.Risk == "" {
|
||||
out.Risk = "low"
|
||||
}
|
||||
if out.Confirmation == "" {
|
||||
out.Confirmation = "not_required"
|
||||
}
|
||||
if out.Idempotency == "" {
|
||||
out.Idempotency = "idempotent"
|
||||
}
|
||||
}
|
||||
// effect_source is assembly-derived for every Contract-declared safety,
|
||||
|
||||
@@ -48,8 +48,9 @@ type PositionalDecl struct {
|
||||
Index int
|
||||
}
|
||||
|
||||
// SafetyDecl is the final Schema Safety payload. Empty Effect/Risk/Confirmation
|
||||
// may be filled from CommandSpec.Risk at embed time; Idempotency is declaration-only.
|
||||
// SafetyDecl is the final Schema Safety payload. Any field left empty is
|
||||
// filled from the CommandSpec.Safety tier (or Risk.SafetyDefault() when
|
||||
// Safety is unset) at embed time, including Idempotency.
|
||||
type SafetyDecl struct {
|
||||
Effect string
|
||||
Risk string
|
||||
@@ -126,18 +127,11 @@ func validateSchemaDecl(spec CommandSpec) {
|
||||
if len(spec.Schema.Selection.Examples) == 0 {
|
||||
missing = append(missing, "Schema.Selection.Examples")
|
||||
}
|
||||
// Safety/interface are unconditional catalog required keys for declared
|
||||
// tools (no hints fallback). effect/risk/confirmation may come from the
|
||||
// Risk shorthand; Idempotency is declaration-only.
|
||||
safety := spec.Schema.Safety
|
||||
safetyCoreFilled := strings.TrimSpace(safety.Effect) != "" &&
|
||||
strings.TrimSpace(safety.Risk) != "" && strings.TrimSpace(safety.Confirmation) != ""
|
||||
if !safetyCoreFilled && strings.TrimSpace(string(spec.Risk)) == "" {
|
||||
missing = append(missing, "Schema.Safety (effect/risk/confirmation, or CommandSpec.Risk)")
|
||||
}
|
||||
if strings.TrimSpace(safety.Idempotency) == "" {
|
||||
missing = append(missing, "Schema.Safety.Idempotency")
|
||||
}
|
||||
// Interface is an unconditional catalog required key for declared tools
|
||||
// (no hints fallback). Safety needs no completeness check: the enum tier
|
||||
// (CommandSpec.Safety, falling back to Risk.SafetyDefault()) fills every
|
||||
// Safety field including Idempotency, so any declared Schema projects a
|
||||
// complete safety block by construction.
|
||||
if iface := spec.Schema.Interface; iface == nil ||
|
||||
strings.TrimSpace(iface.Mode) == "" || strings.TrimSpace(iface.Availability) == "" {
|
||||
missing = append(missing, "Schema.Interface (mode/availability)")
|
||||
|
||||
@@ -124,17 +124,6 @@ func TestNewCommandPanicsOnPartialSchemaDecl(t *testing.T) {
|
||||
Interface: &InterfaceDecl{Mode: "mcp", Availability: "available", ProductID: "dev", RPCName: "get_thing"},
|
||||
Selection: SelectionDecl{AgentSummary: "s", UseWhen: []string{"u"}, AvoidWhen: []string{"a"}},
|
||||
}, "Schema.Selection.Examples"},
|
||||
{"missing safety", SchemaDecl{
|
||||
Description: "d",
|
||||
Interface: &InterfaceDecl{Mode: "mcp", Availability: "available", ProductID: "dev", RPCName: "get_thing"},
|
||||
Selection: SelectionDecl{AgentSummary: "s", UseWhen: []string{"u"}, AvoidWhen: []string{"a"}, Examples: []string{"dws x"}},
|
||||
}, "Schema.Safety"},
|
||||
{"missing idempotency", SchemaDecl{
|
||||
Description: "d",
|
||||
Safety: SafetyDecl{Effect: "read", Risk: "low", Confirmation: "not_required"},
|
||||
Interface: &InterfaceDecl{Mode: "mcp", Availability: "available", ProductID: "dev", RPCName: "get_thing"},
|
||||
Selection: SelectionDecl{AgentSummary: "s", UseWhen: []string{"u"}, AvoidWhen: []string{"a"}, Examples: []string{"dws x"}},
|
||||
}, "Schema.Safety.Idempotency"},
|
||||
{"missing interface", SchemaDecl{
|
||||
Description: "d",
|
||||
Safety: SafetyDecl{Effect: "read", Risk: "low", Confirmation: "not_required", Idempotency: "idempotent"},
|
||||
@@ -203,6 +192,51 @@ func TestNewCommandDerivesHelpExampleFromDeclaredSelection(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestNewCommandSafetyTierComposition(t *testing.T) {
|
||||
schema := func() SchemaDecl {
|
||||
return SchemaDecl{
|
||||
Description: "desc",
|
||||
Interface: &InterfaceDecl{Mode: "mcp", Availability: "available", ProductID: "dev", RPCName: "op"},
|
||||
Selection: SelectionDecl{
|
||||
AgentSummary: "s", UseWhen: []string{"u"}, AvoidWhen: []string{"a"}, Examples: []string{"dws x"},
|
||||
},
|
||||
}
|
||||
}
|
||||
build := func(spec CommandSpec) *cli.SafetySpec {
|
||||
cmd := NewCommand(spec)
|
||||
final, ok := cli.RuntimeContractFinal(cmd)
|
||||
if !ok || final.Safety == nil {
|
||||
t.Fatalf("expected declared safety, final=%#v ok=%v", final, ok)
|
||||
}
|
||||
return final.Safety
|
||||
}
|
||||
|
||||
// Risk-only: tier inferred from Risk.SafetyDefault(), including idempotency.
|
||||
if got := build(CommandSpec{Use: "w", Short: "w", Risk: RiskWrite, Schema: schema(),
|
||||
Invoke: func(*Ctx, map[string]any) error { return nil }}); got.Effect != "write" || got.Risk != "medium" ||
|
||||
got.Confirmation != "user_required" || got.Idempotency != "unknown" {
|
||||
t.Fatalf("RiskWrite default tier = %#v", got)
|
||||
}
|
||||
// Safety enum overrides the Risk default (high-write over destructive).
|
||||
if got := build(CommandSpec{Use: "w", Short: "w", Risk: RiskHighWrite, Safety: SafetyHighWrite, Schema: schema(),
|
||||
Invoke: func(*Ctx, map[string]any) error { return nil }}); got.Effect != "write" || got.Risk != "high" {
|
||||
t.Fatalf("explicit Safety tier must win over Risk default, = %#v", got)
|
||||
}
|
||||
// Explicit SafetyDecl string fields win over the tier fill.
|
||||
s := schema()
|
||||
s.Safety = SafetyDecl{Effect: "destructive"}
|
||||
if got := build(CommandSpec{Use: "w", Short: "w", Risk: RiskWrite, Schema: s,
|
||||
Invoke: func(*Ctx, map[string]any) error { return nil }}); got.Effect != "destructive" || got.Risk != "medium" {
|
||||
t.Fatalf("SafetyDecl field must win over tier fill, = %#v", got)
|
||||
}
|
||||
// Empty Risk + empty Safety infers the read tier.
|
||||
if got := build(CommandSpec{Use: "r", Short: "r", Schema: schema(),
|
||||
Invoke: func(*Ctx, map[string]any) error { return nil }}); got.Effect != "read" || got.Risk != "low" ||
|
||||
got.Confirmation != "not_required" || got.Idempotency != "idempotent" {
|
||||
t.Fatalf("empty Risk/Safety must infer read tier, = %#v", got)
|
||||
}
|
||||
}
|
||||
|
||||
func TestSchemaDeclEmptySkipsFinal(t *testing.T) {
|
||||
cmd := NewCommand(CommandSpec{
|
||||
Use: "get",
|
||||
|
||||
+30
-56
@@ -266,7 +266,6 @@ func newDevAppEventListCommand(runner executor.Runner) *cobra.Command {
|
||||
},
|
||||
Schema: LeafSchema{
|
||||
Description: "查询应用已订阅的事件列表",
|
||||
Safety: devAppReadSafety,
|
||||
DryRun: devAppDryRun,
|
||||
Interface: devAppCompositeInterface(),
|
||||
Selection: LeafSelectionDecl{
|
||||
@@ -288,6 +287,7 @@ func newDevAppEventSubscribeCommand(runner executor.Runner) *cobra.Command {
|
||||
Example: " dws dev app event subscribe --unified-app-id UNIFIED_APP_ID --event-codes bpms_task_change --dry-run --format json",
|
||||
Tool: devAppEventSubscribeTool,
|
||||
Risk: LeafRiskWrite,
|
||||
Safety: LeafSafetyWrite,
|
||||
// devapp 旧版写守卫为 guard-first:确认门先于参数校验。
|
||||
ConfirmFirst: true,
|
||||
Flags: []LeafFlag{
|
||||
@@ -296,7 +296,6 @@ func newDevAppEventSubscribeCommand(runner executor.Runner) *cobra.Command {
|
||||
},
|
||||
Schema: LeafSchema{
|
||||
Description: "订阅应用事件回调",
|
||||
Safety: devAppWriteSafety,
|
||||
DryRun: devAppDryRun,
|
||||
Interface: devAppCompositeInterface(),
|
||||
Selection: LeafSelectionDecl{
|
||||
@@ -318,6 +317,7 @@ func newDevAppEventUnsubscribeCommand(runner executor.Runner) *cobra.Command {
|
||||
Example: " dws dev app event unsubscribe --unified-app-id UNIFIED_APP_ID --event-codes bpms_task_change --dry-run --format json",
|
||||
Tool: devAppEventUnsubscribeTool,
|
||||
Risk: LeafRiskWrite,
|
||||
Safety: LeafSafetyWrite,
|
||||
// devapp 旧版写守卫为 guard-first:确认门先于参数校验。
|
||||
ConfirmFirst: true,
|
||||
Flags: []LeafFlag{
|
||||
@@ -326,7 +326,6 @@ func newDevAppEventUnsubscribeCommand(runner executor.Runner) *cobra.Command {
|
||||
},
|
||||
Schema: LeafSchema{
|
||||
Description: "取消订阅应用事件",
|
||||
Safety: devAppWriteSafety,
|
||||
DryRun: devAppDryRun,
|
||||
Interface: devAppCompositeInterface(),
|
||||
Selection: LeafSelectionDecl{
|
||||
@@ -360,7 +359,6 @@ func newDevAppListCommand(runner executor.Runner) *cobra.Command {
|
||||
},
|
||||
Schema: LeafSchema{
|
||||
Description: "查询开放平台企业内部应用列表",
|
||||
Safety: devAppReadSafety,
|
||||
DryRun: devAppDryRun,
|
||||
Interface: devAppCompositeInterface(),
|
||||
Selection: LeafSelectionDecl{
|
||||
@@ -390,7 +388,6 @@ func newDevAppGetCommand(runner executor.Runner) *cobra.Command {
|
||||
},
|
||||
Schema: LeafSchema{
|
||||
Description: "查询开放平台企业内部应用详情",
|
||||
Safety: devAppReadSafety,
|
||||
DryRun: devAppDryRun,
|
||||
Interface: devAppCompositeInterface(),
|
||||
Selection: LeafSelectionDecl{
|
||||
@@ -414,7 +411,8 @@ func newDevAppCreateCommand(runner executor.Runner) *cobra.Command {
|
||||
Short: "创建开放平台企业内部应用",
|
||||
Example: " dws dev app create --name DemoApp --desc 内部应用 --dry-run --format json",
|
||||
Tool: devAppCreateTool,
|
||||
Risk: LeafRiskWrite,
|
||||
Risk: LeafRiskHighWrite,
|
||||
Safety: LeafSafetyHighWrite,
|
||||
// devapp 旧版写守卫为 guard-first:确认门先于参数校验。
|
||||
ConfirmFirst: true,
|
||||
Flags: []LeafFlag{
|
||||
@@ -424,7 +422,6 @@ func newDevAppCreateCommand(runner executor.Runner) *cobra.Command {
|
||||
},
|
||||
Schema: LeafSchema{
|
||||
Description: "创建开放平台企业内部应用",
|
||||
Safety: devAppWriteSafety,
|
||||
DryRun: devAppDryRun,
|
||||
Interface: devAppCompositeInterface(),
|
||||
Selection: LeafSelectionDecl{
|
||||
@@ -447,6 +444,7 @@ func newDevAppUpdateCommand(runner executor.Runner) *cobra.Command {
|
||||
Example: " dws dev app update --unified-app-id UNIFIED_APP_ID --name DemoApp2 --dry-run --format json",
|
||||
Tool: devAppUpdateTool,
|
||||
Risk: LeafRiskWrite,
|
||||
Safety: LeafSafetyWrite,
|
||||
// devapp 旧版写守卫为 guard-first:确认门先于参数校验。
|
||||
ConfirmFirst: true,
|
||||
Flags: []LeafFlag{
|
||||
@@ -460,7 +458,6 @@ func newDevAppUpdateCommand(runner executor.Runner) *cobra.Command {
|
||||
},
|
||||
Schema: LeafSchema{
|
||||
Description: "修改开放平台企业内部应用基础信息",
|
||||
Safety: devAppWriteSafety,
|
||||
DryRun: devAppDryRun,
|
||||
Interface: devAppCompositeInterface(),
|
||||
Selection: LeafSelectionDecl{
|
||||
@@ -486,7 +483,6 @@ func newDevAppCredentialsGetCommand(runner executor.Runner) *cobra.Command {
|
||||
},
|
||||
Schema: LeafSchema{
|
||||
Description: "读取开放平台应用凭证",
|
||||
Safety: devAppReadSafety,
|
||||
DryRun: devAppDryRun,
|
||||
Interface: devAppCompositeInterface(),
|
||||
Selection: LeafSelectionDecl{
|
||||
@@ -503,10 +499,11 @@ func newDevAppCredentialsGetCommand(runner executor.Runner) *cobra.Command {
|
||||
|
||||
func newDevAppLifecycleCommand(runner executor.Runner, use, short, tool string, selection LeafSelectionDecl) *cobra.Command {
|
||||
return NewLeafCommand(LeafSpec{
|
||||
Use: use,
|
||||
Short: short,
|
||||
Tool: tool,
|
||||
Risk: LeafRiskWrite,
|
||||
Use: use,
|
||||
Short: short,
|
||||
Tool: tool,
|
||||
Risk: LeafRiskWrite,
|
||||
Safety: LeafSafetyWrite,
|
||||
// devapp 旧版写守卫为 guard-first:确认门先于参数校验。
|
||||
ConfirmFirst: true,
|
||||
Flags: []LeafFlag{
|
||||
@@ -514,7 +511,6 @@ func newDevAppLifecycleCommand(runner executor.Runner, use, short, tool string,
|
||||
},
|
||||
Schema: LeafSchema{
|
||||
Description: short,
|
||||
Safety: devAppWriteSafety,
|
||||
DryRun: devAppDryRun,
|
||||
Interface: devAppCompositeInterface(),
|
||||
Selection: selection,
|
||||
@@ -542,13 +538,13 @@ func newDevAppDeleteCommand(runner executor.Runner) *cobra.Command {
|
||||
Example: " dws dev app delete --unified-app-id UNIFIED_APP_ID --confirm-name 应用名 --yes --format json",
|
||||
Tool: devAppDeleteTool,
|
||||
Risk: LeafRiskHighWrite,
|
||||
Safety: LeafSafetyDestructive,
|
||||
Flags: []LeafFlag{
|
||||
{Name: "unified-app-id", Usage: "开放平台统一应用 ID(必填)", Bind: "unifiedAppId", Trim: true, Required: true, RequiredHint: "--unified-app-id 为必填"},
|
||||
{Name: "confirm-name", Usage: "二次确认:必须与被删应用的名称一致(不可逆操作的防误删)", Bind: "confirmName", Trim: true, OmitEmpty: true},
|
||||
},
|
||||
Schema: LeafSchema{
|
||||
Description: "删除开放平台企业内部应用(不可逆,需 --confirm-name 二次确认)",
|
||||
Safety: devAppDeleteSafety,
|
||||
DryRun: devAppDryRun,
|
||||
Interface: devAppCompositeInterface(),
|
||||
Selection: LeafSelectionDecl{
|
||||
@@ -645,7 +641,6 @@ func newDevAppWebappGetCommand(runner executor.Runner) *cobra.Command {
|
||||
},
|
||||
Schema: LeafSchema{
|
||||
Description: "查询网页应用配置",
|
||||
Safety: devAppReadSafety,
|
||||
DryRun: devAppDryRun,
|
||||
Interface: devAppCompositeInterface(),
|
||||
Selection: LeafSelectionDecl{
|
||||
@@ -667,6 +662,7 @@ func newDevAppWebappConfigCommand(runner executor.Runner) *cobra.Command {
|
||||
Example: " dws dev app webapp config --unified-app-id UNIFIED_APP_ID --homepage-url https://example.com --dry-run --format json",
|
||||
Tool: devAppWebappSetTool,
|
||||
Risk: LeafRiskWrite,
|
||||
Safety: LeafSafetyWrite,
|
||||
// devapp 旧版写守卫为 guard-first:确认门先于参数校验。
|
||||
ConfirmFirst: true,
|
||||
Flags: []LeafFlag{
|
||||
@@ -681,7 +677,6 @@ func newDevAppWebappConfigCommand(runner executor.Runner) *cobra.Command {
|
||||
},
|
||||
Schema: LeafSchema{
|
||||
Description: "配置网页应用能力",
|
||||
Safety: devAppWriteSafety,
|
||||
DryRun: devAppDryRun,
|
||||
Interface: devAppCompositeInterface(),
|
||||
Selection: LeafSelectionDecl{
|
||||
@@ -713,7 +708,6 @@ func newDevAppPermissionListCommand(runner executor.Runner) *cobra.Command {
|
||||
},
|
||||
Schema: LeafSchema{
|
||||
Description: "查询开放平台应用权限列表",
|
||||
Safety: devAppReadSafety,
|
||||
DryRun: devAppDryRun,
|
||||
Interface: devAppCompositeInterface(),
|
||||
Selection: LeafSelectionDecl{
|
||||
@@ -738,6 +732,7 @@ func newDevAppPermissionAddCommand(runner executor.Runner) *cobra.Command {
|
||||
Example: " dws dev app permission add --unified-app-id UNIFIED_APP_ID --scope-values Contact.User.mobile --dry-run --format json",
|
||||
Tool: devAppPermissionAddTool,
|
||||
Risk: LeafRiskWrite,
|
||||
Safety: LeafSafetyWrite,
|
||||
// devapp 旧版写守卫为 guard-first:确认门先于参数校验。
|
||||
ConfirmFirst: true,
|
||||
Flags: []LeafFlag{
|
||||
@@ -746,7 +741,6 @@ func newDevAppPermissionAddCommand(runner executor.Runner) *cobra.Command {
|
||||
},
|
||||
Schema: LeafSchema{
|
||||
Description: "申请开放平台应用权限点",
|
||||
Safety: devAppWriteSafety,
|
||||
DryRun: devAppDryRun,
|
||||
Interface: devAppCompositeInterface(),
|
||||
Selection: LeafSelectionDecl{
|
||||
@@ -768,6 +762,7 @@ func newDevAppPermissionRemoveCommand(runner executor.Runner) *cobra.Command {
|
||||
Example: " dws dev app permission remove --unified-app-id UNIFIED_APP_ID --scope-values Contact.User.mobile,qyapi_robot_sendmsg --dry-run --format json",
|
||||
Tool: devAppPermissionRmTool,
|
||||
Risk: LeafRiskWrite,
|
||||
Safety: LeafSafetyWrite,
|
||||
// devapp 旧版写守卫为 guard-first:确认门先于参数校验。
|
||||
ConfirmFirst: true,
|
||||
Flags: []LeafFlag{
|
||||
@@ -776,7 +771,6 @@ func newDevAppPermissionRemoveCommand(runner executor.Runner) *cobra.Command {
|
||||
},
|
||||
Schema: LeafSchema{
|
||||
Description: "取消开放平台应用权限点",
|
||||
Safety: devAppWriteSafety,
|
||||
DryRun: devAppDryRun,
|
||||
Interface: devAppCompositeInterface(),
|
||||
Selection: LeafSelectionDecl{
|
||||
@@ -802,7 +796,6 @@ func newDevAppMemberListCommand(runner executor.Runner) *cobra.Command {
|
||||
},
|
||||
Schema: LeafSchema{
|
||||
Description: "查询开放平台应用成员",
|
||||
Safety: devAppReadSafety,
|
||||
DryRun: devAppDryRun,
|
||||
Interface: devAppCompositeInterface(),
|
||||
Selection: LeafSelectionDecl{
|
||||
@@ -824,6 +817,7 @@ func newDevAppMemberAddCommand(runner executor.Runner) *cobra.Command {
|
||||
Example: " dws dev app member add --unified-app-id <unifiedAppId> --user-ids userId1,userId2 --member-type DEVELOPER --dry-run",
|
||||
Tool: devAppMemberAddTool,
|
||||
Risk: LeafRiskWrite,
|
||||
Safety: LeafSafetyWrite,
|
||||
// devapp 旧版写守卫为 guard-first:确认门先于参数校验。
|
||||
ConfirmFirst: true,
|
||||
Flags: []LeafFlag{
|
||||
@@ -841,7 +835,6 @@ func newDevAppMemberAddCommand(runner executor.Runner) *cobra.Command {
|
||||
},
|
||||
Schema: LeafSchema{
|
||||
Description: "添加开放平台应用成员",
|
||||
Safety: devAppWriteSafety,
|
||||
DryRun: devAppDryRun,
|
||||
Interface: devAppCompositeInterface(),
|
||||
Selection: LeafSelectionDecl{
|
||||
@@ -863,6 +856,7 @@ func newDevAppMemberRemoveCommand(runner executor.Runner) *cobra.Command {
|
||||
Example: " dws dev app member remove --unified-app-id <unifiedAppId> --user-ids userId1,userId2 --member-type DEVELOPER --dry-run",
|
||||
Tool: devAppMemberRemoveTool,
|
||||
Risk: LeafRiskWrite,
|
||||
Safety: LeafSafetyWrite,
|
||||
// devapp 旧版写守卫为 guard-first:确认门先于参数校验。
|
||||
ConfirmFirst: true,
|
||||
Flags: []LeafFlag{
|
||||
@@ -880,7 +874,6 @@ func newDevAppMemberRemoveCommand(runner executor.Runner) *cobra.Command {
|
||||
},
|
||||
Schema: LeafSchema{
|
||||
Description: "移除开放平台应用成员",
|
||||
Safety: devAppWriteSafety,
|
||||
DryRun: devAppDryRun,
|
||||
Interface: devAppCompositeInterface(),
|
||||
Selection: LeafSelectionDecl{
|
||||
@@ -901,8 +894,9 @@ func newDevAppSecurityConfigCommand(runner executor.Runner) *cobra.Command {
|
||||
Short: "更新开放平台应用安全配置",
|
||||
Example: " dws dev app security config --unified-app-id <unifiedAppId> " +
|
||||
"--ip-whitelist 192.0.2.10 --redirect-urls https://callback.example.invalid/callback --sso-urls https://sso.example.invalid/sso --dry-run",
|
||||
Tool: devAppSecurityConfigTool,
|
||||
Risk: LeafRiskWrite,
|
||||
Tool: devAppSecurityConfigTool,
|
||||
Risk: LeafRiskWrite,
|
||||
Safety: LeafSafetyWrite,
|
||||
// devapp 旧版写守卫为 guard-first:确认门先于参数校验。
|
||||
ConfirmFirst: true,
|
||||
Flags: []LeafFlag{
|
||||
@@ -916,7 +910,6 @@ func newDevAppSecurityConfigCommand(runner executor.Runner) *cobra.Command {
|
||||
},
|
||||
Schema: LeafSchema{
|
||||
Description: "更新开放平台应用安全配置",
|
||||
Safety: devAppWriteSafety,
|
||||
DryRun: devAppDryRun,
|
||||
Interface: devAppCompositeInterface(),
|
||||
Selection: LeafSelectionDecl{
|
||||
@@ -945,7 +938,8 @@ func newDevAppRobotSubmitCommand(runner executor.Runner) *cobra.Command {
|
||||
Short: "异步提交钉钉智能体机器人创建任务(支持失败重试)",
|
||||
Example: " dws dev app robot submit --name 我的智能体 --robot-name 小助手 --desc \"处理审批问答\" --dry-run --format json",
|
||||
Tool: devAppRobotSubmitTool,
|
||||
Risk: LeafRiskWrite,
|
||||
Risk: LeafRiskHighWrite,
|
||||
Safety: LeafSafetyHighWrite,
|
||||
// devapp 旧版写守卫为 guard-first:确认门先于参数校验。
|
||||
ConfirmFirst: true,
|
||||
Flags: []LeafFlag{
|
||||
@@ -958,7 +952,6 @@ func newDevAppRobotSubmitCommand(runner executor.Runner) *cobra.Command {
|
||||
},
|
||||
Schema: LeafSchema{
|
||||
Description: "异步提交钉钉智能体机器人创建任务(支持失败重试)",
|
||||
Safety: devAppWriteSafety,
|
||||
DryRun: devAppDryRun,
|
||||
Interface: devAppCompositeInterface(),
|
||||
Selection: LeafSelectionDecl{
|
||||
@@ -1002,7 +995,6 @@ func newDevAppRobotResultCommand(runner executor.Runner) *cobra.Command {
|
||||
},
|
||||
Schema: LeafSchema{
|
||||
Description: "查询机器人异步创建任务结果",
|
||||
Safety: devAppReadSafety,
|
||||
DryRun: devAppDryRun,
|
||||
Interface: devAppCompositeInterface(),
|
||||
Selection: LeafSelectionDecl{
|
||||
@@ -1028,7 +1020,6 @@ func newDevAppRobotConfigGetCommand(runner executor.Runner) *cobra.Command {
|
||||
},
|
||||
Schema: LeafSchema{
|
||||
Description: "查询现有应用的机器人配置",
|
||||
Safety: devAppReadSafety,
|
||||
DryRun: devAppDryRun,
|
||||
Interface: devAppCompositeInterface(),
|
||||
Selection: LeafSelectionDecl{
|
||||
@@ -1059,6 +1050,7 @@ func newDevAppRobotConfigCommand(runner executor.Runner) *cobra.Command {
|
||||
Example: " dws dev app robot config --unified-app-id UNIFIED_APP_ID --name 小助手 --brief 审批助手 --dry-run --format json",
|
||||
Tool: devAppRobotConfigUpsertTool,
|
||||
Risk: LeafRiskWrite,
|
||||
Safety: LeafSafetyWrite,
|
||||
// devapp 旧版写守卫为 guard-first:确认门先于参数校验。
|
||||
ConfirmFirst: true,
|
||||
Flags: []LeafFlag{
|
||||
@@ -1079,7 +1071,6 @@ func newDevAppRobotConfigCommand(runner executor.Runner) *cobra.Command {
|
||||
},
|
||||
Schema: LeafSchema{
|
||||
Description: "创建或更新现有应用的机器人配置(upsert)",
|
||||
Safety: devAppWriteSafety,
|
||||
DryRun: devAppDryRun,
|
||||
Interface: devAppCompositeInterface(),
|
||||
Selection: LeafSelectionDecl{
|
||||
@@ -1119,6 +1110,7 @@ func newDevAppRobotEnableCommand(runner executor.Runner) *cobra.Command {
|
||||
Example: " dws dev app robot enable --unified-app-id UNIFIED_APP_ID --dry-run --format json",
|
||||
Tool: devAppRobotEnableTool,
|
||||
Risk: LeafRiskWrite,
|
||||
Safety: LeafSafetyWrite,
|
||||
// devapp 旧版写守卫为 guard-first:确认门先于参数校验。
|
||||
ConfirmFirst: true,
|
||||
Flags: []LeafFlag{
|
||||
@@ -1126,7 +1118,6 @@ func newDevAppRobotEnableCommand(runner executor.Runner) *cobra.Command {
|
||||
},
|
||||
Schema: LeafSchema{
|
||||
Description: "启用现有应用机器人能力(纯启用,无需配置字段)",
|
||||
Safety: devAppWriteSafety,
|
||||
DryRun: devAppDryRun,
|
||||
Interface: devAppCompositeInterface(),
|
||||
Selection: LeafSelectionDecl{
|
||||
@@ -1148,6 +1139,7 @@ func newDevAppRobotOfflineCommand(runner executor.Runner) *cobra.Command {
|
||||
Example: " dws dev app robot disable --unified-app-id UNIFIED_APP_ID --dry-run --format json",
|
||||
Tool: devAppRobotOfflineTool,
|
||||
Risk: LeafRiskWrite,
|
||||
Safety: LeafSafetyWrite,
|
||||
// devapp 旧版写守卫为 guard-first:确认门先于参数校验。
|
||||
ConfirmFirst: true,
|
||||
Flags: []LeafFlag{
|
||||
@@ -1155,7 +1147,6 @@ func newDevAppRobotOfflineCommand(runner executor.Runner) *cobra.Command {
|
||||
},
|
||||
Schema: LeafSchema{
|
||||
Description: "停用现有应用的机器人能力",
|
||||
Safety: devAppWriteSafety,
|
||||
DryRun: devAppDryRun,
|
||||
Interface: devAppCompositeInterface(),
|
||||
Selection: LeafSelectionDecl{
|
||||
@@ -1261,7 +1252,8 @@ func newDevAppVersionCreateCommand(runner executor.Runner) *cobra.Command {
|
||||
Short: "基于当前配置创建应用新版本",
|
||||
Example: " dws dev app version create --unified-app-id UNIFIED_APP_ID --desc \"新增机器人能力\" --dry-run --format json",
|
||||
Tool: devAppVersionCreateTool,
|
||||
Risk: LeafRiskWrite,
|
||||
Risk: LeafRiskHighWrite,
|
||||
Safety: LeafSafetyHighWrite,
|
||||
// devapp 旧版写守卫为 guard-first:确认门先于参数校验。
|
||||
ConfirmFirst: true,
|
||||
Flags: []LeafFlag{
|
||||
@@ -1271,7 +1263,6 @@ func newDevAppVersionCreateCommand(runner executor.Runner) *cobra.Command {
|
||||
},
|
||||
Schema: LeafSchema{
|
||||
Description: "基于当前配置创建应用新版本",
|
||||
Safety: devAppWriteSafety,
|
||||
DryRun: devAppDryRun,
|
||||
Interface: devAppCompositeInterface(),
|
||||
Selection: LeafSelectionDecl{
|
||||
@@ -1297,7 +1288,6 @@ func newDevAppVersionListCommand(runner executor.Runner) *cobra.Command {
|
||||
},
|
||||
Schema: LeafSchema{
|
||||
Description: "分页查询应用版本列表",
|
||||
Safety: devAppReadSafety,
|
||||
DryRun: devAppDryRun,
|
||||
Interface: devAppCompositeInterface(),
|
||||
Selection: LeafSelectionDecl{
|
||||
@@ -1324,7 +1314,6 @@ func newDevAppVersionGetCommand(runner executor.Runner) *cobra.Command {
|
||||
},
|
||||
Schema: LeafSchema{
|
||||
Description: "查询指定版本详情",
|
||||
Safety: devAppReadSafety,
|
||||
DryRun: devAppDryRun,
|
||||
Interface: devAppCompositeInterface(),
|
||||
Selection: LeafSelectionDecl{
|
||||
@@ -1361,7 +1350,8 @@ func newDevAppVersionPublishCommand(runner executor.Runner) *cobra.Command {
|
||||
Short: "发布指定版本(含高敏权限需 --confirmed-sensitive)",
|
||||
Example: " dws dev app version publish --unified-app-id UNIFIED_APP_ID --version-id VERSION_ID --dry-run --format json",
|
||||
Tool: devAppVersionPublishTool,
|
||||
Risk: LeafRiskWrite,
|
||||
Risk: LeafRiskHighWrite,
|
||||
Safety: LeafSafetyDestructive,
|
||||
// devapp 旧版写守卫为 guard-first:确认门先于参数校验。
|
||||
ConfirmFirst: true,
|
||||
Flags: []LeafFlag{
|
||||
@@ -1373,7 +1363,6 @@ func newDevAppVersionPublishCommand(runner executor.Runner) *cobra.Command {
|
||||
ConstParams: map[string]any{"precheckOnly": false},
|
||||
Schema: LeafSchema{
|
||||
Description: "发布指定版本(含高敏权限需 --confirmed-sensitive)",
|
||||
Safety: devAppWriteSafety,
|
||||
DryRun: devAppDryRun,
|
||||
Interface: devAppCompositeInterface(),
|
||||
Selection: LeafSelectionDecl{
|
||||
@@ -1400,7 +1389,6 @@ func newDevAppVersionStatusCommand(runner executor.Runner) *cobra.Command {
|
||||
},
|
||||
Schema: LeafSchema{
|
||||
Description: "查询版本发布/审批状态",
|
||||
Safety: devAppReadSafety,
|
||||
DryRun: devAppDryRun,
|
||||
Interface: devAppCompositeInterface(),
|
||||
Selection: LeafSelectionDecl{
|
||||
@@ -1464,22 +1452,8 @@ func devAppMeta(tool string) func(*cobra.Command) {
|
||||
// InterfaceDecl.Reason 的最终发布值。
|
||||
const devAppCompositeInterfaceReason = "Reviewed unpinned remote adapter: this executable CLI wrapper calls a remote helper that is absent from the pinned MCP metadata snapshot; no single pinned semantically equivalent interface_ref can represent the command."
|
||||
|
||||
// devAppWriteSafety 是 devapp 普通写叶的 Safety 最终声明:锁评审发布值
|
||||
// (write/high/user_required);运行时确认由 LeafRiskWrite 驱动 ConfirmRisk。
|
||||
var devAppWriteSafety = LeafSafetyDecl{
|
||||
Effect: "write", Risk: "high", Confirmation: "user_required", Idempotency: "unknown",
|
||||
}
|
||||
|
||||
// devAppReadSafety 是 devapp 读叶的 Safety 最终声明(read/low/not_required/
|
||||
// idempotent),锁评审发布值;读叶无确认门。
|
||||
var devAppReadSafety = LeafSafetyDecl{
|
||||
Effect: "read", Risk: "low", Confirmation: "not_required", Idempotency: "idempotent",
|
||||
}
|
||||
|
||||
// devAppDeleteSafety 是 delete 的 Safety 最终声明:不可逆删除发布 destructive。
|
||||
var devAppDeleteSafety = LeafSafetyDecl{
|
||||
Effect: "destructive", Risk: "high", Confirmation: "user_required", Idempotency: "unknown",
|
||||
}
|
||||
// devapp 不写共享 Safety 常量:Safety 元数据由各叶的 LeafSafety 枚举驱动
|
||||
// (读叶留空由框架按 LeafRiskRead 推导),字段值全部来自 cmdcore 的 tier 填充。
|
||||
|
||||
// devAppDryRun 是 devapp 全树共用的 dry_run 最终声明:本地拼装调用预览
|
||||
// (invocation preview),dry-run 不发起任何远端读。
|
||||
|
||||
@@ -75,6 +75,21 @@ const (
|
||||
LeafRiskHighWrite = cmdcore.RiskHighWrite
|
||||
)
|
||||
|
||||
// LeafSafety 声明 Schema 安全元数据等级(cmdcore.Safety 的别名)。独立于
|
||||
// Risk(运行时确认),描述操作对系统状态的影响程度;空值时框架从 Risk 推导。
|
||||
type LeafSafety = cmdcore.Safety
|
||||
|
||||
const (
|
||||
// LeafSafetyRead 只读操作:read/low/not_required/idempotent。
|
||||
LeafSafetyRead = cmdcore.SafetyRead
|
||||
// LeafSafetyWrite 可逆写操作:write/medium/user_required/unknown。
|
||||
LeafSafetyWrite = cmdcore.SafetyWrite
|
||||
// LeafSafetyHighWrite 难撤回写操作:write/high/user_required/unknown。
|
||||
LeafSafetyHighWrite = cmdcore.SafetyHighWrite
|
||||
// LeafSafetyDestructive 破坏性操作:destructive/high/user_required/unknown。
|
||||
LeafSafetyDestructive = cmdcore.SafetyDestructive
|
||||
)
|
||||
|
||||
// LeafConstraintKind 是跨 flag 关系约束的类型(cmdcore.ConstraintKind 的
|
||||
// 别名)。取值与 shortcut 框架的 ConstraintKind 逐字一致。
|
||||
type LeafConstraintKind = cmdcore.ConstraintKind
|
||||
@@ -134,6 +149,11 @@ type LeafSpec struct {
|
||||
// dws.schema.risk 并合成 Schema.Safety。
|
||||
Risk LeafRisk
|
||||
|
||||
// Safety 声明 Schema 安全元数据等级,独立于运行时 Risk。为空时框架从
|
||||
// Risk 推导(Risk.SafetyDefault);显式设置时 Safety 驱动 Schema 元数据,
|
||||
// Risk 仍驱动运行时确认行为。
|
||||
Safety LeafSafety
|
||||
|
||||
// ConfirmFirst 为 true 时确认门先于 required/约束/Validate 校验执行
|
||||
//(devapp 旧版写守卫语义:写命令未带 --yes 时快速失败
|
||||
// confirmation_required,与参数完整性无关)。默认 false 保持 shortcut
|
||||
@@ -186,6 +206,7 @@ func FromLeafSpec(spec LeafSpec) cmdcore.CommandSpec {
|
||||
Flags: spec.Flags,
|
||||
Constraints: spec.Constraints,
|
||||
Risk: spec.Risk,
|
||||
Safety: spec.Safety,
|
||||
ConfirmFirst: spec.ConfirmFirst,
|
||||
ConstParams: spec.ConstParams,
|
||||
Schema: spec.Schema,
|
||||
|
||||
Reference in New Issue
Block a user