From bbf66e23d6d0bfb3bd6b48174b5936b5a354c12d Mon Sep 17 00:00:00 2001 From: xuan Date: Mon, 20 Apr 2026 14:54:57 +0800 Subject: [PATCH 1/3] fix(pat): avoid shared PAT command state in root registration (#129) * chore: remove workspace and bundled artifacts * chore: clean local-only repository artifacts * fix(pat): avoid shared command state in registration --- internal/pat/chmod.go | 116 +++++++++++++++++++++--------------------- internal/pat/pat.go | 5 +- 2 files changed, 60 insertions(+), 61 deletions(-) diff --git a/internal/pat/chmod.go b/internal/pat/chmod.go index 09ada075..7d75880a 100644 --- a/internal/pat/chmod.go +++ b/internal/pat/chmod.go @@ -32,10 +32,11 @@ var validGrantTypes = map[string]bool{ "permanent": true, } -var chmodCmd = &cobra.Command{ - Use: "chmod ...", - Short: "授予指定权限", - Long: `授予指定 scope 的操作权限。 +func newChmodCommand(caller edition.ToolCaller) *cobra.Command { + chmodCmd := &cobra.Command{ + Use: "chmod ...", + Short: "授予指定权限", + Long: `授予指定 scope 的操作权限。 scope 格式: .: 例: aitable.record:read chat.group:write calendar.event:read @@ -44,71 +45,72 @@ grantType 规则: once 一次性,执行一次后自动失效 session 当前会话有效(默认),需要 --session-id permanent 永久有效`, - Args: cobra.MinimumNArgs(1), - Example: ` dws pat chmod aitable.record:read --agentCode agt-xxxx --grant-type session --session-id session-xxx + Args: cobra.MinimumNArgs(1), + Example: ` dws pat chmod aitable.record:read --agentCode agt-xxxx --grant-type session --session-id session-xxx dws pat chmod chat.message:list --grant-type once --agentCode agt-xxxx dws pat chmod aitable.record:read aitable.record:write --agentCode agt-xxxx --grant-type permanent`, - RunE: func(cmd *cobra.Command, args []string) error { - agentCode, _ := cmd.Flags().GetString("agentCode") - if agentCode == "" { - return fmt.Errorf("flag --agentCode is required\n hint: dws pat chmod ... --agentCode ") - } - scopes := args - grantType, _ := cmd.Flags().GetString("grant-type") - sessionID, _ := cmd.Flags().GetString("session-id") - - if !validGrantTypes[grantType] { - return fmt.Errorf("invalid --grant-type %q, must be one of: once, session, permanent", grantType) - } - - if grantType == "session" && sessionID == "" && os.Getenv("DWS_SESSION_ID") == "" { - return fmt.Errorf("--session-id is required when --grant-type is session\n hint: dws pat chmod --agentCode --grant-type session --session-id ") - } - - if caller != nil && caller.DryRun() { - bold := color.New(color.FgYellow, color.Bold) - bold.Println("[DRY-RUN] Preview only, not executed:") - fmt.Printf("%-16s%s\n", "Tool:", "个人授权") - fmt.Printf("%-16s%s\n", "AgentCode:", agentCode) - fmt.Printf("%-16s%v\n", "Scope:", scopes) - fmt.Printf("%-16s%s\n", "GrantType:", grantType) - if sessionID != "" { - fmt.Printf("%-16s%s\n", "SessionID:", sessionID) + RunE: func(cmd *cobra.Command, args []string) error { + agentCode, _ := cmd.Flags().GetString("agentCode") + if agentCode == "" { + return fmt.Errorf("flag --agentCode is required\n hint: dws pat chmod ... --agentCode ") } - return nil - } + scopes := args + grantType, _ := cmd.Flags().GetString("grant-type") + sessionID, _ := cmd.Flags().GetString("session-id") - if caller == nil { - return fmt.Errorf("internal error: tool runtime not initialized") - } + if !validGrantTypes[grantType] { + return fmt.Errorf("invalid --grant-type %q, must be one of: once, session, permanent", grantType) + } - toolArgs := map[string]any{ - "agentCode": agentCode, - "scope": scopes, - "grantType": grantType, - } - if sessionID == "" { - sessionID = os.Getenv("DWS_SESSION_ID") - } - if sessionID != "" { - toolArgs["sessionId"] = sessionID - } + if grantType == "session" && sessionID == "" && os.Getenv("DWS_SESSION_ID") == "" { + return fmt.Errorf("--session-id is required when --grant-type is session\n hint: dws pat chmod --agentCode --grant-type session --session-id ") + } - ctx := context.Background() - result, err := caller.CallTool(ctx, "pat", "个人授权", toolArgs) - if err != nil { - return fmt.Errorf("pat chmod failed: %w", err) - } + if caller != nil && caller.DryRun() { + bold := color.New(color.FgYellow, color.Bold) + bold.Println("[DRY-RUN] Preview only, not executed:") + fmt.Printf("%-16s%s\n", "Tool:", "个人授权") + fmt.Printf("%-16s%s\n", "AgentCode:", agentCode) + fmt.Printf("%-16s%v\n", "Scope:", scopes) + fmt.Printf("%-16s%s\n", "GrantType:", grantType) + if sessionID != "" { + fmt.Printf("%-16s%s\n", "SessionID:", sessionID) + } + return nil + } - return handleToolResult(result) - }, -} + if caller == nil { + return fmt.Errorf("internal error: tool runtime not initialized") + } + + toolArgs := map[string]any{ + "agentCode": agentCode, + "scope": scopes, + "grantType": grantType, + } + if sessionID == "" { + sessionID = os.Getenv("DWS_SESSION_ID") + } + if sessionID != "" { + toolArgs["sessionId"] = sessionID + } + + ctx := context.Background() + result, err := caller.CallTool(ctx, "pat", "个人授权", toolArgs) + if err != nil { + return fmt.Errorf("pat chmod failed: %w", err) + } + + return handleToolResult(result) + }, + } -func init() { chmodCmd.Flags().String("agentCode", "", "Agent 唯一标识(必填)") _ = chmodCmd.MarkFlagRequired("agentCode") chmodCmd.Flags().String("grant-type", "session", "授权策略: once|session|permanent") chmodCmd.Flags().String("session-id", "", "会话标识(session 模式下必填)") + + return chmodCmd } // handleToolResult processes a ToolResult and writes output to stdout. diff --git a/internal/pat/pat.go b/internal/pat/pat.go index 90cc4498..1907dc01 100644 --- a/internal/pat/pat.go +++ b/internal/pat/pat.go @@ -22,11 +22,8 @@ import ( "github.com/DingTalk-Real-AI/dingtalk-workspace-cli/pkg/edition" ) -var caller edition.ToolCaller - // RegisterCommands adds the pat command tree to rootCmd. func RegisterCommands(root *cobra.Command, c edition.ToolCaller) { - caller = c patCmd := &cobra.Command{ Use: "pat", Short: "行为授权管理", @@ -37,6 +34,6 @@ func RegisterCommands(root *cobra.Command, c edition.ToolCaller) { RunE: cmdutil.GroupRunE, } - patCmd.AddCommand(chmodCmd) + patCmd.AddCommand(newChmodCommand(c)) root.AddCommand(patCmd) } From a5bede3a19fa6f5277783dd48c2f2bb22fb69c03 Mon Sep 17 00:00:00 2001 From: ybcstudy <163094287+ybcstudy@users.noreply.github.com> Date: Mon, 20 Apr 2026 19:38:39 +0800 Subject: [PATCH 2/3] =?UTF-8?q?fix:=20-f=20json=E6=A8=A1=E5=BC=8F=E4=B8=8B?= =?UTF-8?q?=E9=94=99=E8=AF=AFJSON=E4=BB=8Estdout=E6=94=B9=E4=B8=BA?= =?UTF-8?q?=E8=BE=93=E5=87=BA=E5=88=B0stderr=20(#133)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 修复背景: CI测试脚本通过检查stderr中是否包含错误关键词来判断命令是否失败。 但-f json模式下,printExecutionError将错误JSON输出到stdout, 导致stderr为空,测试断言失败。 改动: - root.go:150: apperrors.PrintJSON(stdout, err) → apperrors.PrintJSON(stderr, err) - root_execute_test.go: 3处断言方向同步调整(stdout↔stderr) 影响范围: 仅影响-f json模式下的错误输出流向,正常输出不受影响。 符合Unix惯例:错误信息输出到stderr,正常结果输出到stdout。 Co-authored-by: 猷诺 --- internal/app/root.go | 2 +- internal/app/root_execute_test.go | 24 ++++++++++++------------ 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/internal/app/root.go b/internal/app/root.go index c64d97a0..2a036ad2 100644 --- a/internal/app/root.go +++ b/internal/app/root.go @@ -147,7 +147,7 @@ func printExecutionError(root *cobra.Command, stdout, stderr io.Writer, err erro return writeErr } if wantsJSONErrors(root) { - return apperrors.PrintJSON(stdout, err) + return apperrors.PrintJSON(stderr, err) } return apperrors.PrintHumanAt(stderr, err, resolveVerbosity(root)) } diff --git a/internal/app/root_execute_test.go b/internal/app/root_execute_test.go index 6ed41bd4..c4f184a2 100644 --- a/internal/app/root_execute_test.go +++ b/internal/app/root_execute_test.go @@ -51,11 +51,11 @@ func TestPrintExecutionErrorDefaultsToJSON(t *testing.T) { if err != nil { t.Fatalf("printExecutionError() error = %v", err) } - if stderr.Len() != 0 { - t.Fatalf("stderr = %q, want empty for JSON error output", stderr.String()) + if stdout.Len() != 0 { + t.Fatalf("stdout = %q, want empty when errors go to stderr", stdout.String()) } - if !strings.Contains(stdout.String(), "\"category\": \"validation\"") { - t.Fatalf("stdout = %q, want JSON error payload", stdout.String()) + if !strings.Contains(stderr.String(), "\"category\": \"validation\"") { + t.Fatalf("stderr = %q, want JSON error payload", stderr.String()) } } @@ -73,11 +73,11 @@ func TestPrintExecutionErrorUsesJSONWhenFormatIsJSON(t *testing.T) { if err != nil { t.Fatalf("printExecutionError() error = %v", err) } - if stderr.Len() != 0 { - t.Fatalf("stderr = %q, want empty for JSON error output", stderr.String()) + if stdout.Len() != 0 { + t.Fatalf("stdout = %q, want empty when errors go to stderr", stdout.String()) } - if !strings.Contains(stdout.String(), "\"category\": \"validation\"") { - t.Fatalf("stdout = %q, want JSON error payload", stdout.String()) + if !strings.Contains(stderr.String(), "\"category\": \"validation\"") { + t.Fatalf("stderr = %q, want JSON error payload", stderr.String()) } } @@ -105,11 +105,11 @@ func TestPrintExecutionErrorUsesJSONWhenCommandSetsJSONFlag(t *testing.T) { if err != nil { t.Fatalf("printExecutionError() error = %v", err) } - if stderr.Len() != 0 { - t.Fatalf("stderr = %q, want empty for JSON error output", stderr.String()) + if stdout.Len() != 0 { + t.Fatalf("stdout = %q, want empty when errors go to stderr", stdout.String()) } - if !strings.Contains(stdout.String(), "\"category\": \"validation\"") { - t.Fatalf("stdout = %q, want JSON error payload", stdout.String()) + if !strings.Contains(stderr.String(), "\"category\": \"validation\"") { + t.Fatalf("stderr = %q, want JSON error payload", stderr.String()) } } From 383aeefaf638d3e5aad98e987641f9a051c0ebf7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=BF=AE=E9=9B=A8?= <47820304+PeterGuy326@users.noreply.github.com> Date: Mon, 20 Apr 2026 20:51:07 +0800 Subject: [PATCH 3/3] fix(cli): localize plugin/help command strings via i18n (closes #118) (#134) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Wire plugin module + help command + OAuth client-id/secret flags through the existing i18n catalog so --help is consistent Chinese under zh locale and English under en locale, instead of mixing the two. - internal/app/plugin_cmd.go: wrap 16 Short strings with i18n.T - internal/app/flags.go: wrap --client-id/--client-secret descriptions - internal/app/root_help.go: override cobra default help command with a localized one so "dws help --help" and the utility-commands listing share the same catalog - internal/i18n/locales/{en,zh}.json: add 20 new catalog entries Verified under DWS_LANG=zh (all Chinese), DWS_LANG=en (original English preserved), and LANG-based auto-routing. go test ./internal/app/... pass. Co-authored-by: 修雨 Co-authored-by: Claude Opus 4.7 --- internal/app/flags.go | 5 +++-- internal/app/plugin_cmd.go | 33 +++++++++++++++++---------------- internal/app/root_help.go | 21 +++++++++++++++++++++ internal/i18n/locales/en.json | 22 +++++++++++++++++++++- internal/i18n/locales/zh.json | 22 +++++++++++++++++++++- 5 files changed, 83 insertions(+), 20 deletions(-) diff --git a/internal/app/flags.go b/internal/app/flags.go index bcdc3f05..c9a15164 100644 --- a/internal/app/flags.go +++ b/internal/app/flags.go @@ -14,6 +14,7 @@ package app import ( + "github.com/DingTalk-Real-AI/dingtalk-workspace-cli/internal/i18n" "github.com/spf13/cobra" ) @@ -35,8 +36,8 @@ type GlobalFlags struct { } func bindPersistentFlags(cmd *cobra.Command, flags *GlobalFlags) { - cmd.PersistentFlags().StringVar(&flags.ClientID, "client-id", "", "Override OAuth client ID (DingTalk AppKey)") - cmd.PersistentFlags().StringVar(&flags.ClientSecret, "client-secret", "", "Override OAuth client secret (DingTalk AppSecret)") + cmd.PersistentFlags().StringVar(&flags.ClientID, "client-id", "", i18n.T("覆盖 OAuth 客户端 ID (钉钉 AppKey)")) + cmd.PersistentFlags().StringVar(&flags.ClientSecret, "client-secret", "", i18n.T("覆盖 OAuth 客户端密钥 (钉钉 AppSecret)")) cmd.PersistentFlags().BoolVar(&flags.Debug, "debug", false, "显示调试日志") cmd.PersistentFlags().BoolVar(&flags.DryRun, "dry-run", false, "预览操作内容,不实际执行") cmd.PersistentFlags().StringVar(&flags.Fields, "fields", "", "筛选输出字段 (逗号分隔, 如: name,id,status)") diff --git a/internal/app/plugin_cmd.go b/internal/app/plugin_cmd.go index b0a2880a..36a3539b 100644 --- a/internal/app/plugin_cmd.go +++ b/internal/app/plugin_cmd.go @@ -20,13 +20,14 @@ import ( "strings" apperrors "github.com/DingTalk-Real-AI/dingtalk-workspace-cli/internal/errors" + "github.com/DingTalk-Real-AI/dingtalk-workspace-cli/internal/i18n" "github.com/DingTalk-Real-AI/dingtalk-workspace-cli/internal/output" "github.com/DingTalk-Real-AI/dingtalk-workspace-cli/internal/plugin" "github.com/spf13/cobra" ) func newPluginCommand() *cobra.Command { - pluginCmd := newPlaceholderParent("plugin", "Manage plugins") + pluginCmd := newPlaceholderParent("plugin", i18n.T("插件管理")) pluginCmd.AddCommand( newPluginListCommand(), @@ -48,7 +49,7 @@ func newPluginCommand() *cobra.Command { func newPluginListCommand() *cobra.Command { cmd := &cobra.Command{ Use: "list", - Short: "List installed plugins", + Short: i18n.T("列出已安装的插件"), DisableAutoGenTag: true, RunE: func(cmd *cobra.Command, args []string) error { loader := plugin.NewLoader(RawVersion()) @@ -82,7 +83,7 @@ func newPluginListCommand() *cobra.Command { func newPluginInstallCommand() *cobra.Command { cmd := &cobra.Command{ Use: "install", - Short: "Install a plugin", + Short: i18n.T("安装插件"), Example: ` dws plugin install --dir ./conference dws plugin install --git https://github.com/DingTalk-Real-AI/conference.git`, DisableAutoGenTag: true, @@ -122,7 +123,7 @@ func newPluginInstallCommand() *cobra.Command { func newPluginInfoCommand() *cobra.Command { return &cobra.Command{ Use: "info ", - Short: "Show plugin details", + Short: i18n.T("查看插件详情"), Args: cobra.ExactArgs(1), DisableAutoGenTag: true, RunE: func(cmd *cobra.Command, args []string) error { @@ -152,7 +153,7 @@ func newPluginInfoCommand() *cobra.Command { func newPluginEnableCommand() *cobra.Command { return &cobra.Command{ Use: "enable ", - Short: "Enable a plugin", + Short: i18n.T("启用插件"), Args: cobra.ExactArgs(1), DisableAutoGenTag: true, RunE: func(cmd *cobra.Command, args []string) error { @@ -169,7 +170,7 @@ func newPluginEnableCommand() *cobra.Command { func newPluginDisableCommand() *cobra.Command { return &cobra.Command{ Use: "disable ", - Short: "Disable a plugin", + Short: i18n.T("禁用插件"), Args: cobra.ExactArgs(1), DisableAutoGenTag: true, RunE: func(cmd *cobra.Command, args []string) error { @@ -186,7 +187,7 @@ func newPluginDisableCommand() *cobra.Command { func newPluginRemoveCommand() *cobra.Command { cmd := &cobra.Command{ Use: "remove ", - Short: "Remove an installed plugin", + Short: i18n.T("卸载已安装的插件"), Args: cobra.ExactArgs(1), DisableAutoGenTag: true, RunE: func(cmd *cobra.Command, args []string) error { @@ -208,7 +209,7 @@ func newPluginRemoveCommand() *cobra.Command { func newPluginValidateCommand() *cobra.Command { return &cobra.Command{ Use: "validate ", - Short: "Validate a plugin.json", + Short: i18n.T("校验 plugin.json"), Args: cobra.ExactArgs(1), DisableAutoGenTag: true, RunE: func(cmd *cobra.Command, args []string) error { @@ -229,7 +230,7 @@ func newPluginValidateCommand() *cobra.Command { func newPluginCreateCommand() *cobra.Command { cmd := &cobra.Command{ Use: "create ", - Short: "Scaffold a new plugin directory", + Short: i18n.T("脚手架生成新插件目录"), Example: ` dws plugin create my-tool dws plugin create my-tool --description "My awesome tool"`, Args: cobra.ExactArgs(1), @@ -351,7 +352,7 @@ Use this skill when the user mentions: func newPluginDevCommand() *cobra.Command { cmd := &cobra.Command{ Use: "dev ", - Short: "Register a local directory as a dev plugin", + Short: i18n.T("将本地目录注册为开发态插件"), Long: `Registers a plugin from a local source directory for development. The plugin is loaded directly from the source directory on next CLI invocation, without copying files to ~/.dws/plugins/. Use 'dws plugin dev --off ' @@ -405,7 +406,7 @@ to unregister.`, } func newPluginConfigCommand() *cobra.Command { - configCmd := newPlaceholderParent("config", "Manage plugin configuration") + configCmd := newPlaceholderParent("config", i18n.T("管理插件配置")) configCmd.AddCommand( newPluginConfigSetCommand(), newPluginConfigGetCommand(), @@ -418,7 +419,7 @@ func newPluginConfigCommand() *cobra.Command { func newPluginConfigSetCommand() *cobra.Command { return &cobra.Command{ Use: "set ", - Short: "Set a plugin config value", + Short: i18n.T("设置插件配置项"), Long: `Persistently set a configuration value for a plugin. The value is stored in ~/.dws/settings.json and automatically injected as an environment variable when the plugin is loaded. @@ -456,7 +457,7 @@ over values stored in settings.json.`, func newPluginConfigGetCommand() *cobra.Command { return &cobra.Command{ Use: "get ", - Short: "Get a plugin config value", + Short: i18n.T("读取插件配置项"), Args: cobra.ExactArgs(2), DisableAutoGenTag: true, RunE: func(cmd *cobra.Command, args []string) error { @@ -477,7 +478,7 @@ func newPluginConfigGetCommand() *cobra.Command { func newPluginConfigListCommand() *cobra.Command { cmd := &cobra.Command{ Use: "list ", - Short: "List all config values for a plugin", + Short: i18n.T("列出插件所有配置项"), Args: cobra.ExactArgs(1), DisableAutoGenTag: true, RunE: func(cmd *cobra.Command, args []string) error { @@ -562,7 +563,7 @@ func newPluginConfigListCommand() *cobra.Command { func newPluginConfigUnsetCommand() *cobra.Command { return &cobra.Command{ Use: "unset ", - Short: "Remove a plugin config value", + Short: i18n.T("删除插件配置项"), Args: cobra.ExactArgs(2), DisableAutoGenTag: true, RunE: func(cmd *cobra.Command, args []string) error { @@ -606,7 +607,7 @@ func maskSensitiveValue(value string) string { func newPluginBuildCommand() *cobra.Command { return &cobra.Command{ Use: "build ", - Short: "Build plugin's stdio server into a native binary", + Short: i18n.T("将插件 stdio server 编译为原生二进制"), Long: `Runs the build command declared in plugin.json to compile the plugin's server into a single executable. This ensures plugin users don't need any language runtime (Node.js, Python, etc.) installed. diff --git a/internal/app/root_help.go b/internal/app/root_help.go index e55ed7f5..2380dea7 100644 --- a/internal/app/root_help.go +++ b/internal/app/root_help.go @@ -5,6 +5,7 @@ import ( "strings" "text/tabwriter" + "github.com/DingTalk-Real-AI/dingtalk-workspace-cli/internal/i18n" "github.com/DingTalk-Real-AI/dingtalk-workspace-cli/pkg/edition" "github.com/spf13/cobra" ) @@ -14,6 +15,26 @@ func configureRootHelp(root *cobra.Command) { return } + // Replace the cobra-default English help command with a localized one so + // that both its listing short (shown in `dws --help`) and its own + // `dws help --help` long text follow the active locale. + root.SetHelpCommand(&cobra.Command{ + Use: "help [command]", + Short: i18n.T("查看任意命令的帮助信息"), + Long: i18n.T("显示任意命令的帮助文案。\n" + + "用法:dws help [命令路径] 查看完整说明。"), + DisableAutoGenTag: true, + Run: func(c *cobra.Command, args []string) { + target, _, err := c.Root().Find(args) + if target == nil || err != nil { + c.Root().HelpFunc()(c.Root(), args) + return + } + target.InitDefaultHelpFlag() + _ = target.Help() + }, + }) + defaultHelpFunc := root.HelpFunc() root.SetHelpFunc(func(cmd *cobra.Command, args []string) { if cmd != root { diff --git a/internal/i18n/locales/en.json b/internal/i18n/locales/en.json index 972d3433..df9e6550 100644 --- a/internal/i18n/locales/en.json +++ b/internal/i18n/locales/en.json @@ -170,5 +170,25 @@ "等待提交申请中": "Waiting to submit request", "操作超时,请重新登录": "Operation timed out, please re-login", "检查组织 CLI 授权状态...": "Checking organization CLI auth status...", - "🔐 登录钉钉": "🔐 Login to DingTalk" + "🔐 登录钉钉": "🔐 Login to DingTalk", + "插件管理": "Manage plugins", + "列出已安装的插件": "List installed plugins", + "安装插件": "Install a plugin", + "查看插件详情": "Show plugin details", + "启用插件": "Enable a plugin", + "禁用插件": "Disable a plugin", + "卸载已安装的插件": "Remove an installed plugin", + "校验 plugin.json": "Validate a plugin.json", + "脚手架生成新插件目录": "Scaffold a new plugin directory", + "将本地目录注册为开发态插件": "Register a local directory as a dev plugin", + "管理插件配置": "Manage plugin configuration", + "设置插件配置项": "Set a plugin config value", + "读取插件配置项": "Get a plugin config value", + "列出插件所有配置项": "List all config values for a plugin", + "删除插件配置项": "Remove a plugin config value", + "将插件 stdio server 编译为原生二进制": "Build plugin's stdio server into a native binary", + "覆盖 OAuth 客户端 ID (钉钉 AppKey)": "Override OAuth client ID (DingTalk AppKey)", + "覆盖 OAuth 客户端密钥 (钉钉 AppSecret)": "Override OAuth client secret (DingTalk AppSecret)", + "查看任意命令的帮助信息": "Help about any command", + "显示任意命令的帮助文案。\n用法:dws help [命令路径] 查看完整说明。": "Help provides help for any command in the application.\nSimply type dws help [path to command] for full details." } diff --git a/internal/i18n/locales/zh.json b/internal/i18n/locales/zh.json index 6143a97e..e4b933dd 100644 --- a/internal/i18n/locales/zh.json +++ b/internal/i18n/locales/zh.json @@ -170,5 +170,25 @@ "等待提交申请中": "等待提交申请中", "操作超时,请重新登录": "操作超时,请重新登录", "检查组织 CLI 授权状态...": "检查组织 CLI 授权状态...", - "🔐 登录钉钉": "🔐 登录钉钉" + "🔐 登录钉钉": "🔐 登录钉钉", + "插件管理": "插件管理", + "列出已安装的插件": "列出已安装的插件", + "安装插件": "安装插件", + "查看插件详情": "查看插件详情", + "启用插件": "启用插件", + "禁用插件": "禁用插件", + "卸载已安装的插件": "卸载已安装的插件", + "校验 plugin.json": "校验 plugin.json", + "脚手架生成新插件目录": "脚手架生成新插件目录", + "将本地目录注册为开发态插件": "将本地目录注册为开发态插件", + "管理插件配置": "管理插件配置", + "设置插件配置项": "设置插件配置项", + "读取插件配置项": "读取插件配置项", + "列出插件所有配置项": "列出插件所有配置项", + "删除插件配置项": "删除插件配置项", + "将插件 stdio server 编译为原生二进制": "将插件 stdio server 编译为原生二进制", + "覆盖 OAuth 客户端 ID (钉钉 AppKey)": "覆盖 OAuth 客户端 ID (钉钉 AppKey)", + "覆盖 OAuth 客户端密钥 (钉钉 AppSecret)": "覆盖 OAuth 客户端密钥 (钉钉 AppSecret)", + "查看任意命令的帮助信息": "查看任意命令的帮助信息", + "显示任意命令的帮助文案。\n用法:dws help [命令路径] 查看完整说明。": "显示任意命令的帮助文案。\n用法:dws help [命令路径] 查看完整说明。" }