From 7ceb6516023de3e9df1546c897444f4705e74571 Mon Sep 17 00:00:00 2001 From: Oscar Date: Tue, 23 Dec 2025 19:43:40 +0800 Subject: [PATCH 1/4] feat(command): persist aliases on rename and apply to runtime filter --- astrbot/core/star/command_management.py | 49 +++++++++++++++++++++++-- 1 file changed, 45 insertions(+), 4 deletions(-) diff --git a/astrbot/core/star/command_management.py b/astrbot/core/star/command_management.py index 190ef2000..3801932b0 100644 --- a/astrbot/core/star/command_management.py +++ b/astrbot/core/star/command_management.py @@ -90,6 +90,7 @@ async def toggle_command(handler_full_name: str, enabled: bool) -> CommandDescri async def rename_command( handler_full_name: str, new_fragment: str, + aliases: list[str] | None = None, ) -> CommandDescriptor: descriptor = _build_descriptor_by_full_name(handler_full_name) if not descriptor: @@ -99,9 +100,24 @@ async def rename_command( if not new_fragment: raise ValueError("指令名不能为空。") + # 校验主指令名 candidate_full = _compose_command(descriptor.parent_signature, new_fragment) if _is_command_in_use(handler_full_name, candidate_full): - raise ValueError("新的指令名已被其他指令占用,请换一个名称。") + raise ValueError(f"指令名 '{candidate_full}' 已被其他指令占用。") + + # 校验别名 + if aliases: + for alias in aliases: + alias = alias.strip() + if not alias: + continue + alias_full = _compose_command(descriptor.parent_signature, alias) + if _is_command_in_use(handler_full_name, alias_full): + raise ValueError(f"别名 '{alias_full}' 已被其他指令占用。") + + existing_cfg = await db_helper.get_command_config(handler_full_name) + merged_extra = dict(existing_cfg.extra_data or {}) if existing_cfg else {} + merged_extra["resolved_aliases"] = aliases or [] config = await db_helper.upsert_command_config( handler_full_name=handler_full_name, @@ -114,7 +130,7 @@ async def rename_command( conflict_key=descriptor.original_command, resolution_strategy="manual_rename", note=None, - extra_data=None, + extra_data=merged_extra, auto_managed=False, ) _bind_descriptor_with_config(descriptor, config) @@ -363,14 +379,27 @@ def _apply_config_to_descriptor( new_fragment, ) + extra = config.extra_data or {} + resolved_aliases = extra.get("resolved_aliases") + if isinstance(resolved_aliases, list): + descriptor.aliases = [str(x) for x in resolved_aliases if str(x).strip()] + def _apply_config_to_runtime( descriptor: CommandDescriptor, config: CommandConfig, ) -> None: descriptor.handler.enabled = config.enabled - if descriptor.filter_ref and descriptor.current_fragment: - _set_filter_fragment(descriptor.filter_ref, descriptor.current_fragment) + if descriptor.filter_ref: + if descriptor.current_fragment: + _set_filter_fragment(descriptor.filter_ref, descriptor.current_fragment) + extra = config.extra_data or {} + resolved_aliases = extra.get("resolved_aliases") + if isinstance(resolved_aliases, list): + _set_filter_aliases( + descriptor.filter_ref, + [str(x) for x in resolved_aliases if str(x).strip()], + ) def _bind_configs_to_descriptors( @@ -409,6 +438,18 @@ def _set_filter_fragment( filter_ref._cmpl_cmd_names = None +def _set_filter_aliases( + filter_ref: CommandFilter | CommandGroupFilter, + aliases: list[str], +) -> None: + current_aliases = getattr(filter_ref, "alias", set()) + if set(aliases) == current_aliases: + return + setattr(filter_ref, "alias", set(aliases)) + if hasattr(filter_ref, "_cmpl_cmd_names"): + filter_ref._cmpl_cmd_names = None + + def _is_command_in_use( target_handler_full_name: str, candidate_full_command: str, From af21ad2dec37b016d31c506364e03f7588689a97 Mon Sep 17 00:00:00 2001 From: Oscar Date: Tue, 23 Dec 2025 19:44:41 +0800 Subject: [PATCH 2/4] feat(dashboard-api): support aliases in rename command endpoint --- astrbot/dashboard/routes/command.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/astrbot/dashboard/routes/command.py b/astrbot/dashboard/routes/command.py index 5cb267169..abd38d886 100644 --- a/astrbot/dashboard/routes/command.py +++ b/astrbot/dashboard/routes/command.py @@ -61,12 +61,13 @@ async def rename_command(self): data = await request.get_json() handler_full_name = data.get("handler_full_name") new_name = data.get("new_name") + aliases = data.get("aliases") if not handler_full_name or not new_name: return Response().error("handler_full_name 与 new_name 均为必填。").__dict__ try: - await rename_command_service(handler_full_name, new_name) + await rename_command_service(handler_full_name, new_name, aliases=aliases) except ValueError as exc: return Response().error(str(exc)).__dict__ From ab9eacd557fc490b945e5c95f48abd24f5b694f1 Mon Sep 17 00:00:00 2001 From: Oscar Date: Tue, 23 Dec 2025 19:46:11 +0800 Subject: [PATCH 3/4] feat(dashboard-ui): add alias editor to rename command dialog --- .../components/RenameDialog.vue | 75 ++++++++++++++++++- .../composables/useCommandActions.ts | 5 +- .../extension/componentPanel/index.vue | 2 + .../extension/componentPanel/types.ts | 1 + .../i18n/locales/en-US/features/command.json | 2 + .../i18n/locales/zh-CN/features/command.json | 2 + 6 files changed, 85 insertions(+), 2 deletions(-) diff --git a/dashboard/src/components/extension/componentPanel/components/RenameDialog.vue b/dashboard/src/components/extension/componentPanel/components/RenameDialog.vue index ffdc5a826..c2e148698 100644 --- a/dashboard/src/components/extension/componentPanel/components/RenameDialog.vue +++ b/dashboard/src/components/extension/componentPanel/components/RenameDialog.vue @@ -1,14 +1,16 @@