aury-boot 0.0.4__py3-none-any.whl → 0.0.5__py3-none-any.whl

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 (98) hide show
  1. aury/boot/__init__.py +2 -2
  2. aury/boot/_version.py +2 -2
  3. aury/boot/application/__init__.py +45 -36
  4. aury/boot/application/app/__init__.py +12 -8
  5. aury/boot/application/app/base.py +12 -0
  6. aury/boot/application/app/components.py +137 -44
  7. aury/boot/application/app/middlewares.py +2 -0
  8. aury/boot/application/app/startup.py +249 -0
  9. aury/boot/application/config/__init__.py +36 -1
  10. aury/boot/application/config/multi_instance.py +200 -0
  11. aury/boot/application/config/settings.py +341 -12
  12. aury/boot/application/constants/components.py +6 -0
  13. aury/boot/application/errors/handlers.py +17 -3
  14. aury/boot/application/middleware/logging.py +8 -120
  15. aury/boot/application/rpc/__init__.py +2 -2
  16. aury/boot/commands/__init__.py +30 -10
  17. aury/boot/commands/app.py +131 -1
  18. aury/boot/commands/docs.py +104 -17
  19. aury/boot/commands/init.py +27 -8
  20. aury/boot/commands/server/app.py +2 -3
  21. aury/boot/commands/templates/project/AGENTS.md.tpl +217 -0
  22. aury/boot/commands/templates/project/README.md.tpl +2 -2
  23. aury/boot/commands/templates/project/aury_docs/00-overview.md.tpl +59 -0
  24. aury/boot/commands/templates/project/aury_docs/01-model.md.tpl +183 -0
  25. aury/boot/commands/templates/project/aury_docs/02-repository.md.tpl +206 -0
  26. aury/boot/commands/templates/project/aury_docs/03-service.md.tpl +398 -0
  27. aury/boot/commands/templates/project/aury_docs/04-schema.md.tpl +95 -0
  28. aury/boot/commands/templates/project/aury_docs/05-api.md.tpl +116 -0
  29. aury/boot/commands/templates/project/aury_docs/06-exception.md.tpl +118 -0
  30. aury/boot/commands/templates/project/aury_docs/07-cache.md.tpl +122 -0
  31. aury/boot/commands/templates/project/aury_docs/08-scheduler.md.tpl +32 -0
  32. aury/boot/commands/templates/project/aury_docs/09-tasks.md.tpl +38 -0
  33. aury/boot/commands/templates/project/aury_docs/10-storage.md.tpl +115 -0
  34. aury/boot/commands/templates/project/aury_docs/11-logging.md.tpl +92 -0
  35. aury/boot/commands/templates/project/aury_docs/12-admin.md.tpl +56 -0
  36. aury/boot/commands/templates/project/aury_docs/13-channel.md.tpl +92 -0
  37. aury/boot/commands/templates/project/aury_docs/14-mq.md.tpl +102 -0
  38. aury/boot/commands/templates/project/aury_docs/15-events.md.tpl +147 -0
  39. aury/boot/commands/templates/project/config.py.tpl +1 -1
  40. aury/boot/commands/templates/project/env.example.tpl +73 -5
  41. aury/boot/commands/templates/project/modules/tasks.py.tpl +1 -1
  42. aury/boot/contrib/admin_console/auth.py +2 -3
  43. aury/boot/contrib/admin_console/install.py +1 -1
  44. aury/boot/domain/models/mixins.py +48 -1
  45. aury/boot/domain/pagination/__init__.py +94 -0
  46. aury/boot/domain/repository/impl.py +1 -1
  47. aury/boot/domain/repository/interface.py +1 -1
  48. aury/boot/domain/transaction/__init__.py +8 -9
  49. aury/boot/infrastructure/__init__.py +86 -29
  50. aury/boot/infrastructure/cache/backends.py +102 -18
  51. aury/boot/infrastructure/cache/base.py +12 -0
  52. aury/boot/infrastructure/cache/manager.py +153 -91
  53. aury/boot/infrastructure/channel/__init__.py +24 -0
  54. aury/boot/infrastructure/channel/backends/__init__.py +9 -0
  55. aury/boot/infrastructure/channel/backends/memory.py +83 -0
  56. aury/boot/infrastructure/channel/backends/redis.py +88 -0
  57. aury/boot/infrastructure/channel/base.py +92 -0
  58. aury/boot/infrastructure/channel/manager.py +203 -0
  59. aury/boot/infrastructure/clients/__init__.py +22 -0
  60. aury/boot/infrastructure/clients/rabbitmq/__init__.py +9 -0
  61. aury/boot/infrastructure/clients/rabbitmq/config.py +46 -0
  62. aury/boot/infrastructure/clients/rabbitmq/manager.py +288 -0
  63. aury/boot/infrastructure/clients/redis/__init__.py +28 -0
  64. aury/boot/infrastructure/clients/redis/config.py +51 -0
  65. aury/boot/infrastructure/clients/redis/manager.py +264 -0
  66. aury/boot/infrastructure/database/config.py +1 -2
  67. aury/boot/infrastructure/database/manager.py +16 -38
  68. aury/boot/infrastructure/events/__init__.py +18 -21
  69. aury/boot/infrastructure/events/backends/__init__.py +11 -0
  70. aury/boot/infrastructure/events/backends/memory.py +86 -0
  71. aury/boot/infrastructure/events/backends/rabbitmq.py +193 -0
  72. aury/boot/infrastructure/events/backends/redis.py +162 -0
  73. aury/boot/infrastructure/events/base.py +127 -0
  74. aury/boot/infrastructure/events/manager.py +224 -0
  75. aury/boot/infrastructure/mq/__init__.py +24 -0
  76. aury/boot/infrastructure/mq/backends/__init__.py +9 -0
  77. aury/boot/infrastructure/mq/backends/rabbitmq.py +179 -0
  78. aury/boot/infrastructure/mq/backends/redis.py +167 -0
  79. aury/boot/infrastructure/mq/base.py +143 -0
  80. aury/boot/infrastructure/mq/manager.py +239 -0
  81. aury/boot/infrastructure/scheduler/manager.py +7 -3
  82. aury/boot/infrastructure/storage/__init__.py +9 -9
  83. aury/boot/infrastructure/storage/base.py +17 -5
  84. aury/boot/infrastructure/storage/factory.py +0 -1
  85. aury/boot/infrastructure/tasks/__init__.py +2 -2
  86. aury/boot/infrastructure/tasks/manager.py +47 -29
  87. aury/boot/testing/base.py +2 -2
  88. {aury_boot-0.0.4.dist-info → aury_boot-0.0.5.dist-info}/METADATA +19 -2
  89. aury_boot-0.0.5.dist-info/RECORD +176 -0
  90. aury/boot/commands/templates/project/DEVELOPMENT.md.tpl +0 -1397
  91. aury/boot/infrastructure/events/bus.py +0 -362
  92. aury/boot/infrastructure/events/config.py +0 -52
  93. aury/boot/infrastructure/events/consumer.py +0 -134
  94. aury/boot/infrastructure/events/models.py +0 -63
  95. aury_boot-0.0.4.dist-info/RECORD +0 -137
  96. /aury/boot/commands/templates/project/{CLI.md.tpl → aury_docs/99-cli.md.tpl} +0 -0
  97. {aury_boot-0.0.4.dist-info → aury_boot-0.0.5.dist-info}/WHEEL +0 -0
  98. {aury_boot-0.0.4.dist-info → aury_boot-0.0.5.dist-info}/entry_points.txt +0 -0
