scaffold-ca-python 0.3.0__py3-none-any.whl → 0.5.0__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.
@@ -10,43 +10,53 @@ from scaffold_ca_python.commands._shared import (
10
10
  build_and_persist,
11
11
  console,
12
12
  ensure_absent,
13
+ fail,
13
14
  print_dry_run_tree,
14
15
  require_project_root,
15
16
  validate_name_or_exit,
16
17
  )
17
18
  from scaffold_ca_python.core.module_builder import ModuleBuilder
18
- from scaffold_ca_python.core.name_utils import to_snake_case, validate_module_name
19
- from scaffold_ca_python.core.project_detector import load_project_context
19
+ from scaffold_ca_python.core.name_utils import strip_usecase_suffix, to_snake_case, validate_module_name
20
+ from scaffold_ca_python.core.project_detector import load_project_context, resolve_tests_root
20
21
  from scaffold_ca_python.factory.simple.use_case_factory import UseCaseFactory
21
22
  from scaffold_ca_python.models.context import ModuleContext
22
23
  from scaffold_ca_python.models.layer import Layer
23
24
 
24
25
  _GUC_HELP = "Scaffold a use case in domain/usecase/. Alias 'guc'."
25
26
  _GUC_EPILOG = (
26
- "Example:\n\n * scaffold guc --name create_order\n\n * scaffold generate-use-case --name create_order\n\n"
27
+ "Example:\n\n * scaffold guc --name create_order (creates domain/usecase/create_order_usecase.py)\n\n"
28
+ " * scaffold generate-use-case --name create_order\n\n"
27
29
  )
28
30
 
29
31
 
30
32
  def _generate_use_case_impl(name: str, dry_run: bool) -> None:
31
33
  validate_name_or_exit(name, validate_module_name)
34
+ base = strip_usecase_suffix(to_snake_case(name))
35
+ if not base:
36
+ fail(
37
+ f"Use case name '{name}' is only the 'usecase' suffix.",
38
+ hint="Use a descriptive name such as 'create_order'.",
39
+ )
32
40
  project_root = require_project_root()
33
41
  project_ctx = load_project_context(project_root)
34
- module_ctx = ModuleContext(name=name, layer=Layer.DOMAIN_USECASE, project=project_ctx)
42
+ module_ctx = ModuleContext(name=base, layer=Layer.DOMAIN_USECASE, project=project_ctx)
35
43
 
36
- snake = to_snake_case(name)
37
- src_path = project_root / "src" / project_ctx.python_package / "domain" / "usecase" / f"{snake}.py"
38
- ensure_absent(
39
- src_path,
40
- project_root,
41
- kind="File",
42
- hint="Choose a different name or remove the existing file first.",
43
- )
44
+ module = f"{base}_usecase"
45
+ src_path = project_root / "src" / project_ctx.python_package / "domain" / "usecase" / f"{module}.py"
46
+ test_path = resolve_tests_root(project_root) / "domain" / "usecase" / f"test_{module}.py"
47
+ for path in (src_path, test_path):
48
+ ensure_absent(
49
+ path,
50
+ project_root,
51
+ kind="File",
52
+ hint="Choose a different name or remove the existing file first.",
53
+ )
44
54
 
45
55
  builder = ModuleBuilder(project_root=project_root, project_ctx=project_ctx, module_ctx=module_ctx, dry_run=dry_run)
46
56
  created = build_and_persist(UseCaseFactory(), builder)
47
57
 
48
58
  if dry_run:
49
- print_dry_run_tree(snake, created, project_root)
59
+ print_dry_run_tree(module, created, project_root)
50
60
  return
51
61
 
