Files
dingtalk-workspace-cli/internal/helpers/devapp.go
T
2026-06-17 10:03:04 +08:00

1451 lines
49 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// 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.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package helpers
import (
"encoding/json"
"fmt"
"strings"
"github.com/DingTalk-Real-AI/dingtalk-workspace-cli/internal/cobracmd"
apperrors "github.com/DingTalk-Real-AI/dingtalk-workspace-cli/internal/errors"
"github.com/DingTalk-Real-AI/dingtalk-workspace-cli/internal/executor"
"github.com/spf13/cobra"
"github.com/spf13/pflag"
)
const (
devAppProduct = "devapp"
devAppListTool = "list_dev_app"
devAppGetTool = "get_dev_app"
devAppCreateTool = "create_dev_app"
devAppUpdateTool = "update_dev_app"
devAppDeleteTool = "delete_dev_app"
devAppDisableTool = "disable_dev_app"
devAppEnableTool = "enable_dev_app"
devAppCredentialsGet = "get_dev_app_credentials"
devAppMemberListTool = "list_dev_app_members"
devAppMemberAddTool = "add_dev_app_members"
devAppMemberRemoveTool = "remove_dev_app_members"
devAppSecurityConfigTool = "update_dev_app_security_config"
// 机器人能力(op-app MCP 工具,硬编码不走服务发现)。
devAppRobotCreateTool = "create_dingtalk_robot"
devAppRobotSubmitTool = "submit_robot_create_task"
devAppRobotResultTool = "query_robot_create_result"
devAppRobotConfigGetTool = "get_extension_robot_config"
devAppRobotConfigSetTool = "set_extension_robot_config"
devAppRobotEnableTool = "enable_dev_app_robot"
devAppRobotDisableTool = "disable_dev_app_robot"
// 版本发布能力(op-app MCP 工具,硬编码不走服务发现)。
devAppVersionCreateTool = "create_dev_app_version"
devAppVersionListTool = "list_dev_app_versions"
devAppVersionDetailTool = "get_dev_app_version_detail"
devAppVersionPublishTool = "publish_dev_app_version"
devAppVersionStatusTool = "get_dev_app_version_status"
// 事件订阅能力(op-app MCP 工具,硬编码不走服务发现)。
devAppEventListTool = "list_dev_app_events"
devAppEventSubscribeTool = "subscribe_dev_app_events"
devAppEventUnsubscribeTool = "unsubscribe_dev_app_events"
)
func init() {
RegisterPublic(func() Handler {
return devAppHandler{}
})
}
type devAppHandler struct{}
func (devAppHandler) Name() string {
return "devapp"
}
func (devAppHandler) Command(runner executor.Runner) *cobra.Command {
return newDevAppCommand(runner)
}
func newDevAppCommand(runner executor.Runner) *cobra.Command {
root := &cobra.Command{
Use: "devapp",
Aliases: []string{"app"},
Short: "开放平台应用",
Long: "管理开放平台开发者应用:查询、详情、创建、更新、启停、删除、权限、网页应用、成员、安全配置、机器人、版本发布和事件订阅。",
Args: cobra.NoArgs,
TraverseChildren: true,
DisableAutoGenTag: true,
RunE: func(cmd *cobra.Command, args []string) error {
return cmd.Help()
},
}
webapp := &cobra.Command{
Use: "webapp",
Short: "开放平台网页应用配置",
Args: cobra.NoArgs,
TraverseChildren: true,
DisableAutoGenTag: true,
RunE: func(cmd *cobra.Command, args []string) error {
return cmd.Help()
},
}
webapp.AddCommand(
newDevAppWebappGetCommand(runner),
newDevAppWebappConfigCommand(runner),
)
permission := &cobra.Command{
Use: "permission",
Short: "开放平台应用权限",
Args: cobra.NoArgs,
TraverseChildren: true,
DisableAutoGenTag: true,
RunE: func(cmd *cobra.Command, args []string) error {
return cmd.Help()
},
}
permission.AddCommand(
newDevAppPermissionListCommand(runner),
newDevAppPermissionAddCommand(runner),
newDevAppPermissionRemoveCommand(runner),
)
credentials := &cobra.Command{
Use: "credentials",
Short: "开放平台应用凭证",
Args: cobra.NoArgs,
TraverseChildren: true,
DisableAutoGenTag: true,
RunE: func(cmd *cobra.Command, args []string) error {
return cmd.Help()
},
}
credentials.AddCommand(newDevAppCredentialsGetCommand(runner))
member := &cobra.Command{
Use: "member",
Short: "开放平台应用成员管理",
Args: cobra.NoArgs,
TraverseChildren: true,
DisableAutoGenTag: true,
RunE: func(cmd *cobra.Command, args []string) error {
return cmd.Help()
},
}
member.AddCommand(
newDevAppMemberListCommand(runner),
newDevAppMemberAddCommand(runner),
newDevAppMemberRemoveCommand(runner),
)
security := &cobra.Command{
Use: "security",
Short: "开放平台应用安全设置",
Args: cobra.NoArgs,
TraverseChildren: true,
DisableAutoGenTag: true,
RunE: func(cmd *cobra.Command, args []string) error {
return cmd.Help()
},
}
security.AddCommand(newDevAppSecurityConfigCommand(runner))
robot := &cobra.Command{
Use: "robot",
Short: "开放平台应用机器人能力",
Args: cobra.NoArgs,
TraverseChildren: true,
DisableAutoGenTag: true,
RunE: func(cmd *cobra.Command, args []string) error {
return cmd.Help()
},
}
robot.AddCommand(
newDevAppRobotCreateCommand(runner),
newDevAppRobotSubmitCommand(runner),
newDevAppRobotResultCommand(runner),
newDevAppRobotConfigGetCommand(runner),
newDevAppRobotConfigCommand(runner, "config", "创建或更新现有应用机器人配置", devAppRobotConfigSetTool),
newDevAppRobotEnableCommand(runner),
newDevAppRobotDisableCommand(runner),
newDevAppRobotConnectCommand(runner),
)
version := &cobra.Command{
Use: "version",
Short: "开放平台应用版本发布",
Args: cobra.NoArgs,
TraverseChildren: true,
DisableAutoGenTag: true,
RunE: func(cmd *cobra.Command, args []string) error {
return cmd.Help()
},
}
version.AddCommand(
newDevAppVersionCreateCommand(runner),
newDevAppVersionListCommand(runner),
newDevAppVersionGetCommand(runner),
newDevAppVersionCheckApprovalCommand(runner),
newDevAppVersionPublishCommand(runner),
newDevAppVersionStatusCommand(runner),
)
event := &cobra.Command{
Use: "event",
Short: "开放平台应用事件订阅",
Args: cobra.NoArgs,
TraverseChildren: true,
DisableAutoGenTag: true,
RunE: func(cmd *cobra.Command, args []string) error {
return cmd.Help()
},
}
event.AddCommand(
newDevAppEventListCommand(runner),
newDevAppEventSubscribeCommand(runner, "subscribe", "批量订阅事件", devAppEventSubscribeTool),
newDevAppEventSubscribeCommand(runner, "unsubscribe", "批量退订事件", devAppEventUnsubscribeTool),
)
root.AddCommand(
newDevAppListCommand(runner),
newDevAppGetCommand(runner),
newDevAppCreateCommand(runner),
newDevAppUpdateCommand(runner),
newDevAppLifecycleCommand(runner, "delete", "删除开放平台企业内部应用", devAppDeleteTool),
newDevAppLifecycleCommand(runner, "inactive", "停用开放平台企业内部应用", devAppDisableTool),
newDevAppLifecycleCommand(runner, "active", "启用开放平台企业内部应用", devAppEnableTool),
credentials,
webapp,
permission,
member,
security,
robot,
version,
event,
)
return root
}
func newDevAppListCommand(runner executor.Runner) *cobra.Command {
cmd := &cobra.Command{
Use: "list",
Short: "查询开放平台企业内部应用列表",
Example: " dws devapp list --name DemoApp --page-size 20 --format json",
Args: cobra.NoArgs,
DisableAutoGenTag: true,
RunE: func(cmd *cobra.Command, args []string) error {
params := map[string]any{
"pageSize": devAppIntFlag(cmd, "page-size"),
}
devAppPutString(params, "cursor", devAppStringFlag(cmd, "cursor"))
devAppPutString(params, "name", devAppFlagOrFallback(cmd, "name", "keyword"))
return runDevAppTool(runner, cmd, devAppListTool, params)
},
}
cmd.Flags().Int("page-size", 20, "分页大小")
cmd.Flags().String("cursor", "", "游标分页 cursor,首次查询为空")
cmd.Flags().String("name", "", "应用名称关键词")
cmd.Flags().String("keyword", "", "--name 的兼容别名")
_ = cmd.Flags().MarkHidden("keyword")
preferLegacyLeaf(cmd)
return cmd
}
func newDevAppGetCommand(runner executor.Runner) *cobra.Command {
cmd := &cobra.Command{
Use: "get",
Short: "查询开放平台企业内部应用详情",
Example: " dws devapp get --unified-app-id UNIFIED_APP_ID --format json",
Args: cobra.NoArgs,
DisableAutoGenTag: true,
RunE: func(cmd *cobra.Command, args []string) error {
params := devAppUnifiedAppIDParams(cmd)
if len(params) == 0 {
return devAppUnifiedAppIDRequired()
}
return runDevAppTool(runner, cmd, devAppGetTool, params)
},
}
addDevAppUnifiedAppIDFlag(cmd)
preferLegacyLeaf(cmd)
return cmd
}
func newDevAppCreateCommand(runner executor.Runner) *cobra.Command {
cmd := &cobra.Command{
Use: "create",
Short: "创建开放平台企业内部应用",
Example: " dws devapp create --name DemoApp --desc 内部应用 --dry-run --format json",
Args: cobra.NoArgs,
DisableAutoGenTag: true,
RunE: func(cmd *cobra.Command, args []string) error {
if err := devAppRequireWriteGuard(cmd, "create"); err != nil {
return err
}
appType := devAppStringFlag(cmd, "type")
if appType != "" && appType != "internal" {
return apperrors.NewValidation("--type currently only supports internal")
}
name := devAppStringFlag(cmd, "name")
if name == "" {
return apperrors.NewValidation("--name is required")
}
params := map[string]any{"name": name}
devAppPutString(params, "desc", devAppStringFlag(cmd, "desc"))
devAppPutString(params, "icon", devAppStringFlag(cmd, "icon"))
return runDevAppTool(runner, cmd, devAppCreateTool, params)
},
}
cmd.Flags().String("name", "", "应用名称 (必填)")
cmd.Flags().String("desc", "", "应用描述")
cmd.Flags().String("icon", "", "应用图标 mediaId")
cmd.Flags().String("type", "internal", "应用类型;当前仅支持 internal")
preferLegacyLeaf(cmd)
return cmd
}
func newDevAppUpdateCommand(runner executor.Runner) *cobra.Command {
cmd := &cobra.Command{
Use: "update",
Short: "修改开放平台企业内部应用基础信息",
Example: " dws devapp update --unified-app-id UNIFIED_APP_ID --name DemoApp2 --dry-run --format json",
Args: cobra.NoArgs,
DisableAutoGenTag: true,
RunE: func(cmd *cobra.Command, args []string) error {
if err := devAppRequireWriteGuard(cmd, "update"); err != nil {
return err
}
params := devAppUnifiedAppIDParams(cmd)
if len(params) == 0 {
return devAppUnifiedAppIDRequired()
}
updates := 0
if v := devAppStringFlag(cmd, "name"); v != "" {
params["name"] = v
updates++
}
if v := devAppStringFlag(cmd, "desc"); v != "" {
params["desc"] = v
updates++
}
if v := devAppStringFlag(cmd, "icon"); v != "" {
params["icon"] = v
updates++
}
if updates == 0 {
return apperrors.NewValidation("at least one update field is required: --name, --desc, or --icon")
}
return runDevAppTool(runner, cmd, devAppUpdateTool, params)
},
}
addDevAppUnifiedAppIDFlag(cmd)
cmd.Flags().String("name", "", "新的应用名称")
cmd.Flags().String("desc", "", "新的应用描述")
cmd.Flags().String("icon", "", "新的应用图标 mediaId")
preferLegacyLeaf(cmd)
return cmd
}
func newDevAppCredentialsGetCommand(runner executor.Runner) *cobra.Command {
cmd := &cobra.Command{
Use: "get",
Short: "读取开放平台应用凭证",
Example: " dws devapp credentials get --unified-app-id UNIFIED_APP_ID --format json",
Args: cobra.NoArgs,
DisableAutoGenTag: true,
RunE: func(cmd *cobra.Command, args []string) error {
params := devAppUnifiedAppIDParams(cmd)
if len(params) == 0 {
return devAppUnifiedAppIDRequired()
}
return runDevAppTool(runner, cmd, devAppCredentialsGet, params)
},
}
addDevAppUnifiedAppIDFlag(cmd)
preferLegacyLeaf(cmd)
return cmd
}
func newDevAppLifecycleCommand(runner executor.Runner, use, short, tool string) *cobra.Command {
cmd := &cobra.Command{
Use: use,
Short: short,
Args: cobra.NoArgs,
DisableAutoGenTag: true,
RunE: func(cmd *cobra.Command, args []string) error {
if err := devAppRequireWriteGuard(cmd, use); err != nil {
return err
}
params := devAppUnifiedAppIDParams(cmd)
if len(params) == 0 {
return devAppUnifiedAppIDRequired()
}
return runDevAppTool(runner, cmd, tool, params)
},
}
addDevAppUnifiedAppIDFlag(cmd)
preferLegacyLeaf(cmd)
return cmd
}
func newDevAppWebappGetCommand(runner executor.Runner) *cobra.Command {
cmd := &cobra.Command{
Use: "get",
Short: "查询网页应用配置",
Example: " dws devapp webapp get --unified-app-id UNIFIED_APP_ID --format json",
Args: cobra.NoArgs,
DisableAutoGenTag: true,
RunE: func(cmd *cobra.Command, args []string) error {
params := devAppUnifiedAppIDParams(cmd)
if len(params) == 0 {
return devAppUnifiedAppIDRequired()
}
return runDevAppTool(runner, cmd, "get_extension_webapp_config", params)
},
}
addDevAppUnifiedAppIDFlag(cmd)
preferLegacyLeaf(cmd)
return cmd
}
func newDevAppWebappConfigCommand(runner executor.Runner) *cobra.Command {
cmd := &cobra.Command{
Use: "config",
Short: "配置网页应用能力",
Example: " dws devapp webapp config --unified-app-id UNIFIED_APP_ID --homepage-url https://example.com --dry-run --format json",
Args: cobra.NoArgs,
DisableAutoGenTag: true,
RunE: func(cmd *cobra.Command, args []string) error {
if err := devAppRequireWriteGuard(cmd, "webapp config"); err != nil {
return err
}
params := devAppUnifiedAppIDParams(cmd)
if len(params) == 0 {
return devAppUnifiedAppIDRequired()
}
updates := 0
if v := devAppStringFlag(cmd, "h5-page-type"); v != "" {
params["h5PageType"] = v
updates++
}
if v := devAppFlagOrFallback(cmd, "homepage-url", "homepage-link"); v != "" {
params["homepageUrl"] = v
updates++
}
if v := devAppFlagOrFallback(cmd, "pc-homepage-url", "pc-homepage-link"); v != "" {
params["pcHomepageUrl"] = v
updates++
}
if v := devAppFlagOrFallback(cmd, "omp-url", "omp-link"); v != "" {
params["ompUrl"] = v
updates++
}
if updates == 0 {
return apperrors.NewValidation("at least one webapp field is required: --h5-page-type, --homepage-url, --pc-homepage-url, or --omp-url")
}
return runDevAppTool(runner, cmd, "set_extension_webapp_config", params)
},
}
addDevAppUnifiedAppIDFlag(cmd)
cmd.Flags().String("h5-page-type", "", "网页应用生效端/页面类型")
cmd.Flags().String("homepage-url", "", "移动端首页地址")
cmd.Flags().String("homepage-link", "", "--homepage-url 的兼容别名")
_ = cmd.Flags().MarkHidden("homepage-link")
cmd.Flags().String("pc-homepage-url", "", "PC 端首页地址")
cmd.Flags().String("pc-homepage-link", "", "--pc-homepage-url 的兼容别名")
_ = cmd.Flags().MarkHidden("pc-homepage-link")
cmd.Flags().String("omp-url", "", "管理后台地址")
cmd.Flags().String("omp-link", "", "--omp-url 的兼容别名")
_ = cmd.Flags().MarkHidden("omp-link")
preferLegacyLeaf(cmd)
return cmd
}
func newDevAppPermissionListCommand(runner executor.Runner) *cobra.Command {
cmd := &cobra.Command{
Use: "list",
Aliases: []string{"search", "detail"},
Short: "查询开放平台应用权限列表",
Example: " dws devapp permission list --unified-app-id UNIFIED_APP_ID --keyword 通讯录 --page-size 20 --format json",
Args: cobra.NoArgs,
DisableAutoGenTag: true,
RunE: func(cmd *cobra.Command, args []string) error {
params := devAppPermissionLocatorParams(cmd)
if len(params) == 0 {
return devAppPermissionLocatorRequired()
}
devAppPutString(params, "keyword", devAppStringFlag(cmd, "keyword"))
devAppPutString(params, "scopeValue", devAppFlagOrFallback(cmd, "scope", "permission"))
devAppPutString(params, "authStatus", strings.ToUpper(devAppStringFlag(cmd, "status")))
devAppPutString(params, "scopeType", strings.ToUpper(devAppStringFlag(cmd, "scope-type")))
devAppPutString(params, "apiStatus", devAppStringFlag(cmd, "api-status"))
devAppPutString(params, "cursor", devAppStringFlag(cmd, "cursor"))
devAppPutInt(params, "pageSize", devAppIntFlag(cmd, "page-size"))
return runDevAppTool(runner, cmd, "list_dev_app_permissions", params)
},
}
addDevAppPermissionLocatorFlags(cmd)
cmd.Flags().String("keyword", "", "权限名、权限点、接口名关键词")
cmd.Flags().String("scope", "", "精确权限点 scopeValue")
cmd.Flags().String("permission", "", "--scope 的兼容别名")
_ = cmd.Flags().MarkHidden("permission")
cmd.Flags().String("status", "ALL", "权限状态:ALL、AUTHED、UNAUTHED")
cmd.Flags().String("scope-type", "", "权限一级类型:APP 或 SNS")
cmd.Flags().String("api-status", "", "开发者后台 apiStatus 过滤")
cmd.Flags().Int("page-size", 20, "返回数量上限")
cmd.Flags().String("cursor", "", "游标分页 cursor,首次查询为空")
preferLegacyLeaf(cmd)
return cmd
}
func newDevAppPermissionAddCommand(runner executor.Runner) *cobra.Command {
cmd := &cobra.Command{
Use: "add",
Short: "申请开放平台应用权限点",
Example: " dws devapp permission add --unified-app-id UNIFIED_APP_ID --permissions Contact.User.mobile --dry-run --format json",
Args: cobra.NoArgs,
DisableAutoGenTag: true,
RunE: func(cmd *cobra.Command, args []string) error {
if err := devAppRequireWriteGuard(cmd, "permission add"); err != nil {
return err
}
params := devAppPermissionLocatorParams(cmd)
if len(params) == 0 {
return devAppPermissionLocatorRequired()
}
scopes := devAppPermissionScopes(cmd)
if len(scopes) == 0 {
return apperrors.NewValidation("--permissions is required")
}
params["scopeValues"] = scopes
return runDevAppTool(runner, cmd, "apply_dev_app_permissions", params)
},
}
addDevAppPermissionLocatorFlags(cmd)
cmd.Flags().StringSlice("permissions", nil, "权限点 scopeValue,多个用逗号分隔")
cmd.Flags().String("scope", "", "--permissions 的兼容别名,单个权限点 scopeValue")
cmd.Flags().String("permission", "", "--permissions 的兼容别名,单个权限点 scopeValue")
_ = cmd.Flags().MarkHidden("scope")
_ = cmd.Flags().MarkHidden("permission")
preferLegacyLeaf(cmd)
return cmd
}
func newDevAppPermissionRemoveCommand(runner executor.Runner) *cobra.Command {
cmd := &cobra.Command{
Use: "remove",
Short: "取消开放平台应用权限点",
Example: " dws devapp permission remove --unified-app-id UNIFIED_APP_ID --permission Contact.User.mobile --dry-run --format json",
Args: cobra.NoArgs,
DisableAutoGenTag: true,
RunE: func(cmd *cobra.Command, args []string) error {
if err := devAppRequireWriteGuard(cmd, "permission remove"); err != nil {
return err
}
params := devAppPermissionLocatorParams(cmd)
if len(params) == 0 {
return devAppPermissionLocatorRequired()
}
scopes := devAppPermissionRemoveScopes(cmd)
if len(scopes) == 0 {
return apperrors.NewValidation("--permissions is required")
}
params["scopeValues"] = scopes
return runDevAppTool(runner, cmd, "remove_dev_app_permissions", params)
},
}
addDevAppPermissionLocatorFlags(cmd)
cmd.Flags().StringSlice("permissions", nil, "待取消权限点 scopeValue,多个用逗号分隔")
cmd.Flags().String("permission", "", "--permissions 的兼容别名,单个权限点 scopeValue")
cmd.Flags().String("scope", "", "--permissions 的兼容别名,单个权限点 scopeValue")
_ = cmd.Flags().MarkHidden("permission")
_ = cmd.Flags().MarkHidden("scope")
preferLegacyLeaf(cmd)
return cmd
}
func newDevAppMemberListCommand(runner executor.Runner) *cobra.Command {
cmd := &cobra.Command{
Use: "list",
Short: "查询开放平台应用成员",
Example: " dws devapp member list --app-id <unifiedAppId>",
Args: cobra.NoArgs,
DisableAutoGenTag: true,
RunE: func(cmd *cobra.Command, args []string) error {
appID, err := requiredDevAppID(cmd)
if err != nil {
return err
}
return runDevAppTool(runner, cmd, devAppMemberListTool, map[string]any{
"unifiedAppId": appID,
})
},
}
cmd.Flags().String("app-id", "", "开放平台统一应用 ID (必填)")
preferLegacyLeaf(cmd)
return cmd
}
func newDevAppMemberAddCommand(runner executor.Runner) *cobra.Command {
cmd := &cobra.Command{
Use: "add",
Short: "添加开放平台应用成员",
Example: " dws devapp member add --app-id <unifiedAppId> --users userId1,userId2 --member-type DEVELOPER --dry-run",
Args: cobra.NoArgs,
DisableAutoGenTag: true,
RunE: func(cmd *cobra.Command, args []string) error {
return runDevAppMemberMutation(runner, cmd, devAppMemberAddTool, "member add")
},
}
registerDevAppMemberMutationFlags(cmd)
preferLegacyLeaf(cmd)
return cmd
}
func newDevAppMemberRemoveCommand(runner executor.Runner) *cobra.Command {
cmd := &cobra.Command{
Use: "remove",
Short: "移除开放平台应用成员",
Example: " dws devapp member remove --app-id <unifiedAppId> --users userId1,userId2 --member-type DEVELOPER --dry-run",
Args: cobra.NoArgs,
DisableAutoGenTag: true,
RunE: func(cmd *cobra.Command, args []string) error {
return runDevAppMemberMutation(runner, cmd, devAppMemberRemoveTool, "member remove")
},
}
registerDevAppMemberMutationFlags(cmd)
preferLegacyLeaf(cmd)
return cmd
}
func newDevAppSecurityConfigCommand(runner executor.Runner) *cobra.Command {
cmd := &cobra.Command{
Use: "config",
Short: "更新开放平台应用安全配置",
Example: " dws devapp security config --app-id <unifiedAppId> " +
"--ip-whitelist 192.0.2.10 --redirect-url https://callback.example.invalid/callback --sso-url https://sso.example.invalid/sso --dry-run",
Args: cobra.NoArgs,
DisableAutoGenTag: true,
RunE: func(cmd *cobra.Command, args []string) error {
if err := devAppRequireWriteGuard(cmd, "security config"); err != nil {
return err
}
appID, err := requiredDevAppID(cmd)
if err != nil {
return err
}
params := map[string]any{"unifiedAppId": appID}
if values := parseDevAppListFlag(cmd, "ip-whitelist"); len(values) > 0 {
params["ipWhitelist"] = values
}
if values := parseDevAppListFlag(cmd, "redirect-url"); len(values) > 0 {
params["redirectUrls"] = values
}
if values := parseDevAppListFlag(cmd, "sso-url"); len(values) > 0 {
params["ssoUrls"] = values
}
if len(params) == 1 {
return apperrors.NewValidation("one of --ip-whitelist, --redirect-url, or --sso-url is required")
}
return runDevAppTool(runner, cmd, devAppSecurityConfigTool, params)
},
}
cmd.Flags().String("app-id", "", "开放平台统一应用 ID (必填)")
cmd.Flags().String("ip-whitelist", "", "出口 IP 白名单,多个用逗号或分号分隔")
cmd.Flags().String("redirect-url", "", "登录重定向 URL,多个用逗号或分号分隔")
cmd.Flags().String("sso-url", "", "端内免登地址,多个用逗号或分号分隔")
preferLegacyLeaf(cmd)
return cmd
}
// ---------------------------------------------------------------------------
// 机器人能力
// ---------------------------------------------------------------------------
func newDevAppRobotCreateCommand(runner executor.Runner) *cobra.Command {
cmd := &cobra.Command{
Use: "create",
Short: "新建钉钉智能体机器人(一次性同步创建应用+机器人)",
Example: " dws devapp robot create --name 我的智能体 --robot-name 小助手 --desc \"处理审批问答\" --dry-run --format json",
Args: cobra.NoArgs,
DisableAutoGenTag: true,
RunE: func(cmd *cobra.Command, args []string) error {
if err := devAppRequireWriteGuard(cmd, "robot create"); err != nil {
return err
}
params, err := devAppRobotCreateParams(cmd)
if err != nil {
return err
}
return runDevAppTool(runner, cmd, devAppRobotCreateTool, params)
},
}
registerDevAppRobotCreateFlags(cmd)
preferLegacyLeaf(cmd)
return cmd
}
func newDevAppRobotSubmitCommand(runner executor.Runner) *cobra.Command {
cmd := &cobra.Command{
Use: "submit",
Short: "异步提交钉钉智能体机器人创建任务(支持失败重试)",
Example: " dws devapp robot submit --name 我的智能体 --robot-name 小助手 --desc \"处理审批问答\" --dry-run --format json",
Args: cobra.NoArgs,
DisableAutoGenTag: true,
RunE: func(cmd *cobra.Command, args []string) error {
if err := devAppRequireWriteGuard(cmd, "robot submit"); err != nil {
return err
}
params, err := devAppRobotCreateParams(cmd)
if err != nil {
return err
}
devAppPutString(params, "taskId", devAppStringFlag(cmd, "task-id"))
return runDevAppTool(runner, cmd, devAppRobotSubmitTool, params)
},
}
registerDevAppRobotCreateFlags(cmd)
cmd.Flags().String("task-id", "", "失败重试时传入原 taskId;为空时服务端自动生成")
preferLegacyLeaf(cmd)
return cmd
}
func newDevAppRobotResultCommand(runner executor.Runner) *cobra.Command {
cmd := &cobra.Command{
Use: "result",
Short: "查询机器人异步创建任务结果",
Example: " dws devapp robot result --task-id TASK_ID --format json",
Args: cobra.NoArgs,
DisableAutoGenTag: true,
RunE: func(cmd *cobra.Command, args []string) error {
taskID := devAppStringFlag(cmd, "task-id")
if taskID == "" {
return apperrors.NewValidation("--task-id is required")
}
return runDevAppTool(runner, cmd, devAppRobotResultTool, map[string]any{"taskId": taskID})
},
}
cmd.Flags().String("task-id", "", "提交创建任务时返回的 taskId (必填)")
preferLegacyLeaf(cmd)
return cmd
}
func newDevAppRobotConfigGetCommand(runner executor.Runner) *cobra.Command {
cmd := &cobra.Command{
Use: "get",
Short: "查询现有应用的机器人配置",
Example: " dws devapp robot get --unified-app-id UNIFIED_APP_ID --format json",
Args: cobra.NoArgs,
DisableAutoGenTag: true,
RunE: func(cmd *cobra.Command, args []string) error {
appID, err := requiredDevAppUnifiedID(cmd)
if err != nil {
return err
}
return runDevAppTool(runner, cmd, devAppRobotConfigGetTool, map[string]any{"unifiedAppId": appID})
},
}
addDevAppUnifiedIDFlag(cmd)
preferLegacyLeaf(cmd)
return cmd
}
func newDevAppRobotConfigCommand(runner executor.Runner, use, short, tool string) *cobra.Command {
cmd := &cobra.Command{
Use: use,
Short: short,
Example: " dws devapp robot " + use + " --unified-app-id UNIFIED_APP_ID --name 小助手 --brief 审批助手 --dry-run --format json",
Args: cobra.NoArgs,
DisableAutoGenTag: true,
RunE: func(cmd *cobra.Command, args []string) error {
if err := devAppRequireWriteGuard(cmd, "robot "+use); err != nil {
return err
}
appID, err := requiredDevAppUnifiedID(cmd)
if err != nil {
return err
}
params, updates, err := devAppRobotConfigParams(cmd, appID)
if err != nil {
return err
}
if updates == 0 {
return apperrors.NewValidation("at least one robot config field is required, e.g. --name, --brief, --desc, --icon, --outgoing-url, --event-url, --mode, --skills")
}
return runDevAppTool(runner, cmd, tool, params)
},
}
addDevAppUnifiedIDFlag(cmd)
registerDevAppRobotConfigFlags(cmd)
preferLegacyLeaf(cmd)
return cmd
}
func newDevAppRobotEnableCommand(runner executor.Runner) *cobra.Command {
cmd := &cobra.Command{
Use: "enable",
Short: "启用现有应用机器人能力",
Example: " dws devapp robot enable --unified-app-id UNIFIED_APP_ID --dry-run --format json",
Args: cobra.NoArgs,
DisableAutoGenTag: true,
RunE: func(cmd *cobra.Command, args []string) error {
if err := devAppRequireWriteGuard(cmd, "robot enable"); err != nil {
return err
}
appID, err := requiredDevAppUnifiedID(cmd)
if err != nil {
return err
}
return runDevAppTool(runner, cmd, devAppRobotEnableTool, map[string]any{"unifiedAppId": appID})
},
}
addDevAppUnifiedIDFlag(cmd)
preferLegacyLeaf(cmd)
return cmd
}
func newDevAppRobotDisableCommand(runner executor.Runner) *cobra.Command {
cmd := &cobra.Command{
Use: "disable",
Short: "停用现有应用的机器人能力",
Example: " dws devapp robot disable --unified-app-id UNIFIED_APP_ID --dry-run --format json",
Args: cobra.NoArgs,
DisableAutoGenTag: true,
RunE: func(cmd *cobra.Command, args []string) error {
if err := devAppRequireWriteGuard(cmd, "robot disable"); err != nil {
return err
}
appID, err := requiredDevAppUnifiedID(cmd)
if err != nil {
return err
}
return runDevAppTool(runner, cmd, devAppRobotDisableTool, map[string]any{"unifiedAppId": appID})
},
}
addDevAppUnifiedIDFlag(cmd)
preferLegacyLeaf(cmd)
return cmd
}
func registerDevAppRobotCreateFlags(cmd *cobra.Command) {
cmd.Flags().String("name", "", "智能体应用名称,长度 2-20,企业内唯一 (必填)")
cmd.Flags().String("robot-name", "", "承载机器人名称,用于客户端展示 (必填)")
cmd.Flags().String("desc", "", "机器人功能描述,不超过 200 字 (必填)")
cmd.Flags().String("icon", "", "机器人图标 mediaId;为空时使用默认图标")
cmd.Flags().String("preview", "", "机器人预览图 mediaId;为空时复用图标")
}
func devAppRobotCreateParams(cmd *cobra.Command) (map[string]any, error) {
name := devAppStringFlag(cmd, "name")
if name == "" {
return nil, apperrors.NewValidation("--name is required")
}
robotName := devAppStringFlag(cmd, "robot-name")
if robotName == "" {
return nil, apperrors.NewValidation("--robot-name is required")
}
desc := devAppStringFlag(cmd, "desc")
if desc == "" {
return nil, apperrors.NewValidation("--desc is required")
}
params := map[string]any{
"name": name,
"robotName": robotName,
"desc": desc,
}
devAppPutString(params, "iconMediaId", devAppStringFlag(cmd, "icon"))
devAppPutString(params, "previewMediaId", devAppStringFlag(cmd, "preview"))
return params, nil
}
func registerDevAppRobotConfigFlags(cmd *cobra.Command) {
cmd.Flags().String("name", "", "机器人名称")
cmd.Flags().String("brief", "", "机器人简介")
cmd.Flags().String("desc", "", "机器人描述")
cmd.Flags().String("icon", "", "机器人图标 mediaId")
cmd.Flags().String("outgoing-url", "", "消息回调地址 (outgoingUrl)")
cmd.Flags().String("event-url", "", "事件回调地址 (eventCallbackUrl)")
cmd.Flags().Int("mode", 0, "机器人模式枚举")
cmd.Flags().StringSlice("skills", nil, "技能列表,多个用逗号分隔")
cmd.Flags().Bool("add-scope", false, "是否自动添加机器人相关权限")
cmd.Flags().Bool("disable-ssl-verify", false, "回调地址是否关闭 SSL 校验")
cmd.Flags().String("i18n-name", "", "机器人名称国际化 JSON,如 '{\"en_US\":\"Bot\"}'")
cmd.Flags().String("i18n-brief", "", "机器人简介国际化 JSON")
cmd.Flags().String("i18n-description", "", "机器人描述国际化 JSON")
}
func devAppRobotConfigParams(cmd *cobra.Command, appID string) (map[string]any, int, error) {
params := map[string]any{"unifiedAppId": appID}
updates := 0
setString := func(key, flag string) {
if v := devAppStringFlag(cmd, flag); v != "" {
params[key] = v
updates++
}
}
setString("name", "name")
setString("brief", "brief")
setString("desc", "desc")
setString("iconMediaId", "icon")
setString("outgoingUrl", "outgoing-url")
setString("eventCallbackUrl", "event-url")
if cmd.Flags().Changed("mode") {
params["mode"] = devAppIntFlag(cmd, "mode")
updates++
}
if cmd.Flags().Changed("add-scope") {
value, _ := cmd.Flags().GetBool("add-scope")
params["addScope"] = value
updates++
}
if cmd.Flags().Changed("disable-ssl-verify") {
value, _ := cmd.Flags().GetBool("disable-ssl-verify")
params["disableSSLVerify"] = value
updates++
}
if values, _ := cmd.Flags().GetStringSlice("skills"); len(values) > 0 {
params["skills"] = values
updates++
}
for _, item := range []struct{ key, flag string }{
{"i18nName", "i18n-name"},
{"i18nBrief", "i18n-brief"},
{"i18nDescription", "i18n-description"},
} {
raw := devAppStringFlag(cmd, item.flag)
if raw == "" {
continue
}
parsed := map[string]any{}
if err := json.Unmarshal([]byte(raw), &parsed); err != nil {
return nil, 0, apperrors.NewValidation(fmt.Sprintf("--%s must be valid JSON object: %v", item.flag, err))
}
params[item.key] = parsed
updates++
}
return params, updates, nil
}
// ---------------------------------------------------------------------------
// 版本发布能力
// ---------------------------------------------------------------------------
func newDevAppVersionCreateCommand(runner executor.Runner) *cobra.Command {
cmd := &cobra.Command{
Use: "create",
Short: "基于当前配置创建应用新版本",
Example: " dws devapp version create --unified-app-id UNIFIED_APP_ID --version 1.0.1 --desc \"新增机器人能力\" --dry-run --format json",
Args: cobra.NoArgs,
DisableAutoGenTag: true,
RunE: func(cmd *cobra.Command, args []string) error {
if err := devAppRequireWriteGuard(cmd, "version create"); err != nil {
return err
}
appID, err := requiredDevAppUnifiedID(cmd)
if err != nil {
return err
}
params := map[string]any{"unifiedAppId": appID}
devAppPutString(params, "version", devAppStringFlag(cmd, "version"))
devAppPutString(params, "desc", devAppStringFlag(cmd, "desc"))
return runDevAppTool(runner, cmd, devAppVersionCreateTool, params)
},
}
addDevAppUnifiedIDFlag(cmd)
cmd.Flags().String("version", "", "版本号,如 1.0.1")
cmd.Flags().String("desc", "", "版本描述")
preferLegacyLeaf(cmd)
return cmd
}
func newDevAppVersionListCommand(runner executor.Runner) *cobra.Command {
cmd := &cobra.Command{
Use: "list",
Short: "按 cursor 查询应用版本列表",
Example: " dws devapp version list --unified-app-id UNIFIED_APP_ID --page-size 20 --format json\n dws devapp version list --unified-app-id UNIFIED_APP_ID --cursor NEXT_CURSOR --page-size 20 --format json",
Args: cobra.NoArgs,
DisableAutoGenTag: true,
RunE: func(cmd *cobra.Command, args []string) error {
appID, err := requiredDevAppUnifiedID(cmd)
if err != nil {
return err
}
params := map[string]any{
"unifiedAppId": appID,
"pageSize": devAppIntFlag(cmd, "page-size"),
}
devAppPutString(params, "cursor", devAppStringFlag(cmd, "cursor"))
return runDevAppTool(runner, cmd, devAppVersionListTool, params)
},
}
addDevAppUnifiedIDFlag(cmd)
cmd.Flags().String("cursor", "", "服务端返回的不透明分页游标;首次查询留空")
cmd.Flags().Int("page-size", 20, "分页大小")
preferLegacyLeaf(cmd)
return cmd
}
func newDevAppVersionGetCommand(runner executor.Runner) *cobra.Command {
cmd := &cobra.Command{
Use: "get",
Short: "查询指定版本详情",
Example: " dws devapp version get --unified-app-id UNIFIED_APP_ID --version-id VERSION_ID --format json",
Args: cobra.NoArgs,
DisableAutoGenTag: true,
RunE: func(cmd *cobra.Command, args []string) error {
params, err := devAppVersionLocator(cmd)
if err != nil {
return err
}
return runDevAppTool(runner, cmd, devAppVersionDetailTool, params)
},
}
addDevAppVersionLocatorFlags(cmd)
preferLegacyLeaf(cmd)
return cmd
}
func newDevAppVersionCheckApprovalCommand(runner executor.Runner) *cobra.Command {
cmd := &cobra.Command{
Use: "check-approval",
Short: "预检版本发布是否需要审批(不实际发布)",
Example: " dws devapp version check-approval --unified-app-id UNIFIED_APP_ID --version-id VERSION_ID --format json",
Args: cobra.NoArgs,
DisableAutoGenTag: true,
RunE: func(cmd *cobra.Command, args []string) error {
params, err := devAppVersionLocator(cmd)
if err != nil {
return err
}
// 复用 publish 工具的服务端预检模式:precheckOnly=true 只返回审批要求,不发布。
params["precheckOnly"] = true
return runDevAppTool(runner, cmd, devAppVersionPublishTool, params)
},
}
addDevAppVersionLocatorFlags(cmd)
preferLegacyLeaf(cmd)
return cmd
}
func newDevAppVersionPublishCommand(runner executor.Runner) *cobra.Command {
cmd := &cobra.Command{
Use: "publish",
Short: "发布指定版本(含高敏权限需 --confirm-sensitive)",
Example: " dws devapp version publish --unified-app-id UNIFIED_APP_ID --version-id VERSION_ID --dry-run --format json",
Args: cobra.NoArgs,
DisableAutoGenTag: true,
RunE: func(cmd *cobra.Command, args []string) error {
if err := devAppRequireWriteGuard(cmd, "version publish"); err != nil {
return err
}
params, err := devAppVersionLocator(cmd)
if err != nil {
return err
}
params["precheckOnly"] = false
if cmd.Flags().Changed("confirm-sensitive") {
value, _ := cmd.Flags().GetBool("confirm-sensitive")
params["confirmedSensitive"] = value
}
devAppPutString(params, "approverUserId", devAppStringFlag(cmd, "approver"))
return runDevAppTool(runner, cmd, devAppVersionPublishTool, params)
},
}
addDevAppVersionLocatorFlags(cmd)
cmd.Flags().Bool("confirm-sensitive", false, "确认发布包含高敏权限的版本")
cmd.Flags().String("approver", "", "灰度选人模式下指定审批人 userId")
preferLegacyLeaf(cmd)
return cmd
}
func newDevAppVersionStatusCommand(runner executor.Runner) *cobra.Command {
cmd := &cobra.Command{
Use: "status",
Short: "查询版本发布/审批状态",
Example: " dws devapp version status --unified-app-id UNIFIED_APP_ID --version-id VERSION_ID --format json",
Args: cobra.NoArgs,
DisableAutoGenTag: true,
RunE: func(cmd *cobra.Command, args []string) error {
params, err := devAppVersionLocator(cmd)
if err != nil {
return err
}
return runDevAppTool(runner, cmd, devAppVersionStatusTool, params)
},
}
addDevAppVersionLocatorFlags(cmd)
preferLegacyLeaf(cmd)
return cmd
}
func addDevAppVersionLocatorFlags(cmd *cobra.Command) {
addDevAppUnifiedIDFlag(cmd)
cmd.Flags().String("version-id", "", "版本 ID (必填)")
}
func devAppVersionLocator(cmd *cobra.Command) (map[string]any, error) {
appID, err := requiredDevAppUnifiedID(cmd)
if err != nil {
return nil, err
}
versionID := devAppStringFlag(cmd, "version-id")
if versionID == "" {
return nil, apperrors.NewValidation("--version-id is required")
}
return map[string]any{"unifiedAppId": appID, "versionId": versionID}, nil
}
func addDevAppUnifiedIDFlag(cmd *cobra.Command) {
cmd.Flags().String("unified-app-id", "", "统一应用 ID (必填)")
}
func requiredDevAppUnifiedID(cmd *cobra.Command) (string, error) {
appID := devAppStringFlag(cmd, "unified-app-id")
if appID == "" {
return "", apperrors.NewValidation("--unified-app-id is required")
}
return appID, nil
}
// ---------------------------------------------------------------------------
// 事件订阅能力
// ---------------------------------------------------------------------------
func newDevAppEventListCommand(runner executor.Runner) *cobra.Command {
cmd := &cobra.Command{
Use: "list",
Short: "查询应用可订阅事件列表及订阅状态",
Example: " dws devapp event list --unified-app-id UNIFIED_APP_ID --format json",
Args: cobra.NoArgs,
DisableAutoGenTag: true,
RunE: func(cmd *cobra.Command, args []string) error {
appID, err := requiredDevAppUnifiedID(cmd)
if err != nil {
return err
}
return runDevAppTool(runner, cmd, devAppEventListTool, map[string]any{"unifiedAppId": appID})
},
}
addDevAppUnifiedIDFlag(cmd)
preferLegacyLeaf(cmd)
return cmd
}
func newDevAppEventSubscribeCommand(runner executor.Runner, use, short, tool string) *cobra.Command {
cmd := &cobra.Command{
Use: use,
Short: short,
Example: " dws devapp event " + use + " --unified-app-id UNIFIED_APP_ID --event-codes user_add_org,org_dept_modify --dry-run --format json",
Args: cobra.NoArgs,
DisableAutoGenTag: true,
RunE: func(cmd *cobra.Command, args []string) error {
if err := devAppRequireWriteGuard(cmd, "event "+use); err != nil {
return err
}
appID, err := requiredDevAppUnifiedID(cmd)
if err != nil {
return err
}
eventCodes := devAppEventCodes(cmd)
if len(eventCodes) == 0 {
return apperrors.NewValidation("--event-codes is required")
}
return runDevAppTool(runner, cmd, tool, map[string]any{"unifiedAppId": appID, "eventCodes": eventCodes})
},
}
addDevAppUnifiedIDFlag(cmd)
cmd.Flags().StringSlice("event-codes", nil, "事件码列表,多个用逗号分隔 (必填)")
preferLegacyLeaf(cmd)
return cmd
}
func devAppEventCodes(cmd *cobra.Command) []string {
values, _ := cmd.Flags().GetStringSlice("event-codes")
out := make([]string, 0, len(values))
for _, value := range values {
for _, part := range splitDevAppList(value) {
if part != "" {
out = append(out, part)
}
}
}
return out
}
func registerDevAppMemberMutationFlags(cmd *cobra.Command) {
cmd.Flags().String("app-id", "", "开放平台统一应用 ID (必填)")
cmd.Flags().String("users", "", "成员 userId 列表,多个用逗号分隔 (必填)")
cmd.Flags().String("member-type", "", "成员类型,如 DEVELOPER (必填)")
}
func runDevAppMemberMutation(runner executor.Runner, cmd *cobra.Command, tool, operation string) error {
if err := devAppRequireWriteGuard(cmd, operation); err != nil {
return err
}
appID, err := requiredDevAppID(cmd)
if err != nil {
return err
}
users, err := requiredDevAppUsers(cmd)
if err != nil {
return err
}
memberType, err := requiredDevAppMemberType(cmd)
if err != nil {
return err
}
params := map[string]any{
"unifiedAppId": appID,
"memberUserIds": users,
"memberType": memberType,
}
return runDevAppTool(runner, cmd, tool, params)
}
func runDevAppTool(runner executor.Runner, cmd *cobra.Command, tool string, params map[string]any) error {
invocation := executor.NewHelperInvocation(
cobracmd.LegacyCommandPath(cmd),
devAppProduct,
tool,
params,
)
invocation.DryRun = commandDryRun(cmd)
result, err := runner.Run(cmd.Context(), invocation)
if err != nil {
return err
}
result = normalizeDevAppToolResult(tool, normalizeDevAppServiceResult(result))
return writeCommandPayload(cmd, result)
}
func normalizeDevAppServiceResult(result executor.Result) executor.Result {
content, ok := result.Response["content"].(map[string]any)
if !ok {
return result
}
if success, ok := content["success"].(bool); !ok || !success {
return result
}
value, ok := content["result"]
if !ok || value == nil {
return result
}
result.Response["content"] = value
return result
}
func normalizeDevAppToolResult(tool string, result executor.Result) executor.Result {
content, ok := result.Response["content"].(map[string]any)
if !ok {
return result
}
switch tool {
case "remove_dev_app_permissions":
normalizeDevAppScopeValueArray(content, "removedScopeValues")
case devAppDisableTool:
if _, ok := content["disabled"]; !ok {
content["disabled"] = true
}
case devAppEnableTool:
if _, ok := content["enabled"]; !ok {
content["enabled"] = true
}
}
return result
}
func normalizeDevAppScopeValueArray(content map[string]any, key string) {
values, ok := content[key].([]any)
if !ok {
return
}
out := make([]string, 0, len(values))
for _, value := range values {
switch typed := value.(type) {
case string:
if typed != "" {
out = append(out, typed)
}
case map[string]any:
if scopeValue, _ := typed["scopeValue"].(string); scopeValue != "" {
out = append(out, scopeValue)
}
}
}
if len(out) == len(values) {
content[key] = out
}
}
func requiredDevAppID(cmd *cobra.Command) (string, error) {
appID, _ := cmd.Flags().GetString("app-id")
appID = strings.TrimSpace(appID)
if appID == "" {
return "", apperrors.NewValidation("--app-id is required")
}
return appID, nil
}
func requiredDevAppUsers(cmd *cobra.Command) ([]string, error) {
usersRaw, _ := cmd.Flags().GetString("users")
if strings.TrimSpace(usersRaw) == "" {
return nil, apperrors.NewValidation("--users is required")
}
users := splitDevAppList(usersRaw)
if len(users) == 0 {
return nil, apperrors.NewValidation("--users must contain at least one userId")
}
return users, nil
}
func requiredDevAppMemberType(cmd *cobra.Command) (string, error) {
memberType, _ := cmd.Flags().GetString("member-type")
memberType = strings.TrimSpace(memberType)
if memberType == "" {
return "", apperrors.NewValidation("--member-type is required")
}
return memberType, nil
}
func parseDevAppListFlag(cmd *cobra.Command, name string) []string {
raw, _ := cmd.Flags().GetString(name)
return splitDevAppList(raw)
}
func splitDevAppList(raw string) []string {
raw = strings.TrimSpace(raw)
if raw == "" {
return nil
}
raw = strings.ReplaceAll(raw, ";", ",")
parts := strings.Split(raw, ",")
values := make([]string, 0, len(parts))
for _, part := range parts {
if value := strings.TrimSpace(part); value != "" {
values = append(values, value)
}
}
return values
}
func addDevAppUnifiedAppIDFlag(cmd *cobra.Command) {
cmd.Flags().String("unified-app-id", "", "统一应用 ID")
}
func devAppUnifiedAppIDParams(cmd *cobra.Command) map[string]any {
params := map[string]any{}
devAppPutString(params, "unifiedAppId", devAppStringFlag(cmd, "unified-app-id"))
return params
}
func devAppUnifiedAppIDRequired() error {
return apperrors.NewValidation("--unified-app-id is required")
}
func addDevAppPermissionLocatorFlags(cmd *cobra.Command) {
cmd.Flags().String("unified-app-id", "", "统一应用 ID")
}
func devAppPermissionLocatorParams(cmd *cobra.Command) map[string]any {
params := map[string]any{}
devAppPutString(params, "unifiedAppId", devAppStringFlag(cmd, "unified-app-id"))
return params
}
func devAppPermissionLocatorRequired() error {
return apperrors.NewValidation("one app locator is required: --unified-app-id")
}
func devAppRequireWriteGuard(cmd *cobra.Command, operation string) error {
if commandDryRun(cmd) || devAppYes(cmd) {
return nil
}
return apperrors.NewValidation(fmt.Sprintf("%s is a write operation; rerun with --dry-run to preview or --yes after confirmation", operation))
}
func devAppYes(cmd *cobra.Command) bool {
for _, flags := range []*pflag.FlagSet{cmd.Flags(), cmd.InheritedFlags(), cmd.Root().PersistentFlags()} {
if flags == nil || flags.Lookup("yes") == nil {
continue
}
if value, err := flags.GetBool("yes"); err == nil && value {
return true
}
}
return false
}
func devAppPermissionScopes(cmd *cobra.Command) []string {
values, _ := cmd.Flags().GetStringSlice("permissions")
values = append(values, devAppFlagOrFallback(cmd, "scope", "permission"))
out := make([]string, 0, len(values))
for _, value := range values {
for _, part := range splitDevAppList(value) {
if part != "" {
out = append(out, part)
}
}
}
return out
}
func devAppPermissionRemoveScopes(cmd *cobra.Command) []string {
values, _ := cmd.Flags().GetStringSlice("permissions")
values = append(values, devAppFlagOrFallback(cmd, "permission", "scope"))
out := make([]string, 0, len(values))
for _, value := range values {
for _, part := range splitDevAppList(value) {
if part != "" {
out = append(out, part)
}
}
}
return out
}
func devAppStringFlag(cmd *cobra.Command, name string) string {
value, _ := cmd.Flags().GetString(name)
return strings.TrimSpace(value)
}
func devAppIntFlag(cmd *cobra.Command, name string) int {
value, _ := cmd.Flags().GetInt(name)
return value
}
func devAppFlagOrFallback(cmd *cobra.Command, primary, fallback string) string {
if value := devAppStringFlag(cmd, primary); value != "" {
return value
}
return devAppStringFlag(cmd, fallback)
}
func devAppPutString(params map[string]any, key, value string) {
if value != "" {
params[key] = value
}
}
func devAppPutInt(params map[string]any, key string, value int) {
if value != 0 {
params[key] = value
}
}