@@ -1,6 +1,21 @@
1
1
  """命令行工具模块。
2
2
 
3
- 统一入口: aum
3
+ 统一入口: aury
4
+
5
+ CLI 继承接口:
6
+ 子框架(如 aury-django、aury-cloud)可以通过以下接口继承基础命令:
7
+
8
+ - register_commands(app): 将所有命令注册到目标 app
9
+ - get_command_modules(): 获取所有命令模块,供进一步定制
10
+
11
+ 示例:
12
+ ```python
13
+ from typer import Typer
14
+ from aury.boot.commands import register_commands
15
+
16
+ app = Typer(name="aury-django")
17
+ register_commands(app) # 继承所有命令
18
+ ```
4
19
  """
5
20
 
6
21
  from __future__ import annotations
@@ -9,22 +24,27 @@ from __future__ import annotations
9
24
  from .config import ProjectConfig, get_project_config, save_project_config
10
25
 
11
26
 
12
- # 延迟导入 appmain,避免加载重型依赖
27
+ # 延迟导入 appmain、register_commands、get_command_modules,避免加载重型依赖
13
28
  def __getattr__(name: str):
14
- if name in ("app", "main"):
15
- from .app import main as _main
29
+ if name in ("app", "main", "register_commands", "get_command_modules"):
30
+ from .app import _get_app, get_command_modules, main, register_commands
16
31
  if name == "main":