52
62
  msg = (
@@ -4,6 +4,7 @@ from __future__ import annotations
4
4
 
5
5
  from pathlib import Path
6
6
 
7
+ from scaffold_ca_python.core.name_utils import strip_usecase_suffix
7
8
  from scaffold_ca_python.core.project_detector import resolve_tests_root
8
9
 
9
10
 
@@ -11,7 +12,7 @@ def find_module_targets(project_root: Path, pkg: str, snake: str) -> list[tuple[
11
12
  """Return ``(src_path, test_path | None)`` pairs for every match of *snake*.
12
13
 
13
14
  Searches in order: domain/model/<snake>/ (package), domain/model/<snake>.py (legacy flat),
14
- domain/usecase, driven_adapters,
15
+ domain/usecase (``<base>_usecase.py`` first, then legacy ``<snake>.py``), driven_adapters,
15
16
  entry_points, helpers.
16
17
  """
17
18
  src_root = project_root / "src" / pkg
@@ -24,9 +25,25 @@ def find_module_targets(project_root: Path, pkg: str, snake: str) -> list[tuple[
24
25
  model_pkg_test = tests_root / "domain" / "model" / snake
25
26
  candidates.append((model_pkg, model_pkg_test if model_pkg_test.exists() else None))
26
27
 
28
+ usecase_pairs: list[tuple[Path, Path]] = []
29
+ base = strip_usecase_suffix(snake)
30
+ if base:
31
+ usecase_pairs.append(
32
+ (
33
+ src_root / "domain" / "usecase" / f"{base}_usecase.py",
34
+ tests_root / "domain" / "usecase" / f"test_{base}_usecase.py",
35
+ )
36
+ )
37
+ legacy_usecase = (
38
+ src_root / "domain" / "usecase" / f"{snake}.py",
39
+ tests_root / "domain" / "usecase" / f"test_{snake}.py",
40
+ )
41
+ if legacy_usecase not in usecase_pairs:
42
+ usecase_pairs.append(legacy_usecase)
43
+
27
44
  for src_rel, test_rel in [
28
45
  (src_root / "domain" / "model" / f"{snake}.py", tests_root / "domain" / "model" / f"test_{snake}.py"),
29
- (src_root / "domain" / "usecase" / f"{snake}.py", tests_root / "domain" / "usecase" / f"test_{snake}.py"),
46
+ *usecase_pairs,
30
47
  ]:
31
48
  if src_rel.exists():
32
49
  candidates.append((src_rel, test_rel if test_rel.exists() else None))
@@ -9,6 +9,9 @@ NAME_RE = re.compile(r"^[a-z][a-z0-9]*([_-][a-z0-9]+)*$")
9
9
  # Stricter pattern for module/class-generating commands: snake_case only (no hyphens).
10
10
  MODULE_NAME_RE = re.compile(r"^[a-z][a-z0-9]*(_[a-z0-9]+)*$")
11
11
 
12
+ # Trailing use case suffixes (applied to "_" + name so a bare "usecase" also matches)
13
+ _USECASE_SUFFIX_RE = re.compile(r"(?:_(?:usecase|use_case))+$")
14
+
12
15
  # Matches transitions: lowercase→uppercase and letter→digit boundary runs
13
16
  _CAMEL_BOUNDARY_RE = re.compile(r"(?<=[a-z0-9])(?=[A-Z])|(?<=[A-Z])(?=[A-Z][a-z])")
14
17
 
@@ -50,6 +53,11 @@ def to_snake_case(name: str) -> str:
50
53
  return s.lower()
51
54
 
52
55
 
56
+ def strip_usecase_suffix(name: str) -> str:
57
+ """Remove every trailing ``_usecase`` / ``_use_case`` suffix from *name* (may return an empty string)."""
58
+ return _USECASE_SUFFIX_RE.sub("", f"_{name}").removeprefix("_")
59
+
60
+
53
61
  def to_kebab_case(name: str) -> str:
54
62
  """Convert *name* (PascalCase, snake_case, or already kebab-case) to kebab-case."""
55
63
  # Normalise underscores to hyphens first (snake_case support)
@@ -29,7 +29,9 @@ class EntryPointMcp(EntryPointFactory):
29
29
  Always queues:
30
30
  - src/infrastructure/entry_points/mcp_server/__init__.py
31
31
  - src/infrastructure/entry_points/mcp_server/tools.py
32
+ - src/infrastructure/entry_points/mcp_server/routes.py
32
33
  - tests/infrastructure/entry_points/mcp_server/test_tools.py
34
+ - tests/infrastructure/entry_points/mcp_server/test_routes.py
33
35
 
34
36
  Conditionally queues (when builder params are True):
35
37
  - resources.py + test_resources.py (with_resources=True)
@@ -66,12 +68,23 @@ class EntryPointMcp(EntryPointFactory):
66
68
  builder.render(f"{base}/tools.py.jinja2", ctx_dict),
67
69
  template_name=f"{base}/tools.py.jinja2",
68
70
  )
71
+ builder.add_file(
72
+ src_dir / "routes.py",
73
+ builder.render(f"{base}/routes.py.jinja2", ctx_dict),
74
+ template_name=f"{base}/routes.py.jinja2",
75
+ )
69
76
  builder.add_file(
70
77
  test_dir / "test_tools.py",
71
78
  builder.render(f"{base}/test_tools.py.jinja2", ctx_dict),
72
79
  template_name=f"{base}/test_tools.py.jinja2",
73
80
  is_test=True,
74
81
  )
82
+ builder.add_file(
83
+ test_dir / "test_routes.py",
84
+ builder.render(f"{base}/test_routes.py.jinja2", ctx_dict),
85
+ template_name=f"{base}/test_routes.py.jinja2",
86
+ is_test=True,
87
+ )
75
88
 
76
89
  # Optional: resources
77
90
  if with_resources:
@@ -22,7 +22,7 @@ class DeleteModuleFactory(ModuleFactory):
22
22
 
23
23
  Finds and deletes modules across:
24
24
  - domain/model/<snake>/ (package) or domain/model/<snake>.py (legacy)
25
- - domain/usecase/<snake>.py
25
+ - domain/usecase/<base>_usecase.py or domain/usecase/<snake>.py (legacy)
26
26
  - infrastructure/driven_adapters/<snake>/
27
27
  - infrastructure/entry_points/<snake>/
28
28
  - infrastructure/helpers/<snake>/
@@ -19,8 +19,8 @@ class UseCaseFactory(ModuleFactory):
19
19
  """Build domain use case files.
20
20
 
21
21
  Queues files:
22
- - src/domain/usecase/{snake_name}.py
23
- - tests/domain/usecase/test_{snake_name}.py
22
+ - src/domain/usecase/{snake_name}_usecase.py
23
+ - tests/domain/usecase/test_{snake_name}_usecase.py
24
24
 
25
25
  No dependencies injected (async/await are built-in).
26
26
  """
@@ -45,14 +45,14 @@ class UseCaseFactory(ModuleFactory):
45
45
 
46
46
  # Add source file
47
47
  builder.add_file(
48
- src_dir / f"{snake_name}.py",
48
+ src_dir / f"{snake_name}_usecase.py",
49
49
  builder.render(f"{base}/use_case.py.jinja2", ctx_dict),
50
50
  template_name=f"{base}/use_case.py.jinja2",
51
51
  )
52
52
 
53
53
  # Add test file
54
54
  builder.add_file(
55
- test_dir / f"test_{snake_name}.py",
55
+ test_dir / f"test_{snake_name}_usecase.py",
56
56
  builder.render(f"{base}/test_use_case.py.jinja2", ctx_dict),
57
57
  template_name=f"{base}/test_use_case.py.jinja2",
58
58
  is_test=True,
@@ -9,7 +9,7 @@ from starlette.applications import Starlette
9
9
  from starlette.routing import Mount
10
10
 
11
11
  from {{ project.python_package }}.application.config.container import Container
12
- from {{ project.python_package }}.infrastructure.entry_points.mcp_server import tools
12
+ from {{ project.python_package }}.infrastructure.entry_points.mcp_server import routes, tools
13
13
  {%- if with_resources %}
14
14
  from {{ project.python_package }}.infrastructure.entry_points.mcp_server import resources
15
15
  {%- endif %}
@@ -18,6 +18,7 @@ from {{ project.python_package }}.infrastructure.entry_points.mcp_server import
18
18
  {%- endif %}
19
19
 
20
20
  mcp: FastMCP = FastMCP("{{ project.name }}", stateless_http=True)
21
+ routes.bind_routes(mcp)
21
22
 
22
23
 
23
24
  @asynccontextmanager
@@ -0,0 +1,25 @@
1
+ """MCP custom routes binding — register non-MCP HTTP routes such as the health check."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from mcp.server.fastmcp import FastMCP
6
+ from starlette.requests import Request
7
+ from starlette.responses import JSONResponse, Response
8
+
9
+
10
+ def bind_routes(mcp: FastMCP) -> None:
11
+ """
12
+ Bind routes to the FastMCP instance.
13
+ """
14
+
15
+ @mcp.custom_route(name="health_check", path="/api/v1/health", methods=["GET"])
16
+ async def health_check(_request: Request) -> Response:
17
+ """
18
+ Health check endpoint to verify the server is running.
19
+
20
+ Returns:
21
+ JSON response indicating the server is healthy.
22
+ """
23
+
24
+ response_data = {"status": "ok"}
25
+ return JSONResponse(response_data)
@@ -4,6 +4,7 @@ from __future__ import annotations
4
4
 
5
5
  from mcp.server.fastmcp import FastMCP
6
6
  from starlette.applications import Starlette
7
+ from starlette.testclient import TestClient
7
8
 
8
9
  from {{ project.python_package }}.application import app as app_module
9
10
 
@@ -28,3 +29,19 @@ def test_start_server_has_routes() -> None:
28
29
  def test_lifespan_is_callable() -> None:
29
30
  """lifespan must be a callable (async context manager factory)."""
30
31
  assert callable(app_module.lifespan)
32
+
33
+
34
+ def test_health_route_registered_once() -> None:
35
+ """Repeated start_server() calls must not duplicate the health route."""
36
+ app_module.start_server()
37
+ server = app_module.start_server()
38
+ health = [r for r in server.routes[0].routes if getattr(r, "path", None) == "/api/v1/health"]
39
+ assert len(health) == 1
40
+
41
+
42
+ def test_health_route_reachable_through_start_server() -> None:
43
+ """The health route is not shadowed by the Mount('/')."""
44
+ client = TestClient(app_module.start_server())
45
+ response = client.get("/api/v1/health")
46
+ assert response.status_code == 200
47
+ assert response.json() == {"status": "ok"}
@@ -0,0 +1,25 @@
1
+ """Tests for {{ project.python_package }}.infrastructure.entry_points.mcp_server.routes."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from mcp.server.fastmcp import FastMCP
6
+ from starlette.testclient import TestClient
7
+
8
+ from {{ project.python_package }}.infrastructure.entry_points.mcp_server.routes import bind_routes
9
+
10
+
11
+ def _client() -> TestClient:
12
+ mcp = FastMCP("test")
13
+ bind_routes(mcp)
14
+ return TestClient(mcp.streamable_http_app())
15
+
16
+
17
+ def test_health_check_returns_ok() -> None:
18
+ response = _client().get("/api/v1/health")
19
+ assert response.status_code == 200
20
+ assert response.json() == {"status": "ok"}
21
+
22
+
23
+ def test_health_check_rejects_post() -> None:
24
+ response = _client().post("/api/v1/health")
25
+ assert response.status_code == 405
@@ -2,7 +2,7 @@
2
2
 
3
3
  import pytest
4
4
 
5
- from {{ project.python_package }}.domain.usecase.{{ module_name }} import {{ class_name }}UseCase
5
+ from {{ project.python_package }}.domain.usecase.{{ module_name }}_usecase import {{ class_name }}UseCase
6
6
 
7
7
 
8
8
  @pytest.mark.asyncio
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: scaffold-ca-python
3
- Version: 0.3.0
3
+ Version: 0.5.0
4
4
  Summary: Scaffolder to generate Clean Architecture apps
5
5
  Project-URL: Homepage, https://github.com/bancolombia/scaffold-clean-architecture-py
6
6
  Project-URL: Repository, https://github.com/bancolombia/scaffold-clean-architecture-py
@@ -128,7 +128,7 @@ scaffold gm --name order --dry-run
128
128
 
129
129
  ### scaffold guc
130
130
 
131
- Scaffold a use case in `domain/usecase/`.
131
+ Scaffold a use case in `domain/usecase/`. The module is always named `<name>_usecase.py` and the class `<Name>UseCase`. Writing `_usecase` in `--name` is optional and the suffix is never duplicated: `create_order`, `create_order_usecase` and `create_order_use_case` all create `create_order_usecase.py` with `CreateOrderUseCase`.
132
132
 
133
133
  ```bash
134
134
  scaffold guc --name create_order
@@ -11,15 +11,15 @@ scaffold_ca_python/commands/generate_helper.py,sha256=O98ua5Fj3judGxF_vmTYbm_j-q
11
11
  scaffold_ca_python/commands/generate_model.py,sha256=GBHPkoTYrABNdmdILWGLuQFM4ppzYbuHyunjhc-o4Dc,3387
12
12
  scaffold_ca_python/commands/generate_pipeline.py,sha256=Ip-rN4nSbwaUbtJ49awAs4LDURsrDTQsZdG5kBCLdyE,3773
13
13
  scaffold_ca_python/commands/generate_project.py,sha256=5KRsPI_WiWQVY1d_0AblUHKdDQCWpXJA7MaOCHae0fE,5312
14
- scaffold_ca_python/commands/generate_use_case.py,sha256=N72h2BAyNgbCLiphryrwF1aDXkDL5NNj14Lsq7D3YFE,2947
14
+ scaffold_ca_python/commands/generate_use_case.py,sha256=3uKYZik9eF23Z9QMM2psGNWuW2AhxkB468urum5N8WA,3441
15
15
  scaffold_ca_python/commands/update_project.py,sha256=7bu2neRasxEtYK2rIvx0CFISSx9D64BNCkijp90zWGk,2367
16
16
  scaffold_ca_python/commands/validate_structure.py,sha256=p_bYTgOl4_TrC80z-v2teSsssc9xghlkCYlUp3SuzHo,2526
17
17
  scaffold_ca_python/core/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
18
18
  scaffold_ca_python/core/file_writer.py,sha256=KdnNrq33Jsvqs1IQf0jbUKdXls4jBSWAizw4uJhMalU,5561
19
19
  scaffold_ca_python/core/mcp_tool_spec.py,sha256=mPLN7vOSgWFWxHQQxmr0fWEaimHWI-9A0oP7ob73-rU,10602
20
20
  scaffold_ca_python/core/module_builder.py,sha256=AHC3szEdfS3i3q74IM6USZTHWEUK6QizL6NEKcHCrrI,6837
21
- scaffold_ca_python/core/module_locator.py,sha256=VnvD3-g6NvSGJReYamBuoU1s72NdoHgau-SlpaB3xEg,1958
22
- scaffold_ca_python/core/name_utils.py,sha256=195Qb36CafP4CGRomzSAm3Hmm0C-Qld3I90boPAV-7A,2583
21
+ scaffold_ca_python/core/module_locator.py,sha256=FFAwA7Vajxg0JgHoVXc1HpvdB67clvkv_BFVwiQDxHA,2552
22
+ scaffold_ca_python/core/name_utils.py,sha256=IpXAieBKFe7QbOY4K8gNsjr4NXUfJX5MBCy2bQyPIk4,2958
23
23
  scaffold_ca_python/core/openapi_routes.py,sha256=RCQS7mHufWJZgbLI1cxGli-xGbU7p7WI95fHJhDnIss,1098
24
24
  scaffold_ca_python/core/project_detector.py,sha256=vcDAFCGgQVDMQ2MivJVUmn5Yyj58vGpTbzKhZTBQNtw,3524
25
25
  scaffold_ca_python/core/pyproject_writer.py,sha256=zpxgubt-XSZR5domgL4LG_9AWD9b_cNrDM8fuHmZRzE,7792
@@ -35,15 +35,15 @@ scaffold_ca_python/factory/entry_points/__init__.py,sha256=ylyCH8R8iORQjHkx-bzy4
35
35
  scaffold_ca_python/factory/entry_points/base.py,sha256=DOhL2jniv-LdiNIgFINgXX-i6krRO2EAvJAi7L_ZisA,1892
36
36
  scaffold_ca_python/factory/entry_points/ep_agent.py,sha256=ODql04XDXya3ANYez38M3AYoUeRh9OmW7nxGmWHRgIY,3410
37
37
  scaffold_ca_python/factory/entry_points/ep_generic.py,sha256=L51mO007f6LtgBzOAmBlW4dClLK9IzQf3rJjNUbd9xk,2823
38
- scaffold_ca_python/factory/entry_points/ep_mcp.py,sha256=6kS-E0NiyHwAfXbl-bB18YcCj2_nZ1mMp1qZaCQo59E,5687
38
+ scaffold_ca_python/factory/entry_points/ep_mcp.py,sha256=TVJrEFRrviB5tw6RbVtOIbzzgr-hmN0s1XQs5qIJguA,6244
39
39
  scaffold_ca_python/factory/entry_points/ep_restapi.py,sha256=PFkt9TH1aN6YO8w4zAeoqFOuibC8oc7qJUbFfX9YI_U,5951
40
40
  scaffold_ca_python/factory/pipelines/__init__.py,sha256=0YPpPGsZ6A3-udHTSZDyUHleLFLQQh1V5IL6AB0qJ6g,557
41
41
  scaffold_ca_python/factory/pipelines/pipeline_factory.py,sha256=s4fpuyhdxXiwko-LlM6Pv-QJdRGQJb17KVrC-DW6ojo,842
42
42
  scaffold_ca_python/factory/simple/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
43
- scaffold_ca_python/factory/simple/delete_module_factory.py,sha256=hvDZNz8TULYx0zES3697-jnrzDQT6v6nxqPV0H9-mWo,1651
43
+ scaffold_ca_python/factory/simple/delete_module_factory.py,sha256=v_Kl-m7bxvCwUsdQuCPq66uPksuLFLYvbsTNdE4Cs8Q,1696
44
44
  scaffold_ca_python/factory/simple/helper_factory.py,sha256=nBVOu_kGBVrEGnXFa918GPo-UFlcW-Y5-Uk6bwYWuhQ,2295
45
45
  scaffold_ca_python/factory/simple/model_factory.py,sha256=YdUpBvGgUrz4zzXMG2p8d6PWit62B9esjLZG49dT5PU,2467
46
- scaffold_ca_python/factory/simple/use_case_factory.py,sha256=znCyynIGmWgc4P8icJXfb2xSiNZB2Cu4SGVacDrpSdY,1954
46
+ scaffold_ca_python/factory/simple/use_case_factory.py,sha256=CUY2SkneFWv-KukK-Cdn2KoLZwgYukNa25Hv15SQYx8,1986
47
47
  scaffold_ca_python/models/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
48
48
  scaffold_ca_python/models/context.py,sha256=Itp-YyPgY-0yNYA9YlCXrmPfa5nEVklGAOJQGHfBdHE,1909
49
49
  scaffold_ca_python/models/file_operation.py,sha256=R5Tu3KBvUnSmH5QZXBQTPoQjvr4YdH1YOKsKS9ICH_Q,1698
@@ -70,13 +70,15 @@ scaffold_ca_python/templates/entry_point/generic/entrypoint_main.py.jinja2,sha25
70
70
  scaffold_ca_python/templates/entry_point/generic/handler.py.jinja2,sha256=glCst1soTiKG_gDdq5C-OogzljOJ_QooaW_boYt7gsg,417
71
71
  scaffold_ca_python/templates/entry_point/generic/test_handler.py.jinja2,sha256=gRhvVabkylQ8z06JZ9L2CHdTa83oxL1X4ldR3_DZQWg,1195
72
72
  scaffold_ca_python/templates/entry_point/mcp/__init__.py.jinja2,sha256=8J_YmIXHUh26PkaxeM8z5lf-dtK0da1T4haOM8U6Y9A,38
73
- scaffold_ca_python/templates/entry_point/mcp/app.py.jinja2,sha256=VMU2AWXAVJVT0IqTI3E6XGBGn2rR80ViSN0jNyRf3E4,1916
73
+ scaffold_ca_python/templates/entry_point/mcp/app.py.jinja2,sha256=2Kfi3AjRvJi7ee1vO0PyUa4pfX8j1GcsHO89GmQy6JU,1948
74
74
  scaffold_ca_python/templates/entry_point/mcp/prompts.py.jinja2,sha256=PUFRtuWlEzR7bg7zY0O8dx-5tNrEZXrNZ5XgBoUMulQ,765
75
75
  scaffold_ca_python/templates/entry_point/mcp/resources.py.jinja2,sha256=ZV_2WwklhSGhVFel3stS00zmPJuTlznfvFrpiM9dDKo,840
76
+ scaffold_ca_python/templates/entry_point/mcp/routes.py.jinja2,sha256=_JRXwnCMSJ-YBhEsxs-2JuVVQQ5sLeDDnkGB_8E4UJs,752
76
77
  scaffold_ca_python/templates/entry_point/mcp/server.py.jinja2,sha256=gVzJm_ugY9E7-1RYIfbEKduDR71gluq4l3OB_aTRr1w,656
77
- scaffold_ca_python/templates/entry_point/mcp/test_app.py.jinja2,sha256=MjVDhAXTz35HcCOVTsaWA--qvD_Qyn2SNG99CF6wctk,967
78
+ scaffold_ca_python/templates/entry_point/mcp/test_app.py.jinja2,sha256=mvP2BXW_OK4HvPjl1dfHs-y7r9FIYViJ3BCBtAqX8iY,1643
78
79
  scaffold_ca_python/templates/entry_point/mcp/test_prompts.py.jinja2,sha256=Y9C7z7jpjoTKANlFB6hNJUUw2abt5qF2C4Nm7MkvDvA,1566
79
80
  scaffold_ca_python/templates/entry_point/mcp/test_resources.py.jinja2,sha256=2jHfPqyJ4TJZJupxe8T7gVz2ysaqZHcAog6186ie2CI,1763
81
+ scaffold_ca_python/templates/entry_point/mcp/test_routes.py.jinja2,sha256=aYVWQXiRguziMtOnvZc5uwnhgYhsH87yrIDPM4gz95g,753
80
82
  scaffold_ca_python/templates/entry_point/mcp/test_tool_stub.py.jinja2,sha256=Tq4uDcZc77bCC9gCVidmM5HmtjPfACaHBoQW0qEhIWo,295
81
83
  scaffold_ca_python/templates/entry_point/mcp/test_tools.py.jinja2,sha256=bd_8nvLuqPApKIYQoBhEokMYZrPYFUn1pnDEIOVxwCo,1550
82
84
  scaffold_ca_python/templates/entry_point/mcp/tool_stub.py.jinja2,sha256=VaGWAUF-BFQ7EeOHXUHQ2H-Mzr1UfbfziDsS7EVWUCc,289
@@ -119,10 +121,10 @@ scaffold_ca_python/templates/project/application/config/container.py.jinja2,sha2
119
121
  scaffold_ca_python/templates/project/application/config/driven_adapters_container.py.jinja2,sha256=WhRpupvLP8tOJgp4IJ0A5RitntfRPVFjCDUjhAhBt8U,464
120
122
  scaffold_ca_python/templates/project/application/config/resource_container.py.jinja2,sha256=k3wy8uSD7GJZNEf379fv2lMEzdq5eaNqmoaOw9Jq1vs,643
121
123
  scaffold_ca_python/templates/project/application/config/usecases_container.py.jinja2,sha256=3fEHe6mkXkDHlfO5nhLqzLB7ccTpqwtjHZfLyfysbro,527
122
- scaffold_ca_python/templates/use_case/test_use_case.py.jinja2,sha256=3K1bNKDBQc29rcv8UHUZnROCUmcFSCwJhbm0xP9Uako,364
124
+ scaffold_ca_python/templates/use_case/test_use_case.py.jinja2,sha256=spomnRHeXWiWjy3QHQt839yIMFDUqA7h-Wq4KfZxAyg,372
123
125
  scaffold_ca_python/templates/use_case/use_case.py.jinja2,sha256=KPtaK1wvZ-7qHdDZyuVfqXTPYwJdNUMPXQZGuKZFA7Y,217
124
- scaffold_ca_python-0.3.0.dist-info/METADATA,sha256=u5KDkAfy1Wb0HVt1Jrb2MzZr2Nqgb9xnwOZhhmmwVKw,7187
125
- scaffold_ca_python-0.3.0.dist-info/WHEEL,sha256=W3fkpkm7-wf9vBI5Z-7s0eWkeM-spu78I8Neb98DeEg,87
126
- scaffold_ca_python-0.3.0.dist-info/entry_points.txt,sha256=4PyYg6mNCvAlt2yF_o1-QR2CBXiowYGpNyqcP88tu6I,104
127
- scaffold_ca_python-0.3.0.dist-info/licenses/LICENSE,sha256=3ZZEP7DK_h3lEjS8r-DvQCec2q7zAqqq7HmSq6cuL0E,1068
128
- scaffold_ca_python-0.3.0.dist-info/RECORD,,
126
+ scaffold_ca_python-0.5.0.dist-info/METADATA,sha256=LzgbMKXGUltT5VqAjcy4iM1WLe3EzI65blOTxX8N6Cw,7475
127
+ scaffold_ca_python-0.5.0.dist-info/WHEEL,sha256=W3fkpkm7-wf9vBI5Z-7s0eWkeM-spu78I8Neb98DeEg,87
128
+ scaffold_ca_python-0.5.0.dist-info/entry_points.txt,sha256=4PyYg6mNCvAlt2yF_o1-QR2CBXiowYGpNyqcP88tu6I,104
129
+ scaffold_ca_python-0.5.0.dist-info/licenses/LICENSE,sha256=3ZZEP7DK_h3lEjS8r-DvQCec2q7zAqqq7HmSq6cuL0E,1068
130
+ scaffold_ca_python-0.5.0.dist-info/RECORD,,