# 架构设计 > **目标读者**:接续开发 x-cli 的 AI agent 或人类开发者 > **必读**:**在写代码前必须先读本文档** > **状态**:本文档反映 **v0.8.0 实际架构**(2026-07-29) --- ## 1. 整体架构 ### 1.1 当前架构:延迟分发的模块化单体(v0.8.x) **x-cli 5 层架构**(从上到下): ``` x.py (entry point only) ├── --version / --config / --log-level / --config-init 全局 flag ├── build_parser() / main() └── main() → early-exit → 加载 config + log → 请求 core.dispatch 分发 core/dispatch.py (静态白名单 + 延迟加载) ├── SUBCOMMAND_MODULES: {"todo": "plugins.todo", ...} └── load_subcommand_handler(name) → importlib → plugin.run plugins/ (子命令插件与 TODO 内部分层) ├── todo.py ← x todo parser + dispatcher facade ├── todo_presenters.py ← 纯展示、过滤与校验 helpers ├── todo_queries.py ← list / search / stats / export ├── todo_lifecycle.py ← archive / restore / reminder / repeat / remove ├── todo_mutations.py ← add / update / init / import / template ├── secret.py ← x secret 命令族 ├── diary.py ← x diary 写入 + 最近日期列表 ├── note.py ← x note 主题笔记 add/list/show/search └── web.py ← x web 本地 HTTP 服务 + 静态前端 core/ (核心库,被 x.py + plugins/ 共享) ├── dispatch.py ← 内建插件白名单 + 延迟加载 ├── models.py ← Task dataclass + 3 个 enum ├── parser.py ← YAML frontmatter 解析/序列化(手写,stdlib-only) ├── slug.py ← 中英文 slug 生成(stdlib-only) ├── paths.py ← 跨平台路径解析(todo / secret / diary / notes / config / log) ├── formatting.py ← CJK-aware display helpers(display_width + pad) ├── task_service.py ← TaskService:CLI / Web 共用的任务业务 API ├── storage.py ← TaskStore:文件系统 CRUD + 统计 + 索引维护 ├── secret_service.py ← SecretService:CLI / Web 共用的密钥业务 API ├── secrets.py ← SecretStore:JSON DB、事务锁、CRUD + import + export ├── diary.py ← DiaryStore:每日 Markdown 追加 + 日期列表 ├── note.py ← NoteStore:主题 Markdown 创建、列表、显示、搜索 ├── config.py ← AppConfig + YAML 解析(v0.4.y) ├── logging.py ← stdlib logging wrapper(v0.4.y) └── web/ ← 本地 HTTP API、认证与静态资源 # 第三方依赖:0(dependencies = []) ``` **Plugin 合约**(每个 `plugins/.py` 必须实现): ```python def register(parser: argparse.ArgumentParser) -> None: """绑子命令 + flags 到 parser""" def run(args: Sequence[str]) -> int: """解析 + 派发,返回 exit code""" ``` **加新子命令的步骤**: 1. 创建 `plugins/.py`,实现 `register` + `run` 2. 在 `core.dispatch:SUBCOMMAND_MODULES` 加 1 行静态映射 3. 用户可见行为发生变化时写 BDD,并按风险分级补测试 **核心理念**: - **Entry point `x.py` 只做 argparse + config + log + 派发** - **Plugins `plugins/` 各自独立**,互不依赖 - **核心库 `core/` 纯 stdlib,零三方依赖**(`pyproject.toml dependencies = []`) - **依赖方向固定**:`x → core.dispatch → selected plugin → core`;`core` 禁止反向导入 `x` - **插件按需加载**:顶层 version/help/未知命令不导入具体插件 - **数据存储**:x-cli 独立于外部系统(`%LOCALAPPDATA%\x-cli\` Windows / `~/.local/share/x-cli/` Unix) ### 1.2 Phase 4 历史:从单文件到插件(已完成 v0.5.0) v0.4.y 之前 `x.py` 是 1739 行单文件,所有 18 个 handler inline。Phase 4 拆分: - v0.2.0-v0.4.y:单文件 + `SUBCOMMAND_HANDLERS` 字典分发(1739 行) - v0.5.0:拆出 `plugins/todo.py` + `plugins/secret.py`,`x.py` 降到 215 行 - 拆分前后均由完整 pytest 回归保护;具体数量不在架构文档中硬编码 未来可能的扩展(**不**在当前 scope — 见 COMMANDS.md backlog): - `plugins/foo.py` 加新子命令(流程见 1.1) - 可选后台提醒服务复用 core API,不改变 CLI 主进程架构 ### 1.3 数据流(MVP 实际) ``` 用户输入: x todo list --status pending ↓ x.py build_parser: 解析 --version / subcommand ↓ core.dispatch.load_subcommand_handler("todo") ↓ plugins.todo.run("list --status pending") ↓ plugins.todo: argparse 解析 list 的子参数(--status/--priority/--tag/--all) ↓ plugins.todo_queries._todo_list: 调 TaskService.list() 拿所有 active 任务 ↓ core/task_service.py: 统一查询过滤并调用 TaskStore ↓ core/storage.py: glob 任务//TODO.md → parse_frontmatter → Task ↓ core/models.py: Task dataclass(未知字段在 extra,round-trip 不丢) ↓ 返回 list[Task] → 过滤 → 表格输出到 stdout ↓ 退出码 0 ``` ### 1.4 Web 前端架构 自 v0.8.0 起,Web 前端是一个 **Vue 3 SPA**(ADR-0002)。源码集中在仓库根目录的 `web/` 文件夹内(`web/src/**`),用 Vite 构建;构建产物输出到 `core/web/static/`,由 `core/web/server.py` 以 `Cache-Control: no-store` 同源服务。Python 运行时仍保持 stdlib-only——Node/Vite 仅是**开发期**工具链,最终用户无需安装。 - **技术栈**:Vue 3 `