17
- return _main
18
- # app 通过 app 模块的 __getattr__ 获取
19
- from . import app as app_module
20
- return app_module.app
32
+ return main
33
+ if name == "app":
34
+ return _get_app()
35
+ if name == "register_commands":
36
+ return register_commands
37
+ if name == "get_command_modules":
38
+ return get_command_modules
21
39
  raise AttributeError(f"module {__name__!r} has no attribute {name!r}")
22
40
 
23
41
 
24
42
  __all__ = [
25
- "app",
26
- "main",
27
43
  "ProjectConfig",
44
+ "app",
45
+ "get_command_modules",
28
46
  "get_project_config",
47
+ "main",
48
+ "register_commands",
29
49
  "save_project_config",
30
50
  ]
aury/boot/commands/app.py CHANGED
@@ -18,6 +18,22 @@
18
18
  aury worker # 运行 Worker
19
19
  aury migrate up # 执行数据库迁移
20
20
  aury docs all --force # 更新所有文档
21
+
22
+ CLI 继承:
23
+ 子框架(如 aury-django、aury-cloud)可以通过 `register_commands` 继承所有基础命令:
24
+
25
+ ```python
26
+ from typer import Typer
27
+ from aury.boot.commands import register_commands
28
+
29
+ app = Typer(name="aury-django")
30
+ register_commands(app) # 继承所有 aury-boot 命令
31
+
32
+ # 添加 django 特有命令
33
+ @app.command()
34
+ def startapp(name: str):
35
+ ...
36
+ ```
21
37
  """
22
38
 
23
39
  from __future__ import annotations
@@ -92,7 +108,119 @@ def main() -> None:
92
108
  _get_app()()
93
109
 
94
110
 
95
- # 为了向后兼容,允许 `from .app import app`
111
+ def register_commands(
112
+ target_app: typer.Typer,
113
+ *,
114
+ include_init: bool = True,
115
+ include_add: bool = True,
116
+ include_generate: bool = True,
117
+ include_server: bool = True,
118
+ include_scheduler: bool = True,
119
+ include_worker: bool = True,
120
+ include_migrate: bool = True,
121
+ include_docker: bool = True,
122
+ include_docs: bool = True,
123
+ ) -> None:
124
+ """将 aury-boot 的所有命令注册到目标 Typer app。
125
+
126
+ 用于子框架(如 aury-django、aury-cloud)继承基础命令。
127
+
128
+ Args:
129
+ target_app: 目标 Typer 应用
130
+ include_*: 是否包含对应的命令组
131
+
132
+ 使用示例:
133
+ ```python
134
+ from typer import Typer
135
+ from aury.boot.commands import register_commands
136
+
137
+ app = Typer(name="aury-django")
138
+
139
+ # 继承所有 aury-boot 命令
140
+ register_commands(app)
141
+
142
+ # 或选择性继承
143
+ register_commands(app, include_docker=False)
144
+
145
+ # 添加 django 特有命令
146
+ django_app = Typer(name="django")
147
+
148
+ @django_app.command()
149
+ def startapp(name: str):
150
+ '''Django startapp'''
151
+ ...
152
+
153
+ app.add_typer(django_app, name="django")
154
+ ```
155
+ """
156
+ # 延迟导入子命令
157
+ if include_init:
158
+ from .init import init
159
+ target_app.command(name="init", help="🎯 初始化项目脚手架")(init)
160
+
161
+ if include_add:
162
+ from .add import app as add_app
163
+ target_app.add_typer(add_app, name="add", help="➕ 添加可选模块")
164
+
165
+ if include_generate:
166
+ from .generate import app as generate_app
167
+ target_app.add_typer(generate_app, name="generate", help="⚡ 代码生成器")
168
+
169
+ if include_server:
170
+ from .server import app as server_app
171
+ target_app.add_typer(server_app, name="server", help="🖥️ 服务器管理")
172
+
173
+ if include_scheduler:
174
+ from .scheduler import app as scheduler_app
175
+ target_app.add_typer(scheduler_app, name="scheduler", help="🕐 独立运行调度器")
176
+
177
+ if include_worker:
178
+ from .worker import app as worker_app
179
+ target_app.add_typer(worker_app, name="worker", help="⚙️ 运行任务队列 Worker")
180
+
181
+ if include_migrate:
182
+ from .migrate import app as migrate_app
183
+ target_app.add_typer(migrate_app, name="migrate", help="🗃️ 数据库迁移")
184
+
185
+ if include_docker:
186
+ from .docker import app as docker_app
187
+ target_app.add_typer(docker_app, name="docker", help="🐳 Docker 配置")
188
+
189
+ if include_docs:
190
+ from .docs import app as docs_app
191
+ target_app.add_typer(docs_app, name="docs", help="📚 生成/更新项目文档")
192
+
193
+
194
+ def get_command_modules() -> dict[str, type]:
195
+ """获取所有命令模块,供子框架进一步定制。
196
+
197
+ Returns:
198
+ dict: 命令名 -> 模块对象
199
+
200
+ 使用示例:
201
+ ```python
202
+ from aury.boot.commands import get_command_modules
203
+
204
+ modules = get_command_modules()
205
+ # {'init': <module>, 'add': <module>, 'server': <module>, ...}
206
+ ```
207
+ """
208
+ from . import add, docker, docs, generate, init, migrate, scheduler, server, worker
209
+
210
+ return {
211
+ "init": init,
212
+ "add": add,
213
+ "generate": generate,
214
+ "server": server,
215
+ "scheduler": scheduler,
216
+ "worker": worker,
217
+ "migrate": migrate,
218
+ "docker": docker,
219
+ "docs": docs,
220
+ }
221
+
222
+
223
+ # 允许 `from .app import app`
96
224
  def __getattr__(name: str):
97
225
  if name == "app":
98
226
  return _get_app()
@@ -101,5 +229,7 @@ def __getattr__(name: str):
101
229
 
102
230
  __all__ = [
103
231
  "app",
232
+ "get_command_modules",
104
233
  "main",
234
+ "register_commands",
105
235
  ]
@@ -1,13 +1,15 @@
1
1
  """文档生成命令。
