feat(engine): add project-level command disabling support

Implement disabled commands functionality for projects, including config parsing, engine integration, and i18n support. Allows disabling specific commands per-project via config.

generated by llmgit

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
chenhg5andClaude committed 2026-03-05 14:43:51 +08:00
1 parent d6a3a2253e
commit b07b18e181
5 files changed
+46 -4

No files matched your search

+8
View File
@@ -210,6 +210,11 @@ func main() {
engine.SetBannedWords(cfg.BannedWords)
}
// Wire disabled commands (project-level)
if len(proj.DisabledCommands) > 0 {
engine.SetDisabledCommands(proj.DisabledCommands)
}
// Wire display truncation settings
{
dcfg := core.DisplayCfg{
@@ -577,6 +582,9 @@ func reloadConfig(configPath, projName string, engine *core.Engine) (*core.Confi
// Reload banned words
engine.SetBannedWords(cfg.BannedWords)
// Reload disabled commands
engine.SetDisabledCommands(proj.DisabledCommands)
slog.Info("config reloaded", "project", projName)
return result, nil
}
+2
View File
@@ -183,6 +183,8 @@ level = "info" # debug, info, warn, error
[[projects]]
name = "my-backend"
# quiet = true # Override global quiet for this project / 覆盖全局静默模式
# disabled_commands = ["restart", "upgrade", "cron"] # Disable specific commands for this project
# # 禁用该项目的指定命令
[projects.agent]
type = "claudecode"
+5 -4
View File
@@ -52,10 +52,11 @@ type SpeechConfig struct {
// ProjectConfig binds one agent (with a specific work_dir) to one or more platforms.
type ProjectConfig struct {
Name string `toml:"name"`
Agent AgentConfig `toml:"agent"`
Platforms []PlatformConfig `toml:"platforms"`
Quiet *bool `toml:"quiet,omitempty"` // project-level quiet mode; overrides global setting
Name string `toml:"name"`
Agent AgentConfig `toml:"agent"`
Platforms []PlatformConfig `toml:"platforms"`
Quiet *bool `toml:"quiet,omitempty"` // project-level quiet mode; overrides global setting
DisabledCommands []string `toml:"disabled_commands,omitempty"` // commands to disable for this project (e.g. ["restart", "upgrade"])
}
type AgentConfig struct {
+23
View File
@@ -142,6 +142,8 @@ type Engine struct {
bannedWords []string
bannedMu sync.RWMutex
disabledCmds map[string]bool
// Interactive agent session management
interactiveMu sync.Mutex
interactiveStates map[string]*interactiveState // key = sessionKey
@@ -296,6 +298,22 @@ func (e *Engine) ClearAliases() {
e.aliases = make(map[string]string)
}
// SetDisabledCommands sets the list of command IDs that are disabled for this project.
func (e *Engine) SetDisabledCommands(cmds []string) {
m := make(map[string]bool, len(cmds))
for _, c := range cmds {
c = strings.ToLower(strings.TrimPrefix(c, "/"))
// Resolve alias names to canonical IDs
id := matchPrefix(c, builtinCommands)
if id != "" {
m[id] = true
} else {
m[c] = true
}
}
e.disabledCmds = m
}
// SetBannedWords replaces the banned words list.
func (e *Engine) SetBannedWords(words []string) {
e.bannedMu.Lock()
@@ -1042,6 +1060,11 @@ func (e *Engine) handleCommand(p Platform, msg *Message, raw string) bool {
cmdID := matchPrefix(cmd, builtinCommands)
if cmdID != "" && e.disabledCmds[cmdID] {
e.reply(p, msg.ReplyCtx, fmt.Sprintf(e.i18n.T(MsgCommandDisabled), "/"+cmdID))
return true
}
switch cmdID {
case "new":
e.cmdNew(p, msg, args)
+8
View File
@@ -281,6 +281,7 @@ const (
MsgDeleteNotSupported MsgKey = "delete_not_supported"
MsgBannedWordBlocked MsgKey = "banned_word_blocked"
MsgCommandDisabled MsgKey = "command_disabled"
)
var messages = map[MsgKey]map[Language]string{
@@ -1529,6 +1530,13 @@ var messages = map[MsgKey]map[Language]string{
LangJapanese: "⚠️ 禁止ワードが含まれているため、メッセージがブロックされました。",
LangSpanish: "⚠️ Su mensaje fue bloqueado porque contiene una palabra prohibida.",
},
MsgCommandDisabled: {
LangEnglish: "🚫 Command `%s` is disabled for this project.",
LangChinese: "🚫 命令 `%s` 在当前项目中已被禁用。",
LangTraditionalChinese: "🚫 命令 `%s` 在當前專案中已被停用。",
LangJapanese: "🚫 コマンド `%s` はこのプロジェクトで無効化されています。",
LangSpanish: "🚫 El comando `%s` está deshabilitado para este proyecto.",
},
}
func (i *I18n) T(key MsgKey) string {