fix(review): align wukong port with upstream behavior and PR #621 review findings
Must-fix: drive permission apply now gates on confirmDangerousAction and declares confirmation=user_required, matching its help-text promise. Wukong parity restored: formula-verify --exit-on-error (payload-parsing exit path) and --targets conflict error, sheet info --include, chat location/profile message types, search-advanced wukong flag aliases, and a dedicated drive download-version leaf replacing the removed polymorphic download --version. Consistency fixes: transfer-owner --node/--workspace XOR and JSON-aware dry-run after --yes validation; drive list --versions rejects --depth/--pattern instead of misleading depth errors; depth BFS resumes rate-limited folders from the failed page cursor to avoid duplicates; doc style cover upload honors cmd.Context() and a 20 MiB size cap; chat user-settings set validates per-item openConversationId and is risk=medium. Hardened the skill static audit to scan fenced code blocks and reject unknown subcommands on group commands, fixing the stale aitable/drive doc examples it exposed. Added CHANGELOG entry and coverage tests for all changed statements plus previously untested ported commands.
This commit is contained in:
1 parent
6b99685594
commit
9567cfd3d8
35 files changed
+3678
-497
No files matched your search
@@ -6,6 +6,10 @@ The format is inspired by [Keep a Changelog](https://keepachangelog.com/) and th
|
|||||||
|
|
||||||
## [Unreleased]
|
## [Unreleased]
|
||||||
|
|
||||||
|
### Added
|
||||||
|
|
||||||
|
- **Wukong internal command sync** (#621) — ports roughly 30 leaf commands from the internal wukong repository into the open-source CLI: Drive gains `star`, `cover`, `revert`, `download-version`, `permission transfer-owner`/`apply-info`/`apply`, and `list --depth`/`--versions`; Doc gains `style cover`/`style background`; Sheet gains the `comment`, `version`, and `formula-verify` command groups plus `info --include`; Chat gains `message update-text-emotion`, the `location`/`profile` message types, and group `user-settings`/`get-mute-config`. Every new leaf is registered in the Agent-visible Runtime Schema.
|
||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
|
|
||||||
- **Name→ID resolution kept external contacts** — the shared contact resolver (`chat +dm`, `+broadcast`, …) no longer drops `search_contact_by_key_word` rows that carry only an `openDingTalkId` (external / cross-org contacts have an empty `userId`), so those people are found instead of reported missing or collapsed into a wrong single match; the display name also falls back through `nick`/`showName`/`flowerName`/`staffName`/`userName`.
|
- **Name→ID resolution kept external contacts** — the shared contact resolver (`chat +dm`, `+broadcast`, …) no longer drops `search_contact_by_key_word` rows that carry only an `openDingTalkId` (external / cross-org contacts have an empty `userId`), so those people are found instead of reported missing or collapsed into a wrong single match; the display name also falls back through `nick`/`showName`/`flowerName`/`staffName`/`userName`.
|
||||||
|
|||||||
@@ -18667,14 +18667,14 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"risk": {
|
"risk": {
|
||||||
"value": "low",
|
"value": "medium",
|
||||||
"source": "internal/cli/schema_hints/metadata/chat.json",
|
"source": "internal/cli/schema_hints/metadata/chat.json",
|
||||||
"precedence": "reviewed_explicit",
|
"precedence": "reviewed_explicit",
|
||||||
"resolution": "highest_precedence",
|
"resolution": "highest_precedence",
|
||||||
"review_reason": "dws-tool-metadata/chat marks this tool as reviewed",
|
"review_reason": "dws-tool-metadata/chat marks this tool as reviewed",
|
||||||
"candidates": [
|
"candidates": [
|
||||||
{
|
{
|
||||||
"value": "low",
|
"value": "medium",
|
||||||
"source": "internal/cli/schema_hints/metadata/chat.json",
|
"source": "internal/cli/schema_hints/metadata/chat.json",
|
||||||
"precedence": "reviewed_explicit",
|
"precedence": "reviewed_explicit",
|
||||||
"selected": true,
|
"selected": true,
|
||||||
@@ -18707,7 +18707,7 @@
|
|||||||
"interface_mode": "composite",
|
"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.",
|
"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,
|
"reviewed": true,
|
||||||
"risk": "low",
|
"risk": "medium",
|
||||||
"source_refs": [
|
"source_refs": [
|
||||||
"CommandRegistry:canonical_path=chat.batch_update_group_chat_settings",
|
"CommandRegistry:canonical_path=chat.batch_update_group_chat_settings",
|
||||||
"cobra-help:dws chat group user-settings set",
|
"cobra-help:dws chat group user-settings set",
|
||||||
|
|||||||
@@ -3187,6 +3187,273 @@
|
|||||||
"已确认 contentType 非 ALIDOC,需要落盘本地查看时"
|
"已确认 contentType 非 ALIDOC,需要落盘本地查看时"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
"drive download-version": {
|
||||||
|
"agent_summary": "下载钉盘普通文件的指定历史版本到本地(两步下载:取签名 URL 后 HTTP GET)",
|
||||||
|
"agent_summary_source": "dws-agent-selection/drive",
|
||||||
|
"availability": "available",
|
||||||
|
"avoid_when": [
|
||||||
|
"下载最新版本用 drive download",
|
||||||
|
"在线文档(adoc)历史版本用 doc version 系列命令",
|
||||||
|
"在线表格(axls)历史版本用 sheet version 系列命令"
|
||||||
|
],
|
||||||
|
"confirmation": "not_required",
|
||||||
|
"effect": "read",
|
||||||
|
"effect_source": "agent-hint",
|
||||||
|
"examples": [
|
||||||
|
"dws drive download-version --node \u003cdentryUuid\u003e --version 3 --output ./report_v3.pdf"
|
||||||
|
],
|
||||||
|
"field_provenance": {
|
||||||
|
"agent_summary": {
|
||||||
|
"value": "下载钉盘普通文件的指定历史版本到本地(两步下载:取签名 URL 后 HTTP GET)",
|
||||||
|
"source": "internal/cli/schema_hints/selection/drive.json",
|
||||||
|
"precedence": "reviewed_explicit",
|
||||||
|
"resolution": "highest_precedence",
|
||||||
|
"review_reason": "人工审阅:对照悟空 develop drive download --version 分支实现移植为独立命令;单一 download_file_version 远端调用,参数契约与帮助文档一致。",
|
||||||
|
"candidates": [
|
||||||
|
{
|
||||||
|
"value": "下载钉盘普通文件的指定历史版本到本地(两步下载:取签名 URL 后 HTTP GET)",
|
||||||
|
"source": "internal/cli/schema_hints/selection/drive.json",
|
||||||
|
"precedence": "reviewed_explicit",
|
||||||
|
"selected": true,
|
||||||
|
"review_reason": "人工审阅:对照悟空 develop drive download --version 分支实现移植为独立命令;单一 download_file_version 远端调用,参数契约与帮助文档一致。"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"availability": {
|
||||||
|
"value": "available",
|
||||||
|
"source": "internal/cli/schema_hints/metadata/drive.json",
|
||||||
|
"precedence": "reviewed_explicit",
|
||||||
|
"resolution": "highest_precedence",
|
||||||
|
"review_reason": "dws-tool-metadata/drive marks this tool as reviewed",
|
||||||
|
"candidates": [
|
||||||
|
{
|
||||||
|
"value": "available",
|
||||||
|
"source": "internal/cli/schema_hints/metadata/drive.json",
|
||||||
|
"precedence": "reviewed_explicit",
|
||||||
|
"selected": true,
|
||||||
|
"review_reason": "dws-tool-metadata/drive marks this tool as reviewed"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"avoid_when": {
|
||||||
|
"value": [
|
||||||
|
"下载最新版本用 drive download",
|
||||||
|
"在线文档(adoc)历史版本用 doc version 系列命令",
|
||||||
|
"在线表格(axls)历史版本用 sheet version 系列命令"
|
||||||
|
],
|
||||||
|
"source": "internal/cli/schema_hints/selection/drive.json",
|
||||||
|
"precedence": "reviewed_explicit",
|
||||||
|
"resolution": "highest_precedence",
|
||||||
|
"review_reason": "人工审阅:对照悟空 develop drive download --version 分支实现移植为独立命令;单一 download_file_version 远端调用,参数契约与帮助文档一致。",
|
||||||
|
"candidates": [
|
||||||
|
{
|
||||||
|
"value": [
|
||||||
|
"下载最新版本用 drive download",
|
||||||
|
"在线文档(adoc)历史版本用 doc version 系列命令",
|
||||||
|
"在线表格(axls)历史版本用 sheet version 系列命令"
|
||||||
|
],
|
||||||
|
"source": "internal/cli/schema_hints/selection/drive.json",
|
||||||
|
"precedence": "reviewed_explicit",
|
||||||
|
"selected": true,
|
||||||
|
"review_reason": "人工审阅:对照悟空 develop drive download --version 分支实现移植为独立命令;单一 download_file_version 远端调用,参数契约与帮助文档一致。"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"confirmation": {
|
||||||
|
"value": "not_required",
|
||||||
|
"source": "internal/cli/schema_hints/metadata/drive.json",
|
||||||
|
"precedence": "reviewed_explicit",
|
||||||
|
"resolution": "highest_precedence",
|
||||||
|
"review_reason": "dws-tool-metadata/drive marks this tool as reviewed",
|
||||||
|
"candidates": [
|
||||||
|
{
|
||||||
|
"value": "not_required",
|
||||||
|
"source": "internal/cli/schema_hints/metadata/drive.json",
|
||||||
|
"precedence": "reviewed_explicit",
|
||||||
|
"selected": true,
|
||||||
|
"review_reason": "dws-tool-metadata/drive marks this tool as reviewed"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"effect": {
|
||||||
|
"value": "read",
|
||||||
|
"source": "internal/cli/schema_hints/metadata/drive.json",
|
||||||
|
"precedence": "reviewed_explicit",
|
||||||
|
"resolution": "highest_precedence",
|
||||||
|
"review_reason": "dws-tool-metadata/drive marks this tool as reviewed",
|
||||||
|
"candidates": [
|
||||||
|
{
|
||||||
|
"value": "read",
|
||||||
|
"source": "internal/cli/schema_hints/metadata/drive.json",
|
||||||
|
"precedence": "reviewed_explicit",
|
||||||
|
"selected": true,
|
||||||
|
"review_reason": "dws-tool-metadata/drive marks this tool as reviewed"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"examples": {
|
||||||
|
"value": [
|
||||||
|
"dws drive download-version --node \u003cdentryUuid\u003e --version 3 --output ./report_v3.pdf"
|
||||||
|
],
|
||||||
|
"source": "internal/cli/schema_hints/selection/drive.json",
|
||||||
|
"precedence": "reviewed_explicit",
|
||||||
|
"resolution": "highest_precedence",
|
||||||
|
"review_reason": "人工审阅:对照悟空 develop drive download --version 分支实现移植为独立命令;单一 download_file_version 远端调用,参数契约与帮助文档一致。",
|
||||||
|
"candidates": [
|
||||||
|
{
|
||||||
|
"value": [
|
||||||
|
"dws drive download-version --node \u003cdentryUuid\u003e --version 3 --output ./report_v3.pdf"
|
||||||
|
],
|
||||||
|
"source": "internal/cli/schema_hints/selection/drive.json",
|
||||||
|
"precedence": "reviewed_explicit",
|
||||||
|
"selected": true,
|
||||||
|
"review_reason": "人工审阅:对照悟空 develop drive download --version 分支实现移植为独立命令;单一 download_file_version 远端调用,参数契约与帮助文档一致。"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"idempotency": {
|
||||||
|
"value": "idempotent",
|
||||||
|
"source": "internal/cli/schema_hints/metadata/drive.json",
|
||||||
|
"precedence": "reviewed_explicit",
|
||||||
|
"resolution": "highest_precedence",
|
||||||
|
"review_reason": "dws-tool-metadata/drive marks this tool as reviewed",
|
||||||
|
"candidates": [
|
||||||
|
{
|
||||||
|
"value": "idempotent",
|
||||||
|
"source": "internal/cli/schema_hints/metadata/drive.json",
|
||||||
|
"precedence": "reviewed_explicit",
|
||||||
|
"selected": true,
|
||||||
|
"review_reason": "dws-tool-metadata/drive marks this tool as reviewed"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"interface_mode": {
|
||||||
|
"value": "composite",
|
||||||
|
"source": "internal/cli/schema_hints/metadata/drive.json",
|
||||||
|
"precedence": "reviewed_explicit",
|
||||||
|
"resolution": "highest_precedence",
|
||||||
|
"review_reason": "dws-tool-metadata/drive marks this tool as reviewed",
|
||||||
|
"candidates": [
|
||||||
|
{
|
||||||
|
"value": "composite",
|
||||||
|
"source": "internal/cli/schema_hints/metadata/drive.json",
|
||||||
|
"precedence": "reviewed_explicit",
|
||||||
|
"selected": true,
|
||||||
|
"review_reason": "dws-tool-metadata/drive marks this tool as reviewed"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"interface_reason": {
|
||||||
|
"value": "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.",
|
||||||
|
"source": "internal/cli/schema_hints/metadata/drive.json",
|
||||||
|
"precedence": "reviewed_explicit",
|
||||||
|
"resolution": "highest_precedence",
|
||||||
|
"review_reason": "dws-tool-metadata/drive marks this tool as reviewed",
|
||||||
|
"candidates": [
|
||||||
|
{
|
||||||
|
"value": "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.",
|
||||||
|
"source": "internal/cli/schema_hints/metadata/drive.json",
|
||||||
|
"precedence": "reviewed_explicit",
|
||||||
|
"selected": true,
|
||||||
|
"review_reason": "dws-tool-metadata/drive marks this tool as reviewed"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"interface_ref": {
|
||||||
|
"value": null,
|
||||||
|
"source": "internal/cli/schema_hints/metadata/drive.json",
|
||||||
|
"precedence": "reviewed_explicit",
|
||||||
|
"resolution": "interface_disposition_matrix",
|
||||||
|
"review_reason": "final interface mode composite forbids a direct MCP interface_ref",
|
||||||
|
"candidates": [
|
||||||
|
{
|
||||||
|
"value": null,
|
||||||
|
"source": "internal/cli/schema_hints/metadata/drive.json",
|
||||||
|
"precedence": "reviewed_explicit",
|
||||||
|
"selected": true,
|
||||||
|
"review_reason": "final interface mode composite forbids a direct MCP interface_ref"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"reviewed": {
|
||||||
|
"value": true,
|
||||||
|
"source": "internal/cli/schema_hints/metadata/drive.json",
|
||||||
|
"precedence": "reviewed_explicit",
|
||||||
|
"resolution": "highest_precedence",
|
||||||
|
"review_reason": "dws-tool-metadata/drive marks this tool as reviewed",
|
||||||
|
"candidates": [
|
||||||
|
{
|
||||||
|
"value": true,
|
||||||
|
"source": "internal/cli/schema_hints/metadata/drive.json",
|
||||||
|
"precedence": "reviewed_explicit",
|
||||||
|
"selected": true,
|
||||||
|
"review_reason": "dws-tool-metadata/drive marks this tool as reviewed"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"value": true,
|
||||||
|
"source": "internal/cli/schema_hints/selection/drive.json",
|
||||||
|
"precedence": "reviewed_explicit",
|
||||||
|
"selected": false,
|
||||||
|
"review_reason": "人工审阅:对照悟空 develop drive download --version 分支实现移植为独立命令;单一 download_file_version 远端调用,参数契约与帮助文档一致。"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"risk": {
|
||||||
|
"value": "low",
|
||||||
|
"source": "internal/cli/schema_hints/metadata/drive.json",
|
||||||
|
"precedence": "reviewed_explicit",
|
||||||
|
"resolution": "highest_precedence",
|
||||||
|
"review_reason": "dws-tool-metadata/drive marks this tool as reviewed",
|
||||||
|
"candidates": [
|
||||||
|
{
|
||||||
|
"value": "low",
|
||||||
|
"source": "internal/cli/schema_hints/metadata/drive.json",
|
||||||
|
"precedence": "reviewed_explicit",
|
||||||
|
"selected": true,
|
||||||
|
"review_reason": "dws-tool-metadata/drive marks this tool as reviewed"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"use_when": {
|
||||||
|
"value": [
|
||||||
|
"用户要下载文件的历史版本/旧版本",
|
||||||
|
"版本号已通过 drive list --versions 获取"
|
||||||
|
],
|
||||||
|
"source": "internal/cli/schema_hints/selection/drive.json",
|
||||||
|
"precedence": "reviewed_explicit",
|
||||||
|
"resolution": "highest_precedence",
|
||||||
|
"review_reason": "人工审阅:对照悟空 develop drive download --version 分支实现移植为独立命令;单一 download_file_version 远端调用,参数契约与帮助文档一致。",
|
||||||
|
"candidates": [
|
||||||
|
{
|
||||||
|
"value": [
|
||||||
|
"用户要下载文件的历史版本/旧版本",
|
||||||
|
"版本号已通过 drive list --versions 获取"
|
||||||
|
],
|
||||||
|
"source": "internal/cli/schema_hints/selection/drive.json",
|
||||||
|
"precedence": "reviewed_explicit",
|
||||||
|
"selected": true,
|
||||||
|
"review_reason": "人工审阅:对照悟空 develop drive download --version 分支实现移植为独立命令;单一 download_file_version 远端调用,参数契约与帮助文档一致。"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"idempotency": "idempotent",
|
||||||
|
"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": "low",
|
||||||
|
"source_refs": [
|
||||||
|
"CommandRegistry:canonical_path=drive.download_file_version",
|
||||||
|
"cobra-help:dws drive download-version",
|
||||||
|
"internal/cli/schema_hints/metadata/drive.json",
|
||||||
|
"internal/cli/schema_hints/selection/drive.json",
|
||||||
|
"wukong-develop:wukong/products/drive.go"
|
||||||
|
],
|
||||||
|
"use_when": [
|
||||||
|
"用户要下载文件的历史版本/旧版本",
|
||||||
|
"版本号已通过 drive list --versions 获取"
|
||||||
|
]
|
||||||
|
},
|
||||||
"drive info": {
|
"drive info": {
|
||||||
"agent_summary": "获取文件元数据信息",
|
"agent_summary": "获取文件元数据信息",
|
||||||
"agent_summary_source": "dws-agent-selection/drive",
|
"agent_summary_source": "dws-agent-selection/drive",
|
||||||
@@ -4839,7 +5106,7 @@
|
|||||||
"avoid_when": [
|
"avoid_when": [
|
||||||
"先用 apply-info 查可申请角色与审批人;未经用户确认不得自行提交"
|
"先用 apply-info 查可申请角色与审批人;未经用户确认不得自行提交"
|
||||||
],
|
],
|
||||||
"confirmation": "not_required",
|
"confirmation": "user_required",
|
||||||
"effect": "write",
|
"effect": "write",
|
||||||
"effect_source": "agent-hint",
|
"effect_source": "agent-hint",
|
||||||
"examples": [
|
"examples": [
|
||||||
@@ -4899,14 +5166,14 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"confirmation": {
|
"confirmation": {
|
||||||
"value": "not_required",
|
"value": "user_required",
|
||||||
"source": "internal/cli/schema_hints/metadata/drive.json",
|
"source": "internal/cli/schema_hints/metadata/drive.json",
|
||||||
"precedence": "reviewed_explicit",
|
"precedence": "reviewed_explicit",
|
||||||
"resolution": "highest_precedence",
|
"resolution": "highest_precedence",
|
||||||
"review_reason": "dws-tool-metadata/drive marks this tool as reviewed",
|
"review_reason": "dws-tool-metadata/drive marks this tool as reviewed",
|
||||||
"candidates": [
|
"candidates": [
|
||||||
{
|
{
|
||||||
"value": "not_required",
|
"value": "user_required",
|
||||||
"source": "internal/cli/schema_hints/metadata/drive.json",
|
"source": "internal/cli/schema_hints/metadata/drive.json",
|
||||||
"precedence": "reviewed_explicit",
|
"precedence": "reviewed_explicit",
|
||||||
"selected": true,
|
"selected": true,
|
||||||
|
|||||||
@@ -1,17 +1,17 @@
|
|||||||
{
|
{
|
||||||
"version": 1,
|
"version": 1,
|
||||||
"source_hash": "sha256:ced34d4510fddb0b0cd02478f0f5051b0de0aab3d6bc7e1e43aaa1a12717d3b7",
|
"source_hash": "sha256:31a28d1665ebb13fdb131547bda1d84ce1cc3fee0bbff821b76c2fdf6f6904ab",
|
||||||
"surface_hash": "sha256:674e6c00efb4d7f4c177ec0a1c4c097c8fb48b0045d1787c0ed001c32c51f20a",
|
"surface_hash": "sha256:29d4f5f43688cc01bc2277a4528b597de4fbab89a7b2f13fe2e56df85d1c66c4",
|
||||||
"coverage": {
|
"coverage": {
|
||||||
"surface_products": 26,
|
"surface_products": 26,
|
||||||
"products_with_metadata": 26,
|
"products_with_metadata": 26,
|
||||||
"surface_tools": 839,
|
"surface_tools": 840,
|
||||||
"tools_with_metadata": 839,
|
"tools_with_metadata": 840,
|
||||||
"tools_with_agent_summary": 839,
|
"tools_with_agent_summary": 840,
|
||||||
"tools_with_use_when": 839,
|
"tools_with_use_when": 840,
|
||||||
"tools_with_avoid_when": 839,
|
"tools_with_avoid_when": 840,
|
||||||
"tools_with_examples": 839,
|
"tools_with_examples": 840,
|
||||||
"tools_with_interface_mode": 839,
|
"tools_with_interface_mode": 840,
|
||||||
"unmatched_skill_tools": 122,
|
"unmatched_skill_tools": 122,
|
||||||
"unreviewed_skill_tools": 11
|
"unreviewed_skill_tools": 11
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
{
|
{
|
||||||
"version": 1,
|
"version": 1,
|
||||||
"source_hash": "sha256:ced34d4510fddb0b0cd02478f0f5051b0de0aab3d6bc7e1e43aaa1a12717d3b7",
|
"source_hash": "sha256:31a28d1665ebb13fdb131547bda1d84ce1cc3fee0bbff821b76c2fdf6f6904ab",
|
||||||
"surface_hash": "sha256:674e6c00efb4d7f4c177ec0a1c4c097c8fb48b0045d1787c0ed001c32c51f20a",
|
"surface_hash": "sha256:29d4f5f43688cc01bc2277a4528b597de4fbab89a7b2f13fe2e56df85d1c66c4",
|
||||||
"source_files": 160,
|
"source_files": 160,
|
||||||
"hint_files": 54,
|
"hint_files": 54,
|
||||||
"hint_products": 43,
|
"hint_products": 43,
|
||||||
"hint_tools": 1830,
|
"hint_tools": 1832,
|
||||||
"interface_metadata": {
|
"interface_metadata": {
|
||||||
"source": "mcp-tools-list+cli-registry",
|
"source": "mcp-tools-list+cli-registry",
|
||||||
"revision": "4574f7022c32cf4c033e9b7b4156e2fec815fed8",
|
"revision": "4574f7022c32cf4c033e9b7b4156e2fec815fed8",
|
||||||
@@ -29,13 +29,13 @@
|
|||||||
"coverage": {
|
"coverage": {
|
||||||
"surface_products": 26,
|
"surface_products": 26,
|
||||||
"products_with_metadata": 26,
|
"products_with_metadata": 26,
|
||||||
"surface_tools": 839,
|
"surface_tools": 840,
|
||||||
"tools_with_metadata": 839,
|
"tools_with_metadata": 840,
|
||||||
"tools_with_agent_summary": 839,
|
"tools_with_agent_summary": 840,
|
||||||
"tools_with_use_when": 839,
|
"tools_with_use_when": 840,
|
||||||
"tools_with_avoid_when": 839,
|
"tools_with_avoid_when": 840,
|
||||||
"tools_with_examples": 839,
|
"tools_with_examples": 840,
|
||||||
"tools_with_interface_mode": 839,
|
"tools_with_interface_mode": 840,
|
||||||
"unmatched_skill_tools": 122,
|
"unmatched_skill_tools": 122,
|
||||||
"unreviewed_skill_tools": 11
|
"unreviewed_skill_tools": 11
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -1,17 +1,17 @@
|
|||||||
{
|
{
|
||||||
"version": 1,
|
"version": 1,
|
||||||
"surface_hash": "sha256:674e6c00efb4d7f4c177ec0a1c4c097c8fb48b0045d1787c0ed001c32c51f20a",
|
"surface_hash": "sha256:29d4f5f43688cc01bc2277a4528b597de4fbab89a7b2f13fe2e56df85d1c66c4",
|
||||||
"source_hash": "sha256:f2cf7fcd3a70748029688ef5653386d9b503ef898bf763acb1da04a0b150d483",
|
"source_hash": "sha256:346ec3ac857b9a740baf03142296b1e4fb0814f713ceab4ed2ff9f46a85d6b4d",
|
||||||
"catalog": {
|
"catalog": {
|
||||||
"agent_metadata": {
|
"agent_metadata": {
|
||||||
"products_with_metadata": 26,
|
"products_with_metadata": 26,
|
||||||
"source": "embedded-skill-metadata",
|
"source": "embedded-skill-metadata",
|
||||||
"source_hash": "sha256:ced34d4510fddb0b0cd02478f0f5051b0de0aab3d6bc7e1e43aaa1a12717d3b7",
|
"source_hash": "sha256:31a28d1665ebb13fdb131547bda1d84ce1cc3fee0bbff821b76c2fdf6f6904ab",
|
||||||
"surface_hash": "sha256:674e6c00efb4d7f4c177ec0a1c4c097c8fb48b0045d1787c0ed001c32c51f20a",
|
"surface_hash": "sha256:29d4f5f43688cc01bc2277a4528b597de4fbab89a7b2f13fe2e56df85d1c66c4",
|
||||||
"surface_products": 26,
|
"surface_products": 26,
|
||||||
"surface_tools": 839,
|
"surface_tools": 840,
|
||||||
"tools_with_agent_summary": 839,
|
"tools_with_agent_summary": 840,
|
||||||
"tools_with_metadata": 839,
|
"tools_with_metadata": 840,
|
||||||
"unmatched_skill_tools": 122,
|
"unmatched_skill_tools": 122,
|
||||||
"version": 1
|
"version": 1
|
||||||
},
|
},
|
||||||
@@ -7955,7 +7955,7 @@
|
|||||||
"name": "batch_update_group_chat_settings",
|
"name": "batch_update_group_chat_settings",
|
||||||
"primary_cli_path": "chat group user-settings set",
|
"primary_cli_path": "chat group user-settings set",
|
||||||
"reviewed": true,
|
"reviewed": true,
|
||||||
"risk": "low",
|
"risk": "medium",
|
||||||
"title": "批量更新当前用户的群会话设置",
|
"title": "批量更新当前用户的群会话设置",
|
||||||
"use_when": [
|
"use_when": [
|
||||||
"用户说 把这些群都设为免打扰/置顶"
|
"用户说 把这些群都设为免打扰/置顶"
|
||||||
@@ -16172,7 +16172,7 @@
|
|||||||
"id": "drive",
|
"id": "drive",
|
||||||
"name": "钉盘文件管理",
|
"name": "钉盘文件管理",
|
||||||
"runtime": true,
|
"runtime": true,
|
||||||
"tool_count": 40,
|
"tool_count": 41,
|
||||||
"tools": [
|
"tools": [
|
||||||
{
|
{
|
||||||
"agent_metadata_source": "embedded-skill-metadata",
|
"agent_metadata_source": "embedded-skill-metadata",
|
||||||
@@ -16219,7 +16219,7 @@
|
|||||||
"canonical_path": "drive.apply_permission",
|
"canonical_path": "drive.apply_permission",
|
||||||
"cli_name": "apply",
|
"cli_name": "apply",
|
||||||
"cli_path": "drive permission apply",
|
"cli_path": "drive permission apply",
|
||||||
"confirmation": "not_required",
|
"confirmation": "user_required",
|
||||||
"description": "向指定节点的审批人发起权限申请。建议先用 apply-info 获取可申请角色与审批人。\n\n注意: 本命令会真实通知审批人,Agent 必须先获得用户明确同意后再执行。",
|
"description": "向指定节点的审批人发起权限申请。建议先用 apply-info 获取可申请角色与审批人。\n\n注意: 本命令会真实通知审批人,Agent 必须先获得用户明确同意后再执行。",
|
||||||
"effect": "write",
|
"effect": "write",
|
||||||
"group": "permission",
|
"group": "permission",
|
||||||
@@ -16430,6 +16430,35 @@
|
|||||||
"已确认 contentType 非 ALIDOC,需要落盘本地查看时"
|
"已确认 contentType 非 ALIDOC,需要落盘本地查看时"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"agent_metadata_source": "embedded-skill-metadata",
|
||||||
|
"agent_summary": "下载钉盘普通文件的指定历史版本到本地(两步下载:取签名 URL 后 HTTP GET)",
|
||||||
|
"agent_summary_source": "dws-agent-selection/drive",
|
||||||
|
"availability": "available",
|
||||||
|
"avoid_when": [
|
||||||
|
"下载最新版本用 drive download",
|
||||||
|
"在线文档(adoc)历史版本用 doc version 系列命令",
|
||||||
|
"在线表格(axls)历史版本用 sheet version 系列命令"
|
||||||
|
],
|
||||||
|
"canonical_path": "drive.download_file_version",
|
||||||
|
"cli_name": "download-version",
|
||||||
|
"cli_path": "drive download-version",
|
||||||
|
"confirmation": "not_required",
|
||||||
|
"description": "下载钉盘文件的指定历史版本到本地(两步下载流程)。\n\n仅适用于普通文件(如 pdf、docx、xlsx、png 等):\n 钉钉在线文档(adoc)请使用 dws doc version 系列命令\n 钉钉在线表格(axls)请使用 dws sheet version 系列命令\n\n流程:\n 1. 获取历史版本下载 URL 和签名请求头 (download_file_version)\n 2. HTTP GET 下载文件二进制内容到本地\n\n版本号从 dws drive list --node \u003cdentryUuid\u003e --versions 获取。",
|
||||||
|
"effect": "read",
|
||||||
|
"idempotency": "idempotent",
|
||||||
|
"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.",
|
||||||
|
"name": "download_file_version",
|
||||||
|
"primary_cli_path": "drive download-version",
|
||||||
|
"reviewed": true,
|
||||||
|
"risk": "low",
|
||||||
|
"title": "下载文件历史版本到本地",
|
||||||
|
"use_when": [
|
||||||
|
"用户要下载文件的历史版本/旧版本",
|
||||||
|
"版本号已通过 drive list --versions 获取"
|
||||||
|
]
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"agent_metadata_source": "embedded-skill-metadata",
|
"agent_metadata_source": "embedded-skill-metadata",
|
||||||
"agent_summary": "获取节点封面图片地址(文档首图/图片缩略图/类型图标)",
|
"agent_summary": "获取节点封面图片地址(文档首图/图片缩略图/类型图标)",
|
||||||
@@ -26484,6 +26513,6 @@
|
|||||||
}
|
}
|
||||||
],
|
],
|
||||||
"source": "embedded-command-catalog",
|
"source": "embedded-command-catalog",
|
||||||
"tool_count": 839
|
"tool_count": 840
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -5521,14 +5521,14 @@
|
|||||||
"review_reason": "dws-tool-metadata/chat marks this tool as reviewed",
|
"review_reason": "dws-tool-metadata/chat marks this tool as reviewed",
|
||||||
"selected": true,
|
"selected": true,
|
||||||
"source": "internal/cli/schema_hints/metadata/chat.json",
|
"source": "internal/cli/schema_hints/metadata/chat.json",
|
||||||
"value": "low"
|
"value": "medium"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"precedence": "reviewed_explicit",
|
"precedence": "reviewed_explicit",
|
||||||
"resolution": "highest_precedence",
|
"resolution": "highest_precedence",
|
||||||
"review_reason": "dws-tool-metadata/chat marks this tool as reviewed",
|
"review_reason": "dws-tool-metadata/chat marks this tool as reviewed",
|
||||||
"source": "internal/cli/schema_hints/metadata/chat.json",
|
"source": "internal/cli/schema_hints/metadata/chat.json",
|
||||||
"value": "low"
|
"value": "medium"
|
||||||
},
|
},
|
||||||
"title": {
|
"title": {
|
||||||
"candidates": [
|
"candidates": [
|
||||||
@@ -5676,7 +5676,7 @@
|
|||||||
"primary_cli_path": "chat group user-settings set",
|
"primary_cli_path": "chat group user-settings set",
|
||||||
"product_id": "chat",
|
"product_id": "chat",
|
||||||
"reviewed": true,
|
"reviewed": true,
|
||||||
"risk": "low",
|
"risk": "medium",
|
||||||
"source": "reviewed_command_registry",
|
"source": "reviewed_command_registry",
|
||||||
"title": "批量更新当前用户的群会话设置",
|
"title": "批量更新当前用户的群会话设置",
|
||||||
"use_when": [
|
"use_when": [
|
||||||
@@ -46156,7 +46156,7 @@
|
|||||||
"is_alias": false,
|
"is_alias": false,
|
||||||
"metadata_source": "embedded-mcp-metadata",
|
"metadata_source": "embedded-mcp-metadata",
|
||||||
"name": "send_personal_message",
|
"name": "send_personal_message",
|
||||||
"parameter_count": 12,
|
"parameter_count": 17,
|
||||||
"parameters": {
|
"parameters": {
|
||||||
"ai-tag": {
|
"ai-tag": {
|
||||||
"default": "true",
|
"default": "true",
|
||||||
@@ -46492,6 +46492,97 @@
|
|||||||
"required": false,
|
"required": false,
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
|
"contact-id": {
|
||||||
|
"description": "联系人名片 openDingTalkId(msgType=profile 时必填)",
|
||||||
|
"field_provenance": {
|
||||||
|
"description": {
|
||||||
|
"candidates": [
|
||||||
|
{
|
||||||
|
"precedence": "cobra_contract",
|
||||||
|
"selected": true,
|
||||||
|
"source": "cobra_usage",
|
||||||
|
"value": "联系人名片 openDingTalkId(msgType=profile 时必填)"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"precedence": "default",
|
||||||
|
"selected": false,
|
||||||
|
"source": "default",
|
||||||
|
"value": ""
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"precedence": "cobra_contract",
|
||||||
|
"resolution": "highest_precedence",
|
||||||
|
"source": "cobra_usage",
|
||||||
|
"value": "联系人名片 openDingTalkId(msgType=profile 时必填)"
|
||||||
|
},
|
||||||
|
"property": {
|
||||||
|
"candidates": [
|
||||||
|
{
|
||||||
|
"precedence": "reviewed_mapping_exclusion",
|
||||||
|
"review_reason": "serialized into the aggregate content payload",
|
||||||
|
"selected": true,
|
||||||
|
"source": "reviewed_mapping_exclusion",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"precedence": "inference",
|
||||||
|
"selected": false,
|
||||||
|
"source": "flag_name_inference",
|
||||||
|
"value": "contactId"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"precedence": "reviewed_mapping_exclusion",
|
||||||
|
"resolution": "highest_precedence",
|
||||||
|
"review_reason": "serialized into the aggregate content payload",
|
||||||
|
"source": "reviewed_mapping_exclusion",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
"required": {
|
||||||
|
"candidates": [
|
||||||
|
{
|
||||||
|
"precedence": "default",
|
||||||
|
"selected": true,
|
||||||
|
"source": "default",
|
||||||
|
"value": false
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"precedence": "default",
|
||||||
|
"resolution": "fallback",
|
||||||
|
"source": "default",
|
||||||
|
"value": false
|
||||||
|
},
|
||||||
|
"required_when": {
|
||||||
|
"candidates": [
|
||||||
|
{
|
||||||
|
"precedence": "default",
|
||||||
|
"selected": true,
|
||||||
|
"source": "default",
|
||||||
|
"value": ""
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"precedence": "default",
|
||||||
|
"resolution": "highest_precedence",
|
||||||
|
"source": "default",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
"type": {
|
||||||
|
"candidates": [
|
||||||
|
{
|
||||||
|
"precedence": "cobra_contract",
|
||||||
|
"selected": true,
|
||||||
|
"source": "cobra_flag_type",
|
||||||
|
"value": "string"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"precedence": "cobra_contract",
|
||||||
|
"resolution": "highest_precedence",
|
||||||
|
"source": "cobra_flag_type",
|
||||||
|
"value": "string"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"required": false,
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
"file-path": {
|
"file-path": {
|
||||||
"description": "本地文件路径(msgType=file/audio/video 时直接上传并按 file 消息发送)",
|
"description": "本地文件路径(msgType=file/audio/video 时直接上传并按 file 消息发送)",
|
||||||
"field_provenance": {
|
"field_provenance": {
|
||||||
@@ -46714,6 +46805,370 @@
|
|||||||
"required": false,
|
"required": false,
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
|
"latitude": {
|
||||||
|
"description": "位置消息纬度(msgType=location 时必填)",
|
||||||
|
"field_provenance": {
|
||||||
|
"description": {
|
||||||
|
"candidates": [
|
||||||
|
{
|
||||||
|
"precedence": "cobra_contract",
|
||||||
|
"selected": true,
|
||||||
|
"source": "cobra_usage",
|
||||||
|
"value": "位置消息纬度(msgType=location 时必填)"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"precedence": "default",
|
||||||
|
"selected": false,
|
||||||
|
"source": "default",
|
||||||
|
"value": ""
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"precedence": "cobra_contract",
|
||||||
|
"resolution": "highest_precedence",
|
||||||
|
"source": "cobra_usage",
|
||||||
|
"value": "位置消息纬度(msgType=location 时必填)"
|
||||||
|
},
|
||||||
|
"property": {
|
||||||
|
"candidates": [
|
||||||
|
{
|
||||||
|
"precedence": "reviewed_mapping_exclusion",
|
||||||
|
"review_reason": "serialized into the aggregate content payload",
|
||||||
|
"selected": true,
|
||||||
|
"source": "reviewed_mapping_exclusion",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"precedence": "inference",
|
||||||
|
"selected": false,
|
||||||
|
"source": "flag_name_inference",
|
||||||
|
"value": "latitude"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"precedence": "reviewed_mapping_exclusion",
|
||||||
|
"resolution": "highest_precedence",
|
||||||
|
"review_reason": "serialized into the aggregate content payload",
|
||||||
|
"source": "reviewed_mapping_exclusion",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
"required": {
|
||||||
|
"candidates": [
|
||||||
|
{
|
||||||
|
"precedence": "default",
|
||||||
|
"selected": true,
|
||||||
|
"source": "default",
|
||||||
|
"value": false
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"precedence": "default",
|
||||||
|
"resolution": "fallback",
|
||||||
|
"source": "default",
|
||||||
|
"value": false
|
||||||
|
},
|
||||||
|
"required_when": {
|
||||||
|
"candidates": [
|
||||||
|
{
|
||||||
|
"precedence": "default",
|
||||||
|
"selected": true,
|
||||||
|
"source": "default",
|
||||||
|
"value": ""
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"precedence": "default",
|
||||||
|
"resolution": "highest_precedence",
|
||||||
|
"source": "default",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
"type": {
|
||||||
|
"candidates": [
|
||||||
|
{
|
||||||
|
"precedence": "cobra_contract",
|
||||||
|
"selected": true,
|
||||||
|
"source": "cobra_flag_type",
|
||||||
|
"value": "string"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"precedence": "cobra_contract",
|
||||||
|
"resolution": "highest_precedence",
|
||||||
|
"source": "cobra_flag_type",
|
||||||
|
"value": "string"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"required": false,
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"location-name": {
|
||||||
|
"description": "位置消息地址名称(msgType=location 时必填)",
|
||||||
|
"field_provenance": {
|
||||||
|
"description": {
|
||||||
|
"candidates": [
|
||||||
|
{
|
||||||
|
"precedence": "cobra_contract",
|
||||||
|
"selected": true,
|
||||||
|
"source": "cobra_usage",
|
||||||
|
"value": "位置消息地址名称(msgType=location 时必填)"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"precedence": "default",
|
||||||
|
"selected": false,
|
||||||
|
"source": "default",
|
||||||
|
"value": ""
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"precedence": "cobra_contract",
|
||||||
|
"resolution": "highest_precedence",
|
||||||
|
"source": "cobra_usage",
|
||||||
|
"value": "位置消息地址名称(msgType=location 时必填)"
|
||||||
|
},
|
||||||
|
"property": {
|
||||||
|
"candidates": [
|
||||||
|
{
|
||||||
|
"precedence": "reviewed_mapping_exclusion",
|
||||||
|
"review_reason": "serialized into the aggregate content payload",
|
||||||
|
"selected": true,
|
||||||
|
"source": "reviewed_mapping_exclusion",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"precedence": "inference",
|
||||||
|
"selected": false,
|
||||||
|
"source": "flag_name_inference",
|
||||||
|
"value": "locationName"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"precedence": "reviewed_mapping_exclusion",
|
||||||
|
"resolution": "highest_precedence",
|
||||||
|
"review_reason": "serialized into the aggregate content payload",
|
||||||
|
"source": "reviewed_mapping_exclusion",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
"required": {
|
||||||
|
"candidates": [
|
||||||
|
{
|
||||||
|
"precedence": "default",
|
||||||
|
"selected": true,
|
||||||
|
"source": "default",
|
||||||
|
"value": false
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"precedence": "default",
|
||||||
|
"resolution": "fallback",
|
||||||
|
"source": "default",
|
||||||
|
"value": false
|
||||||
|
},
|
||||||
|
"required_when": {
|
||||||
|
"candidates": [
|
||||||
|
{
|
||||||
|
"precedence": "default",
|
||||||
|
"selected": true,
|
||||||
|
"source": "default",
|
||||||
|
"value": ""
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"precedence": "default",
|
||||||
|
"resolution": "highest_precedence",
|
||||||
|
"source": "default",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
"type": {
|
||||||
|
"candidates": [
|
||||||
|
{
|
||||||
|
"precedence": "cobra_contract",
|
||||||
|
"selected": true,
|
||||||
|
"source": "cobra_flag_type",
|
||||||
|
"value": "string"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"precedence": "cobra_contract",
|
||||||
|
"resolution": "highest_precedence",
|
||||||
|
"source": "cobra_flag_type",
|
||||||
|
"value": "string"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"required": false,
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"longitude": {
|
||||||
|
"description": "位置消息经度(msgType=location 时必填)",
|
||||||
|
"field_provenance": {
|
||||||
|
"description": {
|
||||||
|
"candidates": [
|
||||||
|
{
|
||||||
|
"precedence": "cobra_contract",
|
||||||
|
"selected": true,
|
||||||
|
"source": "cobra_usage",
|
||||||
|
"value": "位置消息经度(msgType=location 时必填)"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"precedence": "default",
|
||||||
|
"selected": false,
|
||||||
|
"source": "default",
|
||||||
|
"value": ""
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"precedence": "cobra_contract",
|
||||||
|
"resolution": "highest_precedence",
|
||||||
|
"source": "cobra_usage",
|
||||||
|
"value": "位置消息经度(msgType=location 时必填)"
|
||||||
|
},
|
||||||
|
"property": {
|
||||||
|
"candidates": [
|
||||||
|
{
|
||||||
|
"precedence": "reviewed_mapping_exclusion",
|
||||||
|
"review_reason": "serialized into the aggregate content payload",
|
||||||
|
"selected": true,
|
||||||
|
"source": "reviewed_mapping_exclusion",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"precedence": "inference",
|
||||||
|
"selected": false,
|
||||||
|
"source": "flag_name_inference",
|
||||||
|
"value": "longitude"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"precedence": "reviewed_mapping_exclusion",
|
||||||
|
"resolution": "highest_precedence",
|
||||||
|
"review_reason": "serialized into the aggregate content payload",
|
||||||
|
"source": "reviewed_mapping_exclusion",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
"required": {
|
||||||
|
"candidates": [
|
||||||
|
{
|
||||||
|
"precedence": "default",
|
||||||
|
"selected": true,
|
||||||
|
"source": "default",
|
||||||
|
"value": false
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"precedence": "default",
|
||||||
|
"resolution": "fallback",
|
||||||
|
"source": "default",
|
||||||
|
"value": false
|
||||||
|
},
|
||||||
|
"required_when": {
|
||||||
|
"candidates": [
|
||||||
|
{
|
||||||
|
"precedence": "default",
|
||||||
|
"selected": true,
|
||||||
|
"source": "default",
|
||||||
|
"value": ""
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"precedence": "default",
|
||||||
|
"resolution": "highest_precedence",
|
||||||
|
"source": "default",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
"type": {
|
||||||
|
"candidates": [
|
||||||
|
{
|
||||||
|
"precedence": "cobra_contract",
|
||||||
|
"selected": true,
|
||||||
|
"source": "cobra_flag_type",
|
||||||
|
"value": "string"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"precedence": "cobra_contract",
|
||||||
|
"resolution": "highest_precedence",
|
||||||
|
"source": "cobra_flag_type",
|
||||||
|
"value": "string"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"required": false,
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"map-thumbnail-url": {
|
||||||
|
"description": "位置消息地图缩略图 mediaId,形如 @mediaId(msgType=location 时必填)",
|
||||||
|
"field_provenance": {
|
||||||
|
"description": {
|
||||||
|
"candidates": [
|
||||||
|
{
|
||||||
|
"precedence": "cobra_contract",
|
||||||
|
"selected": true,
|
||||||
|
"source": "cobra_usage",
|
||||||
|
"value": "位置消息地图缩略图 mediaId,形如 @mediaId(msgType=location 时必填)"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"precedence": "default",
|
||||||
|
"selected": false,
|
||||||
|
"source": "default",
|
||||||
|
"value": ""
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"precedence": "cobra_contract",
|
||||||
|
"resolution": "highest_precedence",
|
||||||
|
"source": "cobra_usage",
|
||||||
|
"value": "位置消息地图缩略图 mediaId,形如 @mediaId(msgType=location 时必填)"
|
||||||
|
},
|
||||||
|
"property": {
|
||||||
|
"candidates": [
|
||||||
|
{
|
||||||
|
"precedence": "reviewed_mapping_exclusion",
|
||||||
|
"review_reason": "serialized into the aggregate content payload",
|
||||||
|
"selected": true,
|
||||||
|
"source": "reviewed_mapping_exclusion",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"precedence": "inference",
|
||||||
|
"selected": false,
|
||||||
|
"source": "flag_name_inference",
|
||||||
|
"value": "mapThumbnailUrl"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"precedence": "reviewed_mapping_exclusion",
|
||||||
|
"resolution": "highest_precedence",
|
||||||
|
"review_reason": "serialized into the aggregate content payload",
|
||||||
|
"source": "reviewed_mapping_exclusion",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
"required": {
|
||||||
|
"candidates": [
|
||||||
|
{
|
||||||
|
"precedence": "default",
|
||||||
|
"selected": true,
|
||||||
|
"source": "default",
|
||||||
|
"value": false
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"precedence": "default",
|
||||||
|
"resolution": "fallback",
|
||||||
|
"source": "default",
|
||||||
|
"value": false
|
||||||
|
},
|
||||||
|
"required_when": {
|
||||||
|
"candidates": [
|
||||||
|
{
|
||||||
|
"precedence": "default",
|
||||||
|
"selected": true,
|
||||||
|
"source": "default",
|
||||||
|
"value": ""
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"precedence": "default",
|
||||||
|
"resolution": "highest_precedence",
|
||||||
|
"source": "default",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
"type": {
|
||||||
|
"candidates": [
|
||||||
|
{
|
||||||
|
"precedence": "cobra_contract",
|
||||||
|
"selected": true,
|
||||||
|
"source": "cobra_flag_type",
|
||||||
|
"value": "string"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"precedence": "cobra_contract",
|
||||||
|
"resolution": "highest_precedence",
|
||||||
|
"source": "cobra_flag_type",
|
||||||
|
"value": "string"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"required": false,
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
"media-id": {
|
"media-id": {
|
||||||
"description": "上游已提供的图片 mediaId(仅旧版 msgType=image;CLI 不提供本地上传到 mediaId)",
|
"description": "上游已提供的图片 mediaId(仅旧版 msgType=image;CLI 不提供本地上传到 mediaId)",
|
||||||
"example": "@lADP_schema_smoke",
|
"example": "@lADP_schema_smoke",
|
||||||
@@ -46834,7 +47289,7 @@
|
|||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
"msg-type": {
|
"msg-type": {
|
||||||
"description": "富媒体消息类型: image/file/audio/video(本地图片/文件推荐 file --file-path;image 仅接受已有 mediaId)",
|
"description": "富媒体消息类型: image/file/audio/video/location/profile(本地图片/文件推荐 file --file-path;image 仅接受已有 mediaId)",
|
||||||
"enum": [
|
"enum": [
|
||||||
"image",
|
"image",
|
||||||
"file",
|
"file",
|
||||||
@@ -46848,7 +47303,7 @@
|
|||||||
"precedence": "cobra_contract",
|
"precedence": "cobra_contract",
|
||||||
"selected": true,
|
"selected": true,
|
||||||
"source": "cobra_usage",
|
"source": "cobra_usage",
|
||||||
"value": "富媒体消息类型: image/file/audio/video(本地图片/文件推荐 file --file-path;image 仅接受已有 mediaId)"
|
"value": "富媒体消息类型: image/file/audio/video/location/profile(本地图片/文件推荐 file --file-path;image 仅接受已有 mediaId)"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"precedence": "mcp_metadata",
|
"precedence": "mcp_metadata",
|
||||||
@@ -46866,7 +47321,7 @@
|
|||||||
"precedence": "cobra_contract",
|
"precedence": "cobra_contract",
|
||||||
"resolution": "highest_precedence",
|
"resolution": "highest_precedence",
|
||||||
"source": "cobra_usage",
|
"source": "cobra_usage",
|
||||||
"value": "富媒体消息类型: image/file/audio/video(本地图片/文件推荐 file --file-path;image 仅接受已有 mediaId)"
|
"value": "富媒体消息类型: image/file/audio/video/location/profile(本地图片/文件推荐 file --file-path;image 仅接受已有 mediaId)"
|
||||||
},
|
},
|
||||||
"enum": {
|
"enum": {
|
||||||
"candidates": [
|
"candidates": [
|
||||||
|
|||||||
@@ -828,7 +828,7 @@
|
|||||||
"canonical_path": "drive.apply_permission",
|
"canonical_path": "drive.apply_permission",
|
||||||
"cli_name": "apply",
|
"cli_name": "apply",
|
||||||
"cli_path": "drive permission apply",
|
"cli_path": "drive permission apply",
|
||||||
"confirmation": "not_required",
|
"confirmation": "user_required",
|
||||||
"description": "向指定节点的审批人发起权限申请。建议先用 apply-info 获取可申请角色与审批人。\n\n注意: 本命令会真实通知审批人,Agent 必须先获得用户明确同意后再执行。",
|
"description": "向指定节点的审批人发起权限申请。建议先用 apply-info 获取可申请角色与审批人。\n\n注意: 本命令会真实通知审批人,Agent 必须先获得用户明确同意后再执行。",
|
||||||
"display": "钉盘文件管理",
|
"display": "钉盘文件管理",
|
||||||
"effect": "write",
|
"effect": "write",
|
||||||
@@ -912,14 +912,14 @@
|
|||||||
"review_reason": "dws-tool-metadata/drive marks this tool as reviewed",
|
"review_reason": "dws-tool-metadata/drive marks this tool as reviewed",
|
||||||
"selected": true,
|
"selected": true,
|
||||||
"source": "internal/cli/schema_hints/metadata/drive.json",
|
"source": "internal/cli/schema_hints/metadata/drive.json",
|
||||||
"value": "not_required"
|
"value": "user_required"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"precedence": "reviewed_explicit",
|
"precedence": "reviewed_explicit",
|
||||||
"resolution": "highest_precedence",
|
"resolution": "highest_precedence",
|
||||||
"review_reason": "dws-tool-metadata/drive marks this tool as reviewed",
|
"review_reason": "dws-tool-metadata/drive marks this tool as reviewed",
|
||||||
"source": "internal/cli/schema_hints/metadata/drive.json",
|
"source": "internal/cli/schema_hints/metadata/drive.json",
|
||||||
"value": "not_required"
|
"value": "user_required"
|
||||||
},
|
},
|
||||||
"description": {
|
"description": {
|
||||||
"candidates": [
|
"candidates": [
|
||||||
@@ -5624,6 +5624,625 @@
|
|||||||
"已确认 contentType 非 ALIDOC,需要落盘本地查看时"
|
"已确认 contentType 非 ALIDOC,需要落盘本地查看时"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
"drive.download_file_version": {
|
||||||
|
"agent_metadata_source": "embedded-skill-metadata",
|
||||||
|
"agent_source_refs": [
|
||||||
|
"CommandRegistry:canonical_path=drive.download_file_version",
|
||||||
|
"cobra-help:dws drive download-version",
|
||||||
|
"internal/cli/schema_hints/metadata/drive.json",
|
||||||
|
"internal/cli/schema_hints/selection/drive.json",
|
||||||
|
"wukong-develop:wukong/products/drive.go"
|
||||||
|
],
|
||||||
|
"agent_summary": "下载钉盘普通文件的指定历史版本到本地(两步下载:取签名 URL 后 HTTP GET)",
|
||||||
|
"agent_summary_source": "dws-agent-selection/drive",
|
||||||
|
"availability": "available",
|
||||||
|
"avoid_when": [
|
||||||
|
"下载最新版本用 drive download",
|
||||||
|
"在线文档(adoc)历史版本用 doc version 系列命令",
|
||||||
|
"在线表格(axls)历史版本用 sheet version 系列命令"
|
||||||
|
],
|
||||||
|
"canonical_path": "drive.download_file_version",
|
||||||
|
"cli_name": "download-version",
|
||||||
|
"cli_path": "drive download-version",
|
||||||
|
"confirmation": "not_required",
|
||||||
|
"description": "下载钉盘文件的指定历史版本到本地(两步下载流程)。\n\n仅适用于普通文件(如 pdf、docx、xlsx、png 等):\n 钉钉在线文档(adoc)请使用 dws doc version 系列命令\n 钉钉在线表格(axls)请使用 dws sheet version 系列命令\n\n流程:\n 1. 获取历史版本下载 URL 和签名请求头 (download_file_version)\n 2. HTTP GET 下载文件二进制内容到本地\n\n版本号从 dws drive list --node \u003cdentryUuid\u003e --versions 获取。",
|
||||||
|
"display": "钉盘文件管理",
|
||||||
|
"effect": "read",
|
||||||
|
"effect_source": "agent-hint",
|
||||||
|
"examples": [
|
||||||
|
"dws drive download-version --node \u003cdentryUuid\u003e --version 3 --output ./report_v3.pdf"
|
||||||
|
],
|
||||||
|
"field_provenance": {
|
||||||
|
"agent_summary": {
|
||||||
|
"candidates": [
|
||||||
|
{
|
||||||
|
"precedence": "reviewed_explicit",
|
||||||
|
"review_reason": "人工审阅:对照悟空 develop drive download --version 分支实现移植为独立命令;单一 download_file_version 远端调用,参数契约与帮助文档一致。",
|
||||||
|
"selected": true,
|
||||||
|
"source": "internal/cli/schema_hints/selection/drive.json",
|
||||||
|
"value": "下载钉盘普通文件的指定历史版本到本地(两步下载:取签名 URL 后 HTTP GET)"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"precedence": "reviewed_explicit",
|
||||||
|
"resolution": "highest_precedence",
|
||||||
|
"review_reason": "人工审阅:对照悟空 develop drive download --version 分支实现移植为独立命令;单一 download_file_version 远端调用,参数契约与帮助文档一致。",
|
||||||
|
"source": "internal/cli/schema_hints/selection/drive.json",
|
||||||
|
"value": "下载钉盘普通文件的指定历史版本到本地(两步下载:取签名 URL 后 HTTP GET)"
|
||||||
|
},
|
||||||
|
"availability": {
|
||||||
|
"candidates": [
|
||||||
|
{
|
||||||
|
"precedence": "reviewed_explicit",
|
||||||
|
"review_reason": "dws-tool-metadata/drive marks this tool as reviewed",
|
||||||
|
"selected": true,
|
||||||
|
"source": "internal/cli/schema_hints/metadata/drive.json",
|
||||||
|
"value": "available"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"precedence": "reviewed_explicit",
|
||||||
|
"resolution": "highest_precedence",
|
||||||
|
"review_reason": "dws-tool-metadata/drive marks this tool as reviewed",
|
||||||
|
"source": "internal/cli/schema_hints/metadata/drive.json",
|
||||||
|
"value": "available"
|
||||||
|
},
|
||||||
|
"avoid_when": {
|
||||||
|
"candidates": [
|
||||||
|
{
|
||||||
|
"precedence": "reviewed_explicit",
|
||||||
|
"review_reason": "人工审阅:对照悟空 develop drive download --version 分支实现移植为独立命令;单一 download_file_version 远端调用,参数契约与帮助文档一致。",
|
||||||
|
"selected": true,
|
||||||
|
"source": "internal/cli/schema_hints/selection/drive.json",
|
||||||
|
"value": [
|
||||||
|
"下载最新版本用 drive download",
|
||||||
|
"在线文档(adoc)历史版本用 doc version 系列命令",
|
||||||
|
"在线表格(axls)历史版本用 sheet version 系列命令"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"precedence": "reviewed_explicit",
|
||||||
|
"resolution": "highest_precedence",
|
||||||
|
"review_reason": "人工审阅:对照悟空 develop drive download --version 分支实现移植为独立命令;单一 download_file_version 远端调用,参数契约与帮助文档一致。",
|
||||||
|
"source": "internal/cli/schema_hints/selection/drive.json",
|
||||||
|
"value": [
|
||||||
|
"下载最新版本用 drive download",
|
||||||
|
"在线文档(adoc)历史版本用 doc version 系列命令",
|
||||||
|
"在线表格(axls)历史版本用 sheet version 系列命令"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"canonical_path": {
|
||||||
|
"candidates": [
|
||||||
|
{
|
||||||
|
"precedence": "command_registry",
|
||||||
|
"selected": true,
|
||||||
|
"source": "reviewed_command_registry",
|
||||||
|
"source_ref": "drive download-version",
|
||||||
|
"value": "drive.download_file_version"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"precedence": "command_registry",
|
||||||
|
"resolution": "registry_identity",
|
||||||
|
"source": "reviewed_command_registry",
|
||||||
|
"source_ref": "drive download-version",
|
||||||
|
"value": "drive.download_file_version"
|
||||||
|
},
|
||||||
|
"confirmation": {
|
||||||
|
"candidates": [
|
||||||
|
{
|
||||||
|
"precedence": "reviewed_explicit",
|
||||||
|
"review_reason": "dws-tool-metadata/drive marks this tool as reviewed",
|
||||||
|
"selected": true,
|
||||||
|
"source": "internal/cli/schema_hints/metadata/drive.json",
|
||||||
|
"value": "not_required"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"precedence": "reviewed_explicit",
|
||||||
|
"resolution": "highest_precedence",
|
||||||
|
"review_reason": "dws-tool-metadata/drive marks this tool as reviewed",
|
||||||
|
"source": "internal/cli/schema_hints/metadata/drive.json",
|
||||||
|
"value": "not_required"
|
||||||
|
},
|
||||||
|
"description": {
|
||||||
|
"candidates": [
|
||||||
|
{
|
||||||
|
"precedence": "cobra_help",
|
||||||
|
"selected": true,
|
||||||
|
"source": "cobra_help",
|
||||||
|
"value": "下载钉盘文件的指定历史版本到本地(两步下载流程)。\n\n仅适用于普通文件(如 pdf、docx、xlsx、png 等):\n 钉钉在线文档(adoc)请使用 dws doc version 系列命令\n 钉钉在线表格(axls)请使用 dws sheet version 系列命令\n\n流程:\n 1. 获取历史版本下载 URL 和签名请求头 (download_file_version)\n 2. HTTP GET 下载文件二进制内容到本地\n\n版本号从 dws drive list --node \u003cdentryUuid\u003e --versions 获取。"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"precedence": "cobra_help",
|
||||||
|
"resolution": "highest_precedence",
|
||||||
|
"source": "cobra_help",
|
||||||
|
"value": "下载钉盘文件的指定历史版本到本地(两步下载流程)。\n\n仅适用于普通文件(如 pdf、docx、xlsx、png 等):\n 钉钉在线文档(adoc)请使用 dws doc version 系列命令\n 钉钉在线表格(axls)请使用 dws sheet version 系列命令\n\n流程:\n 1. 获取历史版本下载 URL 和签名请求头 (download_file_version)\n 2. HTTP GET 下载文件二进制内容到本地\n\n版本号从 dws drive list --node \u003cdentryUuid\u003e --versions 获取。"
|
||||||
|
},
|
||||||
|
"effect": {
|
||||||
|
"candidates": [
|
||||||
|
{
|
||||||
|
"precedence": "reviewed_explicit",
|
||||||
|
"review_reason": "dws-tool-metadata/drive marks this tool as reviewed",
|
||||||
|
"selected": true,
|
||||||
|
"source": "internal/cli/schema_hints/metadata/drive.json",
|
||||||
|
"value": "read"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"precedence": "reviewed_explicit",
|
||||||
|
"resolution": "highest_precedence",
|
||||||
|
"review_reason": "dws-tool-metadata/drive marks this tool as reviewed",
|
||||||
|
"source": "internal/cli/schema_hints/metadata/drive.json",
|
||||||
|
"value": "read"
|
||||||
|
},
|
||||||
|
"examples": {
|
||||||
|
"candidates": [
|
||||||
|
{
|
||||||
|
"precedence": "reviewed_explicit",
|
||||||
|
"review_reason": "人工审阅:对照悟空 develop drive download --version 分支实现移植为独立命令;单一 download_file_version 远端调用,参数契约与帮助文档一致。",
|
||||||
|
"selected": true,
|
||||||
|
"source": "internal/cli/schema_hints/selection/drive.json",
|
||||||
|
"value": [
|
||||||
|
"dws drive download-version --node \u003cdentryUuid\u003e --version 3 --output ./report_v3.pdf"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"precedence": "reviewed_explicit",
|
||||||
|
"resolution": "highest_precedence",
|
||||||
|
"review_reason": "人工审阅:对照悟空 develop drive download --version 分支实现移植为独立命令;单一 download_file_version 远端调用,参数契约与帮助文档一致。",
|
||||||
|
"source": "internal/cli/schema_hints/selection/drive.json",
|
||||||
|
"value": [
|
||||||
|
"dws drive download-version --node \u003cdentryUuid\u003e --version 3 --output ./report_v3.pdf"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"idempotency": {
|
||||||
|
"candidates": [
|
||||||
|
{
|
||||||
|
"precedence": "reviewed_explicit",
|
||||||
|
"review_reason": "dws-tool-metadata/drive marks this tool as reviewed",
|
||||||
|
"selected": true,
|
||||||
|
"source": "internal/cli/schema_hints/metadata/drive.json",
|
||||||
|
"value": "idempotent"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"precedence": "reviewed_explicit",
|
||||||
|
"resolution": "highest_precedence",
|
||||||
|
"review_reason": "dws-tool-metadata/drive marks this tool as reviewed",
|
||||||
|
"source": "internal/cli/schema_hints/metadata/drive.json",
|
||||||
|
"value": "idempotent"
|
||||||
|
},
|
||||||
|
"interface_mode": {
|
||||||
|
"candidates": [
|
||||||
|
{
|
||||||
|
"precedence": "reviewed_explicit",
|
||||||
|
"review_reason": "dws-tool-metadata/drive marks this tool as reviewed",
|
||||||
|
"selected": true,
|
||||||
|
"source": "internal/cli/schema_hints/metadata/drive.json",
|
||||||
|
"value": "composite"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"precedence": "reviewed_explicit",
|
||||||
|
"resolution": "highest_precedence",
|
||||||
|
"review_reason": "dws-tool-metadata/drive marks this tool as reviewed",
|
||||||
|
"source": "internal/cli/schema_hints/metadata/drive.json",
|
||||||
|
"value": "composite"
|
||||||
|
},
|
||||||
|
"interface_reason": {
|
||||||
|
"candidates": [
|
||||||
|
{
|
||||||
|
"precedence": "reviewed_explicit",
|
||||||
|
"review_reason": "dws-tool-metadata/drive marks this tool as reviewed",
|
||||||
|
"selected": true,
|
||||||
|
"source": "internal/cli/schema_hints/metadata/drive.json",
|
||||||
|
"value": "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."
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"precedence": "reviewed_explicit",
|
||||||
|
"resolution": "highest_precedence",
|
||||||
|
"review_reason": "dws-tool-metadata/drive marks this tool as reviewed",
|
||||||
|
"source": "internal/cli/schema_hints/metadata/drive.json",
|
||||||
|
"value": "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."
|
||||||
|
},
|
||||||
|
"interface_ref": {
|
||||||
|
"candidates": [
|
||||||
|
{
|
||||||
|
"precedence": "reviewed_explicit",
|
||||||
|
"review_reason": "final interface mode composite forbids a direct MCP interface_ref",
|
||||||
|
"selected": true,
|
||||||
|
"source": "internal/cli/schema_hints/metadata/drive.json",
|
||||||
|
"value": null
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"precedence": "reviewed_explicit",
|
||||||
|
"resolution": "interface_disposition_matrix",
|
||||||
|
"review_reason": "final interface mode composite forbids a direct MCP interface_ref",
|
||||||
|
"source": "internal/cli/schema_hints/metadata/drive.json",
|
||||||
|
"value": null
|
||||||
|
},
|
||||||
|
"reviewed": {
|
||||||
|
"candidates": [
|
||||||
|
{
|
||||||
|
"precedence": "reviewed_explicit",
|
||||||
|
"review_reason": "dws-tool-metadata/drive marks this tool as reviewed",
|
||||||
|
"selected": true,
|
||||||
|
"source": "internal/cli/schema_hints/metadata/drive.json",
|
||||||
|
"value": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"precedence": "reviewed_explicit",
|
||||||
|
"review_reason": "人工审阅:对照悟空 develop drive download --version 分支实现移植为独立命令;单一 download_file_version 远端调用,参数契约与帮助文档一致。",
|
||||||
|
"selected": false,
|
||||||
|
"source": "internal/cli/schema_hints/selection/drive.json",
|
||||||
|
"value": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"precedence": "reviewed_explicit",
|
||||||
|
"resolution": "highest_precedence",
|
||||||
|
"review_reason": "dws-tool-metadata/drive marks this tool as reviewed",
|
||||||
|
"source": "internal/cli/schema_hints/metadata/drive.json",
|
||||||
|
"value": true
|
||||||
|
},
|
||||||
|
"risk": {
|
||||||
|
"candidates": [
|
||||||
|
{
|
||||||
|
"precedence": "reviewed_explicit",
|
||||||
|
"review_reason": "dws-tool-metadata/drive marks this tool as reviewed",
|
||||||
|
"selected": true,
|
||||||
|
"source": "internal/cli/schema_hints/metadata/drive.json",
|
||||||
|
"value": "low"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"precedence": "reviewed_explicit",
|
||||||
|
"resolution": "highest_precedence",
|
||||||
|
"review_reason": "dws-tool-metadata/drive marks this tool as reviewed",
|
||||||
|
"source": "internal/cli/schema_hints/metadata/drive.json",
|
||||||
|
"value": "low"
|
||||||
|
},
|
||||||
|
"title": {
|
||||||
|
"candidates": [
|
||||||
|
{
|
||||||
|
"precedence": "cobra_help",
|
||||||
|
"selected": true,
|
||||||
|
"source": "cobra_help",
|
||||||
|
"value": "下载文件历史版本到本地"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"precedence": "cobra_help",
|
||||||
|
"resolution": "highest_precedence",
|
||||||
|
"source": "cobra_help",
|
||||||
|
"value": "下载文件历史版本到本地"
|
||||||
|
},
|
||||||
|
"use_when": {
|
||||||
|
"candidates": [
|
||||||
|
{
|
||||||
|
"precedence": "reviewed_explicit",
|
||||||
|
"review_reason": "人工审阅:对照悟空 develop drive download --version 分支实现移植为独立命令;单一 download_file_version 远端调用,参数契约与帮助文档一致。",
|
||||||
|
"selected": true,
|
||||||
|
"source": "internal/cli/schema_hints/selection/drive.json",
|
||||||
|
"value": [
|
||||||
|
"用户要下载文件的历史版本/旧版本",
|
||||||
|
"版本号已通过 drive list --versions 获取"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"precedence": "reviewed_explicit",
|
||||||
|
"resolution": "highest_precedence",
|
||||||
|
"review_reason": "人工审阅:对照悟空 develop drive download --version 分支实现移植为独立命令;单一 download_file_version 远端调用,参数契约与帮助文档一致。",
|
||||||
|
"source": "internal/cli/schema_hints/selection/drive.json",
|
||||||
|
"value": [
|
||||||
|
"用户要下载文件的历史版本/旧版本",
|
||||||
|
"版本号已通过 drive list --versions 获取"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"has_parameters": true,
|
||||||
|
"idempotency": "idempotent",
|
||||||
|
"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.",
|
||||||
|
"is_alias": false,
|
||||||
|
"name": "download_file_version",
|
||||||
|
"parameter_count": 3,
|
||||||
|
"parameters": {
|
||||||
|
"node": {
|
||||||
|
"description": "文件 ID (dentryUuid) 或 URL (必填)",
|
||||||
|
"field_provenance": {
|
||||||
|
"description": {
|
||||||
|
"candidates": [
|
||||||
|
{
|
||||||
|
"precedence": "cobra_contract",
|
||||||
|
"selected": true,
|
||||||
|
"source": "cobra_usage",
|
||||||
|
"value": "文件 ID (dentryUuid) 或 URL (必填)"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"precedence": "default",
|
||||||
|
"selected": false,
|
||||||
|
"source": "default",
|
||||||
|
"value": ""
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"precedence": "cobra_contract",
|
||||||
|
"resolution": "highest_precedence",
|
||||||
|
"source": "cobra_usage",
|
||||||
|
"value": "文件 ID (dentryUuid) 或 URL (必填)"
|
||||||
|
},
|
||||||
|
"property": {
|
||||||
|
"candidates": [
|
||||||
|
{
|
||||||
|
"precedence": "reviewed_mapping_exclusion",
|
||||||
|
"review_reason": "Reviewed unpinned adapter: drive.download_file_version has no singular pinned interface_ref; --node is a CLI wrapper input and does not publish a direct interface property.",
|
||||||
|
"selected": true,
|
||||||
|
"source": "reviewed_mapping_exclusion",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"precedence": "inference",
|
||||||
|
"selected": false,
|
||||||
|
"source": "flag_name_inference",
|
||||||
|
"value": "node"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"precedence": "reviewed_mapping_exclusion",
|
||||||
|
"resolution": "highest_precedence",
|
||||||
|
"review_reason": "Reviewed unpinned adapter: drive.download_file_version has no singular pinned interface_ref; --node is a CLI wrapper input and does not publish a direct interface property.",
|
||||||
|
"source": "reviewed_mapping_exclusion",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
"required": {
|
||||||
|
"candidates": [
|
||||||
|
{
|
||||||
|
"precedence": "inference",
|
||||||
|
"selected": true,
|
||||||
|
"source": "usage_required_inference",
|
||||||
|
"value": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"precedence": "default",
|
||||||
|
"selected": false,
|
||||||
|
"source": "default",
|
||||||
|
"value": false
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"precedence": "inference",
|
||||||
|
"resolution": "highest_precedence",
|
||||||
|
"source": "usage_required_inference",
|
||||||
|
"value": true
|
||||||
|
},
|
||||||
|
"required_when": {
|
||||||
|
"candidates": [
|
||||||
|
{
|
||||||
|
"precedence": "default",
|
||||||
|
"selected": true,
|
||||||
|
"source": "default",
|
||||||
|
"value": ""
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"precedence": "default",
|
||||||
|
"resolution": "highest_precedence",
|
||||||
|
"source": "default",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
"type": {
|
||||||
|
"candidates": [
|
||||||
|
{
|
||||||
|
"precedence": "cobra_contract",
|
||||||
|
"selected": true,
|
||||||
|
"source": "cobra_flag_type",
|
||||||
|
"value": "string"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"precedence": "cobra_contract",
|
||||||
|
"resolution": "highest_precedence",
|
||||||
|
"source": "cobra_flag_type",
|
||||||
|
"value": "string"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"required": true,
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"output": {
|
||||||
|
"description": "本地保存路径 (文件路径或目录,必填)",
|
||||||
|
"field_provenance": {
|
||||||
|
"description": {
|
||||||
|
"candidates": [
|
||||||
|
{
|
||||||
|
"precedence": "cobra_contract",
|
||||||
|
"selected": true,
|
||||||
|
"source": "cobra_usage",
|
||||||
|
"value": "本地保存路径 (文件路径或目录,必填)"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"precedence": "default",
|
||||||
|
"selected": false,
|
||||||
|
"source": "default",
|
||||||
|
"value": ""
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"precedence": "cobra_contract",
|
||||||
|
"resolution": "highest_precedence",
|
||||||
|
"source": "cobra_usage",
|
||||||
|
"value": "本地保存路径 (文件路径或目录,必填)"
|
||||||
|
},
|
||||||
|
"property": {
|
||||||
|
"candidates": [
|
||||||
|
{
|
||||||
|
"precedence": "reviewed_mapping_exclusion",
|
||||||
|
"review_reason": "Reviewed unpinned adapter: drive.download_file_version has no singular pinned interface_ref; --output is a CLI wrapper input and does not publish a direct interface property.",
|
||||||
|
"selected": true,
|
||||||
|
"source": "reviewed_mapping_exclusion",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"precedence": "inference",
|
||||||
|
"selected": false,
|
||||||
|
"source": "flag_name_inference",
|
||||||
|
"value": "output"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"precedence": "reviewed_mapping_exclusion",
|
||||||
|
"resolution": "highest_precedence",
|
||||||
|
"review_reason": "Reviewed unpinned adapter: drive.download_file_version has no singular pinned interface_ref; --output is a CLI wrapper input and does not publish a direct interface property.",
|
||||||
|
"source": "reviewed_mapping_exclusion",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
"required": {
|
||||||
|
"candidates": [
|
||||||
|
{
|
||||||
|
"precedence": "inference",
|
||||||
|
"selected": true,
|
||||||
|
"source": "usage_required_inference",
|
||||||
|
"value": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"precedence": "default",
|
||||||
|
"selected": false,
|
||||||
|
"source": "default",
|
||||||
|
"value": false
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"precedence": "inference",
|
||||||
|
"resolution": "highest_precedence",
|
||||||
|
"source": "usage_required_inference",
|
||||||
|
"value": true
|
||||||
|
},
|
||||||
|
"required_when": {
|
||||||
|
"candidates": [
|
||||||
|
{
|
||||||
|
"precedence": "default",
|
||||||
|
"selected": true,
|
||||||
|
"source": "default",
|
||||||
|
"value": ""
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"precedence": "default",
|
||||||
|
"resolution": "highest_precedence",
|
||||||
|
"source": "default",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
"type": {
|
||||||
|
"candidates": [
|
||||||
|
{
|
||||||
|
"precedence": "cobra_contract",
|
||||||
|
"selected": true,
|
||||||
|
"source": "cobra_flag_type",
|
||||||
|
"value": "string"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"precedence": "cobra_contract",
|
||||||
|
"resolution": "highest_precedence",
|
||||||
|
"source": "cobra_flag_type",
|
||||||
|
"value": "string"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"required": true,
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"version": {
|
||||||
|
"description": "历史版本号 (必填,正整数,从 drive list --versions 获取)",
|
||||||
|
"field_provenance": {
|
||||||
|
"description": {
|
||||||
|
"candidates": [
|
||||||
|
{
|
||||||
|
"precedence": "cobra_contract",
|
||||||
|
"selected": true,
|
||||||
|
"source": "cobra_usage",
|
||||||
|
"value": "历史版本号 (必填,正整数,从 drive list --versions 获取)"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"precedence": "default",
|
||||||
|
"selected": false,
|
||||||
|
"source": "default",
|
||||||
|
"value": ""
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"precedence": "cobra_contract",
|
||||||
|
"resolution": "highest_precedence",
|
||||||
|
"source": "cobra_usage",
|
||||||
|
"value": "历史版本号 (必填,正整数,从 drive list --versions 获取)"
|
||||||
|
},
|
||||||
|
"property": {
|
||||||
|
"candidates": [
|
||||||
|
{
|
||||||
|
"precedence": "reviewed_mapping_exclusion",
|
||||||
|
"review_reason": "Reviewed unpinned adapter: drive.download_file_version has no singular pinned interface_ref; --version is a CLI wrapper input and does not publish a direct interface property.",
|
||||||
|
"selected": true,
|
||||||
|
"source": "reviewed_mapping_exclusion",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"precedence": "inference",
|
||||||
|
"selected": false,
|
||||||
|
"source": "flag_name_inference",
|
||||||
|
"value": "version"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"precedence": "reviewed_mapping_exclusion",
|
||||||
|
"resolution": "highest_precedence",
|
||||||
|
"review_reason": "Reviewed unpinned adapter: drive.download_file_version has no singular pinned interface_ref; --version is a CLI wrapper input and does not publish a direct interface property.",
|
||||||
|
"source": "reviewed_mapping_exclusion",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
"required": {
|
||||||
|
"candidates": [
|
||||||
|
{
|
||||||
|
"precedence": "inference",
|
||||||
|
"selected": true,
|
||||||
|
"source": "usage_required_inference",
|
||||||
|
"value": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"precedence": "default",
|
||||||
|
"selected": false,
|
||||||
|
"source": "default",
|
||||||
|
"value": false
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"precedence": "inference",
|
||||||
|
"resolution": "highest_precedence",
|
||||||
|
"source": "usage_required_inference",
|
||||||
|
"value": true
|
||||||
|
},
|
||||||
|
"required_when": {
|
||||||
|
"candidates": [
|
||||||
|
{
|
||||||
|
"precedence": "default",
|
||||||
|
"selected": true,
|
||||||
|
"source": "default",
|
||||||
|
"value": ""
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"precedence": "default",
|
||||||
|
"resolution": "highest_precedence",
|
||||||
|
"source": "default",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
"type": {
|
||||||
|
"candidates": [
|
||||||
|
{
|
||||||
|
"precedence": "cobra_contract",
|
||||||
|
"selected": true,
|
||||||
|
"source": "cobra_flag_type",
|
||||||
|
"value": "integer"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"precedence": "cobra_contract",
|
||||||
|
"resolution": "highest_precedence",
|
||||||
|
"source": "cobra_flag_type",
|
||||||
|
"value": "integer"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"required": true,
|
||||||
|
"type": "integer"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"path": "drive.download_file_version",
|
||||||
|
"primary_cli_path": "drive download-version",
|
||||||
|
"product_id": "drive",
|
||||||
|
"reviewed": true,
|
||||||
|
"risk": "low",
|
||||||
|
"source": "reviewed_command_registry",
|
||||||
|
"title": "下载文件历史版本到本地",
|
||||||
|
"use_when": [
|
||||||
|
"用户要下载文件的历史版本/旧版本",
|
||||||
|
"版本号已通过 drive list --versions 获取"
|
||||||
|
]
|
||||||
|
},
|
||||||
"drive.get_cover": {
|
"drive.get_cover": {
|
||||||
"agent_metadata_source": "embedded-skill-metadata",
|
"agent_metadata_source": "embedded-skill-metadata",
|
||||||
"agent_source_refs": [
|
"agent_source_refs": [
|
||||||
|
|||||||
@@ -26983,8 +26983,99 @@
|
|||||||
"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.",
|
"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.",
|
||||||
"is_alias": false,
|
"is_alias": false,
|
||||||
"name": "formula_verify",
|
"name": "formula_verify",
|
||||||
"parameter_count": 6,
|
"parameter_count": 7,
|
||||||
"parameters": {
|
"parameters": {
|
||||||
|
"exit-on-error": {
|
||||||
|
"description": "发现公式错误时返回非 0 退出码,便于 CI/自动化使用",
|
||||||
|
"field_provenance": {
|
||||||
|
"description": {
|
||||||
|
"candidates": [
|
||||||
|
{
|
||||||
|
"precedence": "cobra_contract",
|
||||||
|
"selected": true,
|
||||||
|
"source": "cobra_usage",
|
||||||
|
"value": "发现公式错误时返回非 0 退出码,便于 CI/自动化使用"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"precedence": "default",
|
||||||
|
"selected": false,
|
||||||
|
"source": "default",
|
||||||
|
"value": ""
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"precedence": "cobra_contract",
|
||||||
|
"resolution": "highest_precedence",
|
||||||
|
"source": "cobra_usage",
|
||||||
|
"value": "发现公式错误时返回非 0 退出码,便于 CI/自动化使用"
|
||||||
|
},
|
||||||
|
"property": {
|
||||||
|
"candidates": [
|
||||||
|
{
|
||||||
|
"precedence": "reviewed_mapping_exclusion",
|
||||||
|
"review_reason": "Reviewed unpinned adapter: sheet.formula_verify has no singular pinned interface_ref; --exit-on-error is a CLI wrapper input and does not publish a direct interface property.",
|
||||||
|
"selected": true,
|
||||||
|
"source": "reviewed_mapping_exclusion",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"precedence": "inference",
|
||||||
|
"selected": false,
|
||||||
|
"source": "flag_name_inference",
|
||||||
|
"value": "exitOnError"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"precedence": "reviewed_mapping_exclusion",
|
||||||
|
"resolution": "highest_precedence",
|
||||||
|
"review_reason": "Reviewed unpinned adapter: sheet.formula_verify has no singular pinned interface_ref; --exit-on-error is a CLI wrapper input and does not publish a direct interface property.",
|
||||||
|
"source": "reviewed_mapping_exclusion",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
"required": {
|
||||||
|
"candidates": [
|
||||||
|
{
|
||||||
|
"precedence": "default",
|
||||||
|
"selected": true,
|
||||||
|
"source": "default",
|
||||||
|
"value": false
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"precedence": "default",
|
||||||
|
"resolution": "fallback",
|
||||||
|
"source": "default",
|
||||||
|
"value": false
|
||||||
|
},
|
||||||
|
"required_when": {
|
||||||
|
"candidates": [
|
||||||
|
{
|
||||||
|
"precedence": "default",
|
||||||
|
"selected": true,
|
||||||
|
"source": "default",
|
||||||
|
"value": ""
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"precedence": "default",
|
||||||
|
"resolution": "highest_precedence",
|
||||||
|
"source": "default",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
"type": {
|
||||||
|
"candidates": [
|
||||||
|
{
|
||||||
|
"precedence": "cobra_contract",
|
||||||
|
"selected": true,
|
||||||
|
"source": "cobra_flag_type",
|
||||||
|
"value": "boolean"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"precedence": "cobra_contract",
|
||||||
|
"resolution": "highest_precedence",
|
||||||
|
"source": "cobra_flag_type",
|
||||||
|
"value": "boolean"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"required": false,
|
||||||
|
"type": "boolean"
|
||||||
|
},
|
||||||
"max-cells": {
|
"max-cells": {
|
||||||
"description": "最多扫描的单元格数",
|
"description": "最多扫描的单元格数",
|
||||||
"field_provenance": {
|
"field_provenance": {
|
||||||
@@ -34913,8 +35004,105 @@
|
|||||||
"is_alias": false,
|
"is_alias": false,
|
||||||
"metadata_source": "embedded-mcp-metadata",
|
"metadata_source": "embedded-mcp-metadata",
|
||||||
"name": "info",
|
"name": "info",
|
||||||
"parameter_count": 2,
|
"parameter_count": 3,
|
||||||
"parameters": {
|
"parameters": {
|
||||||
|
"include": {
|
||||||
|
"description": "可选扩展信息,逗号分隔;支持 groups / row_heights / col_widths / hidden_rows / hidden_cols / frozen",
|
||||||
|
"field_provenance": {
|
||||||
|
"description": {
|
||||||
|
"candidates": [
|
||||||
|
{
|
||||||
|
"precedence": "cobra_contract",
|
||||||
|
"selected": true,
|
||||||
|
"source": "cobra_usage",
|
||||||
|
"value": "可选扩展信息,逗号分隔;支持 groups / row_heights / col_widths / hidden_rows / hidden_cols / frozen"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"precedence": "mcp_metadata",
|
||||||
|
"selected": false,
|
||||||
|
"source": "mcp_metadata",
|
||||||
|
"value": "可选扩展信息列表。当前支持 groups,用于返回 rowGroups / columnGroups 分组信息。未指定时只返回基础工作表信息、冻结信息和 mergedRanges。"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"precedence": "default",
|
||||||
|
"selected": false,
|
||||||
|
"source": "default",
|
||||||
|
"value": ""
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"precedence": "cobra_contract",
|
||||||
|
"resolution": "highest_precedence",
|
||||||
|
"source": "cobra_usage",
|
||||||
|
"value": "可选扩展信息,逗号分隔;支持 groups / row_heights / col_widths / hidden_rows / hidden_cols / frozen"
|
||||||
|
},
|
||||||
|
"property": {
|
||||||
|
"candidates": [
|
||||||
|
{
|
||||||
|
"precedence": "versioned_binding",
|
||||||
|
"selected": true,
|
||||||
|
"source": "versioned_parameter_binding",
|
||||||
|
"value": "include"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"precedence": "inference",
|
||||||
|
"selected": false,
|
||||||
|
"source": "flag_name_inference",
|
||||||
|
"value": "include"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"precedence": "versioned_binding",
|
||||||
|
"resolution": "highest_precedence",
|
||||||
|
"source": "versioned_parameter_binding",
|
||||||
|
"value": "include"
|
||||||
|
},
|
||||||
|
"required": {
|
||||||
|
"candidates": [
|
||||||
|
{
|
||||||
|
"precedence": "default",
|
||||||
|
"selected": true,
|
||||||
|
"source": "default",
|
||||||
|
"value": false
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"precedence": "default",
|
||||||
|
"resolution": "fallback",
|
||||||
|
"source": "default",
|
||||||
|
"value": false
|
||||||
|
},
|
||||||
|
"required_when": {
|
||||||
|
"candidates": [
|
||||||
|
{
|
||||||
|
"precedence": "default",
|
||||||
|
"selected": true,
|
||||||
|
"source": "default",
|
||||||
|
"value": ""
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"precedence": "default",
|
||||||
|
"resolution": "highest_precedence",
|
||||||
|
"source": "default",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
"type": {
|
||||||
|
"candidates": [
|
||||||
|
{
|
||||||
|
"precedence": "cobra_contract",
|
||||||
|
"selected": true,
|
||||||
|
"source": "cobra_flag_type",
|
||||||
|
"value": "array"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"precedence": "cobra_contract",
|
||||||
|
"resolution": "highest_precedence",
|
||||||
|
"source": "cobra_flag_type",
|
||||||
|
"value": "array"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"interface_description": "可选扩展信息列表。当前支持 groups,用于返回 rowGroups / columnGroups 分组信息。未指定时只返回基础工作表信息、冻结信息和 mergedRanges。",
|
||||||
|
"property": "include",
|
||||||
|
"required": false,
|
||||||
|
"type": "array"
|
||||||
|
},
|
||||||
"node": {
|
"node": {
|
||||||
"description": "表格文档 ID 或 URL (必填)",
|
"description": "表格文档 ID 或 URL (必填)",
|
||||||
"field_provenance": {
|
"field_provenance": {
|
||||||
|
|||||||
@@ -49,6 +49,10 @@
|
|||||||
"canonical_path": "drive.download_file",
|
"canonical_path": "drive.download_file",
|
||||||
"cli_path": "drive download"
|
"cli_path": "drive download"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"canonical_path": "drive.download_file_version",
|
||||||
|
"cli_path": "drive download-version"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"canonical_path": "drive.get_file_info",
|
"canonical_path": "drive.get_file_info",
|
||||||
"cli_path": "drive info"
|
"cli_path": "drive info"
|
||||||
|
|||||||
@@ -1382,7 +1382,7 @@
|
|||||||
},
|
},
|
||||||
"chat.batch_update_group_chat_settings": {
|
"chat.batch_update_group_chat_settings": {
|
||||||
"effect": "write",
|
"effect": "write",
|
||||||
"risk": "low",
|
"risk": "medium",
|
||||||
"confirmation": "not_required",
|
"confirmation": "not_required",
|
||||||
"idempotency": "idempotent",
|
"idempotency": "idempotent",
|
||||||
"interface_mode": "composite",
|
"interface_mode": "composite",
|
||||||
|
|||||||
@@ -17,6 +17,17 @@
|
|||||||
"availability": "available",
|
"availability": "available",
|
||||||
"reviewed": true
|
"reviewed": true
|
||||||
},
|
},
|
||||||
|
"drive.apply_permission": {
|
||||||
|
"effect": "write",
|
||||||
|
"risk": "medium",
|
||||||
|
"confirmation": "user_required",
|
||||||
|
"idempotency": "non_idempotent",
|
||||||
|
"interface_mode": "composite",
|
||||||
|
"availability": "available",
|
||||||
|
"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,
|
||||||
|
"runtime_gate": "confirm_delete"
|
||||||
|
},
|
||||||
"drive.commit_upload": {
|
"drive.commit_upload": {
|
||||||
"interface_mode": "mcp",
|
"interface_mode": "mcp",
|
||||||
"availability": "available",
|
"availability": "available",
|
||||||
@@ -64,6 +75,28 @@
|
|||||||
"availability": "available",
|
"availability": "available",
|
||||||
"reviewed": true
|
"reviewed": true
|
||||||
},
|
},
|
||||||
|
"drive.download_file_version": {
|
||||||
|
"effect": "read",
|
||||||
|
"risk": "low",
|
||||||
|
"confirmation": "not_required",
|
||||||
|
"idempotency": "idempotent",
|
||||||
|
"interface_mode": "composite",
|
||||||
|
"availability": "available",
|
||||||
|
"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,
|
||||||
|
"runtime_gate": "none"
|
||||||
|
},
|
||||||
|
"drive.get_cover": {
|
||||||
|
"effect": "read",
|
||||||
|
"risk": "low",
|
||||||
|
"confirmation": "not_required",
|
||||||
|
"idempotency": "idempotent",
|
||||||
|
"interface_mode": "composite",
|
||||||
|
"availability": "available",
|
||||||
|
"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,
|
||||||
|
"runtime_gate": "none"
|
||||||
|
},
|
||||||
"drive.get_file_info": {
|
"drive.get_file_info": {
|
||||||
"interface_mode": "mcp",
|
"interface_mode": "mcp",
|
||||||
"availability": "available",
|
"availability": "available",
|
||||||
@@ -75,6 +108,17 @@
|
|||||||
"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.",
|
"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
|
"reviewed": true
|
||||||
},
|
},
|
||||||
|
"drive.get_star_list": {
|
||||||
|
"effect": "read",
|
||||||
|
"risk": "low",
|
||||||
|
"confirmation": "not_required",
|
||||||
|
"idempotency": "idempotent",
|
||||||
|
"interface_mode": "composite",
|
||||||
|
"availability": "available",
|
||||||
|
"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,
|
||||||
|
"runtime_gate": "none"
|
||||||
|
},
|
||||||
"drive.get_upload_info": {
|
"drive.get_upload_info": {
|
||||||
"interface_mode": "mcp",
|
"interface_mode": "mcp",
|
||||||
"availability": "available",
|
"availability": "available",
|
||||||
@@ -100,6 +144,17 @@
|
|||||||
"availability": "available",
|
"availability": "available",
|
||||||
"reviewed": true
|
"reviewed": true
|
||||||
},
|
},
|
||||||
|
"drive.mark_star": {
|
||||||
|
"effect": "write",
|
||||||
|
"risk": "low",
|
||||||
|
"confirmation": "not_required",
|
||||||
|
"idempotency": "idempotent",
|
||||||
|
"interface_mode": "composite",
|
||||||
|
"availability": "available",
|
||||||
|
"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,
|
||||||
|
"runtime_gate": "none"
|
||||||
|
},
|
||||||
"drive.move_document": {
|
"drive.move_document": {
|
||||||
"interface_ref": {
|
"interface_ref": {
|
||||||
"product_id": "doc",
|
"product_id": "doc",
|
||||||
@@ -164,6 +219,17 @@
|
|||||||
"reviewed": true,
|
"reviewed": true,
|
||||||
"runtime_gate": "confirm_dangerous"
|
"runtime_gate": "confirm_dangerous"
|
||||||
},
|
},
|
||||||
|
"drive.query_permission_apply_info": {
|
||||||
|
"effect": "read",
|
||||||
|
"risk": "low",
|
||||||
|
"confirmation": "not_required",
|
||||||
|
"idempotency": "idempotent",
|
||||||
|
"interface_mode": "composite",
|
||||||
|
"availability": "available",
|
||||||
|
"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,
|
||||||
|
"runtime_gate": "none"
|
||||||
|
},
|
||||||
"drive.recent": {
|
"drive.recent": {
|
||||||
"effect": "read",
|
"effect": "read",
|
||||||
"risk": "low",
|
"risk": "low",
|
||||||
@@ -212,28 +278,46 @@
|
|||||||
"review_reason": "The reviewed CLI reads node metadata before mutation and strips only the exact current extension for non-folder nodes, avoiding both duplicate extensions and dotted-folder corruption without a suffix whitelist.",
|
"review_reason": "The reviewed CLI reads node metadata before mutation and strips only the exact current extension for non-folder nodes, avoiding both duplicate extensions and dotted-folder corruption without a suffix whitelist.",
|
||||||
"cli_path": "drive rename"
|
"cli_path": "drive rename"
|
||||||
},
|
},
|
||||||
|
"drive.revert_file_version": {
|
||||||
|
"effect": "write",
|
||||||
|
"risk": "medium",
|
||||||
|
"confirmation": "user_required",
|
||||||
|
"idempotency": "non_idempotent",
|
||||||
|
"interface_mode": "composite",
|
||||||
|
"availability": "available",
|
||||||
|
"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,
|
||||||
|
"runtime_gate": "confirm_delete"
|
||||||
|
},
|
||||||
"drive.search_files": {
|
"drive.search_files": {
|
||||||
"interface_mode": "mcp",
|
"interface_mode": "mcp",
|
||||||
"availability": "available",
|
"availability": "available",
|
||||||
"reviewed": true
|
"reviewed": true
|
||||||
},
|
},
|
||||||
"drive.upload": {
|
"drive.shortcut_copy": {
|
||||||
"effect": "write",
|
"effect": "write",
|
||||||
"risk": "medium",
|
"risk": "medium",
|
||||||
"confirmation": "not_required",
|
"confirmation": "user_required",
|
||||||
"idempotency": "unknown",
|
"idempotency": "unknown",
|
||||||
"interface_mode": "composite",
|
"interface_mode": "composite",
|
||||||
"availability": "available",
|
"availability": "available",
|
||||||
"interface_reason": "命令包含多个 RPC、条件分派或本地 HTTP/文件步骤,不能绑定为单一 interface_ref",
|
"interface_reason": "Reviewed built-in shortcut adapter: the executable CLI owns validation, optional multi-step orchestration, output projection, and confirmation; the complete command contract is not represented by one pinned MCP interface_ref.",
|
||||||
"reviewed": true,
|
"reviewed": true,
|
||||||
"parameters": {
|
"review_reason": "Reviewed against the built-in Shortcut registry and mounted Cobra command: publishes the executable risk gate and composite interface without inventing a direct MCP identity.",
|
||||||
"node": {
|
"cli_path": "drive +copy",
|
||||||
"property": "nodeId",
|
"runtime_gate": "typed_yes"
|
||||||
"required": false
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
"review_reason": "The reviewed helper preserves the stable command-level Schema contract for ordinary uploads; --node switches to overwrite mode and the runtime still requires explicit confirmation unless --yes is supplied.",
|
"drive.shortcut_find_file": {
|
||||||
"cli_path": "drive upload",
|
"effect": "read",
|
||||||
|
"risk": "low",
|
||||||
|
"confirmation": "not_required",
|
||||||
|
"idempotency": "idempotent",
|
||||||
|
"interface_mode": "composite",
|
||||||
|
"availability": "available",
|
||||||
|
"interface_reason": "Reviewed built-in shortcut adapter: the executable CLI owns validation, optional multi-step orchestration, output projection, and confirmation; the complete command contract is not represented by one pinned MCP interface_ref.",
|
||||||
|
"reviewed": true,
|
||||||
|
"review_reason": "Reviewed against the built-in Shortcut registry and mounted Cobra command: publishes the executable risk gate and composite interface without inventing a direct MCP identity.",
|
||||||
|
"cli_path": "drive +find-file",
|
||||||
"runtime_gate": "none"
|
"runtime_gate": "none"
|
||||||
},
|
},
|
||||||
"drive.shortcut_info": {
|
"drive.shortcut_info": {
|
||||||
@@ -249,6 +333,32 @@
|
|||||||
"cli_path": "drive +info",
|
"cli_path": "drive +info",
|
||||||
"runtime_gate": "none"
|
"runtime_gate": "none"
|
||||||
},
|
},
|
||||||
|
"drive.shortcut_move": {
|
||||||
|
"effect": "write",
|
||||||
|
"risk": "medium",
|
||||||
|
"confirmation": "user_required",
|
||||||
|
"idempotency": "unknown",
|
||||||
|
"interface_mode": "composite",
|
||||||
|
"availability": "available",
|
||||||
|
"interface_reason": "Reviewed built-in shortcut adapter: the executable CLI owns validation, optional multi-step orchestration, output projection, and confirmation; the complete command contract is not represented by one pinned MCP interface_ref.",
|
||||||
|
"reviewed": true,
|
||||||
|
"review_reason": "Reviewed against the built-in Shortcut registry and mounted Cobra command: publishes the executable risk gate and composite interface without inventing a direct MCP identity.",
|
||||||
|
"cli_path": "drive +move",
|
||||||
|
"runtime_gate": "typed_yes"
|
||||||
|
},
|
||||||
|
"drive.shortcut_recent": {
|
||||||
|
"effect": "read",
|
||||||
|
"risk": "low",
|
||||||
|
"confirmation": "not_required",
|
||||||
|
"idempotency": "idempotent",
|
||||||
|
"interface_mode": "composite",
|
||||||
|
"availability": "available",
|
||||||
|
"interface_reason": "Reviewed built-in shortcut adapter: the executable CLI owns validation, optional multi-step orchestration, output projection, and confirmation; the complete command contract is not represented by one pinned MCP interface_ref.",
|
||||||
|
"reviewed": true,
|
||||||
|
"review_reason": "Reviewed against the built-in Shortcut registry and mounted Cobra command: publishes the executable risk gate and composite interface without inventing a direct MCP identity.",
|
||||||
|
"cli_path": "drive +recent",
|
||||||
|
"runtime_gate": "none"
|
||||||
|
},
|
||||||
"drive.shortcut_search": {
|
"drive.shortcut_search": {
|
||||||
"effect": "read",
|
"effect": "read",
|
||||||
"risk": "low",
|
"risk": "low",
|
||||||
@@ -275,68 +385,16 @@
|
|||||||
"cli_path": "drive +search-docs",
|
"cli_path": "drive +search-docs",
|
||||||
"runtime_gate": "none"
|
"runtime_gate": "none"
|
||||||
},
|
},
|
||||||
"drive.shortcut_copy": {
|
"drive.transfer_owner": {
|
||||||
"effect": "write",
|
"effect": "write",
|
||||||
"risk": "medium",
|
"risk": "high",
|
||||||
"confirmation": "user_required",
|
"confirmation": "user_required",
|
||||||
"idempotency": "unknown",
|
"idempotency": "non_idempotent",
|
||||||
"interface_mode": "composite",
|
|
||||||
"availability": "available",
|
|
||||||
"interface_reason": "Reviewed built-in shortcut adapter: the executable CLI owns validation, optional multi-step orchestration, output projection, and confirmation; the complete command contract is not represented by one pinned MCP interface_ref.",
|
|
||||||
"reviewed": true,
|
|
||||||
"review_reason": "Reviewed against the built-in Shortcut registry and mounted Cobra command: publishes the executable risk gate and composite interface without inventing a direct MCP identity.",
|
|
||||||
"cli_path": "drive +copy",
|
|
||||||
"runtime_gate": "typed_yes"
|
|
||||||
},
|
|
||||||
"drive.shortcut_move": {
|
|
||||||
"effect": "write",
|
|
||||||
"risk": "medium",
|
|
||||||
"confirmation": "user_required",
|
|
||||||
"idempotency": "unknown",
|
|
||||||
"interface_mode": "composite",
|
|
||||||
"availability": "available",
|
|
||||||
"interface_reason": "Reviewed built-in shortcut adapter: the executable CLI owns validation, optional multi-step orchestration, output projection, and confirmation; the complete command contract is not represented by one pinned MCP interface_ref.",
|
|
||||||
"reviewed": true,
|
|
||||||
"review_reason": "Reviewed against the built-in Shortcut registry and mounted Cobra command: publishes the executable risk gate and composite interface without inventing a direct MCP identity.",
|
|
||||||
"cli_path": "drive +move",
|
|
||||||
"runtime_gate": "typed_yes"
|
|
||||||
},
|
|
||||||
"drive.shortcut_recent": {
|
|
||||||
"effect": "read",
|
|
||||||
"risk": "low",
|
|
||||||
"confirmation": "not_required",
|
|
||||||
"idempotency": "idempotent",
|
|
||||||
"interface_mode": "composite",
|
|
||||||
"availability": "available",
|
|
||||||
"interface_reason": "Reviewed built-in shortcut adapter: the executable CLI owns validation, optional multi-step orchestration, output projection, and confirmation; the complete command contract is not represented by one pinned MCP interface_ref.",
|
|
||||||
"reviewed": true,
|
|
||||||
"review_reason": "Reviewed against the built-in Shortcut registry and mounted Cobra command: publishes the executable risk gate and composite interface without inventing a direct MCP identity.",
|
|
||||||
"cli_path": "drive +recent",
|
|
||||||
"runtime_gate": "none"
|
|
||||||
},
|
|
||||||
"drive.shortcut_find_file": {
|
|
||||||
"effect": "read",
|
|
||||||
"risk": "low",
|
|
||||||
"confirmation": "not_required",
|
|
||||||
"idempotency": "idempotent",
|
|
||||||
"interface_mode": "composite",
|
|
||||||
"availability": "available",
|
|
||||||
"interface_reason": "Reviewed built-in shortcut adapter: the executable CLI owns validation, optional multi-step orchestration, output projection, and confirmation; the complete command contract is not represented by one pinned MCP interface_ref.",
|
|
||||||
"reviewed": true,
|
|
||||||
"review_reason": "Reviewed against the built-in Shortcut registry and mounted Cobra command: publishes the executable risk gate and composite interface without inventing a direct MCP identity.",
|
|
||||||
"cli_path": "drive +find-file",
|
|
||||||
"runtime_gate": "none"
|
|
||||||
},
|
|
||||||
"drive.mark_star": {
|
|
||||||
"effect": "write",
|
|
||||||
"risk": "low",
|
|
||||||
"confirmation": "not_required",
|
|
||||||
"idempotency": "idempotent",
|
|
||||||
"interface_mode": "composite",
|
"interface_mode": "composite",
|
||||||
"availability": "available",
|
"availability": "available",
|
||||||
"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.",
|
"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,
|
"reviewed": true,
|
||||||
"runtime_gate": "none"
|
"runtime_gate": "confirm_delete"
|
||||||
},
|
},
|
||||||
"drive.unmark_star": {
|
"drive.unmark_star": {
|
||||||
"effect": "write",
|
"effect": "write",
|
||||||
@@ -349,70 +407,23 @@
|
|||||||
"reviewed": true,
|
"reviewed": true,
|
||||||
"runtime_gate": "none"
|
"runtime_gate": "none"
|
||||||
},
|
},
|
||||||
"drive.get_star_list": {
|
"drive.upload": {
|
||||||
"effect": "read",
|
|
||||||
"risk": "low",
|
|
||||||
"confirmation": "not_required",
|
|
||||||
"idempotency": "idempotent",
|
|
||||||
"interface_mode": "composite",
|
|
||||||
"availability": "available",
|
|
||||||
"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,
|
|
||||||
"runtime_gate": "none"
|
|
||||||
},
|
|
||||||
"drive.get_cover": {
|
|
||||||
"effect": "read",
|
|
||||||
"risk": "low",
|
|
||||||
"confirmation": "not_required",
|
|
||||||
"idempotency": "idempotent",
|
|
||||||
"interface_mode": "composite",
|
|
||||||
"availability": "available",
|
|
||||||
"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,
|
|
||||||
"runtime_gate": "none"
|
|
||||||
},
|
|
||||||
"drive.revert_file_version": {
|
|
||||||
"effect": "write",
|
|
||||||
"risk": "medium",
|
|
||||||
"confirmation": "user_required",
|
|
||||||
"idempotency": "non_idempotent",
|
|
||||||
"interface_mode": "composite",
|
|
||||||
"availability": "available",
|
|
||||||
"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,
|
|
||||||
"runtime_gate": "confirm_delete"
|
|
||||||
},
|
|
||||||
"drive.transfer_owner": {
|
|
||||||
"effect": "write",
|
|
||||||
"risk": "high",
|
|
||||||
"confirmation": "user_required",
|
|
||||||
"idempotency": "non_idempotent",
|
|
||||||
"interface_mode": "composite",
|
|
||||||
"availability": "available",
|
|
||||||
"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,
|
|
||||||
"runtime_gate": "confirm_delete"
|
|
||||||
},
|
|
||||||
"drive.query_permission_apply_info": {
|
|
||||||
"effect": "read",
|
|
||||||
"risk": "low",
|
|
||||||
"confirmation": "not_required",
|
|
||||||
"idempotency": "idempotent",
|
|
||||||
"interface_mode": "composite",
|
|
||||||
"availability": "available",
|
|
||||||
"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,
|
|
||||||
"runtime_gate": "none"
|
|
||||||
},
|
|
||||||
"drive.apply_permission": {
|
|
||||||
"effect": "write",
|
"effect": "write",
|
||||||
"risk": "medium",
|
"risk": "medium",
|
||||||
"confirmation": "not_required",
|
"confirmation": "not_required",
|
||||||
"idempotency": "non_idempotent",
|
"idempotency": "unknown",
|
||||||
"interface_mode": "composite",
|
"interface_mode": "composite",
|
||||||
"availability": "available",
|
"availability": "available",
|
||||||
"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.",
|
"interface_reason": "命令包含多个 RPC、条件分派或本地 HTTP/文件步骤,不能绑定为单一 interface_ref",
|
||||||
"reviewed": true,
|
"reviewed": true,
|
||||||
|
"parameters": {
|
||||||
|
"node": {
|
||||||
|
"property": "nodeId",
|
||||||
|
"required": false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"review_reason": "The reviewed helper preserves the stable command-level Schema contract for ordinary uploads; --node switches to overwrite mode and the runtime still requires explicit confirmation unless --yes is supplied.",
|
||||||
|
"cli_path": "drive upload",
|
||||||
"runtime_gate": "none"
|
"runtime_gate": "none"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
"channel": "open-source"
|
"channel": "open-source"
|
||||||
},
|
},
|
||||||
"coverage": {
|
"coverage": {
|
||||||
"source_tools": 839,
|
"source_tools": 840,
|
||||||
"matched_tools": 71
|
"matched_tools": 71
|
||||||
},
|
},
|
||||||
"tools": {
|
"tools": {
|
||||||
|
|||||||
@@ -33,6 +33,25 @@
|
|||||||
"live-mcp:dws schema doc.add_permission"
|
"live-mcp:dws schema doc.add_permission"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
"drive.apply_permission": {
|
||||||
|
"agent_summary": "向审批人发起文档权限申请(会真实通知审批人)",
|
||||||
|
"use_when": [
|
||||||
|
"用户确认要为无权限文档发起权限申请"
|
||||||
|
],
|
||||||
|
"avoid_when": [
|
||||||
|
"先用 apply-info 查可申请角色与审批人;未经用户确认不得自行提交"
|
||||||
|
],
|
||||||
|
"examples": [
|
||||||
|
"dws drive permission apply --node <DOC_ID> --role READER --users <审批人userId> --format json"
|
||||||
|
],
|
||||||
|
"reviewed": true,
|
||||||
|
"review_reason": "人工审阅:对照悟空 develop 同名命令实现、Cobra Long/Example 与 Runtime 确认门禁移植;不改变命令身份、参数契约或接口绑定。",
|
||||||
|
"source_refs": [
|
||||||
|
"CommandRegistry:canonical_path=drive.apply_permission",
|
||||||
|
"cobra-help:dws drive permission apply",
|
||||||
|
"wukong-develop:wukong/products"
|
||||||
|
]
|
||||||
|
},
|
||||||
"drive.commit_upload": {
|
"drive.commit_upload": {
|
||||||
"agent_summary": "提交文件上传",
|
"agent_summary": "提交文件上传",
|
||||||
"use_when": [
|
"use_when": [
|
||||||
@@ -187,6 +206,47 @@
|
|||||||
"live-mcp:dws schema drive.download_file"
|
"live-mcp:dws schema drive.download_file"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
"drive.download_file_version": {
|
||||||
|
"agent_summary": "下载钉盘普通文件的指定历史版本到本地(两步下载:取签名 URL 后 HTTP GET)",
|
||||||
|
"use_when": [
|
||||||
|
"用户要下载文件的历史版本/旧版本",
|
||||||
|
"版本号已通过 drive list --versions 获取"
|
||||||
|
],
|
||||||
|
"avoid_when": [
|
||||||
|
"下载最新版本用 drive download",
|
||||||
|
"在线文档(adoc)历史版本用 doc version 系列命令",
|
||||||
|
"在线表格(axls)历史版本用 sheet version 系列命令"
|
||||||
|
],
|
||||||
|
"examples": [
|
||||||
|
"dws drive download-version --node <dentryUuid> --version 3 --output ./report_v3.pdf"
|
||||||
|
],
|
||||||
|
"reviewed": true,
|
||||||
|
"review_reason": "人工审阅:对照悟空 develop drive download --version 分支实现移植为独立命令;单一 download_file_version 远端调用,参数契约与帮助文档一致。",
|
||||||
|
"source_refs": [
|
||||||
|
"CommandRegistry:canonical_path=drive.download_file_version",
|
||||||
|
"cobra-help:dws drive download-version",
|
||||||
|
"wukong-develop:wukong/products/drive.go"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"drive.get_cover": {
|
||||||
|
"agent_summary": "获取节点封面图片地址(文档首图/图片缩略图/类型图标)",
|
||||||
|
"use_when": [
|
||||||
|
"用户说 封面/封面图/缩略图/预览图"
|
||||||
|
],
|
||||||
|
"avoid_when": [
|
||||||
|
"设置文档封面用 doc style cover set"
|
||||||
|
],
|
||||||
|
"examples": [
|
||||||
|
"dws drive cover --node <dentryUuid> --format json"
|
||||||
|
],
|
||||||
|
"reviewed": true,
|
||||||
|
"review_reason": "人工审阅:对照悟空 develop 同名命令实现、Cobra Long/Example 与 Runtime 确认门禁移植;不改变命令身份、参数契约或接口绑定。",
|
||||||
|
"source_refs": [
|
||||||
|
"CommandRegistry:canonical_path=drive.get_cover",
|
||||||
|
"cobra-help:dws drive cover",
|
||||||
|
"wukong-develop:wukong/products"
|
||||||
|
]
|
||||||
|
},
|
||||||
"drive.get_file_info": {
|
"drive.get_file_info": {
|
||||||
"agent_summary": "获取文件元数据信息",
|
"agent_summary": "获取文件元数据信息",
|
||||||
"use_when": [
|
"use_when": [
|
||||||
@@ -235,6 +295,26 @@
|
|||||||
"live-mcp:none (Cobra+Skill; composite/unpinned)"
|
"live-mcp:none (Cobra+Skill; composite/unpinned)"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
"drive.get_star_list": {
|
||||||
|
"agent_summary": "获取当前用户的收藏列表,支持分页与按内容类型筛选",
|
||||||
|
"use_when": [
|
||||||
|
"用户说 我的收藏/收藏列表/收藏了哪些文档"
|
||||||
|
],
|
||||||
|
"avoid_when": [
|
||||||
|
"操作单个收藏用 mark_star/unmark_star"
|
||||||
|
],
|
||||||
|
"examples": [
|
||||||
|
"dws drive star list --format json",
|
||||||
|
"dws drive star list --content-types doc,sheet --limit 10 --format json"
|
||||||
|
],
|
||||||
|
"reviewed": true,
|
||||||
|
"review_reason": "人工审阅:对照悟空 develop 同名命令实现、Cobra Long/Example 与 Runtime 确认门禁移植;不改变命令身份、参数契约或接口绑定。",
|
||||||
|
"source_refs": [
|
||||||
|
"CommandRegistry:canonical_path=drive.get_star_list",
|
||||||
|
"cobra-help:dws drive star list",
|
||||||
|
"wukong-develop:wukong/products"
|
||||||
|
]
|
||||||
|
},
|
||||||
"drive.get_upload_info": {
|
"drive.get_upload_info": {
|
||||||
"agent_summary": "获取文件上传信息",
|
"agent_summary": "获取文件上传信息",
|
||||||
"use_when": [
|
"use_when": [
|
||||||
@@ -334,6 +414,25 @@
|
|||||||
"live-mcp:dws schema drive.list_spaces"
|
"live-mcp:dws schema drive.list_spaces"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
"drive.mark_star": {
|
||||||
|
"agent_summary": "收藏文档/文件到当前用户收藏列表",
|
||||||
|
"use_when": [
|
||||||
|
"用户说 收藏这个文档/加个收藏/标星"
|
||||||
|
],
|
||||||
|
"avoid_when": [
|
||||||
|
"取消收藏用 unmark_star;查看收藏列表用 get_star_list"
|
||||||
|
],
|
||||||
|
"examples": [
|
||||||
|
"dws drive star add --node <nodeId> --format json"
|
||||||
|
],
|
||||||
|
"reviewed": true,
|
||||||
|
"review_reason": "人工审阅:对照悟空 develop 同名命令实现、Cobra Long/Example 与 Runtime 确认门禁移植;不改变命令身份、参数契约或接口绑定。",
|
||||||
|
"source_refs": [
|
||||||
|
"CommandRegistry:canonical_path=drive.mark_star",
|
||||||
|
"cobra-help:dws drive star add",
|
||||||
|
"wukong-develop:wukong/products"
|
||||||
|
]
|
||||||
|
},
|
||||||
"drive.move_document": {
|
"drive.move_document": {
|
||||||
"agent_summary": "将文件或文档移动到目标文件夹或知识库(原位置不再保留)",
|
"agent_summary": "将文件或文档移动到目标文件夹或知识库(原位置不再保留)",
|
||||||
"use_when": [
|
"use_when": [
|
||||||
@@ -475,6 +574,25 @@
|
|||||||
"live-mcp:none (Cobra+Skill; composite/unpinned)"
|
"live-mcp:none (Cobra+Skill; composite/unpinned)"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
"drive.query_permission_apply_info": {
|
||||||
|
"agent_summary": "查询节点可申请的权限角色列表与审批人列表",
|
||||||
|
"use_when": [
|
||||||
|
"无权限访问文档时,先查可申请角色与审批人"
|
||||||
|
],
|
||||||
|
"avoid_when": [
|
||||||
|
"实际发起申请用 apply_permission"
|
||||||
|
],
|
||||||
|
"examples": [
|
||||||
|
"dws drive permission apply-info --node <DOC_ID> --format json"
|
||||||
|
],
|
||||||
|
"reviewed": true,
|
||||||
|
"review_reason": "人工审阅:对照悟空 develop 同名命令实现、Cobra Long/Example 与 Runtime 确认门禁移植;不改变命令身份、参数契约或接口绑定。",
|
||||||
|
"source_refs": [
|
||||||
|
"CommandRegistry:canonical_path=drive.query_permission_apply_info",
|
||||||
|
"cobra-help:dws drive permission apply-info",
|
||||||
|
"wukong-develop:wukong/products"
|
||||||
|
]
|
||||||
|
},
|
||||||
"drive.recent": {
|
"drive.recent": {
|
||||||
"agent_summary": "获取当前用户最近访问或编辑过的文档列表",
|
"agent_summary": "获取当前用户最近访问或编辑过的文档列表",
|
||||||
"use_when": [
|
"use_when": [
|
||||||
@@ -568,6 +686,25 @@
|
|||||||
"live-mcp:dws schema doc.rename_document"
|
"live-mcp:dws schema doc.rename_document"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
"drive.revert_file_version": {
|
||||||
|
"agent_summary": "回滚普通文件到指定历史版本(生成新最新版本,历史不丢失)",
|
||||||
|
"use_when": [
|
||||||
|
"用户说 回滚版本/恢复到某个版本/版本回退,且目标是普通文件"
|
||||||
|
],
|
||||||
|
"avoid_when": [
|
||||||
|
"在线文档回滚用 doc version revert;在线表格用 sheet version revert"
|
||||||
|
],
|
||||||
|
"examples": [
|
||||||
|
"dws drive revert --node <dentryUuid> --version 3 --format json"
|
||||||
|
],
|
||||||
|
"reviewed": true,
|
||||||
|
"review_reason": "人工审阅:对照悟空 develop 同名命令实现、Cobra Long/Example 与 Runtime 确认门禁移植;不改变命令身份、参数契约或接口绑定。",
|
||||||
|
"source_refs": [
|
||||||
|
"CommandRegistry:canonical_path=drive.revert_file_version",
|
||||||
|
"cobra-help:dws drive revert",
|
||||||
|
"wukong-develop:wukong/products"
|
||||||
|
]
|
||||||
|
},
|
||||||
"drive.search_files": {
|
"drive.search_files": {
|
||||||
"agent_summary": "全局搜索文件,默认同时搜索钉盘和文档空间,合并返回结果",
|
"agent_summary": "全局搜索文件,默认同时搜索钉盘和文档空间,合并返回结果",
|
||||||
"use_when": [
|
"use_when": [
|
||||||
@@ -595,32 +732,43 @@
|
|||||||
"live-mcp:dws schema drive.search_files"
|
"live-mcp:dws schema drive.search_files"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"drive.upload": {
|
"drive.shortcut_copy": {
|
||||||
"agent_summary": "上传本地文件到钉盘或文档空间,或按节点 ID 确认覆盖已有文件",
|
"agent_summary": "复制文件/文档到指定位置",
|
||||||
"use_when": [
|
"use_when": [
|
||||||
"用户要把本地文件上传到钉盘/我的文件(首选一条命令自动完成凭证+PUT+提交)时",
|
"当你想保留原件、把某个文件/文档拷贝一份到指定文件夹或知识库时使用;输入源节点 node 及目标 folder/workspace,会实际生成一个副本,原文件位置不变。"
|
||||||
"上传到知识库/文档空间时加 --workspace;需要转在线文档时加 --convert",
|
|
||||||
"用户明确要求用本地文件替换已有钉盘/文档空间文件时传 --node;该模式会覆盖远端内容并要求确认"
|
|
||||||
],
|
],
|
||||||
"avoid_when": [
|
"avoid_when": [
|
||||||
"常规场景不要拆成 upload-info + 手动 PUT + commit;仅自定义流式上传才用三步",
|
"需要该 Shortcut 未公开的底层参数、原始响应或不同执行语义时,改用对应原子命令"
|
||||||
"要把文件作为文档正文附件插入改用 dws doc media insert",
|
|
||||||
"用户明确说文档空间且走 doc 兼容入口时可用 dws doc upload,默认仍推荐本命令",
|
|
||||||
"用户没有明确同意替换目标文件时不要使用 --node;新建上传应使用 --folder 或目标根目录"
|
|
||||||
],
|
],
|
||||||
"examples": [
|
"examples": [
|
||||||
"dws drive upload --file ./report.pdf --format json",
|
"dws drive +copy --node <nodeId> --folder <targetFolderId>"
|
||||||
"dws drive upload --file ./README.md --node <dentryUuid> --format json"
|
|
||||||
],
|
],
|
||||||
"reviewed": true,
|
"reviewed": true,
|
||||||
"review_reason": "人工审阅:结合本机 dws schema 实时 MCP description/parameters(经 interface_ref)、产品 Skill、Cobra Long 与 Runtime 确认门禁,按飞书风格重写选型文案;不改变命令身份、参数契约或接口绑定。",
|
"review_reason": "Agent-authored and reviewed from the built-in Shortcut intent, executable Cobra path, and declared outcome; it affects selection only and does not alter execution or safety facts.",
|
||||||
"source_refs": [
|
"source_refs": [
|
||||||
"CommandRegistry:canonical_path=drive.upload",
|
"internal/cli/schema_command_registry.json#drive.shortcut_copy",
|
||||||
"cobra-help:dws drive upload",
|
"cobra-help:dws drive +copy",
|
||||||
"Skill:skills/mono/references/products/drive.md",
|
"ShortcutRegistry:drive +copy"
|
||||||
"structured-hint:internal/cli/schema_hints/selection-review.json#drive.upload",
|
]
|
||||||
"structured-hint:internal/cli/schema_hints/products/drive.json",
|
},
|
||||||
"live-mcp:none (Cobra+Skill; composite/unpinned)"
|
"drive.shortcut_find_file": {
|
||||||
|
"agent_summary": "按名称关键词搜索钉盘文件并投影关键字段(只读)",
|
||||||
|
"use_when": [
|
||||||
|
"当你只记得钉盘文件的名字(或其中一部分),想快速按文件名关键词找到它、拿到它的 dentryId 以便后续下载/查看,却不想手动翻目录或写复杂过滤条件时使用;内部调用钉盘的 search_files 工具,把 --query 作为文件名关键词(keyword) 并限定搜索范围为钉盘文件(searchTarget=file),再在本地把每条命中结果精简为「文件名、类型、dentryId、大小」四个字段后打印。这是纯只读操作,只做搜索与本地投影,不会创建、移动或删除任何文件;未命中时返回空列表。"
|
||||||
|
],
|
||||||
|
"avoid_when": [
|
||||||
|
"需要该 Shortcut 未公开的底层参数、原始响应或不同执行语义时,改用对应原子命令"
|
||||||
|
],
|
||||||
|
"examples": [
|
||||||
|
"dws drive +find-file --query 季度汇报",
|
||||||
|
"dws drive +find-file --query 合同"
|
||||||
|
],
|
||||||
|
"reviewed": true,
|
||||||
|
"review_reason": "Agent-authored and reviewed from the built-in Shortcut intent, executable Cobra path, and declared outcome; it affects selection only and does not alter execution or safety facts.",
|
||||||
|
"source_refs": [
|
||||||
|
"internal/cli/schema_command_registry.json#drive.shortcut_find_file",
|
||||||
|
"cobra-help:dws drive +find-file",
|
||||||
|
"ShortcutRegistry:drive +find-file"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"drive.shortcut_info": {
|
"drive.shortcut_info": {
|
||||||
@@ -642,64 +790,6 @@
|
|||||||
"ShortcutRegistry:drive +info"
|
"ShortcutRegistry:drive +info"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"drive.shortcut_search": {
|
|
||||||
"agent_summary": "搜索钉盘文件",
|
|
||||||
"use_when": [
|
|
||||||
"当你只记得文件名或内容关键词、不知道它在哪个目录时用它全局检索钉盘文件;输入 query,可按文件类型、扩展名、创建者、创建/修改时间范围过滤,返回匹配文件及其 ID,便于再做下载或整理。"
|
|
||||||
],
|
|
||||||
"avoid_when": [
|
|
||||||
"需要该 Shortcut 未公开的底层参数、原始响应或不同执行语义时,改用对应原子命令"
|
|
||||||
],
|
|
||||||
"examples": [
|
|
||||||
"dws drive +search --query \"季度汇报\"",
|
|
||||||
"dws drive +search --query \"合同\" --target file --extensions pdf,docx"
|
|
||||||
],
|
|
||||||
"reviewed": true,
|
|
||||||
"review_reason": "Agent-authored and reviewed from the built-in Shortcut intent, executable Cobra path, and declared outcome; it affects selection only and does not alter execution or safety facts.",
|
|
||||||
"source_refs": [
|
|
||||||
"internal/cli/schema_command_registry.json#drive.shortcut_search",
|
|
||||||
"cobra-help:dws drive +search",
|
|
||||||
"ShortcutRegistry:drive +search"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"drive.shortcut_search_docs": {
|
|
||||||
"agent_summary": "搜索文档空间文档",
|
|
||||||
"use_when": [
|
|
||||||
"当你只记得文档标题或关键词、想在文档空间/知识库中检索在线文档(区别于 +search 检索钉盘文件)时使用;输入 query 关键词,返回匹配的文档及其节点信息。"
|
|
||||||
],
|
|
||||||
"avoid_when": [
|
|
||||||
"需要该 Shortcut 未公开的底层参数、原始响应或不同执行语义时,改用对应原子命令"
|
|
||||||
],
|
|
||||||
"examples": [
|
|
||||||
"dws drive +search-docs --query \"季度汇报\""
|
|
||||||
],
|
|
||||||
"reviewed": true,
|
|
||||||
"review_reason": "Agent-authored and reviewed from the built-in Shortcut intent, executable Cobra path, and declared outcome; it affects selection only and does not alter execution or safety facts.",
|
|
||||||
"source_refs": [
|
|
||||||
"internal/cli/schema_command_registry.json#drive.shortcut_search_docs",
|
|
||||||
"cobra-help:dws drive +search-docs",
|
|
||||||
"ShortcutRegistry:drive +search-docs"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"drive.shortcut_copy": {
|
|
||||||
"agent_summary": "复制文件/文档到指定位置",
|
|
||||||
"use_when": [
|
|
||||||
"当你想保留原件、把某个文件/文档拷贝一份到指定文件夹或知识库时使用;输入源节点 node 及目标 folder/workspace,会实际生成一个副本,原文件位置不变。"
|
|
||||||
],
|
|
||||||
"avoid_when": [
|
|
||||||
"需要该 Shortcut 未公开的底层参数、原始响应或不同执行语义时,改用对应原子命令"
|
|
||||||
],
|
|
||||||
"examples": [
|
|
||||||
"dws drive +copy --node <nodeId> --folder <targetFolderId>"
|
|
||||||
],
|
|
||||||
"reviewed": true,
|
|
||||||
"review_reason": "Agent-authored and reviewed from the built-in Shortcut intent, executable Cobra path, and declared outcome; it affects selection only and does not alter execution or safety facts.",
|
|
||||||
"source_refs": [
|
|
||||||
"internal/cli/schema_command_registry.json#drive.shortcut_copy",
|
|
||||||
"cobra-help:dws drive +copy",
|
|
||||||
"ShortcutRegistry:drive +copy"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"drive.shortcut_move": {
|
"drive.shortcut_move": {
|
||||||
"agent_summary": "移动文件/文档到指定位置",
|
"agent_summary": "移动文件/文档到指定位置",
|
||||||
"use_when": [
|
"use_when": [
|
||||||
@@ -739,42 +829,61 @@
|
|||||||
"ShortcutRegistry:drive +recent"
|
"ShortcutRegistry:drive +recent"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"drive.shortcut_find_file": {
|
"drive.shortcut_search": {
|
||||||
"agent_summary": "按名称关键词搜索钉盘文件并投影关键字段(只读)",
|
"agent_summary": "搜索钉盘文件",
|
||||||
"use_when": [
|
"use_when": [
|
||||||
"当你只记得钉盘文件的名字(或其中一部分),想快速按文件名关键词找到它、拿到它的 dentryId 以便后续下载/查看,却不想手动翻目录或写复杂过滤条件时使用;内部调用钉盘的 search_files 工具,把 --query 作为文件名关键词(keyword) 并限定搜索范围为钉盘文件(searchTarget=file),再在本地把每条命中结果精简为「文件名、类型、dentryId、大小」四个字段后打印。这是纯只读操作,只做搜索与本地投影,不会创建、移动或删除任何文件;未命中时返回空列表。"
|
"当你只记得文件名或内容关键词、不知道它在哪个目录时用它全局检索钉盘文件;输入 query,可按文件类型、扩展名、创建者、创建/修改时间范围过滤,返回匹配文件及其 ID,便于再做下载或整理。"
|
||||||
],
|
],
|
||||||
"avoid_when": [
|
"avoid_when": [
|
||||||
"需要该 Shortcut 未公开的底层参数、原始响应或不同执行语义时,改用对应原子命令"
|
"需要该 Shortcut 未公开的底层参数、原始响应或不同执行语义时,改用对应原子命令"
|
||||||
],
|
],
|
||||||
"examples": [
|
"examples": [
|
||||||
"dws drive +find-file --query 季度汇报",
|
"dws drive +search --query \"季度汇报\"",
|
||||||
"dws drive +find-file --query 合同"
|
"dws drive +search --query \"合同\" --target file --extensions pdf,docx"
|
||||||
],
|
],
|
||||||
"reviewed": true,
|
"reviewed": true,
|
||||||
"review_reason": "Agent-authored and reviewed from the built-in Shortcut intent, executable Cobra path, and declared outcome; it affects selection only and does not alter execution or safety facts.",
|
"review_reason": "Agent-authored and reviewed from the built-in Shortcut intent, executable Cobra path, and declared outcome; it affects selection only and does not alter execution or safety facts.",
|
||||||
"source_refs": [
|
"source_refs": [
|
||||||
"internal/cli/schema_command_registry.json#drive.shortcut_find_file",
|
"internal/cli/schema_command_registry.json#drive.shortcut_search",
|
||||||
"cobra-help:dws drive +find-file",
|
"cobra-help:dws drive +search",
|
||||||
"ShortcutRegistry:drive +find-file"
|
"ShortcutRegistry:drive +search"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"drive.mark_star": {
|
"drive.shortcut_search_docs": {
|
||||||
"agent_summary": "收藏文档/文件到当前用户收藏列表",
|
"agent_summary": "搜索文档空间文档",
|
||||||
"use_when": [
|
"use_when": [
|
||||||
"用户说 收藏这个文档/加个收藏/标星"
|
"当你只记得文档标题或关键词、想在文档空间/知识库中检索在线文档(区别于 +search 检索钉盘文件)时使用;输入 query 关键词,返回匹配的文档及其节点信息。"
|
||||||
],
|
],
|
||||||
"avoid_when": [
|
"avoid_when": [
|
||||||
"取消收藏用 unmark_star;查看收藏列表用 get_star_list"
|
"需要该 Shortcut 未公开的底层参数、原始响应或不同执行语义时,改用对应原子命令"
|
||||||
],
|
],
|
||||||
"examples": [
|
"examples": [
|
||||||
"dws drive star add --node <nodeId> --format json"
|
"dws drive +search-docs --query \"季度汇报\""
|
||||||
|
],
|
||||||
|
"reviewed": true,
|
||||||
|
"review_reason": "Agent-authored and reviewed from the built-in Shortcut intent, executable Cobra path, and declared outcome; it affects selection only and does not alter execution or safety facts.",
|
||||||
|
"source_refs": [
|
||||||
|
"internal/cli/schema_command_registry.json#drive.shortcut_search_docs",
|
||||||
|
"cobra-help:dws drive +search-docs",
|
||||||
|
"ShortcutRegistry:drive +search-docs"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"drive.transfer_owner": {
|
||||||
|
"agent_summary": "转交文档或知识库所有者给指定用户(不可逆)",
|
||||||
|
"use_when": [
|
||||||
|
"用户明确要求转交文档/知识库所有权"
|
||||||
|
],
|
||||||
|
"avoid_when": [
|
||||||
|
"普通协作权限变更用 permission add/update/remove"
|
||||||
|
],
|
||||||
|
"examples": [
|
||||||
|
"dws drive permission transfer-owner --node <DOC_ID> --new-owner <userId> --reserve-role EDITOR --recursive=false --format json"
|
||||||
],
|
],
|
||||||
"reviewed": true,
|
"reviewed": true,
|
||||||
"review_reason": "人工审阅:对照悟空 develop 同名命令实现、Cobra Long/Example 与 Runtime 确认门禁移植;不改变命令身份、参数契约或接口绑定。",
|
"review_reason": "人工审阅:对照悟空 develop 同名命令实现、Cobra Long/Example 与 Runtime 确认门禁移植;不改变命令身份、参数契约或接口绑定。",
|
||||||
"source_refs": [
|
"source_refs": [
|
||||||
"CommandRegistry:canonical_path=drive.mark_star",
|
"CommandRegistry:canonical_path=drive.transfer_owner",
|
||||||
"cobra-help:dws drive star add",
|
"cobra-help:dws drive permission transfer-owner",
|
||||||
"wukong-develop:wukong/products"
|
"wukong-develop:wukong/products"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
@@ -797,119 +906,32 @@
|
|||||||
"wukong-develop:wukong/products"
|
"wukong-develop:wukong/products"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"drive.get_star_list": {
|
"drive.upload": {
|
||||||
"agent_summary": "获取当前用户的收藏列表,支持分页与按内容类型筛选",
|
"agent_summary": "上传本地文件到钉盘或文档空间,或按节点 ID 确认覆盖已有文件",
|
||||||
"use_when": [
|
"use_when": [
|
||||||
"用户说 我的收藏/收藏列表/收藏了哪些文档"
|
"用户要把本地文件上传到钉盘/我的文件(首选一条命令自动完成凭证+PUT+提交)时",
|
||||||
|
"上传到知识库/文档空间时加 --workspace;需要转在线文档时加 --convert",
|
||||||
|
"用户明确要求用本地文件替换已有钉盘/文档空间文件时传 --node;该模式会覆盖远端内容并要求确认"
|
||||||
],
|
],
|
||||||
"avoid_when": [
|
"avoid_when": [
|
||||||
"操作单个收藏用 mark_star/unmark_star"
|
"常规场景不要拆成 upload-info + 手动 PUT + commit;仅自定义流式上传才用三步",
|
||||||
|
"要把文件作为文档正文附件插入改用 dws doc media insert",
|
||||||
|
"用户明确说文档空间且走 doc 兼容入口时可用 dws doc upload,默认仍推荐本命令",
|
||||||
|
"用户没有明确同意替换目标文件时不要使用 --node;新建上传应使用 --folder 或目标根目录"
|
||||||
],
|
],
|
||||||
"examples": [
|
"examples": [
|
||||||
"dws drive star list --format json",
|
"dws drive upload --file ./report.pdf --format json",
|
||||||
"dws drive star list --content-types doc,sheet --limit 10 --format json"
|
"dws drive upload --file ./README.md --node <dentryUuid> --format json"
|
||||||
],
|
],
|
||||||
"reviewed": true,
|
"reviewed": true,
|
||||||
"review_reason": "人工审阅:对照悟空 develop 同名命令实现、Cobra Long/Example 与 Runtime 确认门禁移植;不改变命令身份、参数契约或接口绑定。",
|
"review_reason": "人工审阅:结合本机 dws schema 实时 MCP description/parameters(经 interface_ref)、产品 Skill、Cobra Long 与 Runtime 确认门禁,按飞书风格重写选型文案;不改变命令身份、参数契约或接口绑定。",
|
||||||
"source_refs": [
|
"source_refs": [
|
||||||
"CommandRegistry:canonical_path=drive.get_star_list",
|
"CommandRegistry:canonical_path=drive.upload",
|
||||||
"cobra-help:dws drive star list",
|
"cobra-help:dws drive upload",
|
||||||
"wukong-develop:wukong/products"
|
"Skill:skills/mono/references/products/drive.md",
|
||||||
]
|
"structured-hint:internal/cli/schema_hints/selection-review.json#drive.upload",
|
||||||
},
|
"structured-hint:internal/cli/schema_hints/products/drive.json",
|
||||||
"drive.get_cover": {
|
"live-mcp:none (Cobra+Skill; composite/unpinned)"
|
||||||
"agent_summary": "获取节点封面图片地址(文档首图/图片缩略图/类型图标)",
|
|
||||||
"use_when": [
|
|
||||||
"用户说 封面/封面图/缩略图/预览图"
|
|
||||||
],
|
|
||||||
"avoid_when": [
|
|
||||||
"设置文档封面用 doc style cover set"
|
|
||||||
],
|
|
||||||
"examples": [
|
|
||||||
"dws drive cover --node <dentryUuid> --format json"
|
|
||||||
],
|
|
||||||
"reviewed": true,
|
|
||||||
"review_reason": "人工审阅:对照悟空 develop 同名命令实现、Cobra Long/Example 与 Runtime 确认门禁移植;不改变命令身份、参数契约或接口绑定。",
|
|
||||||
"source_refs": [
|
|
||||||
"CommandRegistry:canonical_path=drive.get_cover",
|
|
||||||
"cobra-help:dws drive cover",
|
|
||||||
"wukong-develop:wukong/products"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"drive.revert_file_version": {
|
|
||||||
"agent_summary": "回滚普通文件到指定历史版本(生成新最新版本,历史不丢失)",
|
|
||||||
"use_when": [
|
|
||||||
"用户说 回滚版本/恢复到某个版本/版本回退,且目标是普通文件"
|
|
||||||
],
|
|
||||||
"avoid_when": [
|
|
||||||
"在线文档回滚用 doc version revert;在线表格用 sheet version revert"
|
|
||||||
],
|
|
||||||
"examples": [
|
|
||||||
"dws drive revert --node <dentryUuid> --version 3 --format json"
|
|
||||||
],
|
|
||||||
"reviewed": true,
|
|
||||||
"review_reason": "人工审阅:对照悟空 develop 同名命令实现、Cobra Long/Example 与 Runtime 确认门禁移植;不改变命令身份、参数契约或接口绑定。",
|
|
||||||
"source_refs": [
|
|
||||||
"CommandRegistry:canonical_path=drive.revert_file_version",
|
|
||||||
"cobra-help:dws drive revert",
|
|
||||||
"wukong-develop:wukong/products"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"drive.transfer_owner": {
|
|
||||||
"agent_summary": "转交文档或知识库所有者给指定用户(不可逆)",
|
|
||||||
"use_when": [
|
|
||||||
"用户明确要求转交文档/知识库所有权"
|
|
||||||
],
|
|
||||||
"avoid_when": [
|
|
||||||
"普通协作权限变更用 permission add/update/remove"
|
|
||||||
],
|
|
||||||
"examples": [
|
|
||||||
"dws drive permission transfer-owner --node <DOC_ID> --new-owner <userId> --reserve-role EDITOR --recursive=false --format json"
|
|
||||||
],
|
|
||||||
"reviewed": true,
|
|
||||||
"review_reason": "人工审阅:对照悟空 develop 同名命令实现、Cobra Long/Example 与 Runtime 确认门禁移植;不改变命令身份、参数契约或接口绑定。",
|
|
||||||
"source_refs": [
|
|
||||||
"CommandRegistry:canonical_path=drive.transfer_owner",
|
|
||||||
"cobra-help:dws drive permission transfer-owner",
|
|
||||||
"wukong-develop:wukong/products"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"drive.query_permission_apply_info": {
|
|
||||||
"agent_summary": "查询节点可申请的权限角色列表与审批人列表",
|
|
||||||
"use_when": [
|
|
||||||
"无权限访问文档时,先查可申请角色与审批人"
|
|
||||||
],
|
|
||||||
"avoid_when": [
|
|
||||||
"实际发起申请用 apply_permission"
|
|
||||||
],
|
|
||||||
"examples": [
|
|
||||||
"dws drive permission apply-info --node <DOC_ID> --format json"
|
|
||||||
],
|
|
||||||
"reviewed": true,
|
|
||||||
"review_reason": "人工审阅:对照悟空 develop 同名命令实现、Cobra Long/Example 与 Runtime 确认门禁移植;不改变命令身份、参数契约或接口绑定。",
|
|
||||||
"source_refs": [
|
|
||||||
"CommandRegistry:canonical_path=drive.query_permission_apply_info",
|
|
||||||
"cobra-help:dws drive permission apply-info",
|
|
||||||
"wukong-develop:wukong/products"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"drive.apply_permission": {
|
|
||||||
"agent_summary": "向审批人发起文档权限申请(会真实通知审批人)",
|
|
||||||
"use_when": [
|
|
||||||
"用户确认要为无权限文档发起权限申请"
|
|
||||||
],
|
|
||||||
"avoid_when": [
|
|
||||||
"先用 apply-info 查可申请角色与审批人;未经用户确认不得自行提交"
|
|
||||||
],
|
|
||||||
"examples": [
|
|
||||||
"dws drive permission apply --node <DOC_ID> --role READER --users <审批人userId> --format json"
|
|
||||||
],
|
|
||||||
"reviewed": true,
|
|
||||||
"review_reason": "人工审阅:对照悟空 develop 同名命令实现、Cobra Long/Example 与 Runtime 确认门禁移植;不改变命令身份、参数契约或接口绑定。",
|
|
||||||
"source_refs": [
|
|
||||||
"CommandRegistry:canonical_path=drive.apply_permission",
|
|
||||||
"cobra-help:dws drive permission apply",
|
|
||||||
"wukong-develop:wukong/products"
|
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -2,8 +2,8 @@
|
|||||||
"version": 3,
|
"version": 3,
|
||||||
"baseline": {
|
"baseline": {
|
||||||
"manifest": "schema-parameter-bindings-v3",
|
"manifest": "schema-parameter-bindings-v3",
|
||||||
"sha256": "sha256:f48d7b55b6ca9719c466475ee32d678eab0deaee1d79ac4e4790c7ee441ebe7b",
|
"sha256": "sha256:ff0f76145dd27da5429434a348344c9cdf74c44eaf6f4ea5411d29d904a9066f",
|
||||||
"reason": "Reviewed v3 baseline after exposing the pinned chat.search_messages messageType, onlyRobotMessages, and searchConvType properties through exact Cobra flags.",
|
"reason": "Reviewed v3 baseline after binding sheet.info --include to the include property while porting the wukong sheet info expansion flag.",
|
||||||
"reviewed": true
|
"reviewed": true
|
||||||
},
|
},
|
||||||
"removals": {
|
"removals": {
|
||||||
@@ -1112,7 +1112,8 @@
|
|||||||
"node": "nodeId"
|
"node": "nodeId"
|
||||||
},
|
},
|
||||||
"sheet.info": {
|
"sheet.info": {
|
||||||
"node": "nodeId"
|
"node": "nodeId",
|
||||||
|
"include": "include"
|
||||||
},
|
},
|
||||||
"sheet.insert_dimension": {
|
"sheet.insert_dimension": {
|
||||||
"node": "nodeId"
|
"node": "nodeId"
|
||||||
@@ -1594,7 +1595,10 @@
|
|||||||
"attendance.vacation_update_type --when-can-leave": "Reviewed unpinned adapter: attendance.vacation_update_type has no singular pinned interface_ref; --when-can-leave is a CLI wrapper input and does not publish a direct interface property.",
|
"attendance.vacation_update_type --when-can-leave": "Reviewed unpinned adapter: attendance.vacation_update_type has no singular pinned interface_ref; --when-can-leave is a CLI wrapper input and does not publish a direct interface property.",
|
||||||
"chat.add_message_favorite --open-conversation-id": "Reviewed unpinned adapter: chat.add_message_favorite has no singular pinned interface_ref; --open-conversation-id is a CLI wrapper input and does not publish a direct interface property.",
|
"chat.add_message_favorite --open-conversation-id": "Reviewed unpinned adapter: chat.add_message_favorite has no singular pinned interface_ref; --open-conversation-id is a CLI wrapper input and does not publish a direct interface property.",
|
||||||
"chat.add_message_favorite --open-message-id": "Reviewed unpinned adapter: chat.add_message_favorite has no singular pinned interface_ref; --open-message-id is a CLI wrapper input and does not publish a direct interface property.",
|
"chat.add_message_favorite --open-message-id": "Reviewed unpinned adapter: chat.add_message_favorite has no singular pinned interface_ref; --open-message-id is a CLI wrapper input and does not publish a direct interface property.",
|
||||||
|
"chat.batch_query_group_chat_settings --groups": "Reviewed unpinned adapter: chat.batch_query_group_chat_settings has no singular pinned interface_ref; --groups is a CLI wrapper input and does not publish a direct interface property.",
|
||||||
|
"chat.batch_update_group_chat_settings --items": "Reviewed unpinned adapter: chat.batch_update_group_chat_settings has no singular pinned interface_ref; --items is a CLI wrapper input and does not publish a direct interface property.",
|
||||||
"chat.create_text_emotion --background-id": "Runtime extension: the executable helper forwards backgroundId to im/create_text_emotion, but the pinned source-revision metadata does not declare that optional property; preserve the compatibility flag without advertising it as a pinned RPC field.",
|
"chat.create_text_emotion --background-id": "Runtime extension: the executable helper forwards backgroundId to im/create_text_emotion, but the pinned source-revision metadata does not declare that optional property; preserve the compatibility flag without advertising it as a pinned RPC field.",
|
||||||
|
"chat.get_group_mute_config --group": "Reviewed unpinned adapter: chat.get_group_mute_config has no singular pinned interface_ref; --group is a CLI wrapper input and does not publish a direct interface property.",
|
||||||
"chat.list_conversation_message_v2 --open-dingtalk-id": "selects the alternate list_individual_chat_message branch",
|
"chat.list_conversation_message_v2 --open-dingtalk-id": "selects the alternate list_individual_chat_message branch",
|
||||||
"chat.list_conversation_message_v2 --user": "selects the alternate list_individual_chat_message branch",
|
"chat.list_conversation_message_v2 --user": "selects the alternate list_individual_chat_message branch",
|
||||||
"chat.list_message_favorites --cursor": "Reviewed unpinned adapter: chat.list_message_favorites has no singular pinned interface_ref; --cursor is a CLI wrapper input and does not publish a direct interface property.",
|
"chat.list_message_favorites --cursor": "Reviewed unpinned adapter: chat.list_message_favorites has no singular pinned interface_ref; --cursor is a CLI wrapper input and does not publish a direct interface property.",
|
||||||
@@ -1611,7 +1615,12 @@
|
|||||||
"chat.search_groups --limit": "Reviewed unpinned adapter: chat.search_groups has no singular pinned interface_ref; --limit is a CLI wrapper input and does not publish a direct interface property.",
|
"chat.search_groups --limit": "Reviewed unpinned adapter: chat.search_groups has no singular pinned interface_ref; --limit is a CLI wrapper input and does not publish a direct interface property.",
|
||||||
"chat.search_messages --user": "conditional wrapper: parseCSVValues + appendChatIDArgs routes each supplied identifier to senderUserIds or senderOpenDingTakIds according to its runtime ID shape; there is no single RPC property for this flag",
|
"chat.search_messages --user": "conditional wrapper: parseCSVValues + appendChatIDArgs routes each supplied identifier to senderUserIds or senderOpenDingTakIds according to its runtime ID shape; there is no single RPC property for this flag",
|
||||||
"chat.search_messages --users": "conditional wrapper/alias of --user: parseCSVValues + appendChatIDArgs routes each supplied identifier to senderUserIds or senderOpenDingTakIds according to its runtime ID shape; there is no single RPC property for this flag",
|
"chat.search_messages --users": "conditional wrapper/alias of --user: parseCSVValues + appendChatIDArgs routes each supplied identifier to senderUserIds or senderOpenDingTakIds according to its runtime ID shape; there is no single RPC property for this flag",
|
||||||
|
"chat.send_personal_message --contact-id": "serialized into the aggregate content payload",
|
||||||
"chat.send_personal_message --file-path": "local upload/preprocessing input",
|
"chat.send_personal_message --file-path": "local upload/preprocessing input",
|
||||||
|
"chat.send_personal_message --latitude": "serialized into the aggregate content payload",
|
||||||
|
"chat.send_personal_message --location-name": "serialized into the aggregate content payload",
|
||||||
|
"chat.send_personal_message --longitude": "serialized into the aggregate content payload",
|
||||||
|
"chat.send_personal_message --map-thumbnail-url": "serialized into the aggregate content payload",
|
||||||
"chat.send_personal_message --media-id": "serialized into the aggregate content payload",
|
"chat.send_personal_message --media-id": "serialized into the aggregate content payload",
|
||||||
"chat.send_personal_message --text": "serialized into the aggregate content payload",
|
"chat.send_personal_message --text": "serialized into the aggregate content payload",
|
||||||
"chat.send_personal_message --title": "serialized into the aggregate content payload",
|
"chat.send_personal_message --title": "serialized into the aggregate content payload",
|
||||||
@@ -1619,6 +1628,16 @@
|
|||||||
"chat.set_group_member_mute_list --user": "conditional wrapper/alias of --users: userIds are remotely resolved to openDingTalkIds outside dry-run and otherwise may be sent as uids; openDingTalkId inputs are sent as openDingTalkIds, so one exact property would misdescribe execution",
|
"chat.set_group_member_mute_list --user": "conditional wrapper/alias of --users: userIds are remotely resolved to openDingTalkIds outside dry-run and otherwise may be sent as uids; openDingTalkId inputs are sent as openDingTalkIds, so one exact property would misdescribe execution",
|
||||||
"chat.transfer_group_owner --user": "conditional compatibility input: a userId is sent as newOwnerUid, while an openDingTalkId is sent as newOwnerOpenDingTalkId; the runtime ID-shape branch has no single RPC property",
|
"chat.transfer_group_owner --user": "conditional compatibility input: a userId is sent as newOwnerUid, while an openDingTalkId is sent as newOwnerOpenDingTalkId; the runtime ID-shape branch has no single RPC property",
|
||||||
"chat.update_conv_member_roles --user": "conditional wrapper/alias of --users: splitChatIDValues sends userIds as uids and openDingTalkIds as openDingTalkIds; there is no single RPC property for this flag",
|
"chat.update_conv_member_roles --user": "conditional wrapper/alias of --users: splitChatIDValues sends userIds as uids and openDingTalkIds as openDingTalkIds; there is no single RPC property for this flag",
|
||||||
|
"chat.update_text_emotion --background-id": "Reviewed unpinned adapter: chat.update_text_emotion has no singular pinned interface_ref; --background-id is a CLI wrapper input and does not publish a direct interface property.",
|
||||||
|
"chat.update_text_emotion --chat": "Reviewed unpinned adapter: chat.update_text_emotion has no singular pinned interface_ref; --chat is a CLI wrapper input and does not publish a direct interface property.",
|
||||||
|
"chat.update_text_emotion --conversation-id": "Reviewed unpinned adapter: chat.update_text_emotion has no singular pinned interface_ref; --conversation-id is a CLI wrapper input and does not publish a direct interface property.",
|
||||||
|
"chat.update_text_emotion --emotion-id": "Reviewed unpinned adapter: chat.update_text_emotion has no singular pinned interface_ref; --emotion-id is a CLI wrapper input and does not publish a direct interface property.",
|
||||||
|
"chat.update_text_emotion --emotion-name": "Reviewed unpinned adapter: chat.update_text_emotion has no singular pinned interface_ref; --emotion-name is a CLI wrapper input and does not publish a direct interface property.",
|
||||||
|
"chat.update_text_emotion --group": "Reviewed unpinned adapter: chat.update_text_emotion has no singular pinned interface_ref; --group is a CLI wrapper input and does not publish a direct interface property.",
|
||||||
|
"chat.update_text_emotion --id": "Reviewed unpinned adapter: chat.update_text_emotion has no singular pinned interface_ref; --id is a CLI wrapper input and does not publish a direct interface property.",
|
||||||
|
"chat.update_text_emotion --msg-id": "Reviewed unpinned adapter: chat.update_text_emotion has no singular pinned interface_ref; --msg-id is a CLI wrapper input and does not publish a direct interface property.",
|
||||||
|
"chat.update_text_emotion --old-emotion-id": "Reviewed unpinned adapter: chat.update_text_emotion has no singular pinned interface_ref; --old-emotion-id is a CLI wrapper input and does not publish a direct interface property.",
|
||||||
|
"chat.update_text_emotion --text": "Reviewed unpinned adapter: chat.update_text_emotion has no singular pinned interface_ref; --text is a CLI wrapper input and does not publish a direct interface property.",
|
||||||
"dev.add_dev_app_members --member-type": "Reviewed unpinned adapter: dev.add_dev_app_members has no singular pinned interface_ref; --member-type is a CLI wrapper input and does not publish a direct interface property.",
|
"dev.add_dev_app_members --member-type": "Reviewed unpinned adapter: dev.add_dev_app_members has no singular pinned interface_ref; --member-type is a CLI wrapper input and does not publish a direct interface property.",
|
||||||
"dev.add_dev_app_members --unified-app-id": "Reviewed unpinned adapter: dev.add_dev_app_members has no singular pinned interface_ref; --unified-app-id is a CLI wrapper input and does not publish a direct interface property.",
|
"dev.add_dev_app_members --unified-app-id": "Reviewed unpinned adapter: dev.add_dev_app_members has no singular pinned interface_ref; --unified-app-id is a CLI wrapper input and does not publish a direct interface property.",
|
||||||
"dev.add_dev_app_members --user-ids": "Reviewed unpinned adapter: dev.add_dev_app_members has no singular pinned interface_ref; --user-ids is a CLI wrapper input and does not publish a direct interface property.",
|
"dev.add_dev_app_members --user-ids": "Reviewed unpinned adapter: dev.add_dev_app_members has no singular pinned interface_ref; --user-ids is a CLI wrapper input and does not publish a direct interface property.",
|
||||||
@@ -1636,8 +1655,8 @@
|
|||||||
"dev.disable_dev_app_robot --unified-app-id": "Reviewed unpinned adapter: dev.disable_dev_app_robot has no singular pinned interface_ref; --unified-app-id is a CLI wrapper input and does not publish a direct interface property.",
|
"dev.disable_dev_app_robot --unified-app-id": "Reviewed unpinned adapter: dev.disable_dev_app_robot has no singular pinned interface_ref; --unified-app-id is a CLI wrapper input and does not publish a direct interface property.",
|
||||||
"dev.enable_dev_app --unified-app-id": "Reviewed unpinned adapter: dev.enable_dev_app has no singular pinned interface_ref; --unified-app-id is a CLI wrapper input and does not publish a direct interface property.",
|
"dev.enable_dev_app --unified-app-id": "Reviewed unpinned adapter: dev.enable_dev_app has no singular pinned interface_ref; --unified-app-id is a CLI wrapper input and does not publish a direct interface property.",
|
||||||
"dev.enable_dev_app_robot --unified-app-id": "Reviewed unpinned adapter: dev.enable_dev_app_robot has no singular pinned interface_ref; --unified-app-id is a CLI wrapper input and does not publish a direct interface property.",
|
"dev.enable_dev_app_robot --unified-app-id": "Reviewed unpinned adapter: dev.enable_dev_app_robot has no singular pinned interface_ref; --unified-app-id is a CLI wrapper input and does not publish a direct interface property.",
|
||||||
"dev.get_dev_app --unified-app-id": "Reviewed unpinned adapter: dev.get_dev_app has no singular pinned interface_ref; --unified-app-id is a CLI wrapper input and does not publish a direct interface property.",
|
|
||||||
"dev.get_dev_app --app-key": "Reviewed unpinned adapter: dev.get_dev_app has no singular pinned interface_ref; --app-key is a CLI wrapper input and does not publish a direct interface property.",
|
"dev.get_dev_app --app-key": "Reviewed unpinned adapter: dev.get_dev_app has no singular pinned interface_ref; --app-key is a CLI wrapper input and does not publish a direct interface property.",
|
||||||
|
"dev.get_dev_app --unified-app-id": "Reviewed unpinned adapter: dev.get_dev_app has no singular pinned interface_ref; --unified-app-id is a CLI wrapper input and does not publish a direct interface property.",
|
||||||
"dev.get_dev_app_credentials --unified-app-id": "Reviewed unpinned adapter: dev.get_dev_app_credentials has no singular pinned interface_ref; --unified-app-id is a CLI wrapper input and does not publish a direct interface property.",
|
"dev.get_dev_app_credentials --unified-app-id": "Reviewed unpinned adapter: dev.get_dev_app_credentials has no singular pinned interface_ref; --unified-app-id is a CLI wrapper input and does not publish a direct interface property.",
|
||||||
"dev.get_dev_app_version_detail --unified-app-id": "Reviewed unpinned adapter: dev.get_dev_app_version_detail has no singular pinned interface_ref; --unified-app-id is a CLI wrapper input and does not publish a direct interface property.",
|
"dev.get_dev_app_version_detail --unified-app-id": "Reviewed unpinned adapter: dev.get_dev_app_version_detail has no singular pinned interface_ref; --unified-app-id is a CLI wrapper input and does not publish a direct interface property.",
|
||||||
"dev.get_dev_app_version_detail --version-id": "Reviewed unpinned adapter: dev.get_dev_app_version_detail has no singular pinned interface_ref; --version-id is a CLI wrapper input and does not publish a direct interface property.",
|
"dev.get_dev_app_version_detail --version-id": "Reviewed unpinned adapter: dev.get_dev_app_version_detail has no singular pinned interface_ref; --version-id is a CLI wrapper input and does not publish a direct interface property.",
|
||||||
@@ -1732,6 +1751,7 @@
|
|||||||
"doc.get_document_content --scope": "Runtime extension sends scope for scoped JSONML reads, which is absent from the immutable pinned get_document_content metadata at its declared source revision.",
|
"doc.get_document_content --scope": "Runtime extension sends scope for scoped JSONML reads, which is absent from the immutable pinned get_document_content metadata at its declared source revision.",
|
||||||
"doc.get_document_content --start-block-id": "Runtime extension sends startBlockId for scoped JSONML reads, which is absent from the immutable pinned get_document_content metadata at its declared source revision.",
|
"doc.get_document_content --start-block-id": "Runtime extension sends startBlockId for scoped JSONML reads, which is absent from the immutable pinned get_document_content metadata at its declared source revision.",
|
||||||
"doc.get_document_content --tags": "Runtime extension sends tags for scoped JSONML reads, which is absent from the immutable pinned get_document_content metadata at its declared source revision.",
|
"doc.get_document_content --tags": "Runtime extension sends tags for scoped JSONML reads, which is absent from the immutable pinned get_document_content metadata at its declared source revision.",
|
||||||
|
"doc.get_document_style --node": "Reviewed unpinned adapter: doc.get_document_style has no singular pinned interface_ref; --node is a CLI wrapper input and does not publish a direct interface property.",
|
||||||
"doc.import_get --task-id": "Reviewed unpinned adapter: doc.import_get has no singular pinned interface_ref; --task-id is a CLI wrapper input and does not publish a direct interface property.",
|
"doc.import_get --task-id": "Reviewed unpinned adapter: doc.import_get has no singular pinned interface_ref; --task-id is a CLI wrapper input and does not publish a direct interface property.",
|
||||||
"doc.insert_document_block --fix-jsonml": "local JSONML normalization control",
|
"doc.insert_document_block --fix-jsonml": "local JSONML normalization control",
|
||||||
"doc.insert_document_block --heading": "aggregate convenience input used to build element",
|
"doc.insert_document_block --heading": "aggregate convenience input used to build element",
|
||||||
@@ -1739,6 +1759,14 @@
|
|||||||
"doc.insert_document_block --text": "aggregate convenience input used to build element",
|
"doc.insert_document_block --text": "aggregate convenience input used to build element",
|
||||||
"doc.list_document_blocks --block-id": "runtime extension sends blockId, which is absent from the pinned list_document_blocks metadata",
|
"doc.list_document_blocks --block-id": "runtime extension sends blockId, which is absent from the pinned list_document_blocks metadata",
|
||||||
"doc.reply_comment --mentioned-open-conversation-id": "Runtime extension sends mentionedOpenConversationIds, which is absent from the immutable pinned reply_comment metadata at its declared source revision.",
|
"doc.reply_comment --mentioned-open-conversation-id": "Runtime extension sends mentionedOpenConversationIds, which is absent from the immutable pinned reply_comment metadata at its declared source revision.",
|
||||||
|
"doc.style_background_clear --node": "Reviewed unpinned adapter: doc.style_background_clear has no singular pinned interface_ref; --node is a CLI wrapper input and does not publish a direct interface property.",
|
||||||
|
"doc.style_background_set --color": "Reviewed unpinned adapter: doc.style_background_set has no singular pinned interface_ref; --color is a CLI wrapper input and does not publish a direct interface property.",
|
||||||
|
"doc.style_background_set --node": "Reviewed unpinned adapter: doc.style_background_set has no singular pinned interface_ref; --node is a CLI wrapper input and does not publish a direct interface property.",
|
||||||
|
"doc.style_cover_clear --node": "Reviewed unpinned adapter: doc.style_cover_clear has no singular pinned interface_ref; --node is a CLI wrapper input and does not publish a direct interface property.",
|
||||||
|
"doc.style_cover_set --file": "Reviewed unpinned adapter: doc.style_cover_set has no singular pinned interface_ref; --file is a CLI wrapper input and does not publish a direct interface property.",
|
||||||
|
"doc.style_cover_set --image": "Reviewed unpinned adapter: doc.style_cover_set has no singular pinned interface_ref; --image is a CLI wrapper input and does not publish a direct interface property.",
|
||||||
|
"doc.style_cover_set --node": "Reviewed unpinned adapter: doc.style_cover_set has no singular pinned interface_ref; --node is a CLI wrapper input and does not publish a direct interface property.",
|
||||||
|
"doc.style_cover_set --position": "Reviewed unpinned adapter: doc.style_cover_set has no singular pinned interface_ref; --position is a CLI wrapper input and does not publish a direct interface property.",
|
||||||
"doc.template_apply --folder": "Reviewed unpinned adapter: doc.template_apply has no singular pinned interface_ref; --folder is a CLI wrapper input and does not publish a direct interface property.",
|
"doc.template_apply --folder": "Reviewed unpinned adapter: doc.template_apply has no singular pinned interface_ref; --folder is a CLI wrapper input and does not publish a direct interface property.",
|
||||||
"doc.template_apply --name": "Reviewed unpinned adapter: doc.template_apply has no singular pinned interface_ref; --name is a CLI wrapper input and does not publish a direct interface property.",
|
"doc.template_apply --name": "Reviewed unpinned adapter: doc.template_apply has no singular pinned interface_ref; --name is a CLI wrapper input and does not publish a direct interface property.",
|
||||||
"doc.template_apply --template-id": "Reviewed unpinned adapter: doc.template_apply has no singular pinned interface_ref; --template-id is a CLI wrapper input and does not publish a direct interface property.",
|
"doc.template_apply --template-id": "Reviewed unpinned adapter: doc.template_apply has no singular pinned interface_ref; --template-id is a CLI wrapper input and does not publish a direct interface property.",
|
||||||
@@ -1767,7 +1795,22 @@
|
|||||||
"doc.version_revert --node": "Reviewed unpinned adapter: doc.version_revert has no singular pinned interface_ref; --node is a CLI wrapper input and does not publish a direct interface property.",
|
"doc.version_revert --node": "Reviewed unpinned adapter: doc.version_revert has no singular pinned interface_ref; --node is a CLI wrapper input and does not publish a direct interface property.",
|
||||||
"doc.version_revert --version": "Reviewed unpinned adapter: doc.version_revert has no singular pinned interface_ref; --version is a CLI wrapper input and does not publish a direct interface property.",
|
"doc.version_revert --version": "Reviewed unpinned adapter: doc.version_revert has no singular pinned interface_ref; --version is a CLI wrapper input and does not publish a direct interface property.",
|
||||||
"doc.version_save --node": "Reviewed unpinned adapter: doc.version_save has no singular pinned interface_ref; --node is a CLI wrapper input and does not publish a direct interface property.",
|
"doc.version_save --node": "Reviewed unpinned adapter: doc.version_save has no singular pinned interface_ref; --node is a CLI wrapper input and does not publish a direct interface property.",
|
||||||
|
"drive.apply_permission --node": "Reviewed unpinned adapter: drive.apply_permission has no singular pinned interface_ref; --node is a CLI wrapper input and does not publish a direct interface property.",
|
||||||
|
"drive.apply_permission --notify-mode": "Reviewed unpinned adapter: drive.apply_permission has no singular pinned interface_ref; --notify-mode is a CLI wrapper input and does not publish a direct interface property.",
|
||||||
|
"drive.apply_permission --reason": "Reviewed unpinned adapter: drive.apply_permission has no singular pinned interface_ref; --reason is a CLI wrapper input and does not publish a direct interface property.",
|
||||||
|
"drive.apply_permission --role": "Reviewed unpinned adapter: drive.apply_permission has no singular pinned interface_ref; --role is a CLI wrapper input and does not publish a direct interface property.",
|
||||||
|
"drive.apply_permission --users": "Reviewed unpinned adapter: drive.apply_permission has no singular pinned interface_ref; --users is a CLI wrapper input and does not publish a direct interface property.",
|
||||||
"drive.download_file --output": "local output path",
|
"drive.download_file --output": "local output path",
|
||||||
|
"drive.download_file_version --node": "Reviewed unpinned adapter: drive.download_file_version has no singular pinned interface_ref; --node is a CLI wrapper input and does not publish a direct interface property.",
|
||||||
|
"drive.download_file_version --output": "Reviewed unpinned adapter: drive.download_file_version has no singular pinned interface_ref; --output is a CLI wrapper input and does not publish a direct interface property.",
|
||||||
|
"drive.download_file_version --version": "Reviewed unpinned adapter: drive.download_file_version has no singular pinned interface_ref; --version is a CLI wrapper input and does not publish a direct interface property.",
|
||||||
|
"drive.get_cover --node": "Reviewed unpinned adapter: drive.get_cover has no singular pinned interface_ref; --node is a CLI wrapper input and does not publish a direct interface property.",
|
||||||
|
"drive.get_star_list --content-types": "Reviewed unpinned adapter: drive.get_star_list has no singular pinned interface_ref; --content-types is a CLI wrapper input and does not publish a direct interface property.",
|
||||||
|
"drive.get_star_list --cursor": "Reviewed unpinned adapter: drive.get_star_list has no singular pinned interface_ref; --cursor is a CLI wrapper input and does not publish a direct interface property.",
|
||||||
|
"drive.get_star_list --limit": "Reviewed unpinned adapter: drive.get_star_list has no singular pinned interface_ref; --limit is a CLI wrapper input and does not publish a direct interface property.",
|
||||||
|
"drive.get_star_list --order-by": "Reviewed unpinned adapter: drive.get_star_list has no singular pinned interface_ref; --order-by is a CLI wrapper input and does not publish a direct interface property.",
|
||||||
|
"drive.get_star_list --resource-types": "Reviewed unpinned adapter: drive.get_star_list has no singular pinned interface_ref; --resource-types is a CLI wrapper input and does not publish a direct interface property.",
|
||||||
|
"drive.get_star_list --sort": "Reviewed unpinned adapter: drive.get_star_list has no singular pinned interface_ref; --sort is a CLI wrapper input and does not publish a direct interface property.",
|
||||||
"drive.list_files --cursor": "composite route maps to nextToken for drive.list_files or pageToken for doc.list_nodes",
|
"drive.list_files --cursor": "composite route maps to nextToken for drive.list_files or pageToken for doc.list_nodes",
|
||||||
"drive.list_files --folder": "composite route maps to parentId for drive.list_files or folderId for doc.list_nodes",
|
"drive.list_files --folder": "composite route maps to parentId for drive.list_files or folderId for doc.list_nodes",
|
||||||
"drive.list_files --limit": "composite route maps to maxResults for drive.list_files or pageSize for doc.list_nodes",
|
"drive.list_files --limit": "composite route maps to maxResults for drive.list_files or pageSize for doc.list_nodes",
|
||||||
@@ -1776,10 +1819,12 @@
|
|||||||
"drive.list_files --space-id": "drive-branch-only route input on a composite drive/doc command; no singular interface property is advertised",
|
"drive.list_files --space-id": "drive-branch-only route input on a composite drive/doc command; no singular interface property is advertised",
|
||||||
"drive.list_files --thumbnail": "drive-branch-only option on a composite drive/doc command; no singular interface property is advertised",
|
"drive.list_files --thumbnail": "drive-branch-only option on a composite drive/doc command; no singular interface property is advertised",
|
||||||
"drive.list_files --workspace": "selects the doc.list_nodes branch of the composite drive/doc command",
|
"drive.list_files --workspace": "selects the doc.list_nodes branch of the composite drive/doc command",
|
||||||
|
"drive.mark_star --node": "Reviewed unpinned adapter: drive.mark_star has no singular pinned interface_ref; --node is a CLI wrapper input and does not publish a direct interface property.",
|
||||||
"drive.publish_get --node": "Reviewed unpinned adapter: drive.publish_get has no singular pinned interface_ref; --node is a CLI wrapper input and does not publish a direct interface property.",
|
"drive.publish_get --node": "Reviewed unpinned adapter: drive.publish_get has no singular pinned interface_ref; --node is a CLI wrapper input and does not publish a direct interface property.",
|
||||||
"drive.publish_set --node": "Reviewed unpinned adapter: drive.publish_set has no singular pinned interface_ref; --node is a CLI wrapper input and does not publish a direct interface property.",
|
"drive.publish_set --node": "Reviewed unpinned adapter: drive.publish_set has no singular pinned interface_ref; --node is a CLI wrapper input and does not publish a direct interface property.",
|
||||||
"drive.publish_set --permission": "Reviewed unpinned adapter: drive.publish_set has no singular pinned interface_ref; --permission is a CLI wrapper input and does not publish a direct interface property.",
|
"drive.publish_set --permission": "Reviewed unpinned adapter: drive.publish_set has no singular pinned interface_ref; --permission is a CLI wrapper input and does not publish a direct interface property.",
|
||||||
"drive.publish_unset --node": "Reviewed unpinned adapter: drive.publish_unset has no singular pinned interface_ref; --node is a CLI wrapper input and does not publish a direct interface property.",
|
"drive.publish_unset --node": "Reviewed unpinned adapter: drive.publish_unset has no singular pinned interface_ref; --node is a CLI wrapper input and does not publish a direct interface property.",
|
||||||
|
"drive.query_permission_apply_info --node": "Reviewed unpinned adapter: drive.query_permission_apply_info has no singular pinned interface_ref; --node is a CLI wrapper input and does not publish a direct interface property.",
|
||||||
"drive.recent --creator-type": "Reviewed unpinned adapter: drive.recent has no singular pinned interface_ref; --creator-type is a CLI wrapper input and does not publish a direct interface property.",
|
"drive.recent --creator-type": "Reviewed unpinned adapter: drive.recent has no singular pinned interface_ref; --creator-type is a CLI wrapper input and does not publish a direct interface property.",
|
||||||
"drive.recent --cursor": "Reviewed unpinned adapter: drive.recent has no singular pinned interface_ref; --cursor is a CLI wrapper input and does not publish a direct interface property.",
|
"drive.recent --cursor": "Reviewed unpinned adapter: drive.recent has no singular pinned interface_ref; --cursor is a CLI wrapper input and does not publish a direct interface property.",
|
||||||
"drive.recent --file-types": "Reviewed unpinned adapter: drive.recent has no singular pinned interface_ref; --file-types is a CLI wrapper input and does not publish a direct interface property.",
|
"drive.recent --file-types": "Reviewed unpinned adapter: drive.recent has no singular pinned interface_ref; --file-types is a CLI wrapper input and does not publish a direct interface property.",
|
||||||
@@ -1790,6 +1835,14 @@
|
|||||||
"drive.recycle_list --limit": "Reviewed unpinned adapter: drive.recycle_list has no singular pinned interface_ref; --limit is a CLI wrapper input and does not publish a direct interface property.",
|
"drive.recycle_list --limit": "Reviewed unpinned adapter: drive.recycle_list has no singular pinned interface_ref; --limit is a CLI wrapper input and does not publish a direct interface property.",
|
||||||
"drive.recycle_list --space-id": "Reviewed unpinned adapter: drive.recycle_list has no singular pinned interface_ref; --space-id is a CLI wrapper input and does not publish a direct interface property.",
|
"drive.recycle_list --space-id": "Reviewed unpinned adapter: drive.recycle_list has no singular pinned interface_ref; --space-id is a CLI wrapper input and does not publish a direct interface property.",
|
||||||
"drive.recycle_restore --id": "Reviewed unpinned adapter: drive.recycle_restore has no singular pinned interface_ref; --id is a CLI wrapper input and does not publish a direct interface property.",
|
"drive.recycle_restore --id": "Reviewed unpinned adapter: drive.recycle_restore has no singular pinned interface_ref; --id is a CLI wrapper input and does not publish a direct interface property.",
|
||||||
|
"drive.revert_file_version --node": "Reviewed unpinned adapter: drive.revert_file_version has no singular pinned interface_ref; --node is a CLI wrapper input and does not publish a direct interface property.",
|
||||||
|
"drive.revert_file_version --version": "Reviewed unpinned adapter: drive.revert_file_version has no singular pinned interface_ref; --version is a CLI wrapper input and does not publish a direct interface property.",
|
||||||
|
"drive.transfer_owner --new-owner": "Reviewed unpinned adapter: drive.transfer_owner has no singular pinned interface_ref; --new-owner is a CLI wrapper input and does not publish a direct interface property.",
|
||||||
|
"drive.transfer_owner --node": "Reviewed unpinned adapter: drive.transfer_owner has no singular pinned interface_ref; --node is a CLI wrapper input and does not publish a direct interface property.",
|
||||||
|
"drive.transfer_owner --recursive": "Reviewed unpinned adapter: drive.transfer_owner has no singular pinned interface_ref; --recursive is a CLI wrapper input and does not publish a direct interface property.",
|
||||||
|
"drive.transfer_owner --reserve-role": "Reviewed unpinned adapter: drive.transfer_owner has no singular pinned interface_ref; --reserve-role is a CLI wrapper input and does not publish a direct interface property.",
|
||||||
|
"drive.transfer_owner --workspace": "Reviewed unpinned adapter: drive.transfer_owner has no singular pinned interface_ref; --workspace is a CLI wrapper input and does not publish a direct interface property.",
|
||||||
|
"drive.unmark_star --node": "Reviewed unpinned adapter: drive.unmark_star has no singular pinned interface_ref; --node is a CLI wrapper input and does not publish a direct interface property.",
|
||||||
"mail.create_download_session --name": "local download filename",
|
"mail.create_download_session --name": "local download filename",
|
||||||
"mail.create_download_session --output": "local output path",
|
"mail.create_download_session --output": "local output path",
|
||||||
"mail.create_draft --attachment": "reviewed local attachment preprocessing input",
|
"mail.create_draft --attachment": "reviewed local attachment preprocessing input",
|
||||||
@@ -1835,9 +1888,16 @@
|
|||||||
"sheet.create_pivot_table --source": "Reviewed unpinned adapter: sheet.create_pivot_table has no singular pinned interface_ref; --source is a CLI wrapper input and does not publish a direct interface property.",
|
"sheet.create_pivot_table --source": "Reviewed unpinned adapter: sheet.create_pivot_table has no singular pinned interface_ref; --source is a CLI wrapper input and does not publish a direct interface property.",
|
||||||
"sheet.create_pivot_table --target-position": "Reviewed unpinned adapter: sheet.create_pivot_table has no singular pinned interface_ref; --target-position is a CLI wrapper input and does not publish a direct interface property.",
|
"sheet.create_pivot_table --target-position": "Reviewed unpinned adapter: sheet.create_pivot_table has no singular pinned interface_ref; --target-position is a CLI wrapper input and does not publish a direct interface property.",
|
||||||
"sheet.create_pivot_table --target-sheet-id": "Reviewed unpinned adapter: sheet.create_pivot_table has no singular pinned interface_ref; --target-sheet-id is a CLI wrapper input and does not publish a direct interface property.",
|
"sheet.create_pivot_table --target-sheet-id": "Reviewed unpinned adapter: sheet.create_pivot_table has no singular pinned interface_ref; --target-sheet-id is a CLI wrapper input and does not publish a direct interface property.",
|
||||||
|
"sheet.create_sheet_comment --content": "Reviewed unpinned adapter: sheet.create_sheet_comment has no singular pinned interface_ref; --content is a CLI wrapper input and does not publish a direct interface property.",
|
||||||
|
"sheet.create_sheet_comment --mention": "Reviewed unpinned adapter: sheet.create_sheet_comment has no singular pinned interface_ref; --mention is a CLI wrapper input and does not publish a direct interface property.",
|
||||||
|
"sheet.create_sheet_comment --node": "Reviewed unpinned adapter: sheet.create_sheet_comment has no singular pinned interface_ref; --node is a CLI wrapper input and does not publish a direct interface property.",
|
||||||
|
"sheet.create_sheet_comment --range": "Reviewed unpinned adapter: sheet.create_sheet_comment has no singular pinned interface_ref; --range is a CLI wrapper input and does not publish a direct interface property.",
|
||||||
|
"sheet.create_sheet_comment --sheet-id": "Reviewed unpinned adapter: sheet.create_sheet_comment has no singular pinned interface_ref; --sheet-id is a CLI wrapper input and does not publish a direct interface property.",
|
||||||
"sheet.delete_cond_format --yes": "local confirmation control",
|
"sheet.delete_cond_format --yes": "local confirmation control",
|
||||||
"sheet.delete_pivot_table --pivot-table-id": "Reviewed unpinned adapter: sheet.delete_pivot_table has no singular pinned interface_ref; --pivot-table-id is a CLI wrapper input and does not publish a direct interface property.",
|
"sheet.delete_pivot_table --pivot-table-id": "Reviewed unpinned adapter: sheet.delete_pivot_table has no singular pinned interface_ref; --pivot-table-id is a CLI wrapper input and does not publish a direct interface property.",
|
||||||
"sheet.delete_pivot_table --sheet-id": "Reviewed unpinned adapter: sheet.delete_pivot_table has no singular pinned interface_ref; --sheet-id is a CLI wrapper input and does not publish a direct interface property.",
|
"sheet.delete_pivot_table --sheet-id": "Reviewed unpinned adapter: sheet.delete_pivot_table has no singular pinned interface_ref; --sheet-id is a CLI wrapper input and does not publish a direct interface property.",
|
||||||
|
"sheet.delete_sheet_comment --comment-key": "Reviewed unpinned adapter: sheet.delete_sheet_comment has no singular pinned interface_ref; --comment-key is a CLI wrapper input and does not publish a direct interface property.",
|
||||||
|
"sheet.delete_sheet_comment --node": "Reviewed unpinned adapter: sheet.delete_sheet_comment has no singular pinned interface_ref; --node is a CLI wrapper input and does not publish a direct interface property.",
|
||||||
"sheet.filter_view_get_criteria --column": "local post-filter over get_filter_views response",
|
"sheet.filter_view_get_criteria --column": "local post-filter over get_filter_views response",
|
||||||
"sheet.filter_view_get_criteria --filter-view-id": "local post-filter over get_filter_views response",
|
"sheet.filter_view_get_criteria --filter-view-id": "local post-filter over get_filter_views response",
|
||||||
"sheet.filter_view_info --filter-view-id": "local post-filter over get_filter_views response",
|
"sheet.filter_view_info --filter-view-id": "local post-filter over get_filter_views response",
|
||||||
@@ -1847,6 +1907,13 @@
|
|||||||
"sheet.filter_view_update_criteria --filter-view-id": "Reviewed unpinned adapter: sheet.filter_view_update_criteria has no singular pinned interface_ref; --filter-view-id is a CLI wrapper input and does not publish a direct interface property.",
|
"sheet.filter_view_update_criteria --filter-view-id": "Reviewed unpinned adapter: sheet.filter_view_update_criteria has no singular pinned interface_ref; --filter-view-id is a CLI wrapper input and does not publish a direct interface property.",
|
||||||
"sheet.filter_view_update_criteria --node": "Reviewed unpinned adapter: sheet.filter_view_update_criteria has no singular pinned interface_ref; --node is a CLI wrapper input and does not publish a direct interface property.",
|
"sheet.filter_view_update_criteria --node": "Reviewed unpinned adapter: sheet.filter_view_update_criteria has no singular pinned interface_ref; --node is a CLI wrapper input and does not publish a direct interface property.",
|
||||||
"sheet.filter_view_update_criteria --sheet-id": "Reviewed unpinned adapter: sheet.filter_view_update_criteria has no singular pinned interface_ref; --sheet-id is a CLI wrapper input and does not publish a direct interface property.",
|
"sheet.filter_view_update_criteria --sheet-id": "Reviewed unpinned adapter: sheet.filter_view_update_criteria has no singular pinned interface_ref; --sheet-id is a CLI wrapper input and does not publish a direct interface property.",
|
||||||
|
"sheet.formula_verify --exit-on-error": "Reviewed unpinned adapter: sheet.formula_verify has no singular pinned interface_ref; --exit-on-error is a CLI wrapper input and does not publish a direct interface property.",
|
||||||
|
"sheet.formula_verify --max-cells": "Reviewed unpinned adapter: sheet.formula_verify has no singular pinned interface_ref; --max-cells is a CLI wrapper input and does not publish a direct interface property.",
|
||||||
|
"sheet.formula_verify --max-locations-per-error": "Reviewed unpinned adapter: sheet.formula_verify has no singular pinned interface_ref; --max-locations-per-error is a CLI wrapper input and does not publish a direct interface property.",
|
||||||
|
"sheet.formula_verify --node": "Reviewed unpinned adapter: sheet.formula_verify has no singular pinned interface_ref; --node is a CLI wrapper input and does not publish a direct interface property.",
|
||||||
|
"sheet.formula_verify --range": "Reviewed unpinned adapter: sheet.formula_verify has no singular pinned interface_ref; --range is a CLI wrapper input and does not publish a direct interface property.",
|
||||||
|
"sheet.formula_verify --sheet-id": "Reviewed unpinned adapter: sheet.formula_verify has no singular pinned interface_ref; --sheet-id is a CLI wrapper input and does not publish a direct interface property.",
|
||||||
|
"sheet.formula_verify --targets": "Reviewed unpinned adapter: sheet.formula_verify has no singular pinned interface_ref; --targets is a CLI wrapper input and does not publish a direct interface property.",
|
||||||
"sheet.group_dimension --group-state": "Reviewed unpinned adapter: sheet.group_dimension has no singular pinned interface_ref; --group-state is a CLI wrapper input and does not publish a direct interface property.",
|
"sheet.group_dimension --group-state": "Reviewed unpinned adapter: sheet.group_dimension has no singular pinned interface_ref; --group-state is a CLI wrapper input and does not publish a direct interface property.",
|
||||||
"sheet.group_dimension --node": "Reviewed unpinned adapter: sheet.group_dimension has no singular pinned interface_ref; --node is a CLI wrapper input and does not publish a direct interface property.",
|
"sheet.group_dimension --node": "Reviewed unpinned adapter: sheet.group_dimension has no singular pinned interface_ref; --node is a CLI wrapper input and does not publish a direct interface property.",
|
||||||
"sheet.group_dimension --range": "Reviewed unpinned adapter: sheet.group_dimension has no singular pinned interface_ref; --range is a CLI wrapper input and does not publish a direct interface property.",
|
"sheet.group_dimension --range": "Reviewed unpinned adapter: sheet.group_dimension has no singular pinned interface_ref; --range is a CLI wrapper input and does not publish a direct interface property.",
|
||||||
@@ -1854,6 +1921,12 @@
|
|||||||
"sheet.hide_gridline --sheet-id": "Reviewed unpinned adapter: sheet.hide_gridline has no singular pinned interface_ref; --sheet-id is a CLI wrapper input and does not publish a direct interface property.",
|
"sheet.hide_gridline --sheet-id": "Reviewed unpinned adapter: sheet.hide_gridline has no singular pinned interface_ref; --sheet-id is a CLI wrapper input and does not publish a direct interface property.",
|
||||||
"sheet.list_pivot_tables --pivot-table-id": "Reviewed unpinned adapter: sheet.list_pivot_tables has no singular pinned interface_ref; --pivot-table-id is a CLI wrapper input and does not publish a direct interface property.",
|
"sheet.list_pivot_tables --pivot-table-id": "Reviewed unpinned adapter: sheet.list_pivot_tables has no singular pinned interface_ref; --pivot-table-id is a CLI wrapper input and does not publish a direct interface property.",
|
||||||
"sheet.list_pivot_tables --sheet-id": "Reviewed unpinned adapter: sheet.list_pivot_tables has no singular pinned interface_ref; --sheet-id is a CLI wrapper input and does not publish a direct interface property.",
|
"sheet.list_pivot_tables --sheet-id": "Reviewed unpinned adapter: sheet.list_pivot_tables has no singular pinned interface_ref; --sheet-id is a CLI wrapper input and does not publish a direct interface property.",
|
||||||
|
"sheet.list_sheet_comments --cursor": "Reviewed unpinned adapter: sheet.list_sheet_comments has no singular pinned interface_ref; --cursor is a CLI wrapper input and does not publish a direct interface property.",
|
||||||
|
"sheet.list_sheet_comments --limit": "Reviewed unpinned adapter: sheet.list_sheet_comments has no singular pinned interface_ref; --limit is a CLI wrapper input and does not publish a direct interface property.",
|
||||||
|
"sheet.list_sheet_comments --node": "Reviewed unpinned adapter: sheet.list_sheet_comments has no singular pinned interface_ref; --node is a CLI wrapper input and does not publish a direct interface property.",
|
||||||
|
"sheet.list_sheet_comments --range": "Reviewed unpinned adapter: sheet.list_sheet_comments has no singular pinned interface_ref; --range is a CLI wrapper input and does not publish a direct interface property.",
|
||||||
|
"sheet.list_sheet_comments --resolve-status": "Reviewed unpinned adapter: sheet.list_sheet_comments has no singular pinned interface_ref; --resolve-status is a CLI wrapper input and does not publish a direct interface property.",
|
||||||
|
"sheet.list_sheet_comments --sheet-id": "Reviewed unpinned adapter: sheet.list_sheet_comments has no singular pinned interface_ref; --sheet-id is a CLI wrapper input and does not publish a direct interface property.",
|
||||||
"sheet.range_batch_clear --node": "Reviewed unpinned adapter: sheet.range_batch_clear has no singular pinned interface_ref; --node is a CLI wrapper input and does not publish a direct interface property.",
|
"sheet.range_batch_clear --node": "Reviewed unpinned adapter: sheet.range_batch_clear has no singular pinned interface_ref; --node is a CLI wrapper input and does not publish a direct interface property.",
|
||||||
"sheet.range_batch_clear --ranges": "Reviewed unpinned adapter: sheet.range_batch_clear has no singular pinned interface_ref; --ranges is a CLI wrapper input and does not publish a direct interface property.",
|
"sheet.range_batch_clear --ranges": "Reviewed unpinned adapter: sheet.range_batch_clear has no singular pinned interface_ref; --ranges is a CLI wrapper input and does not publish a direct interface property.",
|
||||||
"sheet.range_batch_clear --type": "Reviewed unpinned adapter: sheet.range_batch_clear has no singular pinned interface_ref; --type is a CLI wrapper input and does not publish a direct interface property.",
|
"sheet.range_batch_clear --type": "Reviewed unpinned adapter: sheet.range_batch_clear has no singular pinned interface_ref; --type is a CLI wrapper input and does not publish a direct interface property.",
|
||||||
@@ -1861,6 +1934,11 @@
|
|||||||
"sheet.range_batch_set_style --continue-on-error": "Composite wrapper consumes this flag in its local multi-call error loop and never sends it to update_range.",
|
"sheet.range_batch_set_style --continue-on-error": "Composite wrapper consumes this flag in its local multi-call error loop and never sends it to update_range.",
|
||||||
"sheet.range_read --range": "Reviewed unpinned adapter: sheet.range_read has no singular pinned interface_ref; --range is a CLI wrapper input and does not publish a direct interface property.",
|
"sheet.range_read --range": "Reviewed unpinned adapter: sheet.range_read has no singular pinned interface_ref; --range is a CLI wrapper input and does not publish a direct interface property.",
|
||||||
"sheet.range_read --sheet-id": "Reviewed unpinned adapter: sheet.range_read has no singular pinned interface_ref; --sheet-id is a CLI wrapper input and does not publish a direct interface property.",
|
"sheet.range_read --sheet-id": "Reviewed unpinned adapter: sheet.range_read has no singular pinned interface_ref; --sheet-id is a CLI wrapper input and does not publish a direct interface property.",
|
||||||
|
"sheet.reply_sheet_comment --comment-key": "Reviewed unpinned adapter: sheet.reply_sheet_comment has no singular pinned interface_ref; --comment-key is a CLI wrapper input and does not publish a direct interface property.",
|
||||||
|
"sheet.reply_sheet_comment --content": "Reviewed unpinned adapter: sheet.reply_sheet_comment has no singular pinned interface_ref; --content is a CLI wrapper input and does not publish a direct interface property.",
|
||||||
|
"sheet.reply_sheet_comment --emoji": "Reviewed unpinned adapter: sheet.reply_sheet_comment has no singular pinned interface_ref; --emoji is a CLI wrapper input and does not publish a direct interface property.",
|
||||||
|
"sheet.reply_sheet_comment --mention": "Reviewed unpinned adapter: sheet.reply_sheet_comment has no singular pinned interface_ref; --mention is a CLI wrapper input and does not publish a direct interface property.",
|
||||||
|
"sheet.reply_sheet_comment --node": "Reviewed unpinned adapter: sheet.reply_sheet_comment has no singular pinned interface_ref; --node is a CLI wrapper input and does not publish a direct interface property.",
|
||||||
"sheet.show_gridline --sheet-id": "Reviewed unpinned adapter: sheet.show_gridline has no singular pinned interface_ref; --sheet-id is a CLI wrapper input and does not publish a direct interface property.",
|
"sheet.show_gridline --sheet-id": "Reviewed unpinned adapter: sheet.show_gridline has no singular pinned interface_ref; --sheet-id is a CLI wrapper input and does not publish a direct interface property.",
|
||||||
"sheet.submit_export_job --output": "local destination consumed after export job completion",
|
"sheet.submit_export_job --output": "local destination consumed after export job completion",
|
||||||
"sheet.table_get --no-header": "Reviewed unpinned adapter: sheet.table_get has no singular pinned interface_ref; --no-header is a CLI wrapper input and does not publish a direct interface property.",
|
"sheet.table_get --no-header": "Reviewed unpinned adapter: sheet.table_get has no singular pinned interface_ref; --no-header is a CLI wrapper input and does not publish a direct interface property.",
|
||||||
@@ -1885,6 +1963,15 @@
|
|||||||
"sheet.update_pivot_table --pivot-table-id": "Reviewed unpinned adapter: sheet.update_pivot_table has no singular pinned interface_ref; --pivot-table-id is a CLI wrapper input and does not publish a direct interface property.",
|
"sheet.update_pivot_table --pivot-table-id": "Reviewed unpinned adapter: sheet.update_pivot_table has no singular pinned interface_ref; --pivot-table-id is a CLI wrapper input and does not publish a direct interface property.",
|
||||||
"sheet.update_pivot_table --properties": "Reviewed unpinned adapter: sheet.update_pivot_table has no singular pinned interface_ref; --properties is a CLI wrapper input and does not publish a direct interface property.",
|
"sheet.update_pivot_table --properties": "Reviewed unpinned adapter: sheet.update_pivot_table has no singular pinned interface_ref; --properties is a CLI wrapper input and does not publish a direct interface property.",
|
||||||
"sheet.update_pivot_table --sheet-id": "Reviewed unpinned adapter: sheet.update_pivot_table has no singular pinned interface_ref; --sheet-id is a CLI wrapper input and does not publish a direct interface property.",
|
"sheet.update_pivot_table --sheet-id": "Reviewed unpinned adapter: sheet.update_pivot_table has no singular pinned interface_ref; --sheet-id is a CLI wrapper input and does not publish a direct interface property.",
|
||||||
|
"sheet.update_sheet_comment --comment-key": "Reviewed unpinned adapter: sheet.update_sheet_comment has no singular pinned interface_ref; --comment-key is a CLI wrapper input and does not publish a direct interface property.",
|
||||||
|
"sheet.update_sheet_comment --content": "Reviewed unpinned adapter: sheet.update_sheet_comment has no singular pinned interface_ref; --content is a CLI wrapper input and does not publish a direct interface property.",
|
||||||
|
"sheet.update_sheet_comment --node": "Reviewed unpinned adapter: sheet.update_sheet_comment has no singular pinned interface_ref; --node is a CLI wrapper input and does not publish a direct interface property.",
|
||||||
|
"sheet.version_list --cursor": "Reviewed unpinned adapter: sheet.version_list has no singular pinned interface_ref; --cursor is a CLI wrapper input and does not publish a direct interface property.",
|
||||||
|
"sheet.version_list --limit": "Reviewed unpinned adapter: sheet.version_list has no singular pinned interface_ref; --limit is a CLI wrapper input and does not publish a direct interface property.",
|
||||||
|
"sheet.version_list --node": "Reviewed unpinned adapter: sheet.version_list has no singular pinned interface_ref; --node is a CLI wrapper input and does not publish a direct interface property.",
|
||||||
|
"sheet.version_revert --node": "Reviewed unpinned adapter: sheet.version_revert has no singular pinned interface_ref; --node is a CLI wrapper input and does not publish a direct interface property.",
|
||||||
|
"sheet.version_revert --version": "Reviewed unpinned adapter: sheet.version_revert has no singular pinned interface_ref; --version is a CLI wrapper input and does not publish a direct interface property.",
|
||||||
|
"sheet.version_save --node": "Reviewed unpinned adapter: sheet.version_save has no singular pinned interface_ref; --node is a CLI wrapper input and does not publish a direct interface property.",
|
||||||
"sheet.write_image --file": "local upload input used to obtain resourceId/resourceUrl",
|
"sheet.write_image --file": "local upload input used to obtain resourceId/resourceUrl",
|
||||||
"sheet.write_image --mime-type": "local upload metadata",
|
"sheet.write_image --mime-type": "local upload metadata",
|
||||||
"sheet.write_image --name": "local upload metadata",
|
"sheet.write_image --name": "local upload metadata",
|
||||||
@@ -1896,83 +1983,6 @@
|
|||||||
"wiki.list_wikiSpaces --cursor": "composite route maps to pageToken for wiki.list_wikiSpaces or nextToken for drive.list_spaces",
|
"wiki.list_wikiSpaces --cursor": "composite route maps to pageToken for wiki.list_wikiSpaces or nextToken for drive.list_spaces",
|
||||||
"wiki.list_wikiSpaces --limit": "composite route maps to pageSize for wiki.list_wikiSpaces or maxResults for drive.list_spaces",
|
"wiki.list_wikiSpaces --limit": "composite route maps to pageSize for wiki.list_wikiSpaces or maxResults for drive.list_spaces",
|
||||||
"wiki.list_wikiSpaces --type": "route selector maps to wikiSpaceType or spaceType on different composite branches",
|
"wiki.list_wikiSpaces --type": "route selector maps to wikiSpaceType or spaceType on different composite branches",
|
||||||
"wiki.search_wikiSpaces --type": "local route selector; myWikiSpace invokes list_wikiSpaces instead",
|
"wiki.search_wikiSpaces --type": "local route selector; myWikiSpace invokes list_wikiSpaces instead"
|
||||||
"chat.batch_query_group_chat_settings --groups": "Reviewed unpinned adapter: chat.batch_query_group_chat_settings has no singular pinned interface_ref; --groups is a CLI wrapper input and does not publish a direct interface property.",
|
|
||||||
"chat.batch_update_group_chat_settings --items": "Reviewed unpinned adapter: chat.batch_update_group_chat_settings has no singular pinned interface_ref; --items is a CLI wrapper input and does not publish a direct interface property.",
|
|
||||||
"chat.get_group_mute_config --group": "Reviewed unpinned adapter: chat.get_group_mute_config has no singular pinned interface_ref; --group is a CLI wrapper input and does not publish a direct interface property.",
|
|
||||||
"chat.update_text_emotion --background-id": "Reviewed unpinned adapter: chat.update_text_emotion has no singular pinned interface_ref; --background-id is a CLI wrapper input and does not publish a direct interface property.",
|
|
||||||
"chat.update_text_emotion --chat": "Reviewed unpinned adapter: chat.update_text_emotion has no singular pinned interface_ref; --chat is a CLI wrapper input and does not publish a direct interface property.",
|
|
||||||
"chat.update_text_emotion --conversation-id": "Reviewed unpinned adapter: chat.update_text_emotion has no singular pinned interface_ref; --conversation-id is a CLI wrapper input and does not publish a direct interface property.",
|
|
||||||
"chat.update_text_emotion --emotion-id": "Reviewed unpinned adapter: chat.update_text_emotion has no singular pinned interface_ref; --emotion-id is a CLI wrapper input and does not publish a direct interface property.",
|
|
||||||
"chat.update_text_emotion --emotion-name": "Reviewed unpinned adapter: chat.update_text_emotion has no singular pinned interface_ref; --emotion-name is a CLI wrapper input and does not publish a direct interface property.",
|
|
||||||
"chat.update_text_emotion --group": "Reviewed unpinned adapter: chat.update_text_emotion has no singular pinned interface_ref; --group is a CLI wrapper input and does not publish a direct interface property.",
|
|
||||||
"chat.update_text_emotion --id": "Reviewed unpinned adapter: chat.update_text_emotion has no singular pinned interface_ref; --id is a CLI wrapper input and does not publish a direct interface property.",
|
|
||||||
"chat.update_text_emotion --msg-id": "Reviewed unpinned adapter: chat.update_text_emotion has no singular pinned interface_ref; --msg-id is a CLI wrapper input and does not publish a direct interface property.",
|
|
||||||
"chat.update_text_emotion --old-emotion-id": "Reviewed unpinned adapter: chat.update_text_emotion has no singular pinned interface_ref; --old-emotion-id is a CLI wrapper input and does not publish a direct interface property.",
|
|
||||||
"chat.update_text_emotion --text": "Reviewed unpinned adapter: chat.update_text_emotion has no singular pinned interface_ref; --text is a CLI wrapper input and does not publish a direct interface property.",
|
|
||||||
"doc.get_document_style --node": "Reviewed unpinned adapter: doc.get_document_style has no singular pinned interface_ref; --node is a CLI wrapper input and does not publish a direct interface property.",
|
|
||||||
"doc.style_background_clear --node": "Reviewed unpinned adapter: doc.style_background_clear has no singular pinned interface_ref; --node is a CLI wrapper input and does not publish a direct interface property.",
|
|
||||||
"doc.style_background_set --color": "Reviewed unpinned adapter: doc.style_background_set has no singular pinned interface_ref; --color is a CLI wrapper input and does not publish a direct interface property.",
|
|
||||||
"doc.style_background_set --node": "Reviewed unpinned adapter: doc.style_background_set has no singular pinned interface_ref; --node is a CLI wrapper input and does not publish a direct interface property.",
|
|
||||||
"doc.style_cover_clear --node": "Reviewed unpinned adapter: doc.style_cover_clear has no singular pinned interface_ref; --node is a CLI wrapper input and does not publish a direct interface property.",
|
|
||||||
"doc.style_cover_set --file": "Reviewed unpinned adapter: doc.style_cover_set has no singular pinned interface_ref; --file is a CLI wrapper input and does not publish a direct interface property.",
|
|
||||||
"doc.style_cover_set --image": "Reviewed unpinned adapter: doc.style_cover_set has no singular pinned interface_ref; --image is a CLI wrapper input and does not publish a direct interface property.",
|
|
||||||
"doc.style_cover_set --node": "Reviewed unpinned adapter: doc.style_cover_set has no singular pinned interface_ref; --node is a CLI wrapper input and does not publish a direct interface property.",
|
|
||||||
"doc.style_cover_set --position": "Reviewed unpinned adapter: doc.style_cover_set has no singular pinned interface_ref; --position is a CLI wrapper input and does not publish a direct interface property.",
|
|
||||||
"drive.apply_permission --node": "Reviewed unpinned adapter: drive.apply_permission has no singular pinned interface_ref; --node is a CLI wrapper input and does not publish a direct interface property.",
|
|
||||||
"drive.apply_permission --notify-mode": "Reviewed unpinned adapter: drive.apply_permission has no singular pinned interface_ref; --notify-mode is a CLI wrapper input and does not publish a direct interface property.",
|
|
||||||
"drive.apply_permission --reason": "Reviewed unpinned adapter: drive.apply_permission has no singular pinned interface_ref; --reason is a CLI wrapper input and does not publish a direct interface property.",
|
|
||||||
"drive.apply_permission --role": "Reviewed unpinned adapter: drive.apply_permission has no singular pinned interface_ref; --role is a CLI wrapper input and does not publish a direct interface property.",
|
|
||||||
"drive.apply_permission --users": "Reviewed unpinned adapter: drive.apply_permission has no singular pinned interface_ref; --users is a CLI wrapper input and does not publish a direct interface property.",
|
|
||||||
"drive.get_cover --node": "Reviewed unpinned adapter: drive.get_cover has no singular pinned interface_ref; --node is a CLI wrapper input and does not publish a direct interface property.",
|
|
||||||
"drive.get_star_list --content-types": "Reviewed unpinned adapter: drive.get_star_list has no singular pinned interface_ref; --content-types is a CLI wrapper input and does not publish a direct interface property.",
|
|
||||||
"drive.get_star_list --cursor": "Reviewed unpinned adapter: drive.get_star_list has no singular pinned interface_ref; --cursor is a CLI wrapper input and does not publish a direct interface property.",
|
|
||||||
"drive.get_star_list --limit": "Reviewed unpinned adapter: drive.get_star_list has no singular pinned interface_ref; --limit is a CLI wrapper input and does not publish a direct interface property.",
|
|
||||||
"drive.get_star_list --order-by": "Reviewed unpinned adapter: drive.get_star_list has no singular pinned interface_ref; --order-by is a CLI wrapper input and does not publish a direct interface property.",
|
|
||||||
"drive.get_star_list --resource-types": "Reviewed unpinned adapter: drive.get_star_list has no singular pinned interface_ref; --resource-types is a CLI wrapper input and does not publish a direct interface property.",
|
|
||||||
"drive.get_star_list --sort": "Reviewed unpinned adapter: drive.get_star_list has no singular pinned interface_ref; --sort is a CLI wrapper input and does not publish a direct interface property.",
|
|
||||||
"drive.mark_star --node": "Reviewed unpinned adapter: drive.mark_star has no singular pinned interface_ref; --node is a CLI wrapper input and does not publish a direct interface property.",
|
|
||||||
"drive.query_permission_apply_info --node": "Reviewed unpinned adapter: drive.query_permission_apply_info has no singular pinned interface_ref; --node is a CLI wrapper input and does not publish a direct interface property.",
|
|
||||||
"drive.revert_file_version --node": "Reviewed unpinned adapter: drive.revert_file_version has no singular pinned interface_ref; --node is a CLI wrapper input and does not publish a direct interface property.",
|
|
||||||
"drive.revert_file_version --version": "Reviewed unpinned adapter: drive.revert_file_version has no singular pinned interface_ref; --version is a CLI wrapper input and does not publish a direct interface property.",
|
|
||||||
"drive.transfer_owner --new-owner": "Reviewed unpinned adapter: drive.transfer_owner has no singular pinned interface_ref; --new-owner is a CLI wrapper input and does not publish a direct interface property.",
|
|
||||||
"drive.transfer_owner --node": "Reviewed unpinned adapter: drive.transfer_owner has no singular pinned interface_ref; --node is a CLI wrapper input and does not publish a direct interface property.",
|
|
||||||
"drive.transfer_owner --recursive": "Reviewed unpinned adapter: drive.transfer_owner has no singular pinned interface_ref; --recursive is a CLI wrapper input and does not publish a direct interface property.",
|
|
||||||
"drive.transfer_owner --reserve-role": "Reviewed unpinned adapter: drive.transfer_owner has no singular pinned interface_ref; --reserve-role is a CLI wrapper input and does not publish a direct interface property.",
|
|
||||||
"drive.transfer_owner --workspace": "Reviewed unpinned adapter: drive.transfer_owner has no singular pinned interface_ref; --workspace is a CLI wrapper input and does not publish a direct interface property.",
|
|
||||||
"drive.unmark_star --node": "Reviewed unpinned adapter: drive.unmark_star has no singular pinned interface_ref; --node is a CLI wrapper input and does not publish a direct interface property.",
|
|
||||||
"sheet.create_sheet_comment --content": "Reviewed unpinned adapter: sheet.create_sheet_comment has no singular pinned interface_ref; --content is a CLI wrapper input and does not publish a direct interface property.",
|
|
||||||
"sheet.create_sheet_comment --mention": "Reviewed unpinned adapter: sheet.create_sheet_comment has no singular pinned interface_ref; --mention is a CLI wrapper input and does not publish a direct interface property.",
|
|
||||||
"sheet.create_sheet_comment --node": "Reviewed unpinned adapter: sheet.create_sheet_comment has no singular pinned interface_ref; --node is a CLI wrapper input and does not publish a direct interface property.",
|
|
||||||
"sheet.create_sheet_comment --range": "Reviewed unpinned adapter: sheet.create_sheet_comment has no singular pinned interface_ref; --range is a CLI wrapper input and does not publish a direct interface property.",
|
|
||||||
"sheet.create_sheet_comment --sheet-id": "Reviewed unpinned adapter: sheet.create_sheet_comment has no singular pinned interface_ref; --sheet-id is a CLI wrapper input and does not publish a direct interface property.",
|
|
||||||
"sheet.delete_sheet_comment --comment-key": "Reviewed unpinned adapter: sheet.delete_sheet_comment has no singular pinned interface_ref; --comment-key is a CLI wrapper input and does not publish a direct interface property.",
|
|
||||||
"sheet.delete_sheet_comment --node": "Reviewed unpinned adapter: sheet.delete_sheet_comment has no singular pinned interface_ref; --node is a CLI wrapper input and does not publish a direct interface property.",
|
|
||||||
"sheet.formula_verify --max-cells": "Reviewed unpinned adapter: sheet.formula_verify has no singular pinned interface_ref; --max-cells is a CLI wrapper input and does not publish a direct interface property.",
|
|
||||||
"sheet.formula_verify --max-locations-per-error": "Reviewed unpinned adapter: sheet.formula_verify has no singular pinned interface_ref; --max-locations-per-error is a CLI wrapper input and does not publish a direct interface property.",
|
|
||||||
"sheet.formula_verify --node": "Reviewed unpinned adapter: sheet.formula_verify has no singular pinned interface_ref; --node is a CLI wrapper input and does not publish a direct interface property.",
|
|
||||||
"sheet.formula_verify --range": "Reviewed unpinned adapter: sheet.formula_verify has no singular pinned interface_ref; --range is a CLI wrapper input and does not publish a direct interface property.",
|
|
||||||
"sheet.formula_verify --sheet-id": "Reviewed unpinned adapter: sheet.formula_verify has no singular pinned interface_ref; --sheet-id is a CLI wrapper input and does not publish a direct interface property.",
|
|
||||||
"sheet.formula_verify --targets": "Reviewed unpinned adapter: sheet.formula_verify has no singular pinned interface_ref; --targets is a CLI wrapper input and does not publish a direct interface property.",
|
|
||||||
"sheet.list_sheet_comments --cursor": "Reviewed unpinned adapter: sheet.list_sheet_comments has no singular pinned interface_ref; --cursor is a CLI wrapper input and does not publish a direct interface property.",
|
|
||||||
"sheet.list_sheet_comments --limit": "Reviewed unpinned adapter: sheet.list_sheet_comments has no singular pinned interface_ref; --limit is a CLI wrapper input and does not publish a direct interface property.",
|
|
||||||
"sheet.list_sheet_comments --node": "Reviewed unpinned adapter: sheet.list_sheet_comments has no singular pinned interface_ref; --node is a CLI wrapper input and does not publish a direct interface property.",
|
|
||||||
"sheet.list_sheet_comments --range": "Reviewed unpinned adapter: sheet.list_sheet_comments has no singular pinned interface_ref; --range is a CLI wrapper input and does not publish a direct interface property.",
|
|
||||||
"sheet.list_sheet_comments --resolve-status": "Reviewed unpinned adapter: sheet.list_sheet_comments has no singular pinned interface_ref; --resolve-status is a CLI wrapper input and does not publish a direct interface property.",
|
|
||||||
"sheet.list_sheet_comments --sheet-id": "Reviewed unpinned adapter: sheet.list_sheet_comments has no singular pinned interface_ref; --sheet-id is a CLI wrapper input and does not publish a direct interface property.",
|
|
||||||
"sheet.reply_sheet_comment --comment-key": "Reviewed unpinned adapter: sheet.reply_sheet_comment has no singular pinned interface_ref; --comment-key is a CLI wrapper input and does not publish a direct interface property.",
|
|
||||||
"sheet.reply_sheet_comment --content": "Reviewed unpinned adapter: sheet.reply_sheet_comment has no singular pinned interface_ref; --content is a CLI wrapper input and does not publish a direct interface property.",
|
|
||||||
"sheet.reply_sheet_comment --emoji": "Reviewed unpinned adapter: sheet.reply_sheet_comment has no singular pinned interface_ref; --emoji is a CLI wrapper input and does not publish a direct interface property.",
|
|
||||||
"sheet.reply_sheet_comment --mention": "Reviewed unpinned adapter: sheet.reply_sheet_comment has no singular pinned interface_ref; --mention is a CLI wrapper input and does not publish a direct interface property.",
|
|
||||||
"sheet.reply_sheet_comment --node": "Reviewed unpinned adapter: sheet.reply_sheet_comment has no singular pinned interface_ref; --node is a CLI wrapper input and does not publish a direct interface property.",
|
|
||||||
"sheet.update_sheet_comment --comment-key": "Reviewed unpinned adapter: sheet.update_sheet_comment has no singular pinned interface_ref; --comment-key is a CLI wrapper input and does not publish a direct interface property.",
|
|
||||||
"sheet.update_sheet_comment --content": "Reviewed unpinned adapter: sheet.update_sheet_comment has no singular pinned interface_ref; --content is a CLI wrapper input and does not publish a direct interface property.",
|
|
||||||
"sheet.update_sheet_comment --node": "Reviewed unpinned adapter: sheet.update_sheet_comment has no singular pinned interface_ref; --node is a CLI wrapper input and does not publish a direct interface property.",
|
|
||||||
"sheet.version_list --cursor": "Reviewed unpinned adapter: sheet.version_list has no singular pinned interface_ref; --cursor is a CLI wrapper input and does not publish a direct interface property.",
|
|
||||||
"sheet.version_list --limit": "Reviewed unpinned adapter: sheet.version_list has no singular pinned interface_ref; --limit is a CLI wrapper input and does not publish a direct interface property.",
|
|
||||||
"sheet.version_list --node": "Reviewed unpinned adapter: sheet.version_list has no singular pinned interface_ref; --node is a CLI wrapper input and does not publish a direct interface property.",
|
|
||||||
"sheet.version_revert --node": "Reviewed unpinned adapter: sheet.version_revert has no singular pinned interface_ref; --node is a CLI wrapper input and does not publish a direct interface property.",
|
|
||||||
"sheet.version_revert --version": "Reviewed unpinned adapter: sheet.version_revert has no singular pinned interface_ref; --version is a CLI wrapper input and does not publish a direct interface property.",
|
|
||||||
"sheet.version_save --node": "Reviewed unpinned adapter: sheet.version_save has no singular pinned interface_ref; --node is a CLI wrapper input and does not publish a direct interface property."
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1582,8 +1582,23 @@ func newChatCommand() *cobra.Command {
|
|||||||
contentJSON = fmt.Sprintf(`{"dentryId":%d,"spaceId":%d,"fileName":"%s","fileType":"%s","filePath":"%s","fileSize":%d}`,
|
contentJSON = fmt.Sprintf(`{"dentryId":%d,"spaceId":%d,"fileName":"%s","fileType":"%s","filePath":"%s","fileSize":%d}`,
|
||||||
dentryId, spaceId, fileName, fileType, filePath, fileSize)
|
dentryId, spaceId, fileName, fileType, filePath, fileSize)
|
||||||
}
|
}
|
||||||
|
case "location":
|
||||||
|
latitude, _ := cmd.Flags().GetString("latitude")
|
||||||
|
longitude, _ := cmd.Flags().GetString("longitude")
|
||||||
|
locationName, _ := cmd.Flags().GetString("location-name")
|
||||||
|
mapThumbnailUrl, _ := cmd.Flags().GetString("map-thumbnail-url")
|
||||||
|
if latitude == "" || longitude == "" || locationName == "" || mapThumbnailUrl == "" {
|
||||||
|
return fmt.Errorf("--latitude, --longitude, --location-name, --map-thumbnail-url are all required for msgType=location")
|
||||||
|
}
|
||||||
|
contentJSON = fmt.Sprintf(`{"locationName":"%s","longitude":"%s","latitude":"%s","mapThumbnailUrl":"%s"}`, locationName, longitude, latitude, mapThumbnailUrl)
|
||||||
|
case "profile":
|
||||||
|
contactID, _ := cmd.Flags().GetString("contact-id")
|
||||||
|
if contactID == "" {
|
||||||
|
return fmt.Errorf("--contact-id is required for msgType=profile")
|
||||||
|
}
|
||||||
|
contentJSON = fmt.Sprintf(`{"openDingTalkId":"%s"}`, contactID)
|
||||||
default:
|
default:
|
||||||
return fmt.Errorf("unsupported --msg-type: %s (supported: image, file, audio, video)", msgType)
|
return fmt.Errorf("unsupported --msg-type: %s (supported: image, file, audio, video, location, profile)", msgType)
|
||||||
}
|
}
|
||||||
|
|
||||||
params := map[string]any{
|
params := map[string]any{
|
||||||
@@ -2184,8 +2199,10 @@ func newChatCommand() *cobra.Command {
|
|||||||
}
|
}
|
||||||
if cmd.Flags().Changed("only-robot") {
|
if cmd.Flags().Changed("only-robot") {
|
||||||
toolArgs["onlyRobotMessages"], _ = cmd.Flags().GetBool("only-robot")
|
toolArgs["onlyRobotMessages"], _ = cmd.Flags().GetBool("only-robot")
|
||||||
|
} else if cmd.Flags().Changed("only-robot-messages") {
|
||||||
|
toolArgs["onlyRobotMessages"], _ = cmd.Flags().GetBool("only-robot-messages")
|
||||||
}
|
}
|
||||||
if v, _ := cmd.Flags().GetString("conversation-type"); v != "" {
|
if v := flagOrFallback(cmd, "conversation-type", "search-conv-type"); v != "" {
|
||||||
toolArgs["searchConvType"] = v
|
toolArgs["searchConvType"] = v
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2492,7 +2509,12 @@ func newChatCommand() *cobra.Command {
|
|||||||
chatMessageSendCmd.Flags().Bool("at-all", false, "@所有人(仅群聊时生效,可选),设置时,消息内容中一定要包含对应的占位符<@all>")
|
chatMessageSendCmd.Flags().Bool("at-all", false, "@所有人(仅群聊时生效,可选),设置时,消息内容中一定要包含对应的占位符<@all>")
|
||||||
chatMessageSendCmd.Flags().String("at-open-dingtalk-ids", "", "@指定成员的 openDingTalkId 列表,逗号分隔(仅群聊时生效,可选),设置--at-open-dingtalk-ids openDingTalkId1,openDingTalkId2时,消息内容中一定要包含对应格式的占位符<@openDingTalkId1> <@openDingTalkId2>")
|
chatMessageSendCmd.Flags().String("at-open-dingtalk-ids", "", "@指定成员的 openDingTalkId 列表,逗号分隔(仅群聊时生效,可选),设置--at-open-dingtalk-ids openDingTalkId1,openDingTalkId2时,消息内容中一定要包含对应格式的占位符<@openDingTalkId1> <@openDingTalkId2>")
|
||||||
chatMessageSendCmd.Flags().String("media-id", "", "上游已提供的图片 mediaId(仅旧版 msgType=image;CLI 不提供本地上传到 mediaId)")
|
chatMessageSendCmd.Flags().String("media-id", "", "上游已提供的图片 mediaId(仅旧版 msgType=image;CLI 不提供本地上传到 mediaId)")
|
||||||
chatMessageSendCmd.Flags().String("msg-type", "", "富媒体消息类型: image/file/audio/video(本地图片/文件推荐 file --file-path;image 仅接受已有 mediaId)")
|
chatMessageSendCmd.Flags().String("msg-type", "", "富媒体消息类型: image/file/audio/video/location/profile(本地图片/文件推荐 file --file-path;image 仅接受已有 mediaId)")
|
||||||
|
chatMessageSendCmd.Flags().String("latitude", "", "位置消息纬度(msgType=location 时必填)")
|
||||||
|
chatMessageSendCmd.Flags().String("longitude", "", "位置消息经度(msgType=location 时必填)")
|
||||||
|
chatMessageSendCmd.Flags().String("location-name", "", "位置消息地址名称(msgType=location 时必填)")
|
||||||
|
chatMessageSendCmd.Flags().String("map-thumbnail-url", "", "位置消息地图缩略图 mediaId,形如 @mediaId(msgType=location 时必填)")
|
||||||
|
chatMessageSendCmd.Flags().String("contact-id", "", "联系人名片 openDingTalkId(msgType=profile 时必填)")
|
||||||
chatMessageSendCmd.Flags().Int64("dentry-id", 0, "文件 dentryId(与 --space-id 成对传入时跳过自动上传)")
|
chatMessageSendCmd.Flags().Int64("dentry-id", 0, "文件 dentryId(与 --space-id 成对传入时跳过自动上传)")
|
||||||
chatMessageSendCmd.Flags().Int64("space-id", 0, "空间 ID(与 --dentry-id 成对传入时跳过自动上传)")
|
chatMessageSendCmd.Flags().Int64("space-id", 0, "空间 ID(与 --dentry-id 成对传入时跳过自动上传)")
|
||||||
chatMessageSendCmd.Flags().String("file-name", "", "文件名")
|
chatMessageSendCmd.Flags().String("file-name", "", "文件名")
|
||||||
@@ -2686,7 +2708,11 @@ func newChatCommand() *cobra.Command {
|
|||||||
_ = chatMessageSearchAdvancedCmd.Flags().MarkHidden("group")
|
_ = chatMessageSearchAdvancedCmd.Flags().MarkHidden("group")
|
||||||
chatMessageSearchAdvancedCmd.Flags().String("message-type", "", "下层消息类型过滤值(可选,以当前 IM Schema 支持值为准)")
|
chatMessageSearchAdvancedCmd.Flags().String("message-type", "", "下层消息类型过滤值(可选,以当前 IM Schema 支持值为准)")
|
||||||
chatMessageSearchAdvancedCmd.Flags().Bool("only-robot", false, "只搜索机器人消息(可选;显式传 false 时也会传给下层)")
|
chatMessageSearchAdvancedCmd.Flags().Bool("only-robot", false, "只搜索机器人消息(可选;显式传 false 时也会传给下层)")
|
||||||
|
chatMessageSearchAdvancedCmd.Flags().Bool("only-robot-messages", false, "--only-robot 的别名")
|
||||||
|
_ = chatMessageSearchAdvancedCmd.Flags().MarkHidden("only-robot-messages")
|
||||||
chatMessageSearchAdvancedCmd.Flags().String("conversation-type", "", "下层会话类型过滤值(可选,以当前 IM Schema 支持值为准)")
|
chatMessageSearchAdvancedCmd.Flags().String("conversation-type", "", "下层会话类型过滤值(可选,以当前 IM Schema 支持值为准)")
|
||||||
|
chatMessageSearchAdvancedCmd.Flags().String("search-conv-type", "", "--conversation-type 的别名")
|
||||||
|
_ = chatMessageSearchAdvancedCmd.Flags().MarkHidden("search-conv-type")
|
||||||
chatMessageSearchAdvancedCmd.Flags().String("start", "", "开始时间,ISO-8601 格式(可选)")
|
chatMessageSearchAdvancedCmd.Flags().String("start", "", "开始时间,ISO-8601 格式(可选)")
|
||||||
chatMessageSearchAdvancedCmd.Flags().String("end", "", "结束时间,ISO-8601 格式(可选)")
|
chatMessageSearchAdvancedCmd.Flags().String("end", "", "结束时间,ISO-8601 格式(可选)")
|
||||||
chatMessageSearchAdvancedCmd.Flags().String("cursor", "0", "分页游标(默认 \"0\")")
|
chatMessageSearchAdvancedCmd.Flags().String("cursor", "0", "分页游标(默认 \"0\")")
|
||||||
@@ -5409,6 +5435,13 @@ pl_PL, sv_SE, fi_FI, cs_CZ, ar_SA, tl_PH, he_IL, nl_NL, lo_LA, it_IT`,
|
|||||||
if len(items) > 100 {
|
if len(items) > 100 {
|
||||||
return fmt.Errorf("--items batch size %d exceeds limit 100", len(items))
|
return fmt.Errorf("--items batch size %d exceeds limit 100", len(items))
|
||||||
}
|
}
|
||||||
|
// 每项必须携带非空 openConversationId,缺失时 fail-fast,避免下发无效批量更新。
|
||||||
|
for i, item := range items {
|
||||||
|
cid, _ := item["openConversationId"].(string)
|
||||||
|
if strings.TrimSpace(cid) == "" {
|
||||||
|
return fmt.Errorf("--items[%d] 缺少非空 openConversationId", i)
|
||||||
|
}
|
||||||
|
}
|
||||||
return callMCPToolOnServer("im", "batch_update_group_chat_settings", map[string]any{
|
return callMCPToolOnServer("im", "batch_update_group_chat_settings", map[string]any{
|
||||||
"items": items,
|
"items": items,
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -0,0 +1,209 @@
|
|||||||
|
package helpers
|
||||||
|
|
||||||
|
import (
|
||||||
|
"io"
|
||||||
|
"reflect"
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/DingTalk-Real-AI/dingtalk-workspace-cli/pkg/edition"
|
||||||
|
)
|
||||||
|
|
||||||
|
func executeChatPortsCoverageCommand(t *testing.T, caller edition.ToolCaller, args ...string) error {
|
||||||
|
t.Helper()
|
||||||
|
previousDeps := deps
|
||||||
|
t.Cleanup(func() { deps = previousDeps })
|
||||||
|
InitDeps(caller)
|
||||||
|
deps.Out.w = io.Discard
|
||||||
|
deps.Out.errW = io.Discard
|
||||||
|
root := newChatCommand()
|
||||||
|
root.SilenceErrors = true
|
||||||
|
root.SilenceUsage = true
|
||||||
|
root.SetArgs(args)
|
||||||
|
return root.Execute()
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestCrossPlatformCoverageChatUpdateTextEmotion(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
args []string
|
||||||
|
want guardedMutationCall
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "conversation-id flag",
|
||||||
|
args: []string{
|
||||||
|
"message", "update-text-emotion",
|
||||||
|
"--conversation-id", "conv-1",
|
||||||
|
"--msg-id", "msg-1",
|
||||||
|
"--old-emotion-id", "old-1",
|
||||||
|
"--emotion-id", "new-1",
|
||||||
|
"--emotion-name", "like",
|
||||||
|
"--text", "nice",
|
||||||
|
"--background-id", "im_bg_5",
|
||||||
|
},
|
||||||
|
want: guardedMutationCall{
|
||||||
|
productID: "im",
|
||||||
|
toolName: "update_text_emotion",
|
||||||
|
args: map[string]any{
|
||||||
|
"openConversationId": "conv-1",
|
||||||
|
"openMsgId": "msg-1",
|
||||||
|
"oldEmotionId": "old-1",
|
||||||
|
"emotionId": "new-1",
|
||||||
|
"emotionName": "like",
|
||||||
|
"text": "nice",
|
||||||
|
"backgroundId": "im_bg_5",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "group alias for conversation-id",
|
||||||
|
args: []string{
|
||||||
|
"message", "update-text-emotion",
|
||||||
|
"--group", "conv-2",
|
||||||
|
"--msg-id", "msg-2",
|
||||||
|
"--old-emotion-id", "old-2",
|
||||||
|
"--emotion-id", "new-2",
|
||||||
|
"--emotion-name", "heart",
|
||||||
|
"--text", "great",
|
||||||
|
"--background-id", "im_bg_1",
|
||||||
|
},
|
||||||
|
want: guardedMutationCall{
|
||||||
|
productID: "im",
|
||||||
|
toolName: "update_text_emotion",
|
||||||
|
args: map[string]any{
|
||||||
|
"openConversationId": "conv-2",
|
||||||
|
"openMsgId": "msg-2",
|
||||||
|
"oldEmotionId": "old-2",
|
||||||
|
"emotionId": "new-2",
|
||||||
|
"emotionName": "heart",
|
||||||
|
"text": "great",
|
||||||
|
"backgroundId": "im_bg_1",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, test := range tests {
|
||||||
|
test := test
|
||||||
|
t.Run(test.name, func(t *testing.T) {
|
||||||
|
caller := &guardedMutationCaller{}
|
||||||
|
err := executeGuardedMutationCommand(t, caller, newChatCommand, test.args...)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("chat %s returned error: %v", strings.Join(test.args, " "), err)
|
||||||
|
}
|
||||||
|
if len(caller.calls) != 1 || !reflect.DeepEqual(caller.calls[0], test.want) {
|
||||||
|
t.Fatalf("tool calls = %#v, want %#v", caller.calls, test.want)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestCrossPlatformCoverageChatUpdateTextEmotionRequiredFlags(t *testing.T) {
|
||||||
|
fullArgs := []string{
|
||||||
|
"message", "update-text-emotion",
|
||||||
|
"--conversation-id", "conv-1",
|
||||||
|
"--msg-id", "msg-1",
|
||||||
|
"--old-emotion-id", "old-1",
|
||||||
|
"--emotion-id", "new-1",
|
||||||
|
"--emotion-name", "like",
|
||||||
|
"--text", "nice",
|
||||||
|
"--background-id", "im_bg_5",
|
||||||
|
}
|
||||||
|
dropFlag := func(name string) []string {
|
||||||
|
out := make([]string, 0, len(fullArgs))
|
||||||
|
for i := 0; i < len(fullArgs); i++ {
|
||||||
|
if fullArgs[i] == name {
|
||||||
|
i++ // skip the flag value too
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
out = append(out, fullArgs[i])
|
||||||
|
}
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
args []string
|
||||||
|
wantErr string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "missing conversation-id and aliases",
|
||||||
|
args: dropFlag("--conversation-id"),
|
||||||
|
wantErr: "--conversation-id",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "missing old-emotion-id",
|
||||||
|
args: dropFlag("--old-emotion-id"),
|
||||||
|
wantErr: "--old-emotion-id",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "missing msg-id and background-id",
|
||||||
|
args: []string{
|
||||||
|
"message", "update-text-emotion",
|
||||||
|
"--conversation-id", "conv-1",
|
||||||
|
"--old-emotion-id", "old-1",
|
||||||
|
"--emotion-id", "new-1",
|
||||||
|
"--emotion-name", "like",
|
||||||
|
"--text", "nice",
|
||||||
|
},
|
||||||
|
wantErr: "--msg-id, --background-id",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, test := range tests {
|
||||||
|
test := test
|
||||||
|
t.Run(test.name, func(t *testing.T) {
|
||||||
|
caller := &guardedMutationCaller{}
|
||||||
|
err := executeGuardedMutationCommand(t, caller, newChatCommand, test.args...)
|
||||||
|
if err == nil || !strings.Contains(err.Error(), test.wantErr) {
|
||||||
|
t.Fatalf("err = %v, want message containing %q", err, test.wantErr)
|
||||||
|
}
|
||||||
|
if len(caller.calls) != 0 {
|
||||||
|
t.Fatalf("tool calls = %#v, want none", caller.calls)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestCrossPlatformCoverageChatGroupGetMuteConfig(t *testing.T) {
|
||||||
|
caller := &guardedMutationCaller{}
|
||||||
|
err := executeGuardedMutationCommand(t, caller, newChatCommand,
|
||||||
|
"group", "get-mute-config", "--group", "conv-1")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("get-mute-config returned error: %v", err)
|
||||||
|
}
|
||||||
|
want := guardedMutationCall{
|
||||||
|
productID: "im",
|
||||||
|
toolName: "get_group_mute_config",
|
||||||
|
args: map[string]any{"openConversationId": "conv-1"},
|
||||||
|
}
|
||||||
|
if len(caller.calls) != 1 || !reflect.DeepEqual(caller.calls[0], want) {
|
||||||
|
t.Fatalf("tool calls = %#v, want %#v", caller.calls, want)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestCrossPlatformCoverageChatGroupGetMuteConfigRecordsRawArgs(t *testing.T) {
|
||||||
|
caller := &depthArgsRecordingCaller{steps: []scriptedToolStep{
|
||||||
|
{text: `{"muteBlackList":[],"muteWhiteList":[]}`},
|
||||||
|
}}
|
||||||
|
err := executeChatPortsCoverageCommand(t, caller,
|
||||||
|
"group", "get-mute-config", "--group", "conv-9")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if len(caller.calls) != 1 {
|
||||||
|
t.Fatalf("calls = %#v, want 1", caller.calls)
|
||||||
|
}
|
||||||
|
if caller.calls[0]["openConversationId"] != "conv-9" {
|
||||||
|
t.Fatalf("raw args = %#v", caller.calls[0])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestCrossPlatformCoverageChatGroupGetMuteConfigRequiresGroup(t *testing.T) {
|
||||||
|
caller := &guardedMutationCaller{}
|
||||||
|
err := executeGuardedMutationCommand(t, caller, newChatCommand,
|
||||||
|
"group", "get-mute-config")
|
||||||
|
if err == nil || !strings.Contains(err.Error(), "--group") {
|
||||||
|
t.Fatalf("err = %v, want message containing --group", err)
|
||||||
|
}
|
||||||
|
if len(caller.calls) != 0 {
|
||||||
|
t.Fatalf("tool calls = %#v, want none", caller.calls)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -44,6 +44,36 @@ func TestCrossPlatformCoverageChatGroupUserSettingsSetValidation(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestCrossPlatformCoverageChatGroupUserSettingsSetItemValidation(t *testing.T) {
|
||||||
|
caller := &guardedMutationCaller{}
|
||||||
|
err := executeGuardedMutationCommand(t, caller, newChatCommand,
|
||||||
|
"group", "user-settings", "set", "--items", `[{"top":true}]`)
|
||||||
|
if err == nil || !strings.Contains(err.Error(), "openConversationId") || !strings.Contains(err.Error(), "--items[0]") {
|
||||||
|
t.Fatalf("err = %v, want missing openConversationId error", err)
|
||||||
|
}
|
||||||
|
if len(caller.calls) != 0 {
|
||||||
|
t.Fatalf("calls = %#v, want no MCP call on invalid item", caller.calls)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 非首项缺失时错误需带正确下标;空白字符串同样视为缺失。
|
||||||
|
caller = &guardedMutationCaller{}
|
||||||
|
err = executeGuardedMutationCommand(t, caller, newChatCommand,
|
||||||
|
"group", "user-settings", "set", "--items", `[{"openConversationId":"cid1"},{"openConversationId":" "}]`)
|
||||||
|
if err == nil || !strings.Contains(err.Error(), "--items[1]") {
|
||||||
|
t.Fatalf("err = %v, want --items[1] error", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 合法条目仍然成功下发。
|
||||||
|
caller = &guardedMutationCaller{}
|
||||||
|
if err := executeGuardedMutationCommand(t, caller, newChatCommand,
|
||||||
|
"group", "user-settings", "set", "--items", `[{"openConversationId":"cid1","top":true,"mute":false}]`); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if len(caller.calls) != 1 || caller.calls[0].toolName != "batch_update_group_chat_settings" {
|
||||||
|
t.Fatalf("calls = %#v", caller.calls)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestCrossPlatformCoverageChatGroupUserSettingsSetHappyPath(t *testing.T) {
|
func TestCrossPlatformCoverageChatGroupUserSettingsSetHappyPath(t *testing.T) {
|
||||||
caller := &guardedMutationCaller{}
|
caller := &guardedMutationCaller{}
|
||||||
err := executeGuardedMutationCommand(t, caller, newChatCommand,
|
err := executeGuardedMutationCommand(t, caller, newChatCommand,
|
||||||
@@ -59,3 +89,74 @@ func TestCrossPlatformCoverageChatGroupUserSettingsSetHappyPath(t *testing.T) {
|
|||||||
t.Fatalf("call = %#v", call)
|
t.Fatalf("call = %#v", call)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestCrossPlatformCoverageChatMessageSendLocation(t *testing.T) {
|
||||||
|
caller := &guardedMutationCaller{}
|
||||||
|
err := executeGuardedMutationCommand(t, caller, newChatCommand,
|
||||||
|
"message", "send", "--group", "cid1", "--msg-type", "location", "--latitude", "39.9")
|
||||||
|
if err == nil || !strings.Contains(err.Error(), "are all required for msgType=location") {
|
||||||
|
t.Fatalf("err = %v, want missing location params", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
caller = &guardedMutationCaller{}
|
||||||
|
err = executeGuardedMutationCommand(t, caller, newChatCommand,
|
||||||
|
"message", "send", "--group", "cid1", "--msg-type", "location",
|
||||||
|
"--latitude", "39.9", "--longitude", "116.4", "--location-name", "国贸", "--map-thumbnail-url", "@media1")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if len(caller.calls) != 1 {
|
||||||
|
t.Fatalf("calls = %#v", caller.calls)
|
||||||
|
}
|
||||||
|
call := caller.calls[0]
|
||||||
|
if call.args["msgType"] != "location" {
|
||||||
|
t.Fatalf("msgType = %#v", call.args["msgType"])
|
||||||
|
}
|
||||||
|
content, _ := call.args["content"].(string)
|
||||||
|
if !strings.Contains(content, `"latitude":"39.9"`) || !strings.Contains(content, `"mapThumbnailUrl":"@media1"`) {
|
||||||
|
t.Fatalf("content = %s", content)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestCrossPlatformCoverageChatMessageSendProfile(t *testing.T) {
|
||||||
|
caller := &guardedMutationCaller{}
|
||||||
|
err := executeGuardedMutationCommand(t, caller, newChatCommand,
|
||||||
|
"message", "send", "--group", "cid1", "--msg-type", "profile")
|
||||||
|
if err == nil || !strings.Contains(err.Error(), "--contact-id is required") {
|
||||||
|
t.Fatalf("err = %v, want contact-id required", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
caller = &guardedMutationCaller{}
|
||||||
|
err = executeGuardedMutationCommand(t, caller, newChatCommand,
|
||||||
|
"message", "send", "--group", "cid1", "--msg-type", "profile", "--contact-id", "od123")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if len(caller.calls) != 1 {
|
||||||
|
t.Fatalf("calls = %#v", caller.calls)
|
||||||
|
}
|
||||||
|
content, _ := caller.calls[0].args["content"].(string)
|
||||||
|
if !strings.Contains(content, `"openDingTalkId":"od123"`) {
|
||||||
|
t.Fatalf("content = %s", content)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestCrossPlatformCoverageChatSearchAdvancedWukongAliases(t *testing.T) {
|
||||||
|
caller := &guardedMutationCaller{}
|
||||||
|
err := executeGuardedMutationCommand(t, caller, newChatCommand,
|
||||||
|
"message", "search-advanced", "--query", "通知",
|
||||||
|
"--only-robot-messages", "--search-conv-type", "group_chat")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if len(caller.calls) != 1 {
|
||||||
|
t.Fatalf("calls = %#v", caller.calls)
|
||||||
|
}
|
||||||
|
args := caller.calls[0].args
|
||||||
|
if args["onlyRobotMessages"] != true {
|
||||||
|
t.Fatalf("onlyRobotMessages = %#v", args["onlyRobotMessages"])
|
||||||
|
}
|
||||||
|
if args["searchConvType"] != "group_chat" {
|
||||||
|
t.Fatalf("searchConvType = %#v", args["searchConvType"])
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -177,7 +177,12 @@ func runDocStyleCoverSet(cmd *cobra.Command, _ []string) error {
|
|||||||
if deps.Caller.DryRun() {
|
if deps.Caller.DryRun() {
|
||||||
cover["resourceId"] = fmt.Sprintf("(pending upload from --file %s)", filePath)
|
cover["resourceId"] = fmt.Sprintf("(pending upload from --file %s)", filePath)
|
||||||
} else {
|
} else {
|
||||||
resourceID, err := uploadDocStyleImage(context.Background(), nodeID, filePath, filepath.Base(filePath), mimeType, fileSize)
|
// 使用命令上下文,让 Ctrl-C 能够取消上传凭证获取与 OSS 上传两次网络请求。
|
||||||
|
ctx := cmd.Context()
|
||||||
|
if ctx == nil {
|
||||||
|
ctx = context.Background()
|
||||||
|
}
|
||||||
|
resourceID, err := uploadDocStyleImage(ctx, nodeID, filePath, filepath.Base(filePath), mimeType, fileSize)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -247,9 +252,13 @@ func runDocStyleGet(cmd *cobra.Command, _ []string) error {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// docStyleCoverMaxBytes 是 cover set --file 本地图片的大小上限(20 MiB)。
|
||||||
|
// 悟空参考实现未设上限,此处补充客户端 fail-fast,避免超大文件被先行上传。
|
||||||
|
const docStyleCoverMaxBytes = 20 << 20
|
||||||
|
|
||||||
// validateCoverImageFile 对 cover set --file 做本地校验(不上传/不读取文件内容):
|
// validateCoverImageFile 对 cover set --file 做本地校验(不上传/不读取文件内容):
|
||||||
// 文件须存在、非目录,且按扩展名推断的 MIME 必须为 image/*。返回 mimeType 与文件大小,
|
// 文件须存在、非目录、不超过大小上限,且按扩展名推断的 MIME 必须为 image/*。
|
||||||
// 供 dry-run 预览与真实上传前 fail-fast,避免非法文件被先行上传。
|
// 返回 mimeType 与文件大小,供 dry-run 预览与真实上传前 fail-fast,避免非法文件被先行上传。
|
||||||
func validateCoverImageFile(filePath string) (mimeType string, fileSize int64, err error) {
|
func validateCoverImageFile(filePath string) (mimeType string, fileSize int64, err error) {
|
||||||
fileInfo, err := os.Stat(filePath)
|
fileInfo, err := os.Stat(filePath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -258,6 +267,9 @@ func validateCoverImageFile(filePath string) (mimeType string, fileSize int64, e
|
|||||||
if fileInfo.IsDir() {
|
if fileInfo.IsDir() {
|
||||||
return "", 0, fmt.Errorf("%s is a directory, not a file", filePath)
|
return "", 0, fmt.Errorf("%s is a directory, not a file", filePath)
|
||||||
}
|
}
|
||||||
|
if fileInfo.Size() > docStyleCoverMaxBytes {
|
||||||
|
return "", 0, fmt.Errorf("封面图片文件过大:上限 %d 字节 (20 MiB),实际 %d 字节 (%s)", int64(docStyleCoverMaxBytes), fileInfo.Size(), filepath.Base(filePath))
|
||||||
|
}
|
||||||
mimeType = inferMimeType(filepath.Base(filePath))
|
mimeType = inferMimeType(filepath.Base(filePath))
|
||||||
if !strings.HasPrefix(mimeType, "image/") {
|
if !strings.HasPrefix(mimeType, "image/") {
|
||||||
return "", 0, fmt.Errorf("cover --file must be an image (png/jpg/jpeg/gif/svg/webp), got %s", filepath.Base(filePath))
|
return "", 0, fmt.Errorf("cover --file must be an image (png/jpg/jpeg/gif/svg/webp), got %s", filepath.Base(filePath))
|
||||||
|
|||||||
@@ -135,3 +135,96 @@ func TestCrossPlatformCoverageUploadDocStyleImageFailures(t *testing.T) {
|
|||||||
t.Fatal("invalid upload info returned nil")
|
t.Fatal("invalid upload info returned nil")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestCrossPlatformCoverageValidateCoverImageFileSizeLimit(t *testing.T) {
|
||||||
|
// 上限以内的正常图片通过校验。
|
||||||
|
path := writeTempImage(t, "cover.png")
|
||||||
|
if _, _, err := validateCoverImageFile(path); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// os.Truncate 生成超过上限 1 字节的稀疏文件(瞬时创建,不占实际磁盘)。
|
||||||
|
if err := os.Truncate(path, docStyleCoverMaxBytes+1); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
_, _, err := validateCoverImageFile(path)
|
||||||
|
if err == nil || !strings.Contains(err.Error(), "封面图片文件过大") || !strings.Contains(err.Error(), "20 MiB") {
|
||||||
|
t.Fatalf("err = %v, want size limit error", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 恰好等于上限时仍应通过。
|
||||||
|
if err := os.Truncate(path, docStyleCoverMaxBytes); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if _, _, err := validateCoverImageFile(path); err != nil {
|
||||||
|
t.Fatalf("size == limit should pass, got %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestCrossPlatformCoverageDocStyleCoverSetSizeLimitViaCommand(t *testing.T) {
|
||||||
|
path := writeTempImage(t, "cover.png")
|
||||||
|
if err := os.Truncate(path, docStyleCoverMaxBytes+1); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
caller := &scriptedToolCaller{}
|
||||||
|
err := executeDocStyleCommand(t, caller, "cover", "set", "--node", "n1", "--file", path)
|
||||||
|
if err == nil || !strings.Contains(err.Error(), "封面图片文件过大") {
|
||||||
|
t.Fatalf("err = %v, want size limit error", err)
|
||||||
|
}
|
||||||
|
if caller.calls != 0 {
|
||||||
|
t.Fatalf("calls = %d, want 0 (fail before any network request)", caller.calls)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestCrossPlatformCoverageDocStyleCoverSetNilContextFallback(t *testing.T) {
|
||||||
|
// 直接调用 RunE(不经 Execute),cmd.Context() 为 nil,覆盖 context.Background() 兜底分支。
|
||||||
|
path := writeTempImage(t, "cover.png")
|
||||||
|
stubHTTPPutFile(t, nil)
|
||||||
|
caller := &scriptedToolCaller{steps: []scriptedToolStep{
|
||||||
|
{text: `{"uploadUrl":"https://oss.test/put","resourceId":"res-1"}`},
|
||||||
|
{text: `{}`},
|
||||||
|
}}
|
||||||
|
installScriptedCaller(t, caller)
|
||||||
|
root := newDocStyleCommand()
|
||||||
|
coverSet, _, err := root.Find([]string{"cover", "set"})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if coverSet.Context() != nil {
|
||||||
|
t.Fatal("expected nil context on unexecuted command")
|
||||||
|
}
|
||||||
|
if err := coverSet.Flags().Set("node", "n1"); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if err := coverSet.Flags().Set("file", path); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if err := runDocStyleCoverSet(coverSet, nil); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if caller.calls != 2 {
|
||||||
|
t.Fatalf("calls = %d, want 2 (upload info + style set)", caller.calls)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestCrossPlatformCoverageDocStyleCoverSetUsesCommandContext(t *testing.T) {
|
||||||
|
// 经 ExecuteContext 执行时,上传流程应使用命令上下文;scriptedToolCaller 忽略 ctx,
|
||||||
|
// 故此处做行为性断言:正常上下文下上传路径成功走通(覆盖 ctx := cmd.Context() 分支)。
|
||||||
|
path := writeTempImage(t, "cover.png")
|
||||||
|
stubHTTPPutFile(t, nil)
|
||||||
|
caller := &scriptedToolCaller{steps: []scriptedToolStep{
|
||||||
|
{text: `{"uploadUrl":"https://oss.test/put","resourceId":"res-1"}`},
|
||||||
|
{text: `{}`},
|
||||||
|
}}
|
||||||
|
installScriptedCaller(t, caller)
|
||||||
|
root := newDocStyleCommand()
|
||||||
|
root.SilenceErrors = true
|
||||||
|
root.SilenceUsage = true
|
||||||
|
root.SetArgs([]string{"cover", "set", "--node", "n1", "--file", path})
|
||||||
|
if err := root.ExecuteContext(context.Background()); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if caller.calls != 2 {
|
||||||
|
t.Fatalf("calls = %d, want 2 (upload info + style set)", caller.calls)
|
||||||
|
}
|
||||||
|
}
|
||||||
+123
-11
@@ -305,14 +305,23 @@ func newDriveCommand() *cobra.Command {
|
|||||||
pattern, _ := cmd.Flags().GetString("pattern")
|
pattern, _ := cmd.Flags().GetString("pattern")
|
||||||
|
|
||||||
depth, _ := cmd.Flags().GetInt("depth")
|
depth, _ := cmd.Flags().GetInt("depth")
|
||||||
if cmd.Flags().Changed("depth") {
|
|
||||||
if err := validateDriveListDepth(cmd, depth); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// --versions 模式:列出文件历史版本(仅普通文件)
|
// --versions 模式:列出文件历史版本(仅普通文件)
|
||||||
|
// 先于 --depth 校验执行:versions 模式合法使用 --limit,
|
||||||
|
// 不应被「--limit 与 --depth 不兼容」的误导性报错拦截。
|
||||||
if cmd.Flags().Changed("versions") {
|
if cmd.Flags().Changed("versions") {
|
||||||
|
if cmd.Flags().Changed("depth") && depth > 1 {
|
||||||
|
return &CLIError{
|
||||||
|
Code: CodeInvalidParam,
|
||||||
|
Message: "--versions 与 --depth 不能同时使用",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if pattern != "" {
|
||||||
|
return &CLIError{
|
||||||
|
Code: CodeInvalidParam,
|
||||||
|
Message: "--versions 与 --pattern 不能同时使用",
|
||||||
|
}
|
||||||
|
}
|
||||||
nodeID, err := mustFlagOrFallback(cmd, "node", "url", "id", "node-id", "doc-id", "file-id")
|
nodeID, err := mustFlagOrFallback(cmd, "node", "url", "id", "node-id", "doc-id", "file-id")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -327,6 +336,12 @@ func newDriveCommand() *cobra.Command {
|
|||||||
return callMCPToolOnServer("drive", "list_file_versions", toolArgs)
|
return callMCPToolOnServer("drive", "list_file_versions", toolArgs)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if cmd.Flags().Changed("depth") {
|
||||||
|
if err := validateDriveListDepth(cmd, depth); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// 如果指定了 --workspace,路由到文档空间(doc MCP server)
|
// 如果指定了 --workspace,路由到文档空间(doc MCP server)
|
||||||
workspaceID := flagOrFallback(cmd, "workspace", "workspace-id")
|
workspaceID := flagOrFallback(cmd, "workspace", "workspace-id")
|
||||||
if workspaceID != "" {
|
if workspaceID != "" {
|
||||||
@@ -519,6 +534,73 @@ func newDriveCommand() *cobra.Command {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
driveDownloadVersionCmd := &cobra.Command{
|
||||||
|
Use: "download-version",
|
||||||
|
Short: "下载文件历史版本到本地",
|
||||||
|
Long: `下载钉盘文件的指定历史版本到本地(两步下载流程)。
|
||||||
|
|
||||||
|
仅适用于普通文件(如 pdf、docx、xlsx、png 等):
|
||||||
|
钉钉在线文档(adoc)请使用 dws doc version 系列命令
|
||||||
|
钉钉在线表格(axls)请使用 dws sheet version 系列命令
|
||||||
|
|
||||||
|
流程:
|
||||||
|
1. 获取历史版本下载 URL 和签名请求头 (download_file_version)
|
||||||
|
2. HTTP GET 下载文件二进制内容到本地
|
||||||
|
|
||||||
|
版本号从 dws drive list --node <dentryUuid> --versions 获取。`,
|
||||||
|
Example: ` dws drive download-version --node <dentryUuid> --version 3 --output ./report_v3.pdf
|
||||||
|
dws drive download-version --node <dentryUuid> --version 3 --output ~/downloads/`,
|
||||||
|
RunE: func(cmd *cobra.Command, args []string) error {
|
||||||
|
fileID, err := mustFlagOrFallback(cmd, "node", "url", "id", "node-id", "doc-id", "file-id")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
versionNum, _ := cmd.Flags().GetInt("version")
|
||||||
|
if versionNum <= 0 {
|
||||||
|
return fmt.Errorf("--version 必须为正整数,当前值: %d(版本号从 drive list --versions 获取)", versionNum)
|
||||||
|
}
|
||||||
|
outputPath, _ := cmd.Flags().GetString("output")
|
||||||
|
if outputPath == "" {
|
||||||
|
return fmt.Errorf("flag --output is required")
|
||||||
|
}
|
||||||
|
|
||||||
|
if deps.Caller.DryRun() {
|
||||||
|
deps.Out.PrintKeyValue("操作", "下载文件历史版本")
|
||||||
|
deps.Out.PrintKeyValue("节点ID", fileID)
|
||||||
|
deps.Out.PrintKeyValue("版本号", fmt.Sprintf("%d", versionNum))
|
||||||
|
deps.Out.PrintKeyValue("输出", outputPath)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx := context.Background()
|
||||||
|
deps.Out.PrintInfo("[1/2] 获取历史版本下载链接...")
|
||||||
|
text, err := callMCPToolReturnTextOnServer(ctx, "drive", "download_file_version", map[string]any{
|
||||||
|
"nodeId": fileID,
|
||||||
|
"version": versionNum,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
resourceURL, dlHeaders, err := parseDownloadInfo(text)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if fi, statErr := os.Stat(outputPath); statErr == nil && fi.IsDir() {
|
||||||
|
filename := extractFileNameFromResponse(text)
|
||||||
|
if filename == "" {
|
||||||
|
filename = inferFilename(resourceURL)
|
||||||
|
}
|
||||||
|
outputPath = filepath.Join(outputPath, filename)
|
||||||
|
}
|
||||||
|
deps.Out.PrintInfo(fmt.Sprintf("[2/2] 下载文件到 %s ...", outputPath))
|
||||||
|
if err := httpGetFile(ctx, resourceURL, dlHeaders, outputPath); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
deps.Out.PrintInfo(fmt.Sprintf("下载完成: %s", outputPath))
|
||||||
|
return nil
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
driveMkdirCmd := &cobra.Command{
|
driveMkdirCmd := &cobra.Command{
|
||||||
Use: "mkdir",
|
Use: "mkdir",
|
||||||
Short: "创建文件夹",
|
Short: "创建文件夹",
|
||||||
@@ -628,6 +710,14 @@ func newDriveCommand() *cobra.Command {
|
|||||||
driveDownloadCmd.Flags().String("space-id", "", "文件所属空间 ID (可选)")
|
driveDownloadCmd.Flags().String("space-id", "", "文件所属空间 ID (可选)")
|
||||||
driveDownloadCmd.Flags().String("output", "", "本地保存路径 (文件路径或目录,必填)")
|
driveDownloadCmd.Flags().String("output", "", "本地保存路径 (文件路径或目录,必填)")
|
||||||
|
|
||||||
|
driveDownloadVersionCmd.Flags().String("node", "", "文件 ID (dentryUuid) 或 URL (必填)")
|
||||||
|
driveDownloadVersionCmd.Flags().Int("version", 0, "历史版本号 (必填,正整数,从 drive list --versions 获取)")
|
||||||
|
driveDownloadVersionCmd.Flags().String("output", "", "本地保存路径 (文件路径或目录,必填)")
|
||||||
|
for _, alias := range []string{"url", "id", "node-id", "doc-id", "file-id"} {
|
||||||
|
driveDownloadVersionCmd.Flags().String(alias, "", "")
|
||||||
|
_ = driveDownloadVersionCmd.Flags().MarkHidden(alias)
|
||||||
|
}
|
||||||
|
|
||||||
driveMkdirCmd.Flags().String("name", "", "文件夹名称,最长 50 字符 (必填)")
|
driveMkdirCmd.Flags().String("name", "", "文件夹名称,最长 50 字符 (必填)")
|
||||||
driveMkdirCmd.Flags().String("space-id", "", "目标空间 ID,不传则使用「我的文件」 (可选)")
|
driveMkdirCmd.Flags().String("space-id", "", "目标空间 ID,不传则使用「我的文件」 (可选)")
|
||||||
driveMkdirCmd.Flags().String("folder", "", "父节点 ID (dentryUuid),不传则在空间根目录下创建 (可选)")
|
driveMkdirCmd.Flags().String("folder", "", "父节点 ID (dentryUuid),不传则在空间根目录下创建 (可选)")
|
||||||
@@ -1211,17 +1301,15 @@ func newDriveCommand() *cobra.Command {
|
|||||||
if nodeID == "" && workspaceID == "" {
|
if nodeID == "" && workspaceID == "" {
|
||||||
return fmt.Errorf("--node or --workspace is required")
|
return fmt.Errorf("--node or --workspace is required")
|
||||||
}
|
}
|
||||||
|
// 不可逆高危操作:帮助文档承诺二选一,两者同传直接失败,绝不静默择一。
|
||||||
|
if nodeID != "" && workspaceID != "" {
|
||||||
|
return fmt.Errorf("--node and --workspace are mutually exclusive; specify exactly one")
|
||||||
|
}
|
||||||
if err := validateRequiredFlags(cmd, "new-owner"); err != nil {
|
if err := validateRequiredFlags(cmd, "new-owner"); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
newOwnerID := mustGetFlag(cmd, "new-owner")
|
newOwnerID := mustGetFlag(cmd, "new-owner")
|
||||||
|
|
||||||
if commandDryRun(cmd) {
|
|
||||||
deps.Out.PrintKeyValue("操作", "转交所有者")
|
|
||||||
deps.Out.PrintKeyValue("新所有者", newOwnerID)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
yesMode, _ := cmd.Flags().GetBool("yes")
|
yesMode, _ := cmd.Flags().GetBool("yes")
|
||||||
if yesMode {
|
if yesMode {
|
||||||
if !cmd.Flags().Changed("reserve-role") {
|
if !cmd.Flags().Changed("reserve-role") {
|
||||||
@@ -1232,6 +1320,26 @@ func newDriveCommand() *cobra.Command {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if commandDryRun(cmd) {
|
||||||
|
if deps.Caller.Format() == "json" {
|
||||||
|
payload := map[string]any{
|
||||||
|
"dry_run": true,
|
||||||
|
"executed": false,
|
||||||
|
"operation": "转交所有者",
|
||||||
|
"newOwnerId": newOwnerID,
|
||||||
|
}
|
||||||
|
if nodeID != "" {
|
||||||
|
payload["nodeId"] = nodeID
|
||||||
|
} else {
|
||||||
|
payload["workspaceId"] = workspaceID
|
||||||
|
}
|
||||||
|
return deps.Out.PrintJSON(payload)
|
||||||
|
}
|
||||||
|
deps.Out.PrintKeyValue("操作", "转交所有者")
|
||||||
|
deps.Out.PrintKeyValue("新所有者", newOwnerID)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
reserveRole := mustGetFlag(cmd, "reserve-role")
|
reserveRole := mustGetFlag(cmd, "reserve-role")
|
||||||
recursive, _ := cmd.Flags().GetBool("recursive")
|
recursive, _ := cmd.Flags().GetBool("recursive")
|
||||||
|
|
||||||
@@ -1309,6 +1417,9 @@ func newDriveCommand() *cobra.Command {
|
|||||||
if v := mustGetFlag(cmd, "reason"); v != "" {
|
if v := mustGetFlag(cmd, "reason"); v != "" {
|
||||||
toolArgs["reason"] = v
|
toolArgs["reason"] = v
|
||||||
}
|
}
|
||||||
|
if !commandDryRun(cmd) && !confirmDangerousAction(cmd, "发起权限申请", fmt.Sprintf("节点 %s(将真实通知审批人 %s)", nodeID, strings.Join(userIds, ","))) {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
return callMCPToolOnServer("drive", "apply_permission", toolArgs)
|
return callMCPToolOnServer("drive", "apply_permission", toolArgs)
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
@@ -1710,6 +1821,7 @@ func newDriveCommand() *cobra.Command {
|
|||||||
driveListSpacesCmd,
|
driveListSpacesCmd,
|
||||||
driveInfoCmd,
|
driveInfoCmd,
|
||||||
driveDownloadCmd,
|
driveDownloadCmd,
|
||||||
|
driveDownloadVersionCmd,
|
||||||
driveMkdirCmd,
|
driveMkdirCmd,
|
||||||
driveUploadInfoCmd,
|
driveUploadInfoCmd,
|
||||||
driveCommitCmd,
|
driveCommitCmd,
|
||||||
|
|||||||
@@ -43,6 +43,9 @@ type driveDepthFolder struct {
|
|||||||
depth int
|
depth int
|
||||||
relPath string
|
relPath string
|
||||||
retried bool // 已因 rate_limited 重新入队过一次,不二次补偿
|
retried bool // 已因 rate_limited 重新入队过一次,不二次补偿
|
||||||
|
// 限流重入队时保留失败页游标:已成功页的条目已进 collected,
|
||||||
|
// 从头重扫会产生重复条目并提前耗尽全局 2000 上限。
|
||||||
|
pageToken string
|
||||||
}
|
}
|
||||||
|
|
||||||
type driveDepthError struct {
|
type driveDepthError struct {
|
||||||
@@ -213,7 +216,7 @@ bfs:
|
|||||||
|
|
||||||
start := time.Now()
|
start := time.Now()
|
||||||
var folderErr error
|
var folderErr error
|
||||||
pageToken := ""
|
pageToken := folder.pageToken
|
||||||
pages := 0
|
pages := 0
|
||||||
for {
|
for {
|
||||||
if ctx.Err() != nil {
|
if ctx.Err() != nil {
|
||||||
@@ -294,8 +297,10 @@ bfs:
|
|||||||
return folderErr
|
return folderErr
|
||||||
}
|
}
|
||||||
if driveDepthErrorCode(folderErr) == driveDepthRateLimitedCode && !folder.retried {
|
if driveDepthErrorCode(folderErr) == driveDepthRateLimitedCode && !folder.retried {
|
||||||
// 限流命中在入口处、业务逻辑未执行,重试零副作用;不加 sleep/退避。
|
// 限流命中在入口处、失败页本身无副作用;但此前成功页已进 collected,
|
||||||
|
// 必须从失败页游标续扫而非整目录重扫。不加 sleep/退避。
|
||||||
folder.retried = true
|
folder.retried = true
|
||||||
|
folder.pageToken = pageToken
|
||||||
queue = append(queue, folder)
|
queue = append(queue, folder)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -534,6 +534,35 @@ func TestCrossPlatformCoverageRunDriveListDepthRateLimitRetry(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestCrossPlatformCoverageRunDriveListDepthRateLimitResumesFromFailedPage(t *testing.T) {
|
||||||
|
useDriveDepthArgs(t)
|
||||||
|
caller := &depthArgsRecordingCaller{steps: []scriptedToolStep{
|
||||||
|
{text: `{"items":[{"fileId":"f1","name":"page1.txt","type":"FILE"}],"nextToken":"p2"}`},
|
||||||
|
{text: `{"errorCode":"invalidRequest.rateLimited","errorMsg":"slow down"}`},
|
||||||
|
{text: `{"items":[{"fileId":"f2","name":"page2.txt","type":"FILE"}]}`},
|
||||||
|
}}
|
||||||
|
previousDeps := deps
|
||||||
|
t.Cleanup(func() { deps = previousDeps })
|
||||||
|
InitDeps(caller)
|
||||||
|
out := &bytes.Buffer{}
|
||||||
|
deps.Out.w = out
|
||||||
|
deps.Out.errW = io.Discard
|
||||||
|
cmd := &cobra.Command{Use: "list"}
|
||||||
|
if err := runDriveListDepth(cmd, newDrivePanDepthRoute(), map[string]any{}, "", 3, "", true); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if len(caller.calls) != 3 {
|
||||||
|
t.Fatalf("calls = %d, want 3", len(caller.calls))
|
||||||
|
}
|
||||||
|
if tok, _ := caller.calls[2]["nextToken"].(string); tok != "p2" {
|
||||||
|
t.Fatalf("retry call args = %#v, want resume with nextToken=p2", caller.calls[2])
|
||||||
|
}
|
||||||
|
items := decodeDepthResult(t, out)["items"].([]any)
|
||||||
|
if len(items) != 2 {
|
||||||
|
t.Fatalf("items = %#v, want 2 without duplicates", items)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestCrossPlatformCoverageRunDriveListDepthRateLimitExhausted(t *testing.T) {
|
func TestCrossPlatformCoverageRunDriveListDepthRateLimitExhausted(t *testing.T) {
|
||||||
useDriveDepthArgs(t)
|
useDriveDepthArgs(t)
|
||||||
caller := &scriptedToolCaller{steps: []scriptedToolStep{
|
caller := &scriptedToolCaller{steps: []scriptedToolStep{
|
||||||
|
|||||||
@@ -213,3 +213,15 @@ func TestCrossPlatformCoverageDriveRevertDeclined(t *testing.T) {
|
|||||||
t.Fatalf("declined revert calls = %#v", caller.calls)
|
t.Fatalf("declined revert calls = %#v", caller.calls)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestCrossPlatformCoverageDriveTransferOwnerRejectsBothTargets(t *testing.T) {
|
||||||
|
caller := &guardedMutationCaller{}
|
||||||
|
err := executeGuardedMutationCommand(t, caller, newDriveCommand,
|
||||||
|
"permission", "transfer-owner", "--node", "node-1", "--workspace", "ws-1", "--new-owner", "user-1")
|
||||||
|
if err == nil || !strings.Contains(err.Error(), "mutually exclusive") {
|
||||||
|
t.Fatalf("err = %v, want mutual exclusion", err)
|
||||||
|
}
|
||||||
|
if len(caller.calls) != 0 {
|
||||||
|
t.Fatalf("calls = %#v, want none", caller.calls)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,263 @@
|
|||||||
|
// Copyright 2026 Alibaba Group
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
|
||||||
|
package helpers
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"context"
|
||||||
|
"encoding/json"
|
||||||
|
"io"
|
||||||
|
"reflect"
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/DingTalk-Real-AI/dingtalk-workspace-cli/pkg/edition"
|
||||||
|
"github.com/spf13/cobra"
|
||||||
|
)
|
||||||
|
|
||||||
|
// executeDriveCommandCapture 执行 drive 命令并捕获 deps.Out 的 stdout 输出,
|
||||||
|
// 供需要断言 JSON 输出形态的测试使用(等价于 installDepthCaller + Execute)。
|
||||||
|
func executeDriveCommandCapture(t *testing.T, caller edition.ToolCaller, args ...string) (*bytes.Buffer, error) {
|
||||||
|
t.Helper()
|
||||||
|
previousDeps := deps
|
||||||
|
t.Cleanup(func() { deps = previousDeps })
|
||||||
|
InitDeps(caller)
|
||||||
|
buf := &bytes.Buffer{}
|
||||||
|
deps.Out.w = buf
|
||||||
|
deps.Out.errW = io.Discard
|
||||||
|
root := newDriveCommand()
|
||||||
|
if root.PersistentFlags().Lookup("yes") == nil {
|
||||||
|
root.PersistentFlags().Bool("yes", false, "confirm high-risk operation")
|
||||||
|
}
|
||||||
|
if root.PersistentFlags().Lookup("dry-run") == nil {
|
||||||
|
root.PersistentFlags().Bool("dry-run", false, "preview without executing")
|
||||||
|
}
|
||||||
|
root.SilenceErrors = true
|
||||||
|
root.SilenceUsage = true
|
||||||
|
root.SetArgs(args)
|
||||||
|
err := root.Execute()
|
||||||
|
return buf, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// ── drive permission apply:确认门禁与帮助文案契约一致 ──
|
||||||
|
|
||||||
|
func TestCrossPlatformCoverageDrivePermissionApplyDeclined(t *testing.T) {
|
||||||
|
caller := &guardedMutationCaller{}
|
||||||
|
root := newDriveCommand()
|
||||||
|
root.SetIn(strings.NewReader("no\n"))
|
||||||
|
err := executeGuardedMutationCommand(t, caller, func() *cobra.Command { return root },
|
||||||
|
"permission", "apply", "--node", "node-1", "--role", "READER", "--users", "u1")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if len(caller.calls) != 0 {
|
||||||
|
t.Fatalf("declined apply calls = %#v, want none", caller.calls)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestCrossPlatformCoverageDrivePermissionApplyYesProceeds(t *testing.T) {
|
||||||
|
caller := &guardedMutationCaller{}
|
||||||
|
err := executeGuardedMutationCommand(t, caller, newDriveCommand,
|
||||||
|
"permission", "apply", "--node", "node-1", "--role", "reader", "--users", "u1,u2", "--yes")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if len(caller.calls) != 1 {
|
||||||
|
t.Fatalf("calls = %#v, want exactly one", caller.calls)
|
||||||
|
}
|
||||||
|
call := caller.calls[0]
|
||||||
|
if call.productID != "drive" || call.toolName != "apply_permission" {
|
||||||
|
t.Fatalf("call = %#v", call)
|
||||||
|
}
|
||||||
|
if call.args["nodeId"] != "node-1" || call.args["roleId"] != "READER" {
|
||||||
|
t.Fatalf("args = %#v", call.args)
|
||||||
|
}
|
||||||
|
if !reflect.DeepEqual(call.args["receivers"], []string{"u1", "u2"}) {
|
||||||
|
t.Fatalf("receivers = %#v", call.args["receivers"])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestCrossPlatformCoverageDrivePermissionApplyDryRunNoPromptNoCall(t *testing.T) {
|
||||||
|
caller := &guardedMutationCaller{dryRun: true}
|
||||||
|
root := newDriveCommand()
|
||||||
|
promptOut := &bytes.Buffer{}
|
||||||
|
root.SetErr(promptOut)
|
||||||
|
root.SetIn(strings.NewReader("no\n"))
|
||||||
|
err := executeGuardedMutationCommand(t, caller, func() *cobra.Command { return root },
|
||||||
|
"permission", "apply", "--node", "node-1", "--role", "READER", "--users", "u1", "--dry-run")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if len(caller.calls) != 0 {
|
||||||
|
t.Fatalf("dry-run apply calls = %#v, want none", caller.calls)
|
||||||
|
}
|
||||||
|
if strings.Contains(promptOut.String(), "Confirm action") {
|
||||||
|
t.Fatalf("dry-run prompted for confirmation: %q", promptOut.String())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ── drive permission transfer-owner:dry-run JSON 输出且校验先于 dry-run ──
|
||||||
|
|
||||||
|
func TestCrossPlatformCoverageDriveTransferOwnerDryRunJSONNode(t *testing.T) {
|
||||||
|
caller := &scriptedToolCaller{format: "json", dry: true}
|
||||||
|
out, err := executeDriveCommandCapture(t, caller,
|
||||||
|
"permission", "transfer-owner", "--node", "node-1", "--new-owner", "user-1", "--dry-run")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if caller.calls != 0 {
|
||||||
|
t.Fatalf("dry-run tool calls = %d, want none", caller.calls)
|
||||||
|
}
|
||||||
|
var payload map[string]any
|
||||||
|
if err := json.Unmarshal(out.Bytes(), &payload); err != nil {
|
||||||
|
t.Fatalf("dry-run output is not JSON: %v\n%s", err, out.String())
|
||||||
|
}
|
||||||
|
if payload["dry_run"] != true || payload["executed"] != false {
|
||||||
|
t.Fatalf("payload = %#v", payload)
|
||||||
|
}
|
||||||
|
if payload["operation"] != "转交所有者" || payload["newOwnerId"] != "user-1" || payload["nodeId"] != "node-1" {
|
||||||
|
t.Fatalf("payload = %#v", payload)
|
||||||
|
}
|
||||||
|
if _, ok := payload["workspaceId"]; ok {
|
||||||
|
t.Fatalf("unexpected workspaceId in %#v", payload)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestCrossPlatformCoverageDriveTransferOwnerDryRunJSONWorkspace(t *testing.T) {
|
||||||
|
caller := &scriptedToolCaller{format: "json", dry: true}
|
||||||
|
out, err := executeDriveCommandCapture(t, caller,
|
||||||
|
"permission", "transfer-owner", "--workspace", "ws-1", "--new-owner", "user-1", "--dry-run")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
var payload map[string]any
|
||||||
|
if err := json.Unmarshal(out.Bytes(), &payload); err != nil {
|
||||||
|
t.Fatalf("dry-run output is not JSON: %v\n%s", err, out.String())
|
||||||
|
}
|
||||||
|
if payload["workspaceId"] != "ws-1" || payload["newOwnerId"] != "user-1" {
|
||||||
|
t.Fatalf("payload = %#v", payload)
|
||||||
|
}
|
||||||
|
if _, ok := payload["nodeId"]; ok {
|
||||||
|
t.Fatalf("unexpected nodeId in %#v", payload)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestCrossPlatformCoverageDriveTransferOwnerDryRunYesValidatesFirst(t *testing.T) {
|
||||||
|
caller := &guardedMutationCaller{dryRun: true}
|
||||||
|
err := executeGuardedMutationCommand(t, caller, newDriveCommand,
|
||||||
|
"permission", "transfer-owner", "--node", "node-1", "--new-owner", "user-1", "--yes", "--dry-run")
|
||||||
|
if err == nil || !strings.Contains(err.Error(), "--reserve-role is required") {
|
||||||
|
t.Fatalf("err = %v, want --reserve-role required even under --dry-run", err)
|
||||||
|
}
|
||||||
|
if len(caller.calls) != 0 {
|
||||||
|
t.Fatalf("calls = %#v, want none", caller.calls)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestCrossPlatformCoverageDriveTransferOwnerDryRunNonJSON(t *testing.T) {
|
||||||
|
caller := &scriptedToolCaller{format: "table", dry: true}
|
||||||
|
_, err := executeDriveCommandCapture(t, caller,
|
||||||
|
"permission", "transfer-owner", "--node", "node-1", "--new-owner", "user-1", "--dry-run")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if caller.calls != 0 {
|
||||||
|
t.Fatalf("dry-run tool calls = %d, want none", caller.calls)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ── drive list:--versions 与 --depth/--pattern 的交互 ──
|
||||||
|
|
||||||
|
func TestCrossPlatformCoverageDriveListVersionsRejectsDepth(t *testing.T) {
|
||||||
|
caller := &guardedMutationCaller{}
|
||||||
|
err := executeGuardedMutationCommand(t, caller, newDriveCommand,
|
||||||
|
"list", "--versions", "--node", "node-1", "--depth", "2", "--limit", "10")
|
||||||
|
if err == nil || !strings.Contains(err.Error(), "--depth") {
|
||||||
|
t.Fatalf("err = %v, want explicit --versions/--depth conflict", err)
|
||||||
|
}
|
||||||
|
if len(caller.calls) != 0 {
|
||||||
|
t.Fatalf("calls = %#v, want none", caller.calls)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestCrossPlatformCoverageDriveListVersionsRejectsPattern(t *testing.T) {
|
||||||
|
caller := &guardedMutationCaller{}
|
||||||
|
err := executeGuardedMutationCommand(t, caller, newDriveCommand,
|
||||||
|
"list", "--versions", "--node", "node-1", "--pattern", "x")
|
||||||
|
if err == nil || !strings.Contains(err.Error(), "--pattern") {
|
||||||
|
t.Fatalf("err = %v, want explicit --versions/--pattern conflict", err)
|
||||||
|
}
|
||||||
|
if len(caller.calls) != 0 {
|
||||||
|
t.Fatalf("calls = %#v, want none", caller.calls)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestCrossPlatformCoverageDriveListVersionsAllowsDepthOne(t *testing.T) {
|
||||||
|
caller := &guardedMutationCaller{}
|
||||||
|
err := executeGuardedMutationCommand(t, caller, newDriveCommand,
|
||||||
|
"list", "--versions", "--node", "node-1", "--depth", "1")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if len(caller.calls) != 1 || caller.calls[0].toolName != "list_file_versions" {
|
||||||
|
t.Fatalf("calls = %#v", caller.calls)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestCrossPlatformCoverageDriveListVersionsWithLimit(t *testing.T) {
|
||||||
|
caller := &guardedMutationCaller{}
|
||||||
|
err := executeGuardedMutationCommand(t, caller, newDriveCommand,
|
||||||
|
"list", "--versions", "--node", "node-1", "--limit", "10")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if len(caller.calls) != 1 {
|
||||||
|
t.Fatalf("calls = %#v, want exactly one", caller.calls)
|
||||||
|
}
|
||||||
|
call := caller.calls[0]
|
||||||
|
if call.productID != "drive" || call.toolName != "list_file_versions" {
|
||||||
|
t.Fatalf("call = %#v", call)
|
||||||
|
}
|
||||||
|
if call.args["nodeId"] != "node-1" || call.args["maxResults"] != 10 {
|
||||||
|
t.Fatalf("args = %#v", call.args)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestCrossPlatformCoverageDriveDownloadVersionDryRun(t *testing.T) {
|
||||||
|
caller := &guardedMutationCaller{dryRun: true}
|
||||||
|
err := executeGuardedMutationCommand(t, caller, newDriveCommand,
|
||||||
|
"download-version", "--node", "node-1", "--version", "3", "--output", "./x.pdf", "--dry-run")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if len(caller.calls) != 0 {
|
||||||
|
t.Fatalf("dry-run calls = %#v, want none", caller.calls)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestCrossPlatformCoverageDriveDownloadVersionDirectoryOutput(t *testing.T) {
|
||||||
|
SetHTTPGetFile(func(context.Context, string, map[string]string, string) error { return nil })
|
||||||
|
t.Cleanup(func() { SetHTTPGetFile(nil) })
|
||||||
|
|
||||||
|
dir := t.TempDir()
|
||||||
|
for _, resp := range []string{
|
||||||
|
`{"downloadUrl":"https://oss.test/get/report_v3.pdf","fileName":"报告v3.pdf"}`,
|
||||||
|
`{"downloadUrl":"https://oss.test/get/inferred_v3.pdf"}`,
|
||||||
|
} {
|
||||||
|
caller := &scriptedToolCaller{steps: []scriptedToolStep{{text: resp}}}
|
||||||
|
installScriptedCaller(t, caller)
|
||||||
|
root := newDriveCommand()
|
||||||
|
root.PersistentFlags().Bool("dry-run", false, "")
|
||||||
|
root.SilenceErrors = true
|
||||||
|
root.SilenceUsage = true
|
||||||
|
root.SetArgs([]string{"download-version", "--node", "node-1", "--version", "3", "--output", dir})
|
||||||
|
if err := root.Execute(); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if caller.calls != 1 {
|
||||||
|
t.Fatalf("calls = %d, want 1", caller.calls)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,168 @@
|
|||||||
|
package helpers
|
||||||
|
|
||||||
|
import (
|
||||||
|
"reflect"
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestCrossPlatformCoverageDriveStarCommands(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
args []string
|
||||||
|
want guardedMutationCall
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "add",
|
||||||
|
args: []string{"star", "add", "--node", "node-1"},
|
||||||
|
want: guardedMutationCall{
|
||||||
|
productID: "drive",
|
||||||
|
toolName: "mark_star",
|
||||||
|
args: map[string]any{"nodeId": "node-1"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "add with url value passed through",
|
||||||
|
args: []string{"star", "add", "--node", "https://alidocs.dingtalk.com/i/nodes/node-2"},
|
||||||
|
want: guardedMutationCall{
|
||||||
|
productID: "drive",
|
||||||
|
toolName: "mark_star",
|
||||||
|
args: map[string]any{"nodeId": "https://alidocs.dingtalk.com/i/nodes/node-2"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "remove",
|
||||||
|
args: []string{"star", "remove", "--node", "node-3"},
|
||||||
|
want: guardedMutationCall{
|
||||||
|
productID: "drive",
|
||||||
|
toolName: "unmark_star",
|
||||||
|
args: map[string]any{"nodeId": "node-3"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "remove rm alias",
|
||||||
|
args: []string{"star", "rm", "--node", "node-4"},
|
||||||
|
want: guardedMutationCall{
|
||||||
|
productID: "drive",
|
||||||
|
toolName: "unmark_star",
|
||||||
|
args: map[string]any{"nodeId": "node-4"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "list without filters",
|
||||||
|
args: []string{"star", "list"},
|
||||||
|
want: guardedMutationCall{
|
||||||
|
productID: "drive",
|
||||||
|
toolName: "get_star_list",
|
||||||
|
args: map[string]any{},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "list with all filters",
|
||||||
|
args: []string{
|
||||||
|
"star", "list",
|
||||||
|
"--limit", "10",
|
||||||
|
"--cursor", "cur-1",
|
||||||
|
"--order-by", "createTime",
|
||||||
|
"--sort", "desc",
|
||||||
|
"--resource-types", "DENTRY,WORKSPACE",
|
||||||
|
"--content-types", "doc,sheet",
|
||||||
|
},
|
||||||
|
want: guardedMutationCall{
|
||||||
|
productID: "drive",
|
||||||
|
toolName: "get_star_list",
|
||||||
|
args: map[string]any{
|
||||||
|
"limit": 10,
|
||||||
|
"cursor": "cur-1",
|
||||||
|
"orderBy": "createTime",
|
||||||
|
"sortType": "desc",
|
||||||
|
"supportResourceTypes": []string{"DENTRY", "WORKSPACE"},
|
||||||
|
"contentTypes": []string{"doc", "sheet"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, test := range tests {
|
||||||
|
test := test
|
||||||
|
t.Run(test.name, func(t *testing.T) {
|
||||||
|
caller := &guardedMutationCaller{}
|
||||||
|
err := executeGuardedMutationCommand(t, caller, newDriveCommand, test.args...)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("drive %s returned error: %v", strings.Join(test.args, " "), err)
|
||||||
|
}
|
||||||
|
if len(caller.calls) != 1 || !reflect.DeepEqual(caller.calls[0], test.want) {
|
||||||
|
t.Fatalf("tool calls = %#v, want %#v", caller.calls, test.want)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestCrossPlatformCoverageDriveStarRequiredFlags(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
args []string
|
||||||
|
wantErr string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "add without node",
|
||||||
|
args: []string{"star", "add"},
|
||||||
|
wantErr: "--node",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "remove without node",
|
||||||
|
args: []string{"star", "remove"},
|
||||||
|
wantErr: "--node",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, test := range tests {
|
||||||
|
test := test
|
||||||
|
t.Run(test.name, func(t *testing.T) {
|
||||||
|
caller := &guardedMutationCaller{}
|
||||||
|
err := executeGuardedMutationCommand(t, caller, newDriveCommand, test.args...)
|
||||||
|
if err == nil || !strings.Contains(err.Error(), test.wantErr) {
|
||||||
|
t.Fatalf("err = %v, want message containing %q", err, test.wantErr)
|
||||||
|
}
|
||||||
|
if len(caller.calls) != 0 {
|
||||||
|
t.Fatalf("tool calls = %#v, want none", caller.calls)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestCrossPlatformCoverageDriveStarListRecordsRawArgs(t *testing.T) {
|
||||||
|
caller := &depthArgsRecordingCaller{steps: []scriptedToolStep{
|
||||||
|
{text: `{"items":[{"nodeId":"n1","name":"doc1"}],"hasMore":false}`},
|
||||||
|
}}
|
||||||
|
err := executeDriveCommand(t, caller,
|
||||||
|
"star", "list", "--limit", "5", "--cursor", "cur-9", "--sort", "asc")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if len(caller.calls) != 1 {
|
||||||
|
t.Fatalf("calls = %#v, want 1", caller.calls)
|
||||||
|
}
|
||||||
|
args := caller.calls[0]
|
||||||
|
if args["limit"] != 5 || args["cursor"] != "cur-9" || args["sortType"] != "asc" {
|
||||||
|
t.Fatalf("star list raw args = %#v", args)
|
||||||
|
}
|
||||||
|
if _, ok := args["orderBy"]; ok {
|
||||||
|
t.Fatalf("unexpected orderBy in %#v", args)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestCrossPlatformCoverageDriveStarAddScriptedSuccess(t *testing.T) {
|
||||||
|
caller := &scriptedToolCaller{format: "json", steps: []scriptedToolStep{
|
||||||
|
{text: `{"success":true}`},
|
||||||
|
}}
|
||||||
|
installScriptedCaller(t, caller)
|
||||||
|
root := newDriveCommand()
|
||||||
|
root.SilenceErrors = true
|
||||||
|
root.SilenceUsage = true
|
||||||
|
root.SetArgs([]string{"star", "add", "--node", "node-1"})
|
||||||
|
if err := root.Execute(); err != nil {
|
||||||
|
t.Fatalf("star add returned error: %v", err)
|
||||||
|
}
|
||||||
|
if caller.calls != 1 {
|
||||||
|
t.Fatalf("tool calls = %d, want 1", caller.calls)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
package helpers
|
package helpers
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
@@ -48,7 +49,8 @@ func newSheetFormulaVerifyCmd() *cobra.Command {
|
|||||||
}
|
}
|
||||||
toolArgs["maxCells"] = v
|
toolArgs["maxCells"] = v
|
||||||
}
|
}
|
||||||
return callMCPToolOnServer("sheet", "formula_verify", toolArgs)
|
exitOnError, _ := cmd.Flags().GetBool("exit-on-error")
|
||||||
|
return callMCPToolFormulaVerify(toolArgs, exitOnError)
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
cmd.Flags().String("node", "", "表格文档 ID 或 URL (必填)")
|
cmd.Flags().String("node", "", "表格文档 ID 或 URL (必填)")
|
||||||
@@ -57,15 +59,66 @@ func newSheetFormulaVerifyCmd() *cobra.Command {
|
|||||||
cmd.Flags().String("targets", "", `扫描目标 JSON 数组、@文件路径 或 - 表示 stdin;每项 {"sheetId":"Sheet1","range":"A1:D100"}`)
|
cmd.Flags().String("targets", "", `扫描目标 JSON 数组、@文件路径 或 - 表示 stdin;每项 {"sheetId":"Sheet1","range":"A1:D100"}`)
|
||||||
cmd.Flags().Int("max-locations-per-error", 0, "每种错误类型最多返回的位置数")
|
cmd.Flags().Int("max-locations-per-error", 0, "每种错误类型最多返回的位置数")
|
||||||
cmd.Flags().Int("max-cells", 0, "最多扫描的单元格数")
|
cmd.Flags().Int("max-cells", 0, "最多扫描的单元格数")
|
||||||
|
cmd.Flags().Bool("exit-on-error", false, "发现公式错误时返回非 0 退出码,便于 CI/自动化使用")
|
||||||
return cmd
|
return cmd
|
||||||
}
|
}
|
||||||
|
|
||||||
func formulaVerifyTargetsFromFlags(cmd *cobra.Command) ([]map[string]any, error) {
|
// callMCPToolFormulaVerify 与常规打印路径的差异:--exit-on-error 需要读取
|
||||||
if v, _ := cmd.Flags().GetString("targets"); v != "" {
|
// 返回 payload 判定是否存在公式错误,故走 ReturnText 再自行 PrintJSON。
|
||||||
return parseFormulaVerifyTargets(cmd, v)
|
func callMCPToolFormulaVerify(toolArgs map[string]any, exitOnError bool) error {
|
||||||
|
if deps.Caller.DryRun() {
|
||||||
|
return callMCPToolOnServer("sheet", "formula_verify", toolArgs)
|
||||||
}
|
}
|
||||||
|
text, err := callMCPToolReturnTextOnServer(context.Background(), "sheet", "formula_verify", toolArgs)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if text == "" {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
var parsed map[string]any
|
||||||
|
if err := json.Unmarshal([]byte(text), &parsed); err != nil {
|
||||||
|
deps.Out.PrintRaw(text)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
if parsed == nil {
|
||||||
|
return fmt.Errorf("formula_verify returned empty result")
|
||||||
|
}
|
||||||
|
if err := deps.Out.PrintJSON(parsed); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if exitOnError && formulaVerifyHasErrors(parsed) {
|
||||||
|
return fmt.Errorf("formula errors found")
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func formulaVerifyHasErrors(parsed map[string]any) bool {
|
||||||
|
result := formulaVerifyResultObject(parsed)
|
||||||
|
status := strings.ToLower(strings.TrimSpace(fmt.Sprint(result["status"])))
|
||||||
|
if status == "errors_found" {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
totalErrors, ok := nonNegativeJSONInt(result["totalErrors"])
|
||||||
|
return ok && totalErrors > 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func formulaVerifyResultObject(parsed map[string]any) map[string]any {
|
||||||
|
if result, ok := parsed["result"].(map[string]any); ok {
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
return parsed
|
||||||
|
}
|
||||||
|
|
||||||
|
func formulaVerifyTargetsFromFlags(cmd *cobra.Command) ([]map[string]any, error) {
|
||||||
sheetID, _ := cmd.Flags().GetString("sheet-id")
|
sheetID, _ := cmd.Flags().GetString("sheet-id")
|
||||||
rangeStr, _ := cmd.Flags().GetString("range")
|
rangeStr, _ := cmd.Flags().GetString("range")
|
||||||
|
if v, _ := cmd.Flags().GetString("targets"); v != "" {
|
||||||
|
if strings.TrimSpace(sheetID) != "" || strings.TrimSpace(rangeStr) != "" {
|
||||||
|
return nil, fmt.Errorf("--targets 不能与 --sheet-id 或 --range 同时使用")
|
||||||
|
}
|
||||||
|
return parseFormulaVerifyTargets(cmd, v)
|
||||||
|
}
|
||||||
if sheetID == "" && rangeStr != "" {
|
if sheetID == "" && rangeStr != "" {
|
||||||
return nil, fmt.Errorf("--range 必须与 --sheet-id 配合使用")
|
return nil, fmt.Errorf("--range 必须与 --sheet-id 配合使用")
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -89,3 +89,87 @@ func TestCrossPlatformCoverageSheetFormulaVerifyTargetsStdinFailure(t *testing.T
|
|||||||
t.Fatalf("err = %v, want stdin failure", err)
|
t.Fatalf("err = %v, want stdin failure", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestCrossPlatformCoverageSheetFormulaVerifyTargetsConflict(t *testing.T) {
|
||||||
|
for _, extra := range [][]string{
|
||||||
|
{"--sheet-id", "Sheet1"},
|
||||||
|
{"--range", "A1:B2"},
|
||||||
|
} {
|
||||||
|
args := append([]string{"--node", "n1", "--targets", `[{"sheetId":"S1"}]`}, extra...)
|
||||||
|
err := executeFormulaVerify(t, &scriptedToolCaller{}, nil, args...)
|
||||||
|
if err == nil || !strings.Contains(err.Error(), "--targets 不能与 --sheet-id 或 --range 同时使用") {
|
||||||
|
t.Fatalf("args %v err = %v, want conflict error", extra, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestCrossPlatformCoverageSheetFormulaVerifyExitOnError(t *testing.T) {
|
||||||
|
caller := &scriptedToolCaller{steps: []scriptedToolStep{
|
||||||
|
{text: `{"status":"ERRORS_FOUND","totalErrors":2}`},
|
||||||
|
}}
|
||||||
|
err := executeFormulaVerify(t, caller, nil, "--node", "n1", "--exit-on-error")
|
||||||
|
if err == nil || !strings.Contains(err.Error(), "formula errors found") {
|
||||||
|
t.Fatalf("err = %v, want formula errors found", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
caller = &scriptedToolCaller{steps: []scriptedToolStep{
|
||||||
|
{text: `{"result":{"status":"partial","totalErrors":1}}`},
|
||||||
|
}}
|
||||||
|
err = executeFormulaVerify(t, caller, nil, "--node", "n1", "--exit-on-error")
|
||||||
|
if err == nil || !strings.Contains(err.Error(), "formula errors found") {
|
||||||
|
t.Fatalf("nested totalErrors err = %v, want formula errors found", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
caller = &scriptedToolCaller{steps: []scriptedToolStep{
|
||||||
|
{text: `{"status":"clean","totalErrors":0}`},
|
||||||
|
}}
|
||||||
|
if err := executeFormulaVerify(t, caller, nil, "--node", "n1", "--exit-on-error"); err != nil {
|
||||||
|
t.Fatalf("clean result err = %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
caller = &scriptedToolCaller{steps: []scriptedToolStep{
|
||||||
|
{text: `{"status":"errors_found"}`},
|
||||||
|
}}
|
||||||
|
if err := executeFormulaVerify(t, caller, nil, "--node", "n1"); err != nil {
|
||||||
|
t.Fatalf("errors without --exit-on-error err = %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestCrossPlatformCoverageSheetFormulaVerifyPayloadEdges(t *testing.T) {
|
||||||
|
caller := &scriptedToolCaller{steps: []scriptedToolStep{{text: `plain text result`}}}
|
||||||
|
if err := executeFormulaVerify(t, caller, nil, "--node", "n1", "--exit-on-error"); err != nil {
|
||||||
|
t.Fatalf("non-JSON payload err = %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
caller = &scriptedToolCaller{steps: []scriptedToolStep{{text: `null`}}}
|
||||||
|
err := executeFormulaVerify(t, caller, nil, "--node", "n1")
|
||||||
|
if err == nil || !strings.Contains(err.Error(), "empty result") {
|
||||||
|
t.Fatalf("null payload err = %v, want empty result", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
caller = &scriptedToolCaller{steps: []scriptedToolStep{{text: `{"errorCode":"forbidden.x","errorMsg":"denied"}`}}}
|
||||||
|
if err := executeFormulaVerify(t, caller, nil, "--node", "n1"); err == nil {
|
||||||
|
t.Fatal("business error returned nil")
|
||||||
|
}
|
||||||
|
|
||||||
|
caller = &scriptedToolCaller{steps: []scriptedToolStep{{text: `{"status":"clean"}`}}}
|
||||||
|
installScriptedCaller(t, caller)
|
||||||
|
deps.Out.w = failingWriter{}
|
||||||
|
cmd := newSheetFormulaVerifyCmd()
|
||||||
|
cmd.SilenceErrors = true
|
||||||
|
cmd.SilenceUsage = true
|
||||||
|
cmd.SetArgs([]string{"--node", "n1"})
|
||||||
|
if err := cmd.Execute(); err == nil || !strings.Contains(err.Error(), "write failed") {
|
||||||
|
t.Fatalf("print failure err = %v, want write failed", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestCrossPlatformCoverageSheetFormulaVerifyDryRunShortCircuit(t *testing.T) {
|
||||||
|
caller := &scriptedToolCaller{dry: true}
|
||||||
|
if err := executeFormulaVerify(t, caller, nil, "--node", "n1", "--exit-on-error"); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if caller.calls != 0 {
|
||||||
|
t.Fatalf("dry-run calls = %d, want 0 (preview only)", caller.calls)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,40 @@
|
|||||||
|
package helpers
|
||||||
|
|
||||||
|
import (
|
||||||
|
"io"
|
||||||
|
"os"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestCrossPlatformCoverageSheetInfoIncludePassthrough(t *testing.T) {
|
||||||
|
oldArgs := os.Args
|
||||||
|
os.Args = []string{"dws", "sheet"}
|
||||||
|
t.Cleanup(func() { os.Args = oldArgs })
|
||||||
|
|
||||||
|
caller := &depthArgsRecordingCaller{steps: []scriptedToolStep{
|
||||||
|
{text: `{"sheetId":"s1"}`},
|
||||||
|
}}
|
||||||
|
previousDeps := deps
|
||||||
|
t.Cleanup(func() { deps = previousDeps })
|
||||||
|
InitDeps(caller)
|
||||||
|
deps.Out.w = io.Discard
|
||||||
|
deps.Out.errW = io.Discard
|
||||||
|
|
||||||
|
root := newSheetCommand()
|
||||||
|
if root.PersistentFlags().Lookup("dry-run") == nil {
|
||||||
|
root.PersistentFlags().Bool("dry-run", false, "")
|
||||||
|
}
|
||||||
|
root.SilenceErrors = true
|
||||||
|
root.SilenceUsage = true
|
||||||
|
root.SetArgs([]string{"info", "--node", "n1", "--sheet-id", "Sheet1", "--include", "row_heights,col_widths"})
|
||||||
|
if err := root.Execute(); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if len(caller.calls) != 1 {
|
||||||
|
t.Fatalf("calls = %#v", caller.calls)
|
||||||
|
}
|
||||||
|
include, _ := caller.calls[0]["include"].([]string)
|
||||||
|
if len(include) != 2 || include[0] != "row_heights" || include[1] != "col_widths" {
|
||||||
|
t.Fatalf("include = %#v", caller.calls[0]["include"])
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,298 @@
|
|||||||
|
package helpers
|
||||||
|
|
||||||
|
import (
|
||||||
|
"reflect"
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestCrossPlatformCoverageSheetCommentCommands(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
args []string
|
||||||
|
want guardedMutationCall
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "list minimal",
|
||||||
|
args: []string{"comment", "list", "--node", "node-1"},
|
||||||
|
want: guardedMutationCall{
|
||||||
|
productID: "doc-comment",
|
||||||
|
toolName: "list_sheet_comments",
|
||||||
|
args: map[string]any{"nodeId": "node-1"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "list with cell and status filters",
|
||||||
|
args: []string{
|
||||||
|
"comment", "list",
|
||||||
|
"--node", "node-1",
|
||||||
|
"--sheet-id", "Sheet1",
|
||||||
|
"--range", "A2",
|
||||||
|
"--resolve-status", "unresolved",
|
||||||
|
"--limit", "10",
|
||||||
|
"--cursor", "cur-1",
|
||||||
|
},
|
||||||
|
want: guardedMutationCall{
|
||||||
|
productID: "doc-comment",
|
||||||
|
toolName: "list_sheet_comments",
|
||||||
|
args: map[string]any{
|
||||||
|
"nodeId": "node-1",
|
||||||
|
"sheetId": "Sheet1",
|
||||||
|
"range": "A2",
|
||||||
|
"resolveStatus": "unresolved",
|
||||||
|
"pageSize": 10,
|
||||||
|
"nextToken": "cur-1",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "create with mention parsing",
|
||||||
|
args: []string{
|
||||||
|
"comment", "create",
|
||||||
|
"--node", "node-1",
|
||||||
|
"--sheet-id", "Sheet1",
|
||||||
|
"--range", "A2",
|
||||||
|
"--content", "check this",
|
||||||
|
"--mention", "uid1, uid2 ,,uid3",
|
||||||
|
},
|
||||||
|
want: guardedMutationCall{
|
||||||
|
productID: "doc-comment",
|
||||||
|
toolName: "create_sheet_comment",
|
||||||
|
args: map[string]any{
|
||||||
|
"nodeId": "node-1",
|
||||||
|
"content": "check this",
|
||||||
|
"sheetId": "Sheet1",
|
||||||
|
"range": "A2",
|
||||||
|
"mentionedUserIds": []string{"uid1", "uid2", "uid3"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "create without mention",
|
||||||
|
args: []string{
|
||||||
|
"comment", "create",
|
||||||
|
"--node", "node-1",
|
||||||
|
"--sheet-id", "Sheet1",
|
||||||
|
"--range", "B3",
|
||||||
|
"--content", "plain",
|
||||||
|
},
|
||||||
|
want: guardedMutationCall{
|
||||||
|
productID: "doc-comment",
|
||||||
|
toolName: "create_sheet_comment",
|
||||||
|
args: map[string]any{
|
||||||
|
"nodeId": "node-1",
|
||||||
|
"content": "plain",
|
||||||
|
"sheetId": "Sheet1",
|
||||||
|
"range": "B3",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "reply with emoji and mention",
|
||||||
|
args: []string{
|
||||||
|
"comment", "reply",
|
||||||
|
"--node", "node-1",
|
||||||
|
"--comment-key", "ck-1",
|
||||||
|
"--content", "heart",
|
||||||
|
"--emoji",
|
||||||
|
"--mention", "uid1",
|
||||||
|
},
|
||||||
|
want: guardedMutationCall{
|
||||||
|
productID: "doc-comment",
|
||||||
|
toolName: "reply_comment",
|
||||||
|
args: map[string]any{
|
||||||
|
"nodeId": "node-1",
|
||||||
|
"content": "heart",
|
||||||
|
"replyCommentKey": "ck-1",
|
||||||
|
"emoji": true,
|
||||||
|
"mentionedUserIds": []string{"uid1"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "reply plain text",
|
||||||
|
args: []string{
|
||||||
|
"comment", "reply",
|
||||||
|
"--node", "node-1",
|
||||||
|
"--comment-key", "ck-2",
|
||||||
|
"--content", "confirmed",
|
||||||
|
},
|
||||||
|
want: guardedMutationCall{
|
||||||
|
productID: "doc-comment",
|
||||||
|
toolName: "reply_comment",
|
||||||
|
args: map[string]any{
|
||||||
|
"nodeId": "node-1",
|
||||||
|
"content": "confirmed",
|
||||||
|
"replyCommentKey": "ck-2",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "update",
|
||||||
|
args: []string{
|
||||||
|
"comment", "update",
|
||||||
|
"--node", "node-1",
|
||||||
|
"--comment-key", "ck-3",
|
||||||
|
"--content", "revised",
|
||||||
|
},
|
||||||
|
want: guardedMutationCall{
|
||||||
|
productID: "doc-comment",
|
||||||
|
toolName: "update_comment",
|
||||||
|
args: map[string]any{
|
||||||
|
"nodeId": "node-1",
|
||||||
|
"commentKey": "ck-3",
|
||||||
|
"content": "revised",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, test := range tests {
|
||||||
|
test := test
|
||||||
|
t.Run(test.name, func(t *testing.T) {
|
||||||
|
caller := &guardedMutationCaller{}
|
||||||
|
err := executeGuardedMutationCommand(t, caller, newSheetCommand, test.args...)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("sheet %s returned error: %v", strings.Join(test.args, " "), err)
|
||||||
|
}
|
||||||
|
if len(caller.calls) != 1 || !reflect.DeepEqual(caller.calls[0], test.want) {
|
||||||
|
t.Fatalf("tool calls = %#v, want %#v", caller.calls, test.want)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestCrossPlatformCoverageSheetCommentRequiredFlags(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
args []string
|
||||||
|
wantErr string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "list without node",
|
||||||
|
args: []string{"comment", "list"},
|
||||||
|
wantErr: "--node",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "create without content sheet-id range",
|
||||||
|
args: []string{"comment", "create", "--node", "node-1"},
|
||||||
|
wantErr: "--content, --sheet-id, --range",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "reply without comment-key",
|
||||||
|
args: []string{"comment", "reply", "--node", "node-1", "--content", "text"},
|
||||||
|
wantErr: "--comment-key",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "update without content",
|
||||||
|
args: []string{"comment", "update", "--node", "node-1", "--comment-key", "ck-1"},
|
||||||
|
wantErr: "--content",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, test := range tests {
|
||||||
|
test := test
|
||||||
|
t.Run(test.name, func(t *testing.T) {
|
||||||
|
caller := &guardedMutationCaller{}
|
||||||
|
err := executeGuardedMutationCommand(t, caller, newSheetCommand, test.args...)
|
||||||
|
if err == nil || !strings.Contains(err.Error(), test.wantErr) {
|
||||||
|
t.Fatalf("err = %v, want message containing %q", err, test.wantErr)
|
||||||
|
}
|
||||||
|
if len(caller.calls) != 0 {
|
||||||
|
t.Fatalf("tool calls = %#v, want none", caller.calls)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestCrossPlatformCoverageSheetVersionCommands(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
args []string
|
||||||
|
want guardedMutationCall
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "save",
|
||||||
|
args: []string{"version", "save", "--node", "node-1"},
|
||||||
|
want: guardedMutationCall{
|
||||||
|
productID: "doc",
|
||||||
|
toolName: "save_doc_version",
|
||||||
|
args: map[string]any{"nodeId": "node-1"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "list minimal",
|
||||||
|
args: []string{"version", "list", "--node", "node-1"},
|
||||||
|
want: guardedMutationCall{
|
||||||
|
productID: "doc",
|
||||||
|
toolName: "list_doc_versions",
|
||||||
|
args: map[string]any{"nodeId": "node-1"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "list with pagination pass-through",
|
||||||
|
args: []string{"version", "list", "--node", "node-1", "--limit", "10", "--cursor", "cur-1"},
|
||||||
|
want: guardedMutationCall{
|
||||||
|
productID: "doc",
|
||||||
|
toolName: "list_doc_versions",
|
||||||
|
args: map[string]any{
|
||||||
|
"nodeId": "node-1",
|
||||||
|
"maxResults": 10,
|
||||||
|
"nextCursor": "cur-1",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "list ls alias",
|
||||||
|
args: []string{"version", "ls", "--node", "node-2"},
|
||||||
|
want: guardedMutationCall{
|
||||||
|
productID: "doc",
|
||||||
|
toolName: "list_doc_versions",
|
||||||
|
args: map[string]any{"nodeId": "node-2"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, test := range tests {
|
||||||
|
test := test
|
||||||
|
t.Run(test.name, func(t *testing.T) {
|
||||||
|
caller := &guardedMutationCaller{}
|
||||||
|
err := executeGuardedMutationCommand(t, caller, newSheetCommand, test.args...)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("sheet %s returned error: %v", strings.Join(test.args, " "), err)
|
||||||
|
}
|
||||||
|
if len(caller.calls) != 1 || !reflect.DeepEqual(caller.calls[0], test.want) {
|
||||||
|
t.Fatalf("tool calls = %#v, want %#v", caller.calls, test.want)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestCrossPlatformCoverageSheetVersionRequiredFlags(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
args []string
|
||||||
|
wantErr string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "save without node",
|
||||||
|
args: []string{"version", "save"},
|
||||||
|
wantErr: "--node",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "list without node",
|
||||||
|
args: []string{"version", "list"},
|
||||||
|
wantErr: "--node",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, test := range tests {
|
||||||
|
test := test
|
||||||
|
t.Run(test.name, func(t *testing.T) {
|
||||||
|
caller := &guardedMutationCaller{}
|
||||||
|
err := executeGuardedMutationCommand(t, caller, newSheetCommand, test.args...)
|
||||||
|
if err == nil || !strings.Contains(err.Error(), test.wantErr) {
|
||||||
|
t.Fatalf("err = %v, want message containing %q", err, test.wantErr)
|
||||||
|
}
|
||||||
|
if len(caller.calls) != 0 {
|
||||||
|
t.Fatalf("tool calls = %#v, want none", caller.calls)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -69,7 +69,8 @@ sheetId 支持传入工作表 ID 或工作表名称,可通过 sheet list 获
|
|||||||
不传 --sheet-id 时默认返回第一个工作表。`,
|
不传 --sheet-id 时默认返回第一个工作表。`,
|
||||||
Example: ` dws sheet info --node NODE_ID
|
Example: ` dws sheet info --node NODE_ID
|
||||||
dws sheet info --node NODE_ID --sheet-id SHEET_ID
|
dws sheet info --node NODE_ID --sheet-id SHEET_ID
|
||||||
dws sheet info --node NODE_ID --sheet-id "Sheet1"`,
|
dws sheet info --node NODE_ID --sheet-id "Sheet1"
|
||||||
|
dws sheet info --node NODE_ID --sheet-id SHEET_ID --include row_heights,col_widths`,
|
||||||
RunE: func(cmd *cobra.Command, args []string) error {
|
RunE: func(cmd *cobra.Command, args []string) error {
|
||||||
toolArgs := map[string]any{
|
toolArgs := map[string]any{
|
||||||
"nodeId": mustGetFlag(cmd, "node"),
|
"nodeId": mustGetFlag(cmd, "node"),
|
||||||
@@ -77,11 +78,15 @@ sheetId 支持传入工作表 ID 或工作表名称,可通过 sheet list 获
|
|||||||
if v, _ := cmd.Flags().GetString("sheet-id"); v != "" {
|
if v, _ := cmd.Flags().GetString("sheet-id"); v != "" {
|
||||||
toolArgs["sheetId"] = v
|
toolArgs["sheetId"] = v
|
||||||
}
|
}
|
||||||
|
if v, _ := cmd.Flags().GetStringSlice("include"); len(v) > 0 {
|
||||||
|
toolArgs["include"] = v
|
||||||
|
}
|
||||||
return callMCPToolSheetInfo(toolArgs)
|
return callMCPToolSheetInfo(toolArgs)
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
infoCmd.Flags().String("node", "", "表格文档 ID 或 URL (必填)")
|
infoCmd.Flags().String("node", "", "表格文档 ID 或 URL (必填)")
|
||||||
infoCmd.Flags().String("sheet-id", "", "工作表 ID 或名称 (不传则返回第一个工作表)")
|
infoCmd.Flags().String("sheet-id", "", "工作表 ID 或名称 (不传则返回第一个工作表)")
|
||||||
|
infoCmd.Flags().StringSlice("include", nil, "可选扩展信息,逗号分隔;支持 groups / row_heights / col_widths / hidden_rows / hidden_cols / frozen")
|
||||||
|
|
||||||
newCmd := &cobra.Command{
|
newCmd := &cobra.Command{
|
||||||
Use: "new",
|
Use: "new",
|
||||||
|
|||||||
@@ -97,7 +97,7 @@ Flags:
|
|||||||
| `view get` | 获取视图配置(不传子命令) | `--base-id` `--table-id` | 不传 `--view-ids` 返回全部视图 |
|
| `view get` | 获取视图配置(不传子命令) | `--base-id` `--table-id` | 不传 `--view-ids` 返回全部视图 |
|
||||||
| `view get <attr>` | 获取视图某个属性 | `--view-id` | 12 个:card/timebar/aggregate/filter/sort/group/visible-fields/field-widths(详见 [aitable-view-config.md](./aitable/aitable-view-config.md))+ lock/frozen-cols/row-height/fill-color-rule(详见 [aitable-view-extras.md](./aitable/aitable-view-extras.md)) |
|
| `view get <attr>` | 获取视图某个属性 | `--view-id` | 12 个:card/timebar/aggregate/filter/sort/group/visible-fields/field-widths(详见 [aitable-view-config.md](./aitable/aitable-view-config.md))+ lock/frozen-cols/row-height/fill-color-rule(详见 [aitable-view-extras.md](./aitable/aitable-view-extras.md)) |
|
||||||
| `view list` | 列出全部视图(`view get` 的别名) | `--base-id` `--table-id` | 与 `view get` 完全等价 |
|
| `view list` | 列出全部视图(`view get` 的别名) | `--base-id` `--table-id` | 与 `view get` 完全等价 |
|
||||||
| `view create` | 创建视图 | `--base-id` `--table-id` `--view-type` | 类型: Grid/Kanban/Gantt/Calendar/Gallery/FormDesigner;可用 `--visible-field-ids`,或用 `--config` 传 visibleFieldIds/filter/sort/group;**Gantt 创建后必须 `view update timebar` 绑定日期字段** |
|
| `view create` | 创建视图 | `--base-id` `--table-id` `--view-type` | 类型: Grid/Kanban/Gantt/Calendar/Gallery/FormDesigner;用 `--config` 传 visibleFieldIds/filter/sort/group;**Gantt 创建后必须 `view update timebar` 绑定日期字段** |
|
||||||
| `view update` | 整体更新视图 / 多属性合并更新 | `--base-id` `--table-id` `--view-id` | 可传 `--name --desc --config '{...}'`,**`--config` 路径继续保留** |
|
| `view update` | 整体更新视图 / 多属性合并更新 | `--base-id` `--table-id` `--view-id` | 可传 `--name --desc --config '{...}'`,**`--config` 路径继续保留** |
|
||||||
| `view update <attr>` | 按属性局部更新(推荐)| `--view-id` + typed flag / `--json` | 12 个:card/timebar/aggregate/field-widths/visible-fields/filter/sort/group/name + frozen-cols/row-height/fill-color-rule |
|
| `view update <attr>` | 按属性局部更新(推荐)| `--view-id` + typed flag / `--json` | 12 个:card/timebar/aggregate/field-widths/visible-fields/filter/sort/group/name + frozen-cols/row-height/fill-color-rule |
|
||||||
| `view lock [--off]` | 锁定/解锁视图 | `--base-id` `--table-id` `--view-id` | 默认锁定;`--off` 解锁。详见 [aitable-view-extras.md](./aitable/aitable-view-extras.md) |
|
| `view lock [--off]` | 锁定/解锁视图 | `--base-id` `--table-id` `--view-id` | 默认锁定;`--off` 解锁。详见 [aitable-view-extras.md](./aitable/aitable-view-extras.md) |
|
||||||
|
|||||||
@@ -20,15 +20,10 @@
|
|||||||
|
|
||||||
## 创建:view create
|
## 创建:view create
|
||||||
|
|
||||||
`--view-type` 支持 `Grid`、`Kanban`、`Gantt`、`Calendar`、`Gallery`、`FormDesigner`。创建时有两种方式设置可见字段:
|
`--view-type` 支持 `Grid`、`Kanban`、`Gantt`、`Calendar`、`Gallery`、`FormDesigner`。创建时通过 `--config` JSON 设置可见字段:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# 推荐:CSV typed flag;主字段必须排第一
|
# --config JSON:可同时配置可见字段、筛选、排序和分组;主字段必须排第一
|
||||||
dws aitable view create --base-id BASE_ID --table-id TABLE_ID \
|
|
||||||
--view-type Grid --name "任务视图" \
|
|
||||||
--visible-field-ids fldPrimary,fldStatus,fldOwner
|
|
||||||
|
|
||||||
# JSON 方式:可同时配置可见字段、筛选、排序和分组
|
|
||||||
dws aitable view create --base-id BASE_ID --table-id TABLE_ID \
|
dws aitable view create --base-id BASE_ID --table-id TABLE_ID \
|
||||||
--view-type Grid --name "任务视图" \
|
--view-type Grid --name "任务视图" \
|
||||||
--config '{"visibleFieldIds":["fldPrimary","fldStatus","fldOwner"],"sort":[{"fieldId":"fldStatus","direction":"asc"}]}'
|
--config '{"visibleFieldIds":["fldPrimary","fldStatus","fldOwner"],"sort":[{"fieldId":"fldStatus","direction":"asc"}]}'
|
||||||
@@ -43,7 +38,7 @@ dws aitable view create --base-id BASE_ID --table-id TABLE_ID \
|
|||||||
| `sort` | `object[]` | 排序规则数组;兼容单个 object,CLI 会自动包装为数组 |
|
| `sort` | `object[]` | 排序规则数组;兼容单个 object,CLI 会自动包装为数组 |
|
||||||
| `group` | `object[]` | 分组规则数组;兼容单个 object,CLI 会自动包装为数组 |
|
| `group` | `object[]` | 分组规则数组;兼容单个 object,CLI 会自动包装为数组 |
|
||||||
|
|
||||||
`--visible-field-ids` 与 `config.visibleFieldIds` 互斥。描述使用独立的 `--desc '{"content":[]}'`;`description`、`fieldWidths`、`aggregate`、`kanbanCard`、`ganttTimebar`、`galleryCard` 等其他 key 会在调用服务端前被拒绝,并提示对应的 `view update` 子命令。
|
描述使用独立的 `--desc '{"content":[]}'`;`description`、`fieldWidths`、`aggregate`、`kanbanCard`、`ganttTimebar`、`galleryCard` 等其他 key 会在调用服务端前被拒绝,并提示对应的 `view update` 子命令。
|
||||||
|
|
||||||
## 读取:view get <attr>
|
## 读取:view get <attr>
|
||||||
|
|
||||||
|
|||||||
@@ -514,18 +514,18 @@ Flags:
|
|||||||
|
|
||||||
```
|
```
|
||||||
Usage:
|
Usage:
|
||||||
dws drive download [flags]
|
dws drive download-version [flags]
|
||||||
Example:
|
Example:
|
||||||
dws drive download --node <dentryUuid> --version 3 --output ./report_v1.pdf --format json
|
dws drive download-version --node <dentryUuid> --version 3 --output ./report_v3.pdf --format json
|
||||||
dws drive download --node <dentryUuid> --version 3 --output <DOWNLOAD_DIR> --format json
|
dws drive download-version --node <dentryUuid> --version 3 --output <DOWNLOAD_DIR> --format json
|
||||||
Flags:
|
Flags:
|
||||||
--node string 文件 ID (dentryUuid) 或 URL (必填)
|
--node string 文件 ID (dentryUuid) 或 URL (必填)
|
||||||
--version int 历史版本号 (必填,正整数,从 list --versions 获取)
|
--version int 历史版本号 (必填,正整数,从 list --versions 获取)
|
||||||
--output string 本地保存路径 (文件路径或目录,不传则保存到当前目录) (可选)
|
--output string 本地保存路径 (文件路径或目录,必填)
|
||||||
```
|
```
|
||||||
|
|
||||||
> **两步下载流程**:先调用 MCP 工具获取下载 URL 和签名头,再 HTTP GET 下载文件内容到本地。
|
> **两步下载流程**:先调用 MCP 工具获取历史版本下载 URL 和签名头,再 HTTP GET 下载文件内容到本地。
|
||||||
> 不传 `--output` 或指定目录时,优先从文件信息中获取原始文件名,获取不到时从下载 URL 推断;均不可用时使用默认名 `download.<扩展名>`。
|
> `--output` 指定目录时,优先从文件信息中获取原始文件名,获取不到时从下载 URL 推断。
|
||||||
|
|
||||||
#### 回滚文件到指定历史版本
|
#### 回滚文件到指定历史版本
|
||||||
|
|
||||||
|
|||||||
@@ -56,6 +56,14 @@ var (
|
|||||||
"dws skill find": true, // backward-compat stub
|
"dws skill find": true, // backward-compat stub
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Full command lines intentionally shown as wrong usage inside fenced
|
||||||
|
// 「错误示例」 blocks (kept in docs to steer LLMs away from hallucinated
|
||||||
|
// flags). Matched against the exact extracted command text.
|
||||||
|
antiPatternExactCommands = map[string]bool{
|
||||||
|
"dws report inbox list --start-date 2026-05-04 --end-date 2026-05-11 --format json": true, // report.md: 禁止 --start-date/--end-date
|
||||||
|
"dws report inbox list --date 2026-05-11 --format json": true, // report.md: 禁止 --date
|
||||||
|
}
|
||||||
|
|
||||||
// Commands in this set are runnable leaves whose following token is a
|
// Commands in this set are runnable leaves whose following token is a
|
||||||
// positional argument rather than another Cobra subcommand.
|
// positional argument rather than another Cobra subcommand.
|
||||||
positionalLeafCommands = map[string]bool{
|
positionalLeafCommands = map[string]bool{
|
||||||
@@ -100,7 +108,11 @@ type cmdRef struct {
|
|||||||
Cmd string
|
Cmd string
|
||||||
}
|
}
|
||||||
|
|
||||||
// extractCommands scans skills/**/*.md for every backtick `dws ...` command.
|
// extractCommands scans skills/**/*.md for every `dws ...` command reference:
|
||||||
|
// inline-backtick commands in prose, plus command lines inside fenced ``` code
|
||||||
|
// blocks (lines whose trimmed text starts with an optional "$ " prefix
|
||||||
|
// followed by "dws "). Backslash-continuation lines inside fenced blocks are
|
||||||
|
// joined before parsing so multi-line invocations audit as one command.
|
||||||
func extractCommands(root string) ([]cmdRef, error) {
|
func extractCommands(root string) ([]cmdRef, error) {
|
||||||
skillsDir := filepath.Join(root, "skills")
|
skillsDir := filepath.Join(root, "skills")
|
||||||
var refs []cmdRef
|
var refs []cmdRef
|
||||||
@@ -126,12 +138,22 @@ func extractCommands(root string) ([]cmdRef, error) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
lineNo := 0
|
var lines []string
|
||||||
scanner := bufio.NewScanner(strings.NewReader(data))
|
scanner := bufio.NewScanner(strings.NewReader(data))
|
||||||
scanner.Buffer(make([]byte, 1024*1024), 1024*1024*4)
|
scanner.Buffer(make([]byte, 1024*1024), 1024*1024*4)
|
||||||
for scanner.Scan() {
|
for scanner.Scan() {
|
||||||
lineNo++
|
lines = append(lines, scanner.Text())
|
||||||
matches := backtickCmd.FindAllStringSubmatch(scanner.Text(), -1)
|
}
|
||||||
|
inFence := false
|
||||||
|
for i := 0; i < len(lines); i++ {
|
||||||
|
lineNo := i + 1
|
||||||
|
trimmed := strings.TrimSpace(lines[i])
|
||||||
|
if strings.HasPrefix(trimmed, "```") {
|
||||||
|
inFence = !inFence
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if !inFence {
|
||||||
|
matches := backtickCmd.FindAllStringSubmatch(lines[i], -1)
|
||||||
for _, m := range matches {
|
for _, m := range matches {
|
||||||
cmd := strings.TrimSpace(m[1])
|
cmd := strings.TrimSpace(m[1])
|
||||||
if shouldSkip(cmd) {
|
if shouldSkip(cmd) {
|
||||||
@@ -139,6 +161,35 @@ func extractCommands(root string) ([]cmdRef, error) {
|
|||||||
}
|
}
|
||||||
refs = append(refs, cmdRef{File: f, Line: lineNo, Cmd: cmd})
|
refs = append(refs, cmdRef{File: f, Line: lineNo, Cmd: cmd})
|
||||||
}
|
}
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
// Inside a fenced block: only lines that *start* with an
|
||||||
|
// (optionally "$ "-prefixed) dws invocation are commands;
|
||||||
|
// everything else is illustrative output.
|
||||||
|
cmdText := strings.TrimPrefix(trimmed, "$ ")
|
||||||
|
if !strings.HasPrefix(cmdText, "dws ") {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
// Join backslash-continuation lines into one logical command.
|
||||||
|
for strings.HasSuffix(cmdText, "\\") && i+1 < len(lines) {
|
||||||
|
next := strings.TrimSpace(lines[i+1])
|
||||||
|
if strings.HasPrefix(next, "```") {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
cmdText = strings.TrimSuffix(cmdText, "\\")
|
||||||
|
cmdText = strings.TrimSpace(cmdText) + " " + next
|
||||||
|
i++
|
||||||
|
}
|
||||||
|
cmdText = strings.TrimSpace(cmdText)
|
||||||
|
// Strip a trailing inline shell comment ("dws ... # 说明") so the
|
||||||
|
// annotation text is not parsed as flags or positional arguments.
|
||||||
|
if idx := strings.Index(cmdText, " # "); idx >= 0 {
|
||||||
|
cmdText = strings.TrimSpace(cmdText[:idx])
|
||||||
|
}
|
||||||
|
if shouldSkip(cmdText) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
refs = append(refs, cmdRef{File: f, Line: lineNo, Cmd: cmdText})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return refs, nil
|
return refs, nil
|
||||||
@@ -276,9 +327,15 @@ func exactCommand(root *cobra.Command, sub string) *cobra.Command {
|
|||||||
}
|
}
|
||||||
if next == nil {
|
if next == nil {
|
||||||
// Once a runnable command is reached, remaining non-flag tokens are
|
// Once a runnable command is reached, remaining non-flag tokens are
|
||||||
// positional arguments rather than descendants. Validate them with
|
// positional arguments rather than descendants. A command that has
|
||||||
// the command's Cobra Args contract when one is present.
|
// registered child commands treats an unknown next token as a
|
||||||
|
// misspelled subcommand, not a positional argument. For true
|
||||||
|
// leaves, validate positionals with the command's Cobra Args
|
||||||
|
// contract when one is present.
|
||||||
if current.Runnable() {
|
if current.Runnable() {
|
||||||
|
if len(current.Commands()) > 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
args := tokens[i:]
|
args := tokens[i:]
|
||||||
if current.Args == nil || current.Args(current, args) == nil {
|
if current.Args == nil || current.Args(current, args) == nil {
|
||||||
return current
|
return current
|
||||||
@@ -350,6 +407,9 @@ func TestSkillCommandsDispatch(t *testing.T) {
|
|||||||
seen := map[string]bool{} // dedupe identical sub-path and flag sets
|
seen := map[string]bool{} // dedupe identical sub-path and flag sets
|
||||||
|
|
||||||
for _, r := range refs {
|
for _, r := range refs {
|
||||||
|
if antiPatternExactCommands[r.Cmd] {
|
||||||
|
continue
|
||||||
|
}
|
||||||
sub, _, flags := parseSubPath(r.Cmd)
|
sub, _, flags := parseSubPath(r.Cmd)
|
||||||
if sub == "" {
|
if sub == "" {
|
||||||
continue
|
continue
|
||||||
|
|||||||
Reference in new issue
Block a user