coopie 0.1.1__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.
Files changed (60) hide show
  1. coopie-0.1.1/.copier-answers.yml +19 -0
  2. coopie-0.1.1/.dockerignore +46 -0
  3. coopie-0.1.1/.github/workflows/ci.yml +58 -0
  4. coopie-0.1.1/.github/workflows/release.yml +36 -0
  5. coopie-0.1.1/.gitignore +18 -0
  6. coopie-0.1.1/.pre-commit-config.yaml +19 -0
  7. coopie-0.1.1/.python-version +1 -0
  8. coopie-0.1.1/.readthedocs.yaml +23 -0
  9. coopie-0.1.1/.trae/.ignore +15 -0
  10. coopie-0.1.1/.trae/rules/dev-workflow.md +23 -0
  11. coopie-0.1.1/.trae/rules/git-commit-message.md +11 -0
  12. coopie-0.1.1/.trae/rules/python-standards.md +155 -0
  13. coopie-0.1.1/.trae/rules/self-driven.md +149 -0
  14. coopie-0.1.1/.vscode/settings.json +35 -0
  15. coopie-0.1.1/Dockerfile +53 -0
  16. coopie-0.1.1/LICENSE +21 -0
  17. coopie-0.1.1/PKG-INFO +171 -0
  18. coopie-0.1.1/README.md +134 -0
  19. coopie-0.1.1/copier.yml +193 -0
  20. coopie-0.1.1/docs/_static/.gitkeep +0 -0
  21. coopie-0.1.1/docs/api.rst +7 -0
  22. coopie-0.1.1/docs/changelog.rst +7 -0
  23. coopie-0.1.1/docs/conf.py +69 -0
  24. coopie-0.1.1/docs/index.rst +58 -0
  25. coopie-0.1.1/pyproject.toml +121 -0
  26. coopie-0.1.1/src/coopie/__init__.py +7 -0
  27. coopie-0.1.1/src/coopie/cli.py +79 -0
  28. coopie-0.1.1/src/coopie/py.typed +0 -0
  29. coopie-0.1.1/template/.copier-answers.yml +2 -0
  30. coopie-0.1.1/template/.gitignore +23 -0
  31. coopie-0.1.1/template/.pre-commit-config.yaml +19 -0
  32. coopie-0.1.1/template/.python-version +1 -0
  33. coopie-0.1.1/template/.trae/.ignore +15 -0
  34. coopie-0.1.1/template/.trae/rules/dev-workflow.md +23 -0
  35. coopie-0.1.1/template/.trae/rules/git-commit-message.md +11 -0
  36. coopie-0.1.1/template/.trae/rules/python-standards.md +155 -0
  37. coopie-0.1.1/template/.trae/rules/self-driven.md +149 -0
  38. coopie-0.1.1/template/.vscode/settings.json +35 -0
  39. coopie-0.1.1/template/README.md +69 -0
  40. coopie-0.1.1/template/pyproject.toml +114 -0
  41. coopie-0.1.1/template/src/{{ package_name }}/__init__.py +7 -0
  42. coopie-0.1.1/template/src/{{ package_name }}/py.typed +0 -0
  43. coopie-0.1.1/template/tests/__init__.py +0 -0
  44. coopie-0.1.1/template/tests/test_{{ package_name }}.py +17 -0
  45. coopie-0.1.1/template/{% if license != 'None' %}LICENSE{% endif %} +65 -0
  46. coopie-0.1.1/template/{% if use_cicd %}.github{% endif %}/workflows/ci.yml +58 -0
  47. coopie-0.1.1/template/{% if use_cicd %}.github{% endif %}/workflows/release.yml +36 -0
  48. coopie-0.1.1/template/{% if use_docker %}.dockerignore{% endif %} +46 -0
  49. coopie-0.1.1/template/{% if use_docker %}Dockerfile{% endif %} +66 -0
  50. coopie-0.1.1/template/{% if use_docs %}.readthedocs.yaml{% endif %} +23 -0
  51. coopie-0.1.1/template/{% if use_docs %}docs{% endif %}/_static/.gitkeep +0 -0
  52. coopie-0.1.1/template/{% if use_docs %}docs{% endif %}/api.rst +7 -0
  53. coopie-0.1.1/template/{% if use_docs %}docs{% endif %}/changelog.rst +7 -0
  54. coopie-0.1.1/template/{% if use_docs %}docs{% endif %}/conf.py +69 -0
  55. coopie-0.1.1/template/{% if use_docs %}docs{% endif %}/index.rst +58 -0
  56. coopie-0.1.1/template/{% if use_tox %}tox.ini{% endif %} +21 -0
  57. coopie-0.1.1/tests/__init__.py +0 -0
  58. coopie-0.1.1/tests/test_coopie.py +17 -0
  59. coopie-0.1.1/tox.ini +21 -0
  60. coopie-0.1.1/uv.lock +2653 -0
