Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
56 changes: 46 additions & 10 deletions ncatbot/cli/commands/init.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,28 +3,30 @@
import getpass
import re
from pathlib import Path
from typing import Optional

import click
import yaml

from ..utils.colors import success, warning, info


@click.command()
@click.option("--dir", "target_dir", default=".", help="目标目录")
def init(target_dir: str):
"""初始化 NcatBot 项目(创建 config.yaml + plugins/ + 模板插件)"""
def ensure_project_initialized(target_dir: str = ".") -> Optional[Path]:
"""确保项目基础结构存在,必要时执行交互式初始化。

返回创建/确认后的 config.yaml 路径;若用户取消初始化则返回 None。
"""
target = Path(target_dir).resolve()
config_path = target / "config.yaml"
plugins_path = target / "plugins"

if config_path.exists():
click.echo(warning(f"config.yaml 已存在: {config_path}"))
if not click.confirm("是否覆盖?"):
click.echo(info("已跳过 config.yaml"))
_ensure_plugins_dir(plugins_path)
_generate_template_plugin(plugins_path)
return
_ensure_plugins_dir(plugins_path)
_generate_template_plugin(plugins_path)
return config_path
Comment on lines 23 to +26
Copy link

Copilot AI Mar 22, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ensure_project_initialized 在 config 已存在时也会无条件生成模板插件(_generate_template_plugin)。这会导致 ncatbot run/dev 仅仅启动机器人也可能在工作目录写入新插件文件,属于比较意外的副作用。建议将“确保 plugins/ 存在”和“生成模板插件”拆分,或仅在显式 init 命令中生成模板插件。

Copilot uses AI. Check for mistakes.

click.echo(warning(f"未检测到 config.yaml: {config_path}"))
click.echo(info("将执行初始化流程。"))

bot_uin = click.prompt("请输入机器人 QQ 号", type=str)
root = click.prompt("请输入管理员 QQ 号", type=str)
Expand All @@ -44,6 +46,40 @@ def init(target_dir: str):
click.echo(success(f"config.yaml 已创建: {config_path}"))
_ensure_plugins_dir(plugins_path)
_generate_template_plugin(plugins_path)
return config_path


@click.command()
@click.option("--dir", "target_dir", default=".", help="目标目录")
def init(target_dir: str):
"""初始化 NcatBot 项目(创建 config.yaml + plugins/ + 模板插件)"""
target = Path(target_dir).resolve()
config_path = target / "config.yaml"

if config_path.exists():
click.echo(warning(f"config.yaml 已存在: {config_path}"))
if click.confirm("是否覆盖?"):
bot_uin = click.prompt("请输入机器人 QQ 号", type=str)
root = click.prompt("请输入管理员 QQ 号", type=str)
config_data = _build_default_config(bot_uin=bot_uin, root=root)
with open(config_path, "w", encoding="utf-8") as f:
yaml.dump(
config_data,
f,
allow_unicode=True,
default_flow_style=False,
sort_keys=False,
)
click.echo(success(f"config.yaml 已覆盖: {config_path}"))
_ensure_plugins_dir(target / "plugins")
_generate_template_plugin(target / "plugins")
click.echo()
Comment on lines +59 to +76
Copy link

Copilot AI Mar 22, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

init 的覆盖分支里重复了与 ensure_project_initialized 相同的 prompt/写文件/创建 plugins/ 与模板插件逻辑,后续默认配置结构变更时容易出现两处实现不一致。建议抽象一个“写入 config(可覆盖)”的内部函数,或让 ensure_project_initialized 支持 overwrite=True 参数,init 仅负责处理交互选择。

Copilot uses AI. Check for mistakes.
click.echo(info("下一步: 运行 'ncatbot run' 启动机器人"))
return

click.echo(info("已跳过 config.yaml"))

ensure_project_initialized(target_dir=target_dir)
click.echo()
click.echo(info("下一步: 运行 'ncatbot run' 启动机器人"))

Expand Down
4 changes: 4 additions & 0 deletions ncatbot/cli/commands/run.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

import click

from .init import ensure_project_initialized


@click.command()
@click.option("--debug", is_flag=True, help="启用调试模式")
Expand All @@ -11,6 +13,7 @@ def run(debug: bool, no_hot_reload: bool, plugin_dir: str):
"""启动 NcatBot(连接 NapCat + 加载插件 + 监听事件)"""
from ncatbot.app import BotClient

ensure_project_initialized(".")
bot = BotClient(debug=debug, plugin_dir=plugin_dir)
bot.run()
Comment on lines +16 to 18
Copy link

Copilot AI Mar 22, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

run/dev 调用 ensure_project_initialized 但忽略了返回值/取消结果;如果未来按 docstring 返回 None(或捕获 click.Abort 后返回 None),这里会继续启动 BotClient,导致在未完成初始化时运行。建议检查返回值并在未初始化时以明确的方式退出(例如抛 click.Abortclick.ClickException)。

Copilot uses AI. Check for mistakes.

Expand All @@ -21,5 +24,6 @@ def dev(plugin_dir: str):
"""以开发模式启动(debug=True + 热重载)"""
from ncatbot.app import BotClient

ensure_project_initialized(".")
bot = BotClient(debug=True, plugin_dir=plugin_dir)
bot.run()
Comment on lines +27 to 29
Copy link

Copilot AI Mar 22, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

dev 同样调用 ensure_project_initialized 但未处理取消/失败结果;如果初始化未完成仍会继续启动 BotClient。建议与 run 一样检查返回值并在未初始化时退出。

Copilot uses AI. Check for mistakes.
Loading