2
2
 
3
3
  提供命令行工具用于在现有项目中生成/更新文档:
4
- - aury docs dev 生成/更新 DEVELOPMENT.md
4
+ - aury docs agents 生成/更新 AGENTS.md(AI 编程助手上下文)
5
+ - aury docs dev 生成/更新 docs/ 目录(开发文档包)
5
6
  - aury docs cli 生成/更新 CLI.md
6
7
  - aury docs env 生成/更新 .env.example
7
8
  - aury docs all 生成/更新所有文档
8
9
 
9
10
  使用示例:
10
- aury docs dev # 生成开发文档
11
+ aury docs agents # 生成 AI 编程助手上下文文档
12
+ aury docs dev # 生成 docs/ 开发文档包
11
13
  aury docs cli # 生成 CLI 文档
12
14
  aury docs env # 生成环境变量示例
13
15
  aury docs all # 生成所有文档
@@ -79,10 +81,17 @@ def _detect_project_info(project_dir: Path) -> dict[str, str]:
79
81
 
80
82
 
81
83
  def _render_template(template_name: str, context: dict[str, str]) -> str:
82
- """渲染模板。"""
84
+ """渲染模板。
85
+
86
+ 支持根目录模板和 aury_docs/ 子目录模板。
87
+ """
88
+ # 先在根目录找
83
89
  template_path = TEMPLATES_DIR / template_name
84
90
  if not template_path.exists():
