Skip to content

feat(init): 重构初始化流程以确保项目结构完整并支持交互式配置#13

Merged
huan-yp merged 1 commit intoncatbot:mainfrom
harkerhand:main
Mar 22, 2026
Merged

feat(init): 重构初始化流程以确保项目结构完整并支持交互式配置#13
huan-yp merged 1 commit intoncatbot:mainfrom
harkerhand:main

Conversation

@harkerhand
Copy link
Collaborator

No description provided.

Copilot AI review requested due to automatic review settings March 22, 2026 11:22
@huan-yp huan-yp merged commit d0001c0 into ncatbot:main Mar 22, 2026
3 checks passed
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

该 PR 将项目初始化流程从单独的 init 命令中抽取为可复用的“确保已初始化”能力,并在 run/dev 启动前自动补齐基础项目结构,以在缺少 config.yaml 时支持交互式配置并避免目录结构不完整导致的运行问题。

Changes:

  • 新增 ensure_project_initialized():检测并创建 config.yamlplugins/,必要时执行交互式初始化。
  • init 命令重构:保留覆盖逻辑,并在非覆盖场景复用 ensure_project_initialized()
  • run/dev 启动前调用 ensure_project_initialized(".") 以确保项目结构完整。

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 4 comments.

File Description
ncatbot/cli/commands/run.py run/dev 启动前自动触发项目初始化保障逻辑
ncatbot/cli/commands/init.py 抽取并复用初始化保障函数,调整 init 行为与覆盖流程
Comments suppressed due to low confidence (1)

ncatbot/cli/commands/init.py:33

  • ensure_project_initialized 的 docstring 声明“用户取消初始化返回 None”,但当前实现没有捕获 click.Abort / 取消路径:click.prompt 取消会直接抛异常而不是返回 None。建议要么更新 docstring 以反映真实行为,要么捕获取消并返回 None(并让调用方决定如何退出)。
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():
        _ensure_plugins_dir(plugins_path)
        _generate_template_plugin(plugins_path)
        return config_path

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

    bot_uin = click.prompt("请输入机器人 QQ 号", type=str)
    root = click.prompt("请输入管理员 QQ 号", type=str)

Comment on lines 23 to +26
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
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.
Comment on lines +59 to +76
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()
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.
Comment on lines +16 to 18
ensure_project_initialized(".")
bot = BotClient(debug=debug, plugin_dir=plugin_dir)
bot.run()
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.
Comment on lines +27 to 29
ensure_project_initialized(".")
bot = BotClient(debug=True, plugin_dir=plugin_dir)
bot.run()
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.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants