fileflow-cli 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Yuluo
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,204 @@
1
+ Metadata-Version: 2.4
2
+ Name: fileflow-cli
3
+ Version: 0.1.0
4
+ Summary: 🧹 智能文件整理器 — YAML 规则引擎驱动的 CLI 文件分类/移动/清理工具
5
+ Author-email: Yuluo <lingeryuluo@gmail.com>
6
+ License: MIT
7
+ Project-URL: Homepage, https://github.com/Linger668/fileflow
8
+ Project-URL: Repository, https://github.com/Linger668/fileflow
9
+ Project-URL: Issues, https://github.com/Linger668/fileflow/issues
10
+ Keywords: file-organization,file-management,cli,productivity
11
+ Classifier: Development Status :: 3 - Alpha
12
+ Classifier: Environment :: Console
13
+ Classifier: Intended Audience :: Developers
14
+ Classifier: Intended Audience :: End Users/Desktop
15
+ Classifier: License :: OSI Approved :: MIT License
16
+ Classifier: Operating System :: OS Independent
17
+ Classifier: Programming Language :: Python :: 3
18
+ Classifier: Programming Language :: Python :: 3.10
19
+ Classifier: Programming Language :: Python :: 3.11
20
+ Classifier: Programming Language :: Python :: 3.12
21
+ Classifier: Topic :: Desktop Environment :: File Managers
22
+ Classifier: Topic :: Utilities
23
+ Requires-Python: >=3.10
24
+ Description-Content-Type: text/markdown
25
+ License-File: LICENSE
26
+ Requires-Dist: typer>=0.12.0
27
+ Requires-Dist: rich>=13.7.0
28
+ Requires-Dist: pyyaml>=6.0
29
+ Provides-Extra: watch
30
+ Requires-Dist: watchdog>=4.0.0; extra == "watch"
31
+ Provides-Extra: dev
32
+ Requires-Dist: pytest>=8.0; extra == "dev"
33
+ Requires-Dist: pytest-cov>=5.0; extra == "dev"
34
+ Requires-Dist: ruff>=0.5.0; extra == "dev"
35
+ Requires-Dist: mypy>=1.10.0; extra == "dev"
36
+ Requires-Dist: build>=1.0.0; extra == "dev"
37
+ Requires-Dist: twine>=5.0.0; extra == "dev"
38
+ Dynamic: license-file
39
+
40
+ # 🧹 FileFlow
41
+
42
+ > 智能文件整理器 — 基于 YAML 规则引擎的 CLI 文件分类/移动/清理工具
43
+
44
+ [![PyPI version](https://img.shields.io/badge/python-3.10%2B-blue)](https://pypi.org/project/fileflow/)
45
+ [![License: MIT](https://img.shields.io/badge/License-MIT-green.svg)](LICENSE)
46
+ [![Ruff](https://img.shields.io/badge/code%20style-ruff-000000.svg)](https://github.com/astral-sh/ruff)
47
+
48
+ ---
49
+
50
+ ## ✨ 功能
51
+
52
+ - 📝 **YAML 规则引擎** — 声明式配置,一目了然
53
+ - 🔍 **预览模式** — 先看效果再执行,安全无副作用
54
+ - 📂 **多种匹配方式** — 扩展名/通配符/正则/文件名/大小
55
+ - 🎯 **智能文件移动** — 自动创建目录,冲突策略可选
56
+ - ⏪ **支持撤销** — 操作历史可追溯(即将推出)
57
+ - 🎨 **Rich 终端美化** — 彩色表格,清晰直观
58
+ - 🔌 **可扩展架构** — 匹配器和操作都支持注册表模式
59
+
60
+ ## 🚀 快速开始
61
+
62
+ ### 安装
63
+
64
+ ```bash
65
+ pip install fileflow
66
+ ```
67
+
68
+ ### 1. 初始化配置
69
+
70
+ 在要整理的目录下生成配置文件:
71
+
72
+ ```bash
73
+ cd ~/Downloads
74
+ fileflow init
75
+ ```
76
+
77
+ 这会生成 `.fileflow.yaml`,内置了图片/文档/视频/代码等常用规则。
78
+
79
+ ### 2. 预览效果
80
+
81
+ ```bash
82
+ fileflow run .
83
+ ```
84
+
85
+ 以预览模式运行,会展示每个文件将被如何整理,**不会真正移动文件**。
86
+
87
+ ### 3. 执行整理
88
+
89
+ ```bash
90
+ fileflow run . --force
91
+ ```
92
+
93
+ 确认无误后,使用 `--force` 真正执行。
94
+
95
+ ### 一键完成(跳过确认)
96
+
97
+ ```bash
98
+ fileflow run . --force --yes
99
+ ```
100
+
101
+ ## 📖 使用指南
102
+
103
+ ### 命令概览
104
+
105
+ ```bash
106
+ fileflow init # 生成默认配置文件
107
+ fileflow run # 运行整理(默认预览)
108
+ fileflow validate # 验证配置文件
109
+ fileflow list-rules # 查看规则列表
110
+ fileflow --help # 查看全部命令
111
+ ```
112
+
113
+ ### 选项
114
+
115
+ | 选项 | 说明 |
116
+ |------|------|
117
+ | `--config, -c` | 指定配置文件路径 |
118
+ | `--dry-run, -n` | 仅预览模式 |
119
+ | `--force, -f` | 跳过预览直接执行 |
120
+ | `--yes, -y` | 自动确认,跳过交互提示 |
121
+ | `--no-recursive` | 不递归扫描子目录 |
122
+ | `--verbose, -v` | 详细输出 |
123
+ | `--version, -V` | 显示版本 |
124
+
125
+ ### 配置示例
126
+
127
+ ```yaml
128
+ # .fileflow.yaml
129
+ version: "1.0"
130
+
131
+ settings:
132
+ dry_run_by_default: true # 默认预览模式
133
+ on_conflict: "skip" # skip | rename | overwrite | ask
134
+ create_target_dirs: true
135
+
136
+ rules:
137
+ - name: "整理图片"
138
+ match:
139
+ extensions: [".jpg", ".jpeg", ".png", ".gif", ".svg"]
140
+ action: move
141
+ target: "Pictures/{ext}/{filename}"
142
+
143
+ - name: "清理旧日志"
144
+ match:
145
+ extensions: [".log"]
146
+ modified_before_days: 30
147
+ action: delete
148
+ enabled: false # 默认禁用
149
+ ```
150
+
151
+ ### 📂 模板变量
152
+
153
+ 目标路径 `target` 支持以下变量:
154
+
155
+ | 变量 | 说明 | 示例 |
156
+ |------|------|------|
157
+ | `{filename}` | 完整文件名 | `report.pdf` |
158
+ | `{name}` | 文件名(不含扩展名) | `report` |
159
+ | `{ext}` | 扩展名(含点,推荐用于文件名) | `.pdf` |
160
+ | `{ext_no_dot}` | 扩展名(不含点,推荐用于目录名) | `pdf` |
161
+ | `{year}` | 4 位年份 | `2026` |
162
+ | `{month}` | 2 位月份 | `07` |
163
+ | `{day}` | 2 位日期 | `13` |
164
+ | `{hour}` | 2 位小时 | `14` |
165
+ | `{minute}` | 2 位分钟 | `30` |
166
+
167
+ ## 🏗 项目架构
168
+
169
+ ```
170
+ fileflow/
171
+ ├── src/fileflow/
172
+ │ ├── cli.py # CLI 命令定义 (Typer)
173
+ │ ├── config.py # YAML 配置加载 & 验证
174
+ │ ├── engine.py # 核心编排引擎
175
+ │ ├── rules.py # 规则数据模型
176
+ │ ├── matchers.py # 匹配器注册表 & 内置匹配器
177
+ │ ├── actions.py # 文件操作 (move/copy/delete)
178
+ │ ├── templates.py # 路径模板变量解析
179
+ │ ├── report.py # Rich 终端输出
180
+ │ └── watcher.py # 实时监控(可选)
181
+ ├── tests/ # 全模块测试覆盖
182
+ └── pyproject.toml # 项目配置
183
+ ```
184
+
185
+ ## 🧪 运行测试
186
+
187
+ ```bash
188
+ pip install -e ".[dev]"
189
+ pytest
190
+ ```
191
+
192
+ 查看测试覆盖率:
193
+
194
+ ```bash
195
+ pytest --cov --cov-report=html
196
+ ```
197
+
198
+ ## 🤝 贡献
199
+
200
+ 欢迎提交 Issue 和 PR!详情见 [CONTRIBUTING.md](CONTRIBUTING.md)。
201
+
202
+ ## 📄 许可证
203
+
204
+ [MIT](LICENSE) © 2026 Yuluo
@@ -0,0 +1,165 @@
1
+ # 🧹 FileFlow
2
+
3
+ > 智能文件整理器 — 基于 YAML 规则引擎的 CLI 文件分类/移动/清理工具
4
+
5
+ [![PyPI version](https://img.shields.io/badge/python-3.10%2B-blue)](https://pypi.org/project/fileflow/)
6
+ [![License: MIT](https://img.shields.io/badge/License-MIT-green.svg)](LICENSE)
7
+ [![Ruff](https://img.shields.io/badge/code%20style-ruff-000000.svg)](https://github.com/astral-sh/ruff)
8
+
9
+ ---
10
+
11
+ ## ✨ 功能
12
+
13
+ - 📝 **YAML 规则引擎** — 声明式配置,一目了然
14
+ - 🔍 **预览模式** — 先看效果再执行,安全无副作用
15
+ - 📂 **多种匹配方式** — 扩展名/通配符/正则/文件名/大小
16
+ - 🎯 **智能文件移动** — 自动创建目录,冲突策略可选
17
+ - ⏪ **支持撤销** — 操作历史可追溯(即将推出)
18
+ - 🎨 **Rich 终端美化** — 彩色表格,清晰直观
19
+ - 🔌 **可扩展架构** — 匹配器和操作都支持注册表模式
20
+
21
+ ## 🚀 快速开始
22
+
23
+ ### 安装
24
+
25
+ ```bash
26
+ pip install fileflow
27
+ ```
28
+
29
+ ### 1. 初始化配置
30
+
31
+ 在要整理的目录下生成配置文件:
32
+
33
+ ```bash
34
+ cd ~/Downloads
35
+ fileflow init
36
+ ```
37
+
38
+ 这会生成 `.fileflow.yaml`,内置了图片/文档/视频/代码等常用规则。
39
+
40
+ ### 2. 预览效果
41
+
42
+ ```bash
43
+ fileflow run .
44
+ ```
45
+
46
+ 以预览模式运行,会展示每个文件将被如何整理,**不会真正移动文件**。
47
+
48
+ ### 3. 执行整理
49
+
50
+ ```bash
51
+ fileflow run . --force
52
+ ```
53
+
54
+ 确认无误后,使用 `--force` 真正执行。
55
+
56
+ ### 一键完成(跳过确认)
57
+
58
+ ```bash
59
+ fileflow run . --force --yes
60
+ ```
61
+
62
+ ## 📖 使用指南
63
+
64
+ ### 命令概览
65
+
66
+ ```bash
67
+ fileflow init # 生成默认配置文件
68
+ fileflow run # 运行整理(默认预览)
69
+ fileflow validate # 验证配置文件
70
+ fileflow list-rules # 查看规则列表
71
+ fileflow --help # 查看全部命令
72
+ ```
73
+
74
+ ### 选项
75
+
76
+ | 选项 | 说明 |
77
+ |------|------|
78
+ | `--config, -c` | 指定配置文件路径 |
79
+ | `--dry-run, -n` | 仅预览模式 |
80
+ | `--force, -f` | 跳过预览直接执行 |
81
+ | `--yes, -y` | 自动确认,跳过交互提示 |
82
+ | `--no-recursive` | 不递归扫描子目录 |
83
+ | `--verbose, -v` | 详细输出 |
84
+ | `--version, -V` | 显示版本 |
85
+
86
+ ### 配置示例
87
+
88
+ ```yaml
89
+ # .fileflow.yaml
90
+ version: "1.0"
91
+
92
+ settings:
93
+ dry_run_by_default: true # 默认预览模式
94
+ on_conflict: "skip" # skip | rename | overwrite | ask
95
+ create_target_dirs: true
96
+
97
+ rules:
98
+ - name: "整理图片"
99
+ match:
100
+ extensions: [".jpg", ".jpeg", ".png", ".gif", ".svg"]
101
+ action: move
102
+ target: "Pictures/{ext}/{filename}"
103
+
104
+ - name: "清理旧日志"
105
+ match:
106
+ extensions: [".log"]
107
+ modified_before_days: 30
108
+ action: delete
109
+ enabled: false # 默认禁用
110
+ ```
111
+
112
+ ### 📂 模板变量
113
+
114
+ 目标路径 `target` 支持以下变量:
115
+
116
+ | 变量 | 说明 | 示例 |
117
+ |------|------|------|
118
+ | `{filename}` | 完整文件名 | `report.pdf` |
119
+ | `{name}` | 文件名(不含扩展名) | `report` |
120
+ | `{ext}` | 扩展名(含点,推荐用于文件名) | `.pdf` |
121
+ | `{ext_no_dot}` | 扩展名(不含点,推荐用于目录名) | `pdf` |
122
+ | `{year}` | 4 位年份 | `2026` |
123
+ | `{month}` | 2 位月份 | `07` |
124
+ | `{day}` | 2 位日期 | `13` |
125
+ | `{hour}` | 2 位小时 | `14` |
126
+ | `{minute}` | 2 位分钟 | `30` |
127
+
128
+ ## 🏗 项目架构
129
+
130
+ ```
131
+ fileflow/
132
+ ├── src/fileflow/
133
+ │ ├── cli.py # CLI 命令定义 (Typer)
134
+ │ ├── config.py # YAML 配置加载 & 验证
135
+ │ ├── engine.py # 核心编排引擎
136
+ │ ├── rules.py # 规则数据模型
137
+ │ ├── matchers.py # 匹配器注册表 & 内置匹配器
138
+ │ ├── actions.py # 文件操作 (move/copy/delete)
139
+ │ ├── templates.py # 路径模板变量解析
140
+ │ ├── report.py # Rich 终端输出
141
+ │ └── watcher.py # 实时监控(可选)
142
+ ├── tests/ # 全模块测试覆盖
143
+ └── pyproject.toml # 项目配置
144
+ ```
145
+
146
+ ## 🧪 运行测试
147
+
148
+ ```bash
149
+ pip install -e ".[dev]"
150
+ pytest
151
+ ```
152
+
153
+ 查看测试覆盖率:
154
+
155
+ ```bash
156
+ pytest --cov --cov-report=html
157
+ ```
158
+
159
+ ## 🤝 贡献
160
+
161
+ 欢迎提交 Issue 和 PR!详情见 [CONTRIBUTING.md](CONTRIBUTING.md)。
162
+
163
+ ## 📄 许可证
164
+
165
+ [MIT](LICENSE) © 2026 Yuluo
@@ -0,0 +1,81 @@
1
+ [build-system]
2
+ requires = ["setuptools>=68.0"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "fileflow-cli"
7
+ version = "0.1.0"
8
+ description = "🧹 智能文件整理器 — YAML 规则引擎驱动的 CLI 文件分类/移动/清理工具"
9
+ readme = "README.md"
10
+ requires-python = ">=3.10"
11
+ license = { text = "MIT" }
12
+ authors = [
13
+ { name = "Yuluo", email = "lingeryuluo@gmail.com" },
14
+ ]
15
+ keywords = ["file-organization", "file-management", "cli", "productivity"]
16
+ classifiers = [
17
+ "Development Status :: 3 - Alpha",
18
+ "Environment :: Console",
19
+ "Intended Audience :: Developers",
20
+ "Intended Audience :: End Users/Desktop",
21
+ "License :: OSI Approved :: MIT License",
22
+ "Operating System :: OS Independent",
23
+ "Programming Language :: Python :: 3",
24
+ "Programming Language :: Python :: 3.10",
25
+ "Programming Language :: Python :: 3.11",
26
+ "Programming Language :: Python :: 3.12",
27
+ "Topic :: Desktop Environment :: File Managers",
28
+ "Topic :: Utilities",
29
+ ]
30
+
31
+ dependencies = [
32
+ "typer>=0.12.0",
33
+ "rich>=13.7.0",
34
+ "pyyaml>=6.0",
35
+ ]
36
+
37
+ [project.optional-dependencies]
38
+ watch = ["watchdog>=4.0.0"]
39
+ dev = [
40
+ "pytest>=8.0",
41
+ "pytest-cov>=5.0",
42
+ "ruff>=0.5.0",
43
+ "mypy>=1.10.0",
44
+ "build>=1.0.0",
45
+ "twine>=5.0.0",
46
+ ]
47
+
48
+ [project.urls]
49
+ Homepage = "https://github.com/Linger668/fileflow"
50
+ Repository = "https://github.com/Linger668/fileflow"
51
+ Issues = "https://github.com/Linger668/fileflow/issues"
52
+
53
+ [project.scripts]
54
+ fileflow = "fileflow.cli:app"
55
+
56
+ [tool.setuptools.packages.find]
57
+ where = ["src"]
58
+
59
+ [tool.ruff]
60
+ target-version = "py310"
61
+ line-length = 100
62
+
63
+ [tool.ruff.lint]
64
+ select = ["E", "F", "I", "N", "W", "UP", "SIM"]
65
+
66
+ [tool.ruff.format]
67
+ quote-style = "double"
68
+
69
+ [tool.mypy]
70
+ strict = true
71
+ python_version = "3.10"
72
+ exclude = ["tests/"]
73
+ ignore_missing_imports = true
74
+
75
+ [tool.pytest.ini_options]
76
+ testpaths = ["tests"]
77
+ python_files = ["test_*.py"]
78
+ addopts = "-v --cov=fileflow --cov-report=term-missing"
79
+
80
+ [tool.coverage.run]
81
+ source = ["fileflow"]
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,3 @@
1
+ """FileFlow — 智能文件整理器."""
2
+
3
+ __version__ = "0.1.0"
@@ -0,0 +1,6 @@
1
+ """支持 python -m fileflow 运行."""
2
+
3
+ from .cli import app
4
+
5
+ if __name__ == "__main__":
6
+ app()
@@ -0,0 +1,164 @@
1
+ """文件操作:移动、复制、删除等.
2
+
3
+ 支持冲突策略:
4
+ - skip: 跳过目标已存在的文件
5
+ - rename: 自动添加后缀 (1), (2)...
6
+ - overwrite: 覆盖目标文件
7
+ """
8
+
9
+ from __future__ import annotations
10
+
11
+ import shutil
12
+ from enum import Enum
13
+ from pathlib import Path
14
+ from typing import Callable
15
+
16
+ from .templates import resolve_path
17
+
18
+
19
+ class ConflictStrategy(str, Enum):
20
+ """文件冲突处理策略."""
21
+
22
+ SKIP = "skip"
23
+ RENAME = "rename"
24
+ OVERWRITE = "overwrite"
25
+
26
+
27
+ class ActionResult:
28
+ """一次文件操作的结果."""
29
+
30
+ def __init__(
31
+ self,
32
+ source: Path,
33
+ target: Path | None = None,
34
+ success: bool = True,
35
+ action: str = "move",
36
+ skipped: bool = False,
37
+ error: str | None = None,
38
+ ) -> None:
39
+ self.source = source
40
+ self.target = target
41
+ self.success = success
42
+ self.action = action
43
+ self.skipped = skipped
44
+ self.error = error
45
+
46
+ @property
47
+ def summary(self) -> str:
48
+ if self.error:
49
+ return f"[red]✗ {self.action}: {self.source.name}[/] → {self.error}"
50
+ if self.skipped:
51
+ return f"[yellow]– 跳过: {self.source.name}[/] (目标已存在)"
52
+ return f"[green]✓ {self.action}: {self.source.name}[/] → {self.target}"
53
+
54
+
55
+ def resolve_target_path(
56
+ target_template: str,
57
+ source: Path,
58
+ base_dir: Path,
59
+ conflict: ConflictStrategy = ConflictStrategy.SKIP,
60
+ ) -> Path:
61
+ """解析目标路径,并根据冲突策略处理.
62
+
63
+ Returns:
64
+ 最终的目标路径(可能已根据冲突策略调整).
65
+ """
66
+ dest = resolve_path(target_template, source, base_dir)
67
+
68
+ if conflict == ConflictStrategy.RENAME and dest.exists():
69
+ dest = _find_available_name(dest)
70
+
71
+ return dest
72
+
73
+
74
+ def _find_available_name(dest: Path) -> Path:
75
+ """找到一个不存在的路径,如 file (1).txt, file (2).txt."""
76
+ parent = dest.parent
77
+ stem = dest.stem
78
+ suffix = dest.suffix
79
+ counter = 1
80
+ while True:
81
+ new_name = f"{stem} ({counter}){suffix}"
82
+ candidate = parent / new_name
83
+ if not candidate.exists():
84
+ return candidate
85
+ counter += 1
86
+
87
+
88
+ def move_file(
89
+ source: Path,
90
+ target_template: str,
91
+ base_dir: Path,
92
+ create_dirs: bool = True,
93
+ conflict: ConflictStrategy = ConflictStrategy.SKIP,
94
+ ) -> ActionResult:
95
+ """移动文件."""
96
+ try:
97
+ dest = resolve_target_path(target_template, source, base_dir, conflict)
98
+ if dest == source:
99
+ return ActionResult(source, dest, success=True, action="move")
100
+
101
+ if dest.exists() and conflict == ConflictStrategy.SKIP:
102
+ return ActionResult(source, dest, skipped=True, action="move")
103
+
104
+ if create_dirs:
105
+ dest.parent.mkdir(parents=True, exist_ok=True)
106
+
107
+ shutil.move(str(source), str(dest))
108
+ return ActionResult(source, dest, success=True, action="move")
109
+ except OSError as e:
110
+ return ActionResult(source, error=str(e), success=False, action="move")
111
+
112
+
113
+ def copy_file(
114
+ source: Path,
115
+ target_template: str,
116
+ base_dir: Path,
117
+ create_dirs: bool = True,
118
+ conflict: ConflictStrategy = ConflictStrategy.SKIP,
119
+ ) -> ActionResult:
120
+ """复制文件."""
121
+ try:
122
+ dest = resolve_target_path(target_template, source, base_dir, conflict)
123
+ if dest.exists() and conflict == ConflictStrategy.SKIP:
124
+ return ActionResult(source, dest, skipped=True, action="copy")
125
+
126
+ if create_dirs:
127
+ dest.parent.mkdir(parents=True, exist_ok=True)
128
+
129
+ shutil.copy2(str(source), str(dest))
130
+ return ActionResult(source, dest, success=True, action="copy")
131
+ except OSError as e:
132
+ return ActionResult(source, error=str(e), success=False, action="copy")
133
+
134
+
135
+ def delete_file(source: Path) -> ActionResult:
136
+ """删除文件."""
137
+ try:
138
+ source.unlink()
139
+ return ActionResult(source, success=True, action="delete")
140
+ except OSError as e:
141
+ return ActionResult(source, error=str(e), success=False, action="delete")
142
+
143
+
144
+ # ── 操作注册表 ─────────────────────────────────────────────
145
+
146
+ ActionFunc = Callable[..., ActionResult]
147
+
148
+ _actions: dict[str, ActionFunc] = {
149
+ "move": move_file,
150
+ "copy": copy_file,
151
+ "delete": delete_file,
152
+ }
153
+
154
+
155
+ def get_action(name: str) -> ActionFunc:
156
+ """按名称获取操作函数."""
157
+ if name not in _actions:
158
+ raise KeyError(f"未知操作: {name!r},可选: {list(_actions.keys())}")
159
+ return _actions[name]
160
+
161
+
162
+ def list_actions() -> list[str]:
163
+ """列出所有注册的操作名称."""
164
+ return list(_actions.keys())