85
- raise FileNotFoundError(f"模板文件不存在: {template_path}")
91
+ # 再在 aury_docs/ 子目录找
92
+ template_path = AURY_DOCS_TPL_DIR / template_name
93
+ if not template_path.exists():
94
+ raise FileNotFoundError(f"模板文件不存在: {template_name}")
86
95
 
87
96
  content = template_path.read_text(encoding="utf-8")
88
97
  return content.format(**context)
@@ -116,8 +125,8 @@ def _write_file(
116
125
  return True
117
126
 
118
127
 
119
- @app.command(name="dev")
120
- def generate_dev_doc(
128
+ @app.command(name="agents")
129
+ def generate_agents_doc(
121
130
  project_dir: Path = typer.Argument(
122
131
  Path("."),
123
132
  help="项目目录路径",
@@ -139,20 +148,84 @@ def generate_dev_doc(
139
148
  help="预览模式,不实际写入文件",
140
149
  ),
141
150
  ) -> None:
142
- """生成/更新 DEVELOPMENT.md 开发文档。"""
151
+ """生成/更新 AGENTS.md(AI 编程助手上下文文档)。"""
143
152
  context = _detect_project_info(project_dir)
144
153
 
145
154
  console.print(f"[cyan]📚 检测到项目: {context['project_name']}[/cyan]")
146
155
 
147
156
  try:
148
- content = _render_template("DEVELOPMENT.md.tpl", context)
149
- output_path = project_dir / "DEVELOPMENT.md"
157
+ content = _render_template("AGENTS.md.tpl", context)
158
+ output_path = project_dir / "AGENTS.md"
150
159
  _write_file(output_path, content, force=force, dry_run=dry_run)
151
160
  except Exception as e:
152
161
  console.print(f"[red]❌ 生成失败: {e}[/red]")
153
162
  raise typer.Exit(1)
154
163
 
155
164
 
165
+ # aury_docs/ 模板目录
166
+ AURY_DOCS_TPL_DIR = TEMPLATES_DIR / "aury_docs"
167
+
168
+
169
+ def _get_aury_docs_templates() -> list[Path]:
170
+ """动态扫描 aury_docs/ 模板目录。"""
171
+ if not AURY_DOCS_TPL_DIR.exists():
172
+ return []
173
+ return sorted(AURY_DOCS_TPL_DIR.glob("*.md.tpl"))
174
+
175
+
176
+ @app.command(name="dev")
177
+ def generate_dev_doc(
178
+ project_dir: Path = typer.Argument(
179
+ Path("."),
180
+ help="项目目录路径",
181
+ exists=True,
182
+ file_okay=False,
183
+ dir_okay=True,
184
+ resolve_path=True,
185
+ ),
186
+ force: bool = typer.Option(
187
+ False,
188
+ "--force",
189
+ "-f",
190
+ help="强制覆盖已存在的文件",
191
+ ),
192
+ dry_run: bool = typer.Option(
193
+ False,
194
+ "--dry-run",
195
+ "-n",
196
+ help="预览模式,不实际写入文件",
197
+ ),
198
+ ) -> None:
199
+ """生成/更新 aury_docs/ 开发文档包。"""
200
+ context = _detect_project_info(project_dir)
201
+
202
+ console.print(f"[cyan]📚 检测到项目: {context['project_name']}[/cyan]")
203
+ console.print()
204
+
205
+ # 确保输出目录存在
206
+ aury_docs_dir = project_dir / "aury_docs"
207
+ if not dry_run:
208
+ aury_docs_dir.mkdir(parents=True, exist_ok=True)
209
+
210
+ success_count = 0
211
+ for tpl_path in _get_aury_docs_templates():
212
+ try:
213
+ output_name = tpl_path.stem # 去掉 .tpl 后缀,保留 .md
214
+ output_path = aury_docs_dir / output_name
215
+ content = tpl_path.read_text(encoding="utf-8")
216
+ content = content.format(**context)
217
+ if _write_file(output_path, content, force=force, dry_run=dry_run):
218
+ success_count += 1
219
+ except Exception as e:
220
+ console.print(f"[red]❌ 生成 {tpl_path.name} 失败: {e}[/red]")
221
+
222
+ console.print()
223
+ if dry_run:
224
+ console.print(f"[dim]🔍 预览模式完成,将生成 {success_count} 个文档到 aury_docs/ 目录[/dim]")
225
+ else:
226
+ console.print(f"[green]✨ 完成!成功生成 {success_count} 个文档到 aury_docs/ 目录[/green]")
227
+
228
+
156
229
  @app.command(name="cli")
157
230
  def generate_cli_doc(
158
231
  project_dir: Path = typer.Argument(
@@ -176,14 +249,18 @@ def generate_cli_doc(
176
249
  help="预览模式,不实际写入文件",
177
250
  ),
178
251
  ) -> None:
179
- """生成/更新 CLI.md 命令行文档。"""
252
+ """生成/更新 aury_docs/99-cli.md 命令行文档。"""
180
253
  context = _detect_project_info(project_dir)
181
254
 
182
255
  console.print(f"[cyan]📚 检测到项目: {context['project_name']}[/cyan]")
183
256
 
184
257
  try:
185
- content = _render_template("CLI.md.tpl", context)
186
- output_path = project_dir / "CLI.md"
258
+ tpl_path = AURY_DOCS_TPL_DIR / "99-cli.md.tpl"
259
+ content = tpl_path.read_text(encoding="utf-8")
260
+ content = content.format(**context)
261
+ output_path = project_dir / "aury_docs" / "99-cli.md"
262
+ if not dry_run:
263
+ output_path.parent.mkdir(parents=True, exist_ok=True)
187
264
  _write_file(output_path, content, force=force, dry_run=dry_run)
188
265
  except Exception as e:
189
266
  console.print(f"[red]❌ 生成失败: {e}[/red]")
@@ -250,20 +327,30 @@ def generate_all_docs(
250
327
  help="预览模式,不实际写入文件",
251
328
  ),
252
329
  ) -> None:
253
- """生成/更新所有文档(DEVELOPMENT.md, CLI.md, .env.example)。"""
330
+ """生成/更新所有文档(AGENTS.md, docs/, CLI.md, .env.example)。"""
254
331
  context = _detect_project_info(project_dir)
255
332
 
256
333
  console.print(f"[cyan]📚 检测到项目: {context['project_name']}[/cyan]")
257
334
  console.print()
258
335
 
259
- docs_to_generate = [
260
- ("DEVELOPMENT.md.tpl", "DEVELOPMENT.md", "开发文档"),
261
- ("CLI.md.tpl", "CLI.md", "CLI 文档"),
336
+ # 根目录文档
337
+ root_docs: list[tuple[str, str, str]] = [
338
+ ("AGENTS.md.tpl", "AGENTS.md", "AI 编程助手上下文"),
262
339
  ("env.example.tpl", ".env.example", "环境变量示例"),
263
340
  ]
264
341
 
342
+ # aury_docs/ 开发文档
343
+ aury_docs_templates = _get_aury_docs_templates()
344
+ dev_docs = [
345
+ (tpl.name, f"aury_docs/{tpl.stem}", f"开发文档: {tpl.stem}")
346
+ for tpl in aury_docs_templates
347
+ ]
348
+
349
+ # 合并所有文档
350
+ all_docs = root_docs + dev_docs
351
+
265
352
  success_count = 0
266
- for template_name, output_name, description in docs_to_generate:
353
+ for template_name, output_name, description in all_docs:
267
354
  try:
268
355
  content = _render_template(template_name, context)
269
356
  output_path = project_dir / output_name
@@ -156,8 +156,7 @@ TEMPLATE_FILE_MAP = {
156
156
  ".env.example": "env.example.tpl",
157
157
  ".gitignore": "gitignore.tpl",
158
158
  "README.md": "README.md.tpl",
159
- "DEVELOPMENT.md": "DEVELOPMENT.md.tpl",
160
- "CLI.md": "CLI.md.tpl",
159
+ "AGENTS.md": "AGENTS.md.tpl",
161
160
  "conftest.py": "conftest.py.tpl",
162
161
  "admin_console/__init__.py": "admin_console_init.py.tpl",
163
162
  }
@@ -712,8 +711,7 @@ def init(
712
711
  (code_root / "admin_console" / "__init__.py", "admin_console/__init__.py", False),
713
712
  (base_path / "tests" / "conftest.py", "conftest.py", False), # tests 放在项目根目录
714
713
  (base_path / "README.md", "README.md", True), # 覆盖 uv init 创建的默认 README
715
- (base_path / "DEVELOPMENT.md", "DEVELOPMENT.md", False), # 开发指南
716
- (base_path / "CLI.md", "CLI.md", False), # CLI 命令参考
714
+ (base_path / "AGENTS.md", "AGENTS.md", False), # AI 编程助手上下文
717
715
  (base_path / ".gitignore", ".gitignore", False), # Git 忽略文件
718
716
  ]
719
717
 
@@ -806,13 +804,34 @@ def init(
806
804
  else:
807
805
  console.print(" [dim]ℹ️ migrations/ 目录已存在,跳过[/dim]")
808
806
 
809
- # 5. 生成 Docker 配置
807
+ # 5. 生成开发文档 (aury_docs/) - 动态扫描模板目录
808
+ console.print("\n[bold]📚 生成开发文档...[/bold]")
809
+ aury_docs_tpl_dir = TEMPLATES_DIR / "aury_docs"
810
+ aury_docs_dir = base_path / "aury_docs"
811
+ aury_docs_dir.mkdir(parents=True, exist_ok=True)
812
+ docs_count = 0
813
+ if aury_docs_tpl_dir.exists():
814
+ for tpl_path in sorted(aury_docs_tpl_dir.glob("*.md.tpl")):
815
+ output_name = tpl_path.stem # 去掉 .tpl 后缀,保留 .md
816
+ output_path = aury_docs_dir / output_name
817
+ if output_path.exists() and not force:
818
+ continue
819
+ try:
820
+ content = tpl_path.read_text(encoding="utf-8")
821
+ content = content.format(**template_vars)
822
+ output_path.write_text(content, encoding="utf-8")
823
+ docs_count += 1
824
+ except Exception:
825
+ pass
826
+ console.print(f" [green]✅ 已生成 {docs_count} 个文档到 aury_docs/[/green]")
827
+
828
+ # 6. 生成 Docker 配置
810
829
  if with_docker:
811
830
  console.print("\n[bold]🐳 生成 Docker 配置...[/bold]")
812
831
  from .docker import docker_init
813
832
  docker_init(force=force)
814
833
 
815
- # 6. 显示结果
834
+ # 7. 显示结果
816
835
  console.print("\n")
817
836
 
818
837
  tree = Tree(f"[bold cyan]{project_name}/[/bold cyan]")
@@ -821,8 +840,8 @@ def init(
821
840
  tree.add("[dim]alembic.ini[/dim]")
822
841
  tree.add("[dim]pyproject.toml[/dim]")
823
842
  tree.add("[dim]README.md[/dim]")
824
- tree.add("[dim]DEVELOPMENT.md[/dim]")
825
- tree.add("[dim]CLI.md[/dim]")
843
+ tree.add("[dim]AGENTS.md[/dim]")
844
+ tree.add("[blue]aury_docs/[/blue]")
826
845
  if with_docker:
827
846
  tree.add("[dim]Dockerfile[/dim]")
828
847
  tree.add("[dim]docker-compose.yml[/dim]")
@@ -2,6 +2,7 @@
2
2
 
3
3
  from __future__ import annotations
4
4
 
5
+ import contextlib
5
6
  import os
6
7
  from pathlib import Path
7
8
  import sys
@@ -339,13 +340,11 @@ def dev(
339
340
  typer.echo(f" 应用模块: {app_module_path}")
340
341
 
341
342
  # 在应用启动完成后打印一次服务地址
342
- try:
343
+ with contextlib.suppress(Exception):
343
344
  app_instance.add_event_handler(
344
345
  "startup",
345
346
  lambda: typer.echo(f"✅ 服务已就绪: http://{server_host}:{server_port}"),
346
347
  )
347
- except Exception:
348
- pass
349
348
 
350
349
  # 默认包含/排除规则(watchfiles 支持)
351
350
  reload_includes = [