Files
dingtalk-workspace-cli/internal/cli/param_concepts.json
T
克谨 abc62622fb feat(param): add reviewed param-concept dictionary, closed schema, and loader
Introduce internal/cli/param_concepts.json as the single reviewed source of
parameter-normalization concepts and per-command overrides, guarded by a closed
JSON schema and a go:embed loader with contract tests. Add the design spec.
2026-07-29 10:00:41 +08:00

145 lines
18 KiB
JSON

{
"$schema": "./param_concepts.schema.json",
"version": 1,
"morphological_rules": {
"kebab_camel_equivalence": {"desc": "--page-size == --pageSize", "enabled": true},
"separator_normalization": {"desc": "-, _, . are equivalent separators", "enabled": true},
"trailing_id_tolerance": {"desc": "--base tolerates --base-id when only one is a real flag on the command", "enabled": true, "guard": "the two must not both be real flags with different semantics"},
"pluralization": {"desc": "--id<->--ids, --user<->--users", "enabled": false, "reason": "singular/list semantics can differ; handled by concept+intersection or command override instead"}
},
"concepts": {
"search_query": {"denotes": "search keyword string", "canonical_hint": "query", "members": ["query", "keyword", "keywords", "q", "search-word"], "excludes": ["name", "subject", "text", "title"], "risk": "green"},
"pagination_size": {"denotes": "returned item count upper bound", "canonical_hint": "limit", "members": ["limit", "size", "page-size", "max-results", "max-result", "take", "top", "per-page"], "excludes": ["count", "page", "cursor"], "risk": "green"},
"page_number": {"denotes": "page number", "canonical_hint": "page", "members": ["page", "page-no", "page-index", "current-page", "page-num"], "excludes": ["cursor", "page-size", "page-token"], "risk": "green"},
"page_cursor": {"denotes": "pagination cursor/token", "canonical_hint": "cursor", "members": ["cursor", "next-cursor", "page-token", "next-token", "next-page-token"], "excludes": ["page", "offset"], "risk": "green"},
"content_text": {"denotes": "text body content", "canonical_hint": "text", "members": ["text", "content", "body"], "excludes": ["title", "name"], "risk": "green"},
"time_start": {"denotes": "start time point", "canonical_hint": "start", "members": ["start", "start-time", "start-date", "from", "from-date", "begin", "since", "time-min", "min-time"], "excludes": ["date", "time", "end"], "risk": "yellow"},
"time_end": {"denotes": "end time point", "canonical_hint": "end", "members": ["end", "end-time", "end-date", "time-max", "max-time"], "excludes": ["date", "time", "start"], "risk": "yellow"},
"base_id": {"denotes": "multi-dimensional table Base id", "canonical_hint": "base-id", "members": ["base", "base-id", "base-token"], "excludes": [], "risk": "green"},
"dept_id": {"denotes": "department id", "canonical_hint": "dept", "members": ["dept", "dept-id", "department", "department-id", "depts", "dept-ids"], "excludes": ["name", "query", "parent"], "risk": "yellow"},
"group_id": {"denotes": "group/conversation id", "canonical_hint": "conversation-id", "members": ["group", "group-id", "conversation-id", "conversation-ids", "chat-id", "open-conversation-id"], "excludes": ["id", "name"], "risk": "yellow"},
"user_id": {"denotes": "user id", "canonical_hint": "user-id", "members": ["user", "users", "user-id", "user-ids", "userid", "uid", "staff-id"], "excludes": ["at-user-ids", "to-user", "name"], "risk": "yellow"},
"ding_id": {"denotes": "DING id", "canonical_hint": "ding-id", "members": ["ding-id", "open-ding-id"], "excludes": ["id"], "risk": "yellow"},
"folder_id": {"denotes": "drive folder id", "canonical_hint": "folder", "members": ["folder", "folder-id"], "excludes": ["space-id"], "risk": "green"},
"space_id": {"denotes": "drive/wiki space id", "canonical_hint": "space-id", "members": ["space-id", "space", "workspace", "workspace-id"], "excludes": ["folder", "node"], "risk": "yellow"},
"app_id": {"denotes": "application id", "canonical_hint": "unified-app-id", "members": ["app-id", "unified-app-id", "application-id"], "excludes": ["app-key", "app-secret", "agent-id"], "risk": "yellow"},
"robot_code": {"denotes": "robot id", "canonical_hint": "robot-code", "members": ["robot-code", "robot", "robot-id"], "excludes": [], "risk": "yellow"}
},
"command_overrides": {
"chat group rename": {"bind": {"id": "group_id"}, "note": "this command's --id is the group id; --group thus reduces to --id"},
"chat group members": {"bind": {"id": "group_id"}},
"chat group members add": {"bind": {"id": "group_id"}},
"chat group members remove": {"bind": {"id": "group_id"}},
"chat group set-admin": {"ambiguous": ["user-id", "user-ids", "userid", "uid", "staff-id"], "note": "command has both real --user (single) and --users (batch); CO-OCCURRENCE guard -> do not guess, did-you-mean"},
"chat group-mute-member": {"ambiguous": ["user-id", "user-ids", "userid", "uid", "staff-id"], "note": "both --user (single) and --users (batch) are real; CO-OCCURRENCE guard -> did-you-mean"},
"chat message read-status": {"ambiguous": ["user-id", "user-ids", "userid", "uid", "staff-id"], "note": "both --user (single) and --users (batch) are real; CO-OCCURRENCE guard -> did-you-mean"},
"chat message search-advanced": {"ambiguous": ["user-id", "user-ids", "userid", "uid", "staff-id"], "note": "sender --user (single) and --users (batch) are both real; CO-OCCURRENCE guard -> did-you-mean (group_id still reduces to conversation-ids)"},
"chat message add-emoji": {"ambiguous": ["group-id", "conversation-ids", "chat-id", "open-conversation-id"], "note": "both --conversation-id and --group are real; CO-OCCURRENCE guard -> did-you-mean"},
"chat message add-text-emotion": {"ambiguous": ["group-id", "conversation-ids", "chat-id", "open-conversation-id"], "note": "both --conversation-id and --group are real; CO-OCCURRENCE guard -> did-you-mean"},
"chat message remove-emoji": {"ambiguous": ["group-id", "conversation-ids", "chat-id", "open-conversation-id"], "note": "both --conversation-id and --group are real; CO-OCCURRENCE guard -> did-you-mean"},
"chat message remove-text-emotion": {"ambiguous": ["group-id", "conversation-ids", "chat-id", "open-conversation-id"], "note": "both --conversation-id and --group are real; CO-OCCURRENCE guard -> did-you-mean"},
"drive list": {"ambiguous": ["space", "workspace-id"], "note": "both --space-id and --workspace are real; CO-OCCURRENCE guard -> did-you-mean (folder_id still reduces folder-id->folder)"},
"drive upload": {"ambiguous": ["space", "workspace-id"], "note": "both --space-id and --workspace are real; CO-OCCURRENCE guard -> did-you-mean"},
"ding +receiver-status": {"scoped_aliases": {"id": "ding-id"}, "note": "generic id reduces to ding-id"},
"ding message receiver-status": {"scoped_aliases": {"id": "ding-id"}},
"contact user profile get": {"scoped_aliases": {"id": "staff-id", "ids": "staff-id"}, "note": "user-id is reduced by the user_id concept; generic id/ids bound explicitly"},
"mail folder update": {"bind": {"id": "folder_id"}, "note": "this command's --id is the folder id; --folder-id reduces to --id"},
"contact dept list-children": {"scoped_aliases": {"parent": "dept", "parent-id": "dept"}, "confirm": true, "note": "parent department is the target dept; needs confirmation"},
"mail message search": {"scoped_aliases": {"subject": "query"}, "scope_strict": true, "note": "never globalize: mail template create has a real and different --subject"},
"calendar event list": {"scoped_aliases": {"date": "start", "calendar": "calendar-id"}, "confirm": true, "note": "date->start (date excluded from time_start on purpose) and calendar->calendar-id are the only scoped gaps; time-min/min-time reduce via time_start, time-max/max-time/end-time/end-date via time_end, start-time/start-date via time_start, size/page-size/max-results via pagination_size, cursor family via page_cursor, calendarId via morphology; count kept (excluded from pagination_size). confirm applies command-wide for now (per-alias confirm is a later refinement)."},
"chat message list-by-sender": {"scoped_aliases": {"time": "start"}, "confirm": true},
"contact +resolve-dept": {"scoped_aliases": {"query": "name"}, "confirm": true, "note": "search term maps to the department name field"},
"contact +list-sub-depts": {"scoped_aliases": {"name": "dept", "query": "dept"}, "confirm": true, "note": "dept-id->dept handled by morph + dept_id concept; name/query uncertain"},
"contact +dept-members": {"scoped_aliases": {"name": "dept", "query": "dept"}, "confirm": true},
"chat message send": {"scoped_aliases": {"to-user": "user"}, "confirm": true},
"chat +group-members": {"scoped_aliases": {"group-name": "group"}, "confirm": true, "note": "group name vs group id needs confirmation"},
"doc block insert": {"scoped_aliases": {"before-block-id": "ref-block"}, "confirm": true, "note": "may lose the where=before position semantics"},
"chat message send-by-bot": {"ambiguous": ["to-user-id"], "note": "only --users is real for the user_id concept (at-user-ids is the @ list, excluded), so user-id reduces to users; to-user-id stays ambiguous because it may mean the @ target or the recipient"},
"doc +export-get": {"block": ["node"], "note": "node is a document node id, a different entity from job-id"},
"doc block delete": {"block": ["index"], "note": "index (position) vs node (node id) are different"},
"report outbox list": {"block": ["template-type"], "note": "type vs name are different fields"},
"chat conversation-info": {"block": ["user"], "investigate": true, "note": "canonical and alias share the same name; suspected data/case-sensitivity artifact, needs source case review"}
},
"validation_fixture": {
"cases": [
{"command": "oa +search-forms", "emitted": "keyword", "expect": "query", "via": "concept:search_query", "occ": 28},
{"command": "aitable +list-tables", "emitted": "base-id", "expect": "base", "via": "concept:base_id+morph", "occ": 26},
{"command": "mail +find-mail-user", "emitted": "keyword", "expect": "query", "via": "concept:search_query", "occ": 18},
{"command": "aitable +field-get", "emitted": "base", "expect": "base-id", "via": "concept:base_id+morph", "occ": 8},
{"command": "aitable +record-query", "emitted": "base", "expect": "base-id", "via": "concept:base_id+morph", "occ": 8},
{"command": "aitable +table-get", "emitted": "base", "expect": "base-id", "via": "concept:base_id+morph", "occ": 8},
{"command": "doc block update", "emitted": "content", "expect": "text", "via": "concept:content_text", "occ": 6},
{"command": "contact +resolve-dept", "emitted": "query", "expect": "name", "via": "override:scoped(confirm)", "occ": 4},
{"command": "devdoc article search", "emitted": "limit", "expect": "size", "via": "concept:pagination_size", "occ": 2},
{"command": "devdoc article search", "emitted": "page-size", "expect": "size", "via": "concept:pagination_size", "occ": 2},
{"command": "devdoc article search", "emitted": "current-page", "expect": "page", "via": "concept:page_number", "occ": 2},
{"command": "mail message search", "emitted": "subject", "expect": "query", "via": "override:scoped_strict", "occ": 4},
{"command": "aitable +record-share-url", "emitted": "base", "expect": "base-id", "via": "concept:base_id+morph", "occ": 3},
{"command": "aitable record query", "emitted": "max-results", "expect": "limit", "via": "concept:pagination_size", "occ": 2},
{"command": "calendar event list", "emitted": "date", "expect": "start", "via": "override:scoped(confirm)", "occ": 2},
{"command": "calendar event list", "emitted": "start-time", "expect": "start", "via": "concept:time_start", "occ": 2},
{"command": "calendar event list", "emitted": "min-time", "expect": "start", "via": "concept:time_start", "occ": 2},
{"command": "calendar event list", "emitted": "time-min", "expect": "start", "via": "concept:time_start", "occ": 2},
{"command": "calendar event list", "emitted": "end-time", "expect": "end", "via": "concept:time_end", "occ": 2},
{"command": "calendar event list", "emitted": "time-max", "expect": "end", "via": "concept:time_end", "occ": 2},
{"command": "calendar event list", "emitted": "max-results", "expect": "limit", "via": "concept:pagination_size", "occ": 2},
{"command": "calendar event list", "emitted": "next-cursor", "expect": "cursor", "via": "concept:page_cursor", "occ": 2},
{"command": "calendar event list", "emitted": "calendar", "expect": "calendar-id", "via": "override:scoped(confirm)", "occ": 2},
{"command": "chat message list", "emitted": "max-results", "expect": "limit", "via": "concept:pagination_size", "occ": 2},
{"command": "chat message list-by-sender", "emitted": "time", "expect": "start", "via": "override:scoped(confirm)", "occ": 2},
{"command": "doc +template-search", "emitted": "keyword", "expect": "query", "via": "concept:search_query", "occ": 2},
{"command": "doc block insert", "emitted": "content", "expect": "text", "via": "concept:content_text", "occ": 2},
{"command": "drive list", "emitted": "folder-id", "expect": "folder", "via": "concept:folder_id+morph", "occ": 2},
{"command": "mail thread list", "emitted": "max-results", "expect": "limit", "via": "concept:pagination_size", "occ": 2},
{"command": "mail user search", "emitted": "query", "expect": "keyword", "via": "concept:search_query", "occ": 2},
{"command": "oa +list-executed", "emitted": "take", "expect": "limit", "via": "concept:pagination_size", "occ": 2},
{"command": "oa approval search-forms", "emitted": "keyword", "expect": "query", "via": "concept:search_query", "occ": 2},
{"command": "report list", "emitted": "from-date", "expect": "start", "via": "concept:time_start", "occ": 2},
{"command": "aitable +base-search", "emitted": "keyword", "expect": "query", "via": "concept:search_query", "occ": 1},
{"command": "contact +search-user", "emitted": "keyword", "expect": "query", "via": "concept:search_query", "occ": 1},
{"command": "chat group rename", "emitted": "group", "expect": "id", "via": "override:bind(group_id)", "occ": 31},
{"command": "ding +receiver-status", "emitted": "id", "expect": "ding-id", "via": "override:scoped(ding_id)", "occ": 24},
{"command": "chat group members", "emitted": "group", "expect": "id", "via": "override:bind(group_id)", "occ": 8},
{"command": "contact +list-sub-depts", "emitted": "dept-id", "expect": "dept", "via": "concept:dept_id+morph", "occ": 4},
{"command": "contact +list-sub-depts", "emitted": "name", "expect": "dept", "via": "override:scoped(confirm)", "occ": 2},
{"command": "contact +list-sub-depts", "emitted": "query", "expect": "dept", "via": "override:scoped(confirm)", "occ": 2},
{"command": "contact user profile get", "emitted": "user-id", "expect": "staff-id", "via": "concept:user_id", "occ": 2},
{"command": "contact user profile get", "emitted": "id", "expect": "staff-id", "via": "override:scoped", "occ": 2},
{"command": "contact user profile get", "emitted": "ids", "expect": "staff-id", "via": "override:scoped", "occ": 2},
{"command": "chat message send-by-bot", "emitted": "user-id", "expect": "users", "via": "concept:user_id", "occ": 4},
{"command": "chat message send-by-bot", "emitted": "to-user-id", "expect": "did-you-mean:ambiguous", "via": "override:ambiguous", "occ": 1},
{"command": "dev app get", "emitted": "app-id", "expect": "unified-app-id", "via": "concept:app_id", "occ": 5},
{"command": "chat conversation-info", "emitted": "user", "expect": "did-you-mean:blocked", "via": "override:block(investigate)", "occ": 4},
{"command": "chat message list-all", "emitted": "from", "expect": "start", "via": "concept:time_start", "occ": 2},
{"command": "chat message list-all", "emitted": "start-time", "expect": "start", "via": "concept:time_start", "occ": 2},
{"command": "chat message search-advanced", "emitted": "group", "expect": "conversation-ids", "via": "concept:group_id", "occ": 4},
{"command": "chat message send", "emitted": "to-user", "expect": "user", "via": "override:scoped(confirm)", "occ": 4},
{"command": "contact +dept-members", "emitted": "name", "expect": "dept", "via": "override:scoped(confirm)", "occ": 2},
{"command": "contact +dept-members", "emitted": "query", "expect": "dept", "via": "override:scoped(confirm)", "occ": 2},
{"command": "contact dept list-children", "emitted": "parent-id", "expect": "dept", "via": "override:scoped(confirm)", "occ": 2},
{"command": "contact dept list-children", "emitted": "parent", "expect": "dept", "via": "override:scoped(confirm)", "occ": 2},
{"command": "ding message receiver-status", "emitted": "id", "expect": "ding-id", "via": "override:scoped(ding_id)", "occ": 2},
{"command": "ding message receiver-status", "emitted": "open-ding-id", "expect": "ding-id", "via": "concept:ding_id", "occ": 2},
{"command": "chat group members add", "emitted": "group", "expect": "id", "via": "override:bind(group_id)", "occ": 3},
{"command": "attendance +check-result", "emitted": "user-id", "expect": "users", "via": "concept:user_id", "occ": 2},
{"command": "attendance check result", "emitted": "user-ids", "expect": "users", "via": "concept:user_id", "occ": 2},
{"command": "chat group members remove", "emitted": "group", "expect": "id", "via": "override:bind(group_id)", "occ": 2},
{"command": "chat group set-admin", "emitted": "user-id", "expect": "did-you-mean:ambiguous", "via": "guard:co_occurrence(user,users)", "occ": 2},
{"command": "chat message add-emoji", "emitted": "chat-id", "expect": "did-you-mean:ambiguous", "via": "guard:co_occurrence(conversation-id,group)", "occ": 2},
{"command": "drive list", "emitted": "space", "expect": "did-you-mean:ambiguous", "via": "guard:co_occurrence(space-id,workspace)", "occ": 2},
{"command": "ding message send", "emitted": "robot", "expect": "robot-code", "via": "concept:robot_code", "occ": 2},
{"command": "doc +export-get", "emitted": "node", "expect": "did-you-mean:blocked", "via": "override:block", "occ": 2},
{"command": "doc block delete", "emitted": "index", "expect": "did-you-mean:blocked", "via": "override:block", "occ": 2},
{"command": "doc block insert", "emitted": "before-block-id", "expect": "ref-block", "via": "override:scoped(confirm)", "occ": 2},
{"command": "drive info", "emitted": "workspace", "expect": "space-id", "via": "concept:space_id", "occ": 2},
{"command": "mail folder update", "emitted": "folder-id", "expect": "id", "via": "override:bind(folder_id)", "occ": 2},
{"command": "report outbox list", "emitted": "template-type", "expect": "did-you-mean:blocked", "via": "override:block", "occ": 2},
{"command": "chat +group-members", "emitted": "group-name", "expect": "group", "via": "override:scoped(confirm)", "occ": 1}
]
}
}