@@ -0,0 +1,19 @@
1
+ # Changes here will be overwritten by Copier
2
+ _commit: 298f2f8
3
+ _src_path: https://github.com/gookeryoung/coopie
4
+ author_email: gooker_young@qq.com
5
+ author_name: gooker_young
6
+ coverage_fail_under: 95
7
+ description: 基于 [copier](https://copier.readthedocs.io/) 的通用 Python 项目模板。
8
+ license: MIT
9
+ max_python_version: '3.14'
10
+ min_python_version: '3.8'
11
+ package_name: coopie
12
+ project_name: coopie
13
+ pypi_token_secret: PYPI_TOKEN
14
+ use_cicd: true
15
+ use_docker: true
16
+ use_docs: true
17
+ use_domestic_mirrors: true
18
+ use_tox: true
19
+
@@ -0,0 +1,46 @@
1
+ # 版本控制
2
+ .git
3
+ .gitignore
4
+ .github
5
+
6
+ # Python 缓存与构建产物
7
+ __pycache__
8
+ *.pyc
9
+ *.pyo
10
+ *.pyd
11
+ *.egg-info
12
+ *.egg
13
+ dist
14
+ build
15
+ .eggs
16
+
17
+ # 测试与覆盖率
18
+ .pytest_cache
19
+ .coverage
20
+ htmlcov
21
+ .tox
22
+ coverage.xml
23
+
24
+ # 虚拟环境
25
+ .venv
26
+ venv
27
+ env
28
+
29
+ # 工具缓存
30
+ .uv-cache
31
+ .ruff_cache
32
+ .pyrefly_cache
33
+ .mypy_cache
34
+
35
+ # IDE 与编辑器
36
+ .idea
37
+ .vscode
38
+ *.swp
39
+ *.swo
40
+
41
+ # 文档(按需保留)
42
+ docs
43
+
44
+ # 系统文件
45
+ .DS_Store
46
+ Thumbs.db
@@ -0,0 +1,58 @@
1
+ name: CI
2
+
3
+ on:
4
+ push:
5
+ branches: [main, develop]
6
+ pull_request:
7
+ branches: [main, develop]
8
+
9
+ concurrency:
10
+ group: ${{ github.workflow }}-${{ github.ref }}
11
+ cancel-in-progress: true
12
+
13
+ jobs:
14
+ lint:
15
+ name: Lint & Typecheck
16
+ runs-on: ubuntu-latest
17
+ steps:
18
+ - uses: actions/checkout@v4
19
+
20
+ - name: Install uv
21
+ uses: astral-sh/setup-uv@v3
22
+ with:
23
+ enable-cache: true
24
+
25
+ - name: Sync dependencies
26
+ run: uv sync --extra dev
27
+
28
+ - name: Ruff check
29
+ run: uv run ruff check src tests
30
+
31
+ - name: Ruff format check
32
+ run: uv run ruff format --check src tests
33
+
34
+ - name: Pyrefly check
35
+ run: uv run pyrefly check .
36
+
37
+ test:
38
+ name: Test (Python 3.8 & 3.14)
39
+ runs-on: ubuntu-latest
40
+ strategy:
41
+ matrix:
42
+ python-version: ["3.8", "3.14"]
43
+ steps:
44
+ - uses: actions/checkout@v4
45
+
46
+ - name: Install uv
47
+ uses: astral-sh/setup-uv@v3
48
+ with:
49
+ enable-cache: true
50
+
51
+ - name: Set up Python ${{ matrix.python-version }}
52
+ run: uv python install ${{ matrix.python-version }}
53
+
54
+ - name: Sync dependencies
55
+ run: uv sync --extra dev --python ${{ matrix.python-version }}
56
+
57
+ - name: Run tests
58
+ run: uv run pytest -m "not slow" --cov=coopie --cov-fail-under=95 --cov-report=term-missing
@@ -0,0 +1,36 @@
1
+ name: Release
2
+
3
+ on:
4
+ push:
5
+ tags: ['v*.*.*']
6
+
7
+ permissions:
8
+ contents: write
9
+
10
+ jobs:
11
+ release:
12
+ name: Build & Publish
13
+ runs-on: ubuntu-latest
14
+ steps:
15
+ - uses: actions/checkout@v4
16
+
17
+ - name: Install uv
18
+ uses: astral-sh/setup-uv@v3
19
+ with:
20
+ enable-cache: true
21
+
22
+ - name: Build distributions
23
+ run: uv build
24
+
25
+ - name: Publish to PyPI
26
+ run: uv publish --token '${{ secrets.PYPI_TOKEN }}'
27
+
28
+ - name: Create GitHub Release
29
+ env:
30
+ GH_TOKEN: ${{ github.token }}
31
+ TAG_NAME: ${{ github.ref_name }}
32
+ run: |
33
+ gh release create "$TAG_NAME" \
34
+ --title "Release $TAG_NAME" \
35
+ --notes "Automated release from CI" \
36
+ dist/*
@@ -0,0 +1,18 @@
1
+ # Python-generated files
2
+ __pycache__/
3
+ *.py[oc]
4
+ build/
5
+ dist/
6
+ wheels/
7
+ *.egg-info
8
+
9
+ # Virtual environments
10
+ .venv
11
+ .coverage
12
+ .idea
13
+ *_profile.html
14
+
15
+ # Sphinx 文档构建输出
16
+ docs/_build/
17
+ .trae/refs
18
+
@@ -0,0 +1,19 @@
1
+ # prek / pre-commit 配置
2
+ # See https://pre-commit.com for more information
3
+ repos:
4
+ - repo: https://github.com/astral-sh/ruff-pre-commit
5
+ # Ruff 版本 - 与 pyproject.toml 保持同步
6
+ rev: v0.15.4
7
+ hooks:
8
+ # 运行 linter
9
+ - id: ruff
10
+ args: [--fix, --exit-non-zero-on-fix]
11
+ - repo: https://github.com/pre-commit/pre-commit-hooks
12
+ rev: v5.0.0
13
+ hooks:
14
+ - id: check-merge-conflict
15
+ - id: debug-statements
16
+ - id: fix-byte-order-marker
17
+ - id: trailing-whitespace
18
+ args: [--markdown-linebreak-ext=md]
19
+ - id: end-of-file-fixer
@@ -0,0 +1 @@
1
+ 3.8
@@ -0,0 +1,23 @@
1
+ # ReadTheDocs 配置
2
+ # https://docs.readthedocs.io/en/stable/config-file/v2.html
3
+ version: 2
4
+
5
+ # 构建配置
6
+ build:
7
+ os: ubuntu-24.04
8
+ tools:
9
+ python: "3.8"
10
+
11
+ # Python 依赖与构建命令
12
+ python:
13
+ install:
14
+ - method: pip
15
+ path: .
16
+ extra_requirements:
17
+ - docs
18
+
19
+ # Sphinx 构建
20
+ sphinx:
21
+ configuration: docs/conf.py
22
+ builder: html
23
+ fail_on_warning: false
@@ -0,0 +1,15 @@
1
+ # PYTHON
2
+ .coverage
3
+ .pytest_cache/
4
+ .ruff_cache/
5
+ .tox/
6
+ .venv/
7
+ __pycache__/
8
+
9
+ # NODEJS
10
+ node_modules/
11
+
12
+ # IDE
13
+ .idea
14
+ .trae
15
+ .vscode
@@ -0,0 +1,23 @@
1
+ # 开发流程约束
2
+
3
+ 本规则补充 `self-driven.md`,定义执行过程记录与规则变更的两条硬约束。
4
+
5
+ ## 执行过程记录
6
+
7
+ - **每次迭代**(一个完整的"计划 → 实现 → 测试 → 文档 → 验证"闭环)必须记录到
8
+ `.trae/docs/` 目录,文件名形如 `iter-NN-<主题>.md`,`NN` 为零填充序号。
9
+ - 记录内容至少包括:本轮目标、改动文件清单、关键决策与依据、验证结果、遗留事项。
10
+ - **每 5 次迭代后**清理 `.trae/docs/`:
11
+ - 把需要长期保留的整合性内容(可复用模式、踩坑总结、设计决策)
12
+ 归档到 `.trae/skills/` 对应技能文档中;
13
+ - 其余过程性记录删除;
14
+ - docs 目录只保留最近未归档的迭代记录(即第 6 次迭代开始前,清理 1–5 号记录)。
15
+ - 归档动作需在迭代记录中标注"已归档至 skills/<文件>"。
16
+
17
+ ## 规则变更约束
18
+
19
+ - 任何对 `.trae/rules/` 下文件的修改(新增、编辑、删除)**必须先询问用户**,
20
+ 获得明确授权后方可变动;**未授权前不得擅自修改 rules**。
21
+ - 用户在对话中显式要求写入的规则内容(如"把 X 写入 rules")视为已授权,
22
+ 可直接写入,写入后在回复中说明改了哪个文件、加了什么。
23
+ - 规则变更后需同步更新 `project_memory.md` 中的"开发约定"小节。
@@ -0,0 +1,11 @@
1
+ ---
2
+ alwaysApply: true
3
+ scene: git_message
4
+ ---
5
+
6
+ 在此处编写规则,自定义 AI 生成提交信息的风格。
7
+
8
+ ## 提交信息格式
9
+ - 提交信息必须使用中文。
10
+ - 提交信息必须包含变更的类型(例如 "fix"、"feat"、"refactor" 等)。
11
+ - 提交信息必须尽简洁明了,不要超过一段落。
@@ -0,0 +1,155 @@
1
+ # Python 开发规范
2
+
3
+ 本规范结合 Python 最佳实践,作为编写与审查 Python 代码的统一标准。
4
+
5
+ ## 工具链(以 pyproject.toml 为准)
6
+
7
+ | 工具 | 用途 | 配置要点 |
8
+ |------|------|---------|
9
+ | **ruff** | lint + format | `line-length=120`,`target-version="py38"` |
10
+ | **pyrefly** | 类型检查 | `preset="strict"`,`python-version="3.8"` |
11
+ | **pytest** | 测试 | `asyncio_default_fixture_loop_scope="function"`,marker `slow` |
12
+ | **coverage** | 覆盖率 | `branch=true`,`fail_under=95`,`concurrency=["thread"]` |
13
+ | **pre-commit** | 提交前检查 | ruff `--fix` + trailing-whitespace + end-of-file-fixer |
14
+
15
+ 验证(每次修改后必做):
16
+
17
+ ```bash
18
+ uv run ruff check src tests
19
+ uv run ruff format --check src tests
20
+ uv run pyrefly check .
21
+ uv run pytest -m "not slow" --cov=coopie --cov-fail-under=95
22
+ ```
23
+
24
+ ## 兼容性
25
+
26
+ - **最低 Python 3.8**:用 `from __future__ import annotations` 延迟注解求值;
27
+ 按版本用 `typing.List`(3.8) → 内置泛型(3.9) → `X | Y`(3.10) → `typing.override`(3.12)。
28
+ - **版本守卫**:`if sys.version_info >= (3, X):` 引入高版本 API;低版本回退分支加 `# pragma: no cover`。
29
+ - **优先标准库**:优先使用标准库实现功能;需 `typing-extensions` 用于 `override`/`TypeVar` 前向兼容
30
+ (`python_version < '3.13'` 时自动引入)。新增第三方依赖须审慎,优先用标准库。
31
+
32
+ ## 类型注解
33
+
34
+ - **公共 API 必须有完整类型注解**,包括返回类型;私有函数也应有注解。
35
+ - 泛型用 `TypeVar`;PEP 696 `default=` 仅 3.13+ 标准库支持,3.8–3.12 用 `typing_extensions.TypeVar`。
36
+ - `Mapping`/`Sequence` 用于只读参数,`dict`/`list` 用于可变返回。
37
+ - `Any` 仅用于真正动态场景;内部类型必须完全静态。
38
+ - 禁用裸 `# type: ignore`;确需时加具体规则码(如 `# type: ignore[union-attr]`)。
39
+ - **`TYPE_CHECKING` 守卫**:仅类型检查需要的导入放 `if TYPE_CHECKING:` 块内,避免循环依赖。
40
+ - **类型收窄**:用 `assert isinstance(x, Y)` 辅助 pyrefly 推断;`cast()` 仅用于类型系统无法表达的场景。
41
+
42
+ ## 数据结构
43
+
44
+ - **不可变优先**:配置/描述类用 `@dataclass(frozen=True)`;可变类属性标注 `RUF012` 豁免。
45
+ - **缓存**:实例级用 `functools.cached_property`,按参数键控用 `functools.lru_cache`;
46
+ 不可哈希参数需 try/except 回退。修改被缓存数据源后必须手动清空缓存。
47
+ - **抽象基类**:接口用 `abc.ABC` + `@abstractmethod`。
48
+ - **枚举**:状态/标志值用 `enum.Enum`,禁止裸字符串/魔术数字;枚举值用 `UPPER_SNAKE`。
49
+ - **`__repr__`**:可变类实现 `__repr__`(含关键字段);`frozen=True` dataclass 自动生成。
50
+
51
+ ## 模块与导入
52
+
53
+ - **单一职责**:每模块只做一件事。禁止跨职责边界。
54
+ - **导入顺序**(ruff isort):`__future__` → 标准库 → 第三方 → 本地,各组间空行。
55
+ - **惰性导入**:仅为打破循环依赖时使用,函数体内导入并注释说明;顶层导入是默认。
56
+ - **`__all__`**:定义 `__all__` 显式声明导出符号,位置仅次于 `__future__` 之后。
57
+ - **禁用 star imports**:`from x import *` 污染命名空间、破坏类型检查(`__init__.py` 聚合经 `__all__` 控制为例外)。
58
+ - **避免 `utils.py`/`helpers.py`**:按职责归入对应模块。
59
+
60
+ ## 函数设计
61
+
62
+ - **模块级函数优于 Mixin**:共享逻辑用模块级函数,类只持有状态与薄方法。
63
+ - **静态方法慎用**:纯函数直接放模块级。
64
+ - **参数 ≤ 5 个**为宜;超出用 dataclass 封装参数对象。
65
+ - **单一职责**:一个函数做一件事;过长函数考虑拆分。
66
+ - **异常范围要窄**:只捕获预期异常(如 `(TypeError, ValueError, KeyError, AttributeError)`),
67
+ **禁止** `except Exception` 掩盖 bug;捕获后至少 `logger.warning` 记录。
68
+ - **可变默认参数**:`def f(x=[])` 是经典坑;用 `None` 哨兵或 `field(default_factory=list)`。
69
+
70
+ ## 异常处理
71
+
72
+ - **自定义异常家族**:继承公共基类,按错误场景分类。
73
+ - **异常包装**:`raise NewError(...) from exc` 保留因果链。
74
+ - **不要吞异常**:捕获后必须处理(记录/包装/重抛),禁止空 `except: pass`。
75
+ - **钩子/回调异常**:第三方回调异常仅记录,不影响主流程。
76
+
77
+ ## 并发与线程安全
78
+
79
+ - **进程全局状态**(`os.environ`/`os.chdir`)在并发场景下必须用全局锁(`threading.RLock`)序列化。
80
+ - **批量 I/O**:循环内多次写盘改为批量一次(`contextmanager` 包裹延迟落盘)。
81
+ - **信号量限流**:按组限流时用 `Semaphore`。
82
+
83
+ ## 测试
84
+
85
+ - **覆盖率 ≥ 95%**(branch coverage),不得下降。
86
+ - **公共 API 优先测试**:用公共接口测试,不访问私有方法;
87
+ 故障注入等场景可临时访问私有属性,docstring 注明原因。
88
+ - **命名**:`test_<被测对象>_<场景>`。
89
+ - **断言**:原生 `assert x == 1`,禁用 `self.assertEqual`;`pytest.raises` 必填 `match=`。
90
+ - **Mock 优先级**:`monkeypatch` > 内联 stub > `unittest.mock` > `pytest-mock`。
91
+ 禁用 `@patch` 装饰器、`mock.patch.object` 上下文、`pytest-mock` 的 `mocker` fixture。
92
+ - **fixture**:`tmp_path`/`monkeypatch`/`capsys` 优先;autouse 仅全局必需时用。
93
+ - **slow 标记**:耗时测试加 `@pytest.mark.slow`,CI 可 `-m "not slow"` 跳过。
94
+ - **测试代码也跑 ruff**:`tests/**` 忽略 `ARG001`/`ARG002`。
95
+
96
+ ## 代码风格
97
+
98
+ - **行宽 120**(ruff formatter 处理)。
99
+ - **docstring**:公共 API 必须有;中文叙述 + 中文注释是本项目既有风格。
100
+ - **打印和日志**:使用中文打印和日志,避免使用英文。
101
+ - **命名**:`snake_case` 函数/变量,`PascalCase` 类,`UPPER_SNAKE` 常量,`_leading_underscore` 私有。
102
+ - **字符串引号**:ruff 默认双引号。
103
+ - **末尾单 `\n`**、**无尾随空格**(pre-commit 强制)。
104
+ - **不用 emoji**:除非用户明确要求。
105
+
106
+ ## Pythonic 风格
107
+
108
+ - **`is` 比较 `None`/`True`/`False`**:单例用 `is`,值用 `==`(PEP 8 E711/E712)。
109
+ - **EAFP 优于 LBYL**:先尝试再处理异常,而非先检查再执行(避免竞态窗口)。
110
+ - **truthiness**:`if items:` 优于 `if len(items) > 0:`。
111
+ - **字符串格式化**:首选 f-string;`%` 仅用于 `logging` 延迟格式化。
112
+ - **推导式**优于 `map`+`filter`;> 2 层拆为显式循环。
113
+ - **`enumerate`** 替代 `range(len())`;**`zip`** 并行迭代(3.10+ 用 `strict=True`)。
114
+ - **解包** `a, b = pair` 优于索引访问;忽略值用 `_`。
115
+ - **海象运算符 `:=`**(3.8+):赋值+判断合一,但不滥用。
116
+
117
+ ## 日志
118
+
119
+ - **`logging.getLogger(__name__)`**:每模块独立 logger,禁用 `print` 调试残留。
120
+ - **结构化上下文**:`extra={...}` 传字段;`logger.warning("task %r failed: %s", name, exc)` 优于 f-string(延迟格式化)。
121
+ - **日志级别**:`DEBUG` 诊断 / `INFO` 关键流程 / `WARNING` 可恢复异常 / `ERROR` 需人工介入。
122
+ - **禁止日志密码/密钥**:脱敏后再记录。
123
+
124
+ ## 路径与资源
125
+
126
+ - **优先 `pathlib.Path`**:`Path("a") / "b"` 而非 `os.path.join`(ruff `PTH` 强制);
127
+ 禁止字符串拼接路径。类型注解用 `Path`,边界 `str` 立即包装。
128
+ - **`with` 语句**:文件、锁、连接、临时目录一律用 `with` 或 `contextlib.contextmanager`;
129
+ 多资源用 `contextlib.ExitStack`。
130
+ - **显式关闭**:长生命周期对象(连接池、线程池)实现 `close()`,但优先 `with`。
131
+ - **批量操作**:循环内多次 acquire/release 改为批量一次。
132
+
133
+ ## 安全
134
+
135
+ - **禁用 `eval`/`exec`**:处理不可信输入时绝不使用;用 `ast.literal_eval` 或专用解析器。
136
+ - **`subprocess`**:禁用 `shell=True` 除非命令完全可信;优先 `list[str]` 形式。
137
+ - **凭证不入仓**:密钥/token/密码放 `.env` 或环境变量,`.gitignore` 必须包含 `.env`。
138
+ - **日志脱敏**:记录请求/响应时移除 `Authorization`、`password` 等字段。
139
+ - **依赖审计**:`uv lock` 后审阅新增依赖,避免引入已知 CVE 的包。
140
+
141
+ ## 性能要点
142
+
143
+ - **避免重复计算**:循环内查询应缓存或预构建映射(如 `{name: spec}`)。
144
+ - **避免双重查找**:`has(k)` + `get(k)` 改为单次 `get(k)` + `KeyError` 回退。
145
+ - **统一校验**:入口校验一次,下游路径不重复。
146
+ - **事件 emit**:生命周期必须 emit 完整状态转换,不要留死分支
147
+ (`# pragma: no cover` 是清理信号,应激活或删除)。
148
+
149
+ ## Git 与提交
150
+
151
+ - **自动提交**:任务完成后自动 `git add`(按文件名)+ `git commit` + `git push`(仅当分支已跟踪远程时执行 push;新分支跳过 push 并在总结中说明)。
152
+ - **不修改 git config**。
153
+ - **不运行破坏性命令**(`push --force`/`reset --hard`/`clean -f`)除非用户明确要求。
154
+ - **staging**:按文件名添加,不用 `git add -A`/`git add .`,避免误加敏感文件。
155
+ - **commit message**:简洁,聚焦"为什么"而非"是什么";遵循仓库既有风格。
@@ -0,0 +1,149 @@
1
+ ---
2
+ alwaysApply: true
3
+ ---
4
+
5
+ # 自驱动开发规则
6
+
7
+ 本规则定义一种"目标驱动、闭环执行"的工作模式:仅在任务开始时与用户确认一次目标与边界,后续由 Agent 自主完成"计划 → 编码 → 测试 → 文档 → 验证"的迭代循环,直到用户目标达成。
8
+
9
+ ## 核心原则
10
+
11
+ - **目标导向**:始终以用户最终目标为准绳,所有阶段产出都应服务于该目标。
12
+ - **闭环执行**:每个子任务必须走完"计划 → 实现 → 测试 → 文档 → 验证"五步;禁止跳步留半成品。
13
+ - **自主决策**:初始确认之后,实现路径、API 形态、重构范围、文件命名、测试组织、错误修复策略等由 Agent 自行决断,不再逐项请示。**可逆操作(编辑文件、运行测试、修复 lint、调整实现)直接执行,不询问**;只有不可逆/高风险操作才暂停。
14
+ - **透明沟通**:每个阶段开始前用一句话说明意图;关键节点(完成、阻塞、转向)给简短更新;不复述内部思考,**不在收尾时停下询问"是否继续"或"是否提交"**——直接输出总结并结束。
15
+ - **安全边界**:仅在高风险、不可逆操作或真正阻塞时才暂停找用户。
16
+
17
+ ## 初始确认(一次性,仅在最开始)
18
+
19
+ 任务启动时,用 `AskUserQuestion` 一次性确认以下信息(已由项目规范覆盖的不必重复确认):
20
+
21
+ 1. **目标与范围**:要解决什么问题?交付物是什么?显式列出不在范围内的内容。
22
+ 2. **验收标准**:怎样算"完成"?可观测的判定条件(功能、性能、覆盖率阈值)。
23
+ 3. **特殊约束**:除 `python-standards.md` 之外的约束(兼容性、依赖限制、API 兼容策略等)。
24
+ 4. **测试要求**:覆盖率门槛(项目默认 ≥95%,branch);是否需要新增 `slow` 标记。
25
+
26
+ **git commit/push 不在确认范围内**:任务完成后自动 commit + push(仅当分支已跟踪远程时执行 push;新分支跳过 push 并在总结中说明),遵循 `.trae/rules/git-commit-message.md` 风格。仅 force-push、reset --hard、clean -f、修改 git config 等真正破坏性操作才需暂停确认。
27
+
28
+ 确认后,将目标与验收标准固化进 `TaskCreate` 任务列表,后续不再就同一信息反复询问。
29
+
30
+ ## 迭代循环
31
+
32
+ 下列五个阶段构成一个完整闭环。未达验收标准时,回到「计划」开启下一轮;达标准时,进入「收尾」。
33
+
34
+ ### 1. 计划(Plan)
35
+
36
+ - 用 Explore/Glob/Grep 研究相关代码与既有模式,避免凭空设计。
37
+ - 用 `TaskCreate` 把目标拆为可独立验证的子任务;每完成一项立即 `TaskUpdate` 为 completed。
38
+ - 优先复用现有抽象;不为本轮假想需求设计接口。
39
+ - 不过早抽象:三处相似才考虑提取,否则就地写。
40
+
41
+ ### 2. 实现(Code)
42
+
43
+ - 严格遵守 `.trae/rules/python-standards.md` 与既有代码风格。
44
+ - 优先 Edit 现有文件;新增文件需有明确职责边界。
45
+ - 公共 API 必须有完整类型注解与中文 docstring。
46
+ - 不写未被要求的功能、不为未来场景预留扩展点。
47
+
48
+ ### 3. 测试(Test)
49
+
50
+ - 新增/修改的公共 API 必须配套测试;优先通过公共接口测试,故障注入可访问私有属性并在 docstring 注明。
51
+ - Mock 优先级:`monkeypatch` > 内联 stub > `unittest.mock` > `pytest-mock`;禁用 `@patch` 装饰器。
52
+ - 必跑校验(每次修改后):
53
+
54
+ ```bash
55
+ uv run ruff check src tests
56
+ uv run pytest -m "not slow" --cov=coopie --cov-fail-under=95
57
+ ```
58
+
59
+ - 测试失败时定位根因再修复,不通过放宽断言或 `# pragma: no cover` 绕过。
60
+ - 覆盖率不得低于上一次的值(项目门槛 95%,branch)。
61
+
62
+ ### 4. 文档(Docs)
63
+
64
+ - 同步更新 docstring、README、模块结构说明。
65
+ - 跨会话有价值的设计决策、约束、陷阱,追加到 memory(`project_memory.md` 或对应 `topics.md`)。
66
+ - 不主动新建 `*.md` 文档;除非用户明确要求。
67
+
68
+ ### 5. 验证(Verify)
69
+
70
+ - 逐条对照初始确认的「验收标准」核验;未满足则回到「计划」继续下一轮。
71
+ - 全套门禁通过:ruff、pyrefly、pytest、coverage。
72
+ - 给出本轮变更清单(改了哪些文件、为什么)。
73
+
74
+ ## 多阶段项目
75
+
76
+ 当项目按阶段(P0/P1/P2/...)划分时,初始确认的目标是**整个项目**,而非单个阶段。
77
+
78
+ - **阶段是里程碑,不是边界**:确认"推进 P1"只是指定下一步重点,不缩小整体目标范围;
79
+ 也不意味着 P1 完成后就可以停下。整体目标 = 所有阶段交付完毕。
80
+ - **阶段完成不是停止条件**:某阶段验收标准全部满足后,**自动进入下一阶段的「计划」步骤**,
81
+ 不停下来输出"是否继续"或"是否扩展范围"的询问。仅在阶段切换时用一句话说明
82
+ "进入 Pn,重点:…",然后继续自驱动迭代。
83
+ - **「收尾」仅适用于整个项目完成**:只有所有阶段(含最后一个)都交付后,才执行
84
+ 「收尾」输出最终总结。单阶段完成 → 进入下一阶段的「计划」,不触发收尾。
85
+ - **跨阶段依赖**:若下一阶段依赖外部资源(如新依赖审批、环境配置),属"不可恢复的失败"
86
+ 暂停条件;否则一律连续推进。
87
+ - **阶段范围超出预期**:执行中发现某阶段需要显著扩大范围或改变方向,
88
+ 属"超出初始确认范围"暂停条件,需找用户确认。
89
+
90
+ ## 暂停条件(仅在以下情况中断自驱动找用户)
91
+
92
+ 1. **歧义无法自决**:需求存在多种合理解读且无既有约定可循。
93
+ 2. **高风险/不可逆操作**:删除非临时文件、`git push --force`、`reset --hard`、删表、修改 CI 配置、修改 git config、卸载依赖等。**普通 `git commit`/`push` 不属于此类**(任务完成后自动执行)。
94
+ 3. **不可恢复的失败**:根因不在本仓库、需外部环境/权限配合、或经两轮尝试仍无法定位。
95
+ 4. **超出初始确认范围**:用户目标在执行中发现需要显著扩大范围或改变方向。
96
+ 5. **用户主动询问**:用户在对话中提出新问题或要求澄清。
97
+
98
+ **注意**:"目标已达成"**不是**暂停条件——但"目标已达成"指**整个项目目标**(所有阶段交付完毕),而非单个阶段验收满足。单阶段验收满足后应自动进入下一阶段(见「多阶段项目」),不触发收尾。
99
+
100
+ 非以上情况,一律继续自驱动,不要为"求确认"而暂停。
101
+
102
+ ## 决策判据:该问还是自决
103
+
104
+ 遇到不确定时,按以下顺序判断:
105
+
106
+ 1. **是否不可逆/高风险?** 是 → 暂停确认(如删除文件、`push --force`、修改 CI 配置、卸载依赖)。否 → 继续。
107
+ 2. **是否在初始确认范围内?** 是 → 按确认执行,不询问。否 → 视为"超出初始确认范围",暂停。
108
+ 3. **是否有既有约定可循?** 是 → 按约定执行(参考 `python-standards.md`、`project_memory.md`)。否 → 视为"歧义无法自决",暂停。
109
+ 4. **是否可逆?** 是 → 直接执行,即使结果可能不完美(可在后续迭代修正)。否 → 暂停。
110
+
111
+ **可直接自决(不询问)的典型情况**:
112
+
113
+ - 测试失败、覆盖率不达标、lint/类型检查报错 → 定位根因并修复。
114
+ - 代码风格选择(命名、模块划分、参数顺序)→ 自决。
115
+ - 文件编辑、运行测试、运行校验命令 → 直接执行。
116
+ - 任务完成后输出收尾总结 → 直接输出,不询问下一步。
117
+ - 显式指定 `name` 参数以保持测试兼容性 → 自决。
118
+ - 重命名局部变量以避免遮蔽 → 自决。
119
+
120
+ **必须暂停询问的典型情况**:
121
+
122
+ - 删除非临时文件、重命名公共模块/包。
123
+ - `git push --force`、`reset --hard`、`clean -f`、修改 git config(普通 commit/push 自动执行,无需询问)。
124
+ - 引入新的运行时依赖。
125
+ - 修改 CI 配置、pre-commit 钩子、pyproject.toml 的工具链配置。
126
+ - 卸载或降级既有依赖。
127
+
128
+ ## 沟通风格
129
+
130
+ - 阶段切换时一句话说明即可;不要把内部推理写给用户看。
131
+ - 完成子任务后用一两句总结改了什么、下一步做什么。
132
+ - 遇到阻塞时直接说明:卡在哪、试了什么、需要用户做什么。
133
+ - **不在收尾时询问"是否需要提交"或"是否扩展范围"**——直接输出总结并结束。用户后续若有新需求,由用户主动提出。
134
+ - 不使用 emoji,除非用户明确要求。
135
+
136
+ ## 工具使用
137
+
138
+ - 独立操作尽量并行调用(多个 Read/Grep/Glob 一批发出)。
139
+ - 用 `TaskCreate`/`TaskUpdate` 维护进度,不批量推迟标记。
140
+ - 长命令用后台运行(`run_in_background`),完成会自动通知。
141
+ - 文件操作一律用专用工具:Read/Edit/Write/Glob/Grep,不用 `cat`/`sed`/`grep`/`find`。
142
+
143
+ ## 收尾
144
+
145
+ - **仅当整个项目所有阶段都交付后**,才执行收尾:直接输出最终总结并结束任务(交付物、关键决策、遗留事项)。
146
+ - 单阶段完成**不属于收尾**——见「多阶段项目」,应自动进入下一阶段的「计划」。
147
+ - **自动提交**:收尾时自动 `git add`(按文件名)+ `git commit`(遵循 `.trae/rules/git-commit-message.md` 风格)+ `git push`(仅当分支已跟踪远程时执行;新分支跳过 push 并在总结中说明);**不询问**"是否需要提交"或"是否扩展范围"。
148
+ - 若验收标准未全部满足,回到「计划」继续下一轮,不停下询问。
149
+ - 将本次会话的关键产出与决策更新到 memory,便于后续会话续接。
@@ -0,0 +1,35 @@
1
+ {
2
+ "[python]": {
3
+ "editor.codeActionsOnSave": {
4
+ "source.fixAll.ruff": "always",
5
+ "source.organizeImports.ruff": "always",
6
+ "source.sort.json": "always"
7
+ },
8
+ "editor.defaultFormatter": "charliermarsh.ruff",
9
+ "editor.formatOnSave": true
10
+ },
11
+ "[toml]": {
12
+ "editor.defaultFormatter": "tamasfe.even-better-toml",
13
+ "editor.formatOnSave": true
14
+ },
15
+ "evenBetterToml.formatter.alignComments": true,
16
+ "evenBetterToml.formatter.alignEntries": true,
17
+ "evenBetterToml.formatter.allowedBlankLines": 1,
18
+ "evenBetterToml.formatter.arrayAutoCollapse": true,
19
+ "evenBetterToml.formatter.arrayAutoExpand": true,
20
+ "evenBetterToml.formatter.arrayTrailingComma": true,
21
+ "evenBetterToml.formatter.compactEntries": false,
22
+ "evenBetterToml.formatter.indentEntries": false,
23
+ "evenBetterToml.formatter.indentTables": false,
24
+ "evenBetterToml.formatter.reorderArrays": true,
25
+ "evenBetterToml.formatter.reorderInlineTables": true,
26
+ "evenBetterToml.formatter.reorderKeys": true,
27
+ "python.languageServer": "None",
28
+ "python.testing.pytestArgs": [
29
+ "src",
30
+ "tests",
31
+ ],
32
+ "python.testing.pytestEnabled": true,
33
+ "python.testing.unittestEnabled": false,
34
+ "ruff.importStrategy": "fromEnvironment"
35
+ }