rapidkit 0.40.1 → 0.41.1
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.
- package/README.md +48 -7
- package/contracts/agent-customization-pack.v1.json +52 -2
- package/contracts/extension-cli-compatibility.v1.json +14 -2
- package/contracts/runtime-command-surface.v1.json +7 -1
- package/contracts/workspace-intelligence/agent-action-outcome.v1.json +38 -0
- package/contracts/workspace-intelligence/blocker-resolution.v1.json +65 -0
- package/contracts/workspace-intelligence/doctor-fix-result.v1.json +34 -0
- package/contracts/workspace-intelligence/studio-blocker-handoff.v1.json +91 -0
- package/contracts/workspace-intelligence/workspace-contract-verify.v1.json +51 -0
- package/contracts/workspace-intelligence/workspace-dependency-graph.v1.json +61 -1
- package/contracts/workspace-intelligence/workspace-explain.v1.json +31 -0
- package/contracts/workspace-intelligence/workspace-intelligence-history.v1.json +36 -0
- package/contracts/workspace-intelligence/workspace-operational-skill.v1.json +37 -0
- package/contracts/workspace-intelligence/workspace-skills-index.v1.json +27 -0
- package/dist/analyze-QYHMGLSG.js +1 -0
- package/dist/autopilot-release-AHMQEUFH.js +1 -0
- package/dist/chunk-33LR2QEM.js +2 -0
- package/dist/chunk-3PTJID76.js +2 -0
- package/dist/chunk-46AGNYI7.js +50 -0
- package/dist/chunk-64RTZBHU.js +2 -0
- package/dist/chunk-AQ4XZZC6.js +1 -0
- package/dist/{chunk-RXWM5DSC.js → chunk-BFEBZABL.js} +3 -3
- package/dist/{chunk-3YLMCP3V.js → chunk-CDCYRBAY.js} +1 -1
- package/dist/chunk-CDPR2YKL.js +13 -0
- package/dist/chunk-CKXJR3YT.js +7 -0
- package/dist/chunk-E5ZVQL3C.js +13 -0
- package/dist/chunk-ELU3G6DQ.js +9 -0
- package/dist/chunk-EN6YCX36.js +1 -0
- package/dist/chunk-FMBSON6H.js +33 -0
- package/dist/chunk-GBJBQ43T.js +1 -0
- package/dist/chunk-ICGWHIMK.js +1 -0
- package/dist/{chunk-4FJQWL7P.js → chunk-ITJ6RKUW.js} +3 -3
- package/dist/{workspace-graph-ICB7OVAZ.js → chunk-JEI6BTZI.js} +1 -1
- package/dist/{chunk-G76C74EV.js → chunk-JU3VNLTY.js} +1 -1
- package/dist/chunk-JW2FSKT3.js +2 -0
- package/dist/chunk-KIUSCFHF.js +1 -0
- package/dist/chunk-LKX3L7TE.js +2 -0
- package/dist/chunk-MIWDCR6I.js +2 -0
- package/dist/{chunk-6G2KSHP6.js → chunk-OLDPVVSV.js} +1 -1
- package/dist/{chunk-4Q2ZZKGB.js → chunk-PCXSTKZ5.js} +1 -1
- package/dist/{chunk-6KD5F6LX.js → chunk-Q2KZIBV4.js} +1 -1
- package/dist/{chunk-ERCD6NFF.js → chunk-RSYUNEH7.js} +13 -13
- package/dist/chunk-TJN7G2MA.js +1 -0
- package/dist/chunk-UQR6G7KH.js +32 -0
- package/dist/chunk-VMJA36WD.js +1 -0
- package/dist/chunk-WRMCPKGA.js +1 -0
- package/dist/{create-XVDDQA42.js → create-RNP5ACQL.js} +1 -1
- package/dist/demo-kit-N5U3NGAE.js +149 -0
- package/dist/{doctor-UOLOGJ2Z.js → doctor-XM6QDTDC.js} +1 -1
- package/dist/{dotnet-webapi-clean-RTBRPDPL.js → dotnet-webapi-clean-K33C77EI.js} +1 -1
- package/dist/{gofiber-standard-UGIRKPKL.js → gofiber-standard-BQ4HCXL2.js} +1 -1
- package/dist/{gogin-standard-HJ7SPFNT.js → gogin-standard-PUBCYW3A.js} +1 -1
- package/dist/index.d.ts +45 -7
- package/dist/index.js +145 -127
- package/dist/{pipeline-XK62WL4D.js → pipeline-DH6Z47O4.js} +1 -1
- package/dist/platform-capabilities-TSLK667K.js +1 -0
- package/dist/{pythonRapidkitExec-MNWRC4F2.js → pythonRapidkitExec-SGKW76XM.js} +1 -1
- package/dist/{springboot-standard-IWJSVDLZ.js → springboot-standard-XFVQI37R.js} +1 -1
- package/dist/{workspace-L4ITCKMM.js → workspace-E554C5SM.js} +1 -1
- package/dist/workspace-agent-sync-2HRPM5ZD.js +1 -0
- package/dist/{workspace-context-NMMQMHNU.js → workspace-context-VJTXW3K4.js} +1 -1
- package/dist/workspace-contract-OO4GMENV.js +1 -0
- package/dist/workspace-explain-3WSJLIJ6.js +1 -0
- package/dist/workspace-explain-contract-24RQ7KIW.js +1 -0
- package/dist/workspace-feedback-65NR3EZH.js +1 -0
- package/dist/{workspace-foundation-HNIRAIBF.js → workspace-foundation-LISDH53T.js} +1 -1
- package/dist/workspace-graph-2A5THUCI.js +1 -0
- package/dist/workspace-history-VPDADQKG.js +1 -0
- package/dist/{workspace-intelligence-64IWAYHS.js → workspace-intelligence-E3KXEZCM.js} +1 -1
- package/dist/workspace-mcp-serve-RFYDCA2L.js +3 -0
- package/dist/workspace-model-YL7W3573.js +1 -0
- package/dist/workspace-registry-summary-X5WRUU3T.js +1 -0
- package/dist/workspace-run-GCIQD73R.js +1 -0
- package/dist/workspace-verify-NRYH7RNB.js +1 -0
- package/dist/workspace-watch-H2AETGFI.js +1 -0
- package/docs/DEVELOPMENT.md +1 -1
- package/docs/OPEN_SOURCE_USER_SCENARIOS.md +1 -1
- package/docs/README.md +1 -1
- package/docs/commands-reference.md +10 -2
- package/docs/contracts/ARTIFACT_CATALOG.md +3 -1
- package/docs/contracts/NAMING_AND_COEXISTENCE.md +58 -0
- package/docs/workspace-run.md +25 -1
- package/package.json +7 -3
- package/scripts/enterprise-package-smoke.mjs +427 -0
- package/scripts/prepack-enterprise.mjs +40 -0
- package/templates/generator.js +175 -0
- package/templates/kits/fastapi-ddd/README.md.j2 +122 -0
- package/templates/kits/fastapi-ddd/common/env.example.j2 +10 -0
- package/templates/kits/fastapi-ddd/env.example.j2 +1 -0
- package/templates/kits/fastapi-ddd/pyproject.toml.j2 +64 -0
- package/templates/kits/fastapi-ddd/src/__init__.py.j2 +3 -0
- package/templates/kits/fastapi-ddd/src/app/__init__.py.j2 +11 -0
- package/templates/kits/fastapi-ddd/src/app/application/__init__.py.j2 +5 -0
- package/templates/kits/fastapi-ddd/src/app/application/interfaces.py.j2 +43 -0
- package/templates/kits/fastapi-ddd/src/app/application/use_cases/__init__.py.j2 +6 -0
- package/templates/kits/fastapi-ddd/src/app/application/use_cases/health.py.j2 +14 -0
- package/templates/kits/fastapi-ddd/src/app/application/use_cases/notes.py.j2 +24 -0
- package/templates/kits/fastapi-ddd/src/app/config/__init__.py.j2 +16 -0
- package/templates/kits/fastapi-ddd/src/app/domain/__init__.py.j2 +3 -0
- package/templates/kits/fastapi-ddd/src/app/domain/models/__init__.py.j2 +6 -0
- package/templates/kits/fastapi-ddd/src/app/domain/models/health.py.j2 +16 -0
- package/templates/kits/fastapi-ddd/src/app/domain/models/note.py.j2 +27 -0
- package/templates/kits/fastapi-ddd/src/app/infrastructure/__init__.py.j2 +5 -0
- package/templates/kits/fastapi-ddd/src/app/infrastructure/repositories/__init__.py.j2 +6 -0
- package/templates/kits/fastapi-ddd/src/app/infrastructure/repositories/health.py.j2 +17 -0
- package/templates/kits/fastapi-ddd/src/app/infrastructure/repositories/notes.py.j2 +28 -0
- package/templates/kits/fastapi-ddd/src/app/main.py.j2 +61 -0
- package/templates/kits/fastapi-ddd/src/app/presentation/__init__.py.j2 +3 -0
- package/templates/kits/fastapi-ddd/src/app/presentation/api/__init__.py.j2 +5 -0
- package/templates/kits/fastapi-ddd/src/app/presentation/api/dependencies/__init__.py.j2 +19 -0
- package/templates/kits/fastapi-ddd/src/app/presentation/api/router.py.j2 +10 -0
- package/templates/kits/fastapi-ddd/src/app/presentation/api/routes/__init__.py.j2 +5 -0
- package/templates/kits/fastapi-ddd/src/app/presentation/api/routes/health.py.j2 +27 -0
- package/templates/kits/fastapi-ddd/src/app/presentation/api/routes/notes.py.j2 +50 -0
- package/templates/kits/fastapi-ddd/src/app/shared/__init__.py.j2 +5 -0
- package/templates/kits/fastapi-ddd/src/app/shared/result.py.j2 +28 -0
- package/templates/kits/fastapi-ddd/src/cli.py.j2 +167 -0
- package/templates/kits/fastapi-ddd/src/main.py.j2 +35 -0
- package/templates/kits/fastapi-ddd/src/modules/__init__.py.j2 +3 -0
- package/templates/kits/fastapi-ddd/src/routing/__init__.py.j2 +13 -0
- package/templates/kits/fastapi-ddd/src/routing/health.py.j2 +7 -0
- package/templates/kits/fastapi-ddd/src/routing/notes.py.j2 +7 -0
- package/templates/kits/fastapi-ddd/tests/__init__.py.j2 +1 -0
- package/templates/kits/fastapi-ddd/tests/test_app_factory.py.j2 +22 -0
- package/templates/kits/fastapi-ddd/tests/test_health.py.j2 +17 -0
- package/templates/kits/fastapi-ddd/tests/test_notes.py.j2 +27 -0
- package/templates/kits/fastapi-standard/README.md.j2 +145 -0
- package/templates/kits/fastapi-standard/common/env.example.j2 +10 -0
- package/templates/kits/fastapi-standard/env.example.j2 +1 -0
- package/templates/kits/fastapi-standard/pyproject.toml.j2 +64 -0
- package/templates/kits/fastapi-standard/src/__init__.py.j2 +3 -0
- package/templates/kits/fastapi-standard/src/cli.py.j2 +168 -0
- package/templates/kits/fastapi-standard/src/main.py.j2 +66 -0
- package/templates/kits/fastapi-standard/src/modules/__init__.py.j2 +3 -0
- package/templates/kits/fastapi-standard/src/routing/__init__.py.j2 +16 -0
- package/templates/kits/fastapi-standard/src/routing/examples.py.j2 +71 -0
- package/templates/kits/fastapi-standard/src/routing/health.py.j2 +22 -0
- package/templates/kits/fastapi-standard/tests/__init__.py.j2 +1 -0
- package/templates/kits/fastapi-standard/tests/test_examples.py.j2 +29 -0
- package/templates/kits/fastapi-standard/tests/test_health.py.j2 +17 -0
- package/templates/kits/nestjs-standard/Dockerfile.j2 +41 -0
- package/templates/kits/nestjs-standard/README.md.j2 +139 -0
- package/templates/kits/nestjs-standard/docker-compose.yml.j2 +94 -0
- package/templates/kits/nestjs-standard/docs/README.md.j2 +15 -0
- package/templates/kits/nestjs-standard/env.example.j2 +18 -0
- package/templates/kits/nestjs-standard/eslint.config.cjs.j2 +9 -0
- package/templates/kits/nestjs-standard/jest.config.ts.j2 +22 -0
- package/templates/kits/nestjs-standard/nest-cli.json.j2 +10 -0
- package/templates/kits/nestjs-standard/package.json.j2 +101 -0
- package/templates/kits/nestjs-standard/src/app.controller.ts.j2 +14 -0
- package/templates/kits/nestjs-standard/src/app.module.ts.j2 +26 -0
- package/templates/kits/nestjs-standard/src/app.service.ts.j2 +16 -0
- package/templates/kits/nestjs-standard/src/auth/auth.controller.ts.j2 +20 -0
- package/templates/kits/nestjs-standard/src/auth/auth.module.ts.j2 +13 -0
- package/templates/kits/nestjs-standard/src/auth/auth.service.ts.j2 +6 -0
- package/templates/kits/nestjs-standard/src/auth/entities/token.entity.ts.j2 +3 -0
- package/templates/kits/nestjs-standard/src/auth/entities/user.entity.ts.j2 +3 -0
- package/templates/kits/nestjs-standard/src/auth/entities/webauthn.entity.ts.j2 +3 -0
- package/templates/kits/nestjs-standard/src/config/configuration.ts.j2 +85 -0
- package/templates/kits/nestjs-standard/src/config/index.ts.j2 +2 -0
- package/templates/kits/nestjs-standard/src/config/validation.ts.j2 +21 -0
- package/templates/kits/nestjs-standard/src/examples/dto/create-note.dto.ts.j2 +11 -0
- package/templates/kits/nestjs-standard/src/examples/examples.controller.ts.j2 +24 -0
- package/templates/kits/nestjs-standard/src/examples/examples.module.ts.j2 +10 -0
- package/templates/kits/nestjs-standard/src/examples/examples.service.ts.j2 +33 -0
- package/templates/kits/nestjs-standard/src/main.ts.j2 +53 -0
- package/templates/kits/nestjs-standard/src/modules/index.ts.j2 +25 -0
- package/templates/kits/nestjs-standard/test/app.controller.spec.ts.j2 +24 -0
- package/templates/kits/nestjs-standard/test/app.e2e-spec.ts.j2 +60 -0
- package/templates/kits/nestjs-standard/test/examples.controller.spec.ts.j2 +28 -0
- package/templates/kits/nestjs-standard/test/jest-e2e.json.j2 +15 -0
- package/templates/kits/nestjs-standard/tsconfig.build.json.j2 +12 -0
- package/templates/kits/nestjs-standard/tsconfig.json.j2 +26 -0
- package/dist/analyze-RHQM4AB2.js +0 -1
- package/dist/autopilot-release-OJTLXPMX.js +0 -1
- package/dist/chunk-5VBRMLRU.js +0 -7
- package/dist/chunk-7VI4U7Q5.js +0 -2
- package/dist/chunk-FV5A3N3I.js +0 -2
- package/dist/chunk-GDGATWR5.js +0 -2
- package/dist/chunk-GOM3RFB3.js +0 -2
- package/dist/chunk-GX7UU7LL.js +0 -33
- package/dist/chunk-KYH364KQ.js +0 -1
- package/dist/chunk-OWNGSAO3.js +0 -2
- package/dist/chunk-QPEBI6AB.js +0 -2
- package/dist/chunk-TYZPPUBH.js +0 -1
- package/dist/chunk-VQMZC5TC.js +0 -9
- package/dist/chunk-WHCON2VN.js +0 -50
- package/dist/chunk-X7PWDIQW.js +0 -1
- package/dist/chunk-Z5LKRG57.js +0 -1
- package/dist/chunk-ZWKLRZE5.js +0 -13
- package/dist/demo-kit-RWGOEDW4.js +0 -141
- package/dist/workspace-agent-sync-G7JU77IK.js +0 -25
- package/dist/workspace-contract-D5O4OZD5.js +0 -1
- package/dist/workspace-history-LHUTLE3S.js +0 -1
- package/dist/workspace-model-SDHH5RBC.js +0 -1
- package/dist/workspace-registry-summary-MIPHVB56.js +0 -1
- package/dist/workspace-run-SPP32MPV.js +0 -1
- package/dist/workspace-verify-6Q6MGRG6.js +0 -1
- package/dist/workspace-watch-JDXVGW4H.js +0 -1
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
"""Basic result type shared across layers."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from dataclasses import dataclass
|
|
6
|
+
from typing import Generic, Optional, TypeVar
|
|
7
|
+
|
|
8
|
+
T = TypeVar("T")
|
|
9
|
+
E = TypeVar("E")
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
@dataclass(frozen=True, slots=True)
|
|
13
|
+
class Result(Generic[T, E]):
|
|
14
|
+
"""Simple functional-style result wrapper."""
|
|
15
|
+
|
|
16
|
+
value: Optional[T] = None
|
|
17
|
+
error: Optional[E] = None
|
|
18
|
+
|
|
19
|
+
@property
|
|
20
|
+
def is_ok(self) -> bool:
|
|
21
|
+
return self.error is None
|
|
22
|
+
|
|
23
|
+
@property
|
|
24
|
+
def is_err(self) -> bool:
|
|
25
|
+
return self.error is not None
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
__all__ = ["Result"]
|
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""Project CLI wrapper for {{ project_name }} (DDD edition).
|
|
3
|
+
|
|
4
|
+
Prefer a per-project CLI in `.rapidkit/cli.py` when present. Otherwise
|
|
5
|
+
provide helpful guidance to the developer rather than guessing environment
|
|
6
|
+
details.
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
import importlib.util
|
|
10
|
+
import sys
|
|
11
|
+
import argparse
|
|
12
|
+
from pathlib import Path
|
|
13
|
+
from typing import Optional
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def _missing_cli(name: str) -> None:
|
|
17
|
+
print(f"❌ Missing project-local CLI (.rapidkit/cli.py) - can't run '{name}'")
|
|
18
|
+
print("💡 If you're a new user run: rapidkit init # create venv + install deps")
|
|
19
|
+
sys.exit(127)
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def _load_project_cli_module() -> Optional[object]:
|
|
23
|
+
project_root = Path(__file__).resolve().parents[1]
|
|
24
|
+
cli_file = project_root / ".rapidkit" / "cli.py"
|
|
25
|
+
if not cli_file.exists():
|
|
26
|
+
return None
|
|
27
|
+
spec = importlib.util.spec_from_file_location("project_cli", str(cli_file))
|
|
28
|
+
if spec is None or spec.loader is None:
|
|
29
|
+
return None
|
|
30
|
+
module = importlib.util.module_from_spec(spec)
|
|
31
|
+
spec.loader.exec_module(module) # type: ignore
|
|
32
|
+
return module
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
_mod = _load_project_cli_module()
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
# Default placeholders -- call `_missing_cli` if the project-local CLI isn't
|
|
39
|
+
# available. These are real functions so linters don't complain.
|
|
40
|
+
def init() -> None:
|
|
41
|
+
_missing_cli("init")
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
def dev() -> None:
|
|
45
|
+
_missing_cli("dev")
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
def start() -> None:
|
|
49
|
+
_missing_cli("start")
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
def build() -> None:
|
|
53
|
+
_missing_cli("build")
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
def test() -> None:
|
|
57
|
+
_missing_cli("test")
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
def lint() -> None:
|
|
61
|
+
_missing_cli("lint")
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
def format() -> None: # type: ignore[misc]
|
|
65
|
+
_missing_cli("format")
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
def help_cmd() -> None:
|
|
69
|
+
print("Usage: poetry run <command> # (init|dev|start|build|test|lint|format)")
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
if _mod is not None:
|
|
73
|
+
# prefer project-provided implementations when available
|
|
74
|
+
init = getattr(_mod, "init", init)
|
|
75
|
+
dev = getattr(_mod, "dev", dev)
|
|
76
|
+
start = getattr(_mod, "start", start)
|
|
77
|
+
build = getattr(_mod, "build", build)
|
|
78
|
+
test = getattr(_mod, "test", test)
|
|
79
|
+
lint = getattr(_mod, "lint", lint)
|
|
80
|
+
format = getattr(_mod, "format", format)
|
|
81
|
+
help_cmd = getattr(_mod, "help_cmd", help_cmd)
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
_dev_impl = dev
|
|
85
|
+
_start_impl = start
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
def _runtime_kwargs_from_argv(argv: list[str]) -> dict:
|
|
89
|
+
parser = argparse.ArgumentParser(add_help=False)
|
|
90
|
+
parser.add_argument("-p", "--port", type=int, dest="port")
|
|
91
|
+
parser.add_argument("--host", dest="host")
|
|
92
|
+
parser.add_argument("--allow-global-runtime", action="store_true", dest="allow_global_runtime")
|
|
93
|
+
ns, _ = parser.parse_known_args(argv)
|
|
94
|
+
|
|
95
|
+
kwargs = {}
|
|
96
|
+
if ns.port is not None:
|
|
97
|
+
kwargs["port"] = ns.port
|
|
98
|
+
if ns.host is not None:
|
|
99
|
+
kwargs["host"] = ns.host
|
|
100
|
+
if ns.allow_global_runtime:
|
|
101
|
+
kwargs["allow_global_runtime"] = True
|
|
102
|
+
return kwargs
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
def dev() -> None: # type: ignore[no-redef]
|
|
106
|
+
kwargs = _runtime_kwargs_from_argv(sys.argv[1:])
|
|
107
|
+
try:
|
|
108
|
+
_dev_impl(**kwargs)
|
|
109
|
+
except TypeError:
|
|
110
|
+
_dev_impl()
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
def start() -> None: # type: ignore[no-redef]
|
|
114
|
+
kwargs = _runtime_kwargs_from_argv(sys.argv[1:])
|
|
115
|
+
try:
|
|
116
|
+
_start_impl(**kwargs)
|
|
117
|
+
except TypeError:
|
|
118
|
+
_start_impl()
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
def main() -> None:
|
|
122
|
+
if len(sys.argv) < 2:
|
|
123
|
+
help_cmd()
|
|
124
|
+
return
|
|
125
|
+
|
|
126
|
+
command = sys.argv[1]
|
|
127
|
+
commands = {
|
|
128
|
+
"init": init,
|
|
129
|
+
"dev": dev,
|
|
130
|
+
"start": start,
|
|
131
|
+
"build": build,
|
|
132
|
+
"test": test,
|
|
133
|
+
"lint": lint,
|
|
134
|
+
"format": format,
|
|
135
|
+
"help": help_cmd,
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
if command in commands:
|
|
139
|
+
if command in ("dev", "start"):
|
|
140
|
+
parser = argparse.ArgumentParser(prog=f"poetry run {command}", add_help=False)
|
|
141
|
+
parser.add_argument("-p", "--port", type=int, dest="port")
|
|
142
|
+
parser.add_argument("--host", dest="host")
|
|
143
|
+
parser.add_argument("--allow-global-runtime", action="store_true", dest="allow_global_runtime")
|
|
144
|
+
ns, _ = parser.parse_known_args(sys.argv[2:])
|
|
145
|
+
|
|
146
|
+
kwargs = {}
|
|
147
|
+
if ns.port is not None:
|
|
148
|
+
kwargs["port"] = ns.port
|
|
149
|
+
if ns.host is not None:
|
|
150
|
+
kwargs["host"] = ns.host
|
|
151
|
+
if ns.allow_global_runtime:
|
|
152
|
+
kwargs["allow_global_runtime"] = True
|
|
153
|
+
|
|
154
|
+
try:
|
|
155
|
+
commands[command](**kwargs)
|
|
156
|
+
except TypeError:
|
|
157
|
+
commands[command]()
|
|
158
|
+
else:
|
|
159
|
+
commands[command]()
|
|
160
|
+
else:
|
|
161
|
+
print(f"Unknown command: {command}")
|
|
162
|
+
print("Run 'poetry run help' to see available commands.")
|
|
163
|
+
sys.exit(1)
|
|
164
|
+
|
|
165
|
+
|
|
166
|
+
if __name__ == "__main__":
|
|
167
|
+
main()
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
"""{{ project_name }} FastAPI application entrypoint (DDD)."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from collections.abc import AsyncIterator
|
|
6
|
+
from contextlib import asynccontextmanager
|
|
7
|
+
|
|
8
|
+
from fastapi import FastAPI
|
|
9
|
+
|
|
10
|
+
from src.app.main import create_app
|
|
11
|
+
|
|
12
|
+
# <<<inject:imports>>>
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
@asynccontextmanager
|
|
16
|
+
async def lifespan(app: FastAPI) -> AsyncIterator[None]:
|
|
17
|
+
"""Coordinate startup/shutdown hooks contributed by RapidKit modules."""
|
|
18
|
+
|
|
19
|
+
_ = app # ensure the app reference stays available for injected hooks
|
|
20
|
+
# <<<inject:startup>>>
|
|
21
|
+
try:
|
|
22
|
+
yield
|
|
23
|
+
finally:
|
|
24
|
+
# <<<inject:shutdown>>>
|
|
25
|
+
pass
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
app: FastAPI = create_app(
|
|
29
|
+
title="{{ project_name }}",
|
|
30
|
+
description="{{ description }}",
|
|
31
|
+
version="{{ app_version }}",
|
|
32
|
+
lifespan=lifespan,
|
|
33
|
+
)
|
|
34
|
+
|
|
35
|
+
# <<<inject:routes>>>
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
"""API router assembly bridging DDD presentation routes."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from src.app.presentation.api.router import get_api_router
|
|
6
|
+
from .health import router as health_router
|
|
7
|
+
from .notes import router as notes_router
|
|
8
|
+
# <<<inject:router-imports>>>
|
|
9
|
+
|
|
10
|
+
api_router = get_api_router()
|
|
11
|
+
api_router.include_router(health_router, prefix="/health", tags=["health"])
|
|
12
|
+
api_router.include_router(notes_router, prefix="/examples", tags=["examples"])
|
|
13
|
+
# <<<inject:router-mount>>>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"""Test package placeholder."""
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
"""Smoke tests for the generated FastAPI DDD scaffold."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from fastapi import FastAPI
|
|
6
|
+
from fastapi.testclient import TestClient
|
|
7
|
+
|
|
8
|
+
from src.app.main import create_app
|
|
9
|
+
from src.main import app
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def test_create_app_returns_fastapi_instance() -> None:
|
|
13
|
+
instance = create_app(title="Test", description="Sample", version="1.0.0")
|
|
14
|
+
assert isinstance(instance, FastAPI)
|
|
15
|
+
assert instance.title == "Test"
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def test_health_route_returns_ok() -> None:
|
|
19
|
+
client = TestClient(app)
|
|
20
|
+
response = client.get("/api/health/")
|
|
21
|
+
assert response.status_code == 200
|
|
22
|
+
assert response.json()["status"] == "ok"
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
"""Health-check regression tests for FastAPI DDD projects."""
|
|
2
|
+
|
|
3
|
+
from fastapi.testclient import TestClient
|
|
4
|
+
|
|
5
|
+
from src.main import app
|
|
6
|
+
|
|
7
|
+
client = TestClient(app)
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def test_health_endpoint() -> None:
|
|
11
|
+
response = client.get("/api/health/")
|
|
12
|
+
assert response.status_code == 200
|
|
13
|
+
payload = response.json()
|
|
14
|
+
assert payload["status"] == "ok"
|
|
15
|
+
assert "version" in payload
|
|
16
|
+
assert "uptime" in payload
|
|
17
|
+
assert "module" in payload
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
"""Example feature tests exercising the DDD notes handlers."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from fastapi.testclient import TestClient
|
|
6
|
+
|
|
7
|
+
from src.main import app
|
|
8
|
+
|
|
9
|
+
client = TestClient(app)
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def test_create_and_fetch_note() -> None:
|
|
13
|
+
payload = {"title": "architecture note", "body": "Documented via FastAPI DDD kit."}
|
|
14
|
+
create_response = client.post("/api/examples/notes", json=payload)
|
|
15
|
+
assert create_response.status_code == 201
|
|
16
|
+
body = create_response.json()
|
|
17
|
+
note_id = body["id"]
|
|
18
|
+
assert body["title"] == payload["title"]
|
|
19
|
+
|
|
20
|
+
get_response = client.get(f"/api/examples/notes/{note_id}")
|
|
21
|
+
assert get_response.status_code == 200
|
|
22
|
+
assert get_response.json()["id"] == note_id
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
def test_missing_note_returns_404() -> None:
|
|
26
|
+
response = client.get("/api/examples/notes/999")
|
|
27
|
+
assert response.status_code == 404
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
# {{ project_name | replace('_', ' ') | title }}
|
|
2
|
+
|
|
3
|
+
A minimal FastAPI service generated with the **FastAPI Standard Kit**. All domain-specific capabilities (configuration, logging, persistence, observability, authentication, etc.) are provided by RapidKit modules.
|
|
4
|
+
|
|
5
|
+
## Quick start
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
# Load the project-aware RapidKit CLI (adds .rapidkit/rapidkit to PATH)
|
|
9
|
+
source .rapidkit/activate
|
|
10
|
+
|
|
11
|
+
# Bootstrap dependencies (creates .venv + installs Poetry-managed deps)
|
|
12
|
+
rapidkit init # use make init if you prefer a Make target
|
|
13
|
+
|
|
14
|
+
# Copy env templates and install hooks/tooling
|
|
15
|
+
./bootstrap.sh
|
|
16
|
+
|
|
17
|
+
# Run linting, typing, testing, and supply-chain audits
|
|
18
|
+
make lint
|
|
19
|
+
make typecheck
|
|
20
|
+
make test
|
|
21
|
+
make audit
|
|
22
|
+
|
|
23
|
+
# Start development server with hot reload
|
|
24
|
+
make dev
|
|
25
|
+
rapidkit dev # same as make dev but auto-detects the project
|
|
26
|
+
|
|
27
|
+
# Prefer RapidKit CLI helpers when you want it to resolve scripts automatically
|
|
28
|
+
rapidkit lint
|
|
29
|
+
rapidkit test
|
|
30
|
+
rapidkit start
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
> Always run `source .rapidkit/activate` after opening a new shell so the project-local `rapidkit` launcher and helper scripts stay on your PATH.
|
|
34
|
+
|
|
35
|
+
> Re-run `rapidkit init` (or `make init`) whenever dependencies change, or use `SKIP_INIT=1 make install` if you only need to refresh tooling/hooks without reinstalling packages.
|
|
36
|
+
|
|
37
|
+
> Lockfiles are generated automatically during scaffolding. Set `RAPIDKIT_SKIP_LOCKS=1` (or `RAPIDKIT_GENERATE_LOCKS=0`) before running `rapidkit create` if you need to opt out.
|
|
38
|
+
|
|
39
|
+
> Want the full RapidKit CLI catalog? Run `rapidkit --help` or visit the CLI reference in the docs to explore every global/project command.
|
|
40
|
+
|
|
41
|
+
---
|
|
42
|
+
|
|
43
|
+
## Local development
|
|
44
|
+
|
|
45
|
+
- `rapidkit init` bootstraps dependencies via the project-local CLI (run it after sourcing `.rapidkit/activate`).
|
|
46
|
+
- `make init` is an optional alias for `rapidkit init` when you prefer Make targets.
|
|
47
|
+
- `make install` re-runs `rapidkit init` (unless you set `SKIP_INIT=1`) and refreshes developer tooling such as pre-commit hooks.
|
|
48
|
+
- `./bootstrap.sh` copies `.env.example` to `.env` (if missing) and runs `SKIP_INIT=1 make install` for you.
|
|
49
|
+
- `make dev` (or `rapidkit dev`) launches Uvicorn with the correct module path and reload settings.
|
|
50
|
+
- `make lint`, `make typecheck`, and `make test` wrap Ruff, mypy, and pytest for consistent CI parity.
|
|
51
|
+
- `make audit` shells out to `pip-audit` to surface vulnerable dependencies.
|
|
52
|
+
- Prefer `rapidkit lint`, `rapidkit test`, and `rapidkit start` if you want RapidKit to autodetect the virtualenv and command wiring.
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
## Available commands
|
|
56
|
+
|
|
57
|
+
```bash
|
|
58
|
+
rapidkit init # 🔧 Bootstrap the project (create .venv + install deps)
|
|
59
|
+
make init # 🔧 Optional alias for rapidkit init (wraps the local CLI)
|
|
60
|
+
./bootstrap.sh # 🪄 Copy env template + install hooks/tooling (idempotent)
|
|
61
|
+
rapidkit dev # 🚀 Start development server with hot reload
|
|
62
|
+
make dev # 🚀 Alternative via Makefile helper
|
|
63
|
+
rapidkit start # ⚡ Start production server
|
|
64
|
+
rapidkit lint # 🔧 Run lint checks via project-aware CLI
|
|
65
|
+
rapidkit test # 🧪 Run pytest through RapidKit CLI
|
|
66
|
+
make install # 📦 Install Poetry deps + hooks
|
|
67
|
+
make lint # ✅ Lint via Ruff + Black
|
|
68
|
+
make typecheck # 🔍 Run mypy on src
|
|
69
|
+
make test # 🧪 Run tests
|
|
70
|
+
make audit # 🔐 Run pip-audit across dependencies
|
|
71
|
+
make docker-up # 🐳 Start docker compose stack (if enabled)
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
## Project layout
|
|
75
|
+
|
|
76
|
+
- `src/main.py` – FastAPI application entrypoint
|
|
77
|
+
- `src/routing/` – Core routers (health) and anchors for module routers
|
|
78
|
+
- `src/modules/` – Module bootstrap anchors
|
|
79
|
+
- `pyproject.toml` – Poetry configuration and dependencies
|
|
80
|
+
- `Makefile` – Common developer workflows (format, lint, docker, etc.)
|
|
81
|
+
- `Dockerfile` / `docker-compose.yml` – Optional container setup for local dev and deployment
|
|
82
|
+
- `.github/workflows/ci.yml` – Optional GitHub Actions pipeline for linting and tests
|
|
83
|
+
|
|
84
|
+
## Example feature
|
|
85
|
+
|
|
86
|
+
The scaffold ships with a tiny in-memory **notes** API mounted under `/api/examples/notes`. Use it as a safe playground for wiring routers, schemas, and tests without touching your real domain logic:
|
|
87
|
+
|
|
88
|
+
```bash
|
|
89
|
+
# Create a note
|
|
90
|
+
curl -s -X POST http://localhost:8000/api/examples/notes \
|
|
91
|
+
-H "Content-Type: application/json" \
|
|
92
|
+
-d '{"title":"first","body":"scaffolded by RapidKit"}'
|
|
93
|
+
|
|
94
|
+
# List notes
|
|
95
|
+
curl -s http://localhost:8000/api/examples/notes | jq
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
The implementation intentionally stays in memory so you can replace it with a repository-backed service once you install RapidKit database modules.
|
|
99
|
+
|
|
100
|
+
{% if selected_modules %}
|
|
101
|
+
## Recommended RapidKit modules
|
|
102
|
+
|
|
103
|
+
The following RapidKit modules are suggested during scaffolding; install them any time with `rapidkit add module <name>`:
|
|
104
|
+
|
|
105
|
+
{% for module in selected_modules %}- {{ module.name | replace('_', ' ') | title }} (`{{ module.name }}`{% if not module.required %}, optional{% endif %}) – tier: {{ module.tier }}
|
|
106
|
+
{% endfor %}
|
|
107
|
+
{% endif %}
|
|
108
|
+
|
|
109
|
+
## Adding features
|
|
110
|
+
|
|
111
|
+
Use `rapidkit add module <module-name>` to install optional capabilities. Modules inject imports, routes, and services through the anchors defined in `src/main.py` and `src/routing/__init__.py`.
|
|
112
|
+
|
|
113
|
+
During kit generation you can decide whether the core RapidKit modules ship with the scaffold:
|
|
114
|
+
|
|
115
|
+
```text
|
|
116
|
+
Install the RapidKit settings module? [Y/n]
|
|
117
|
+
Install the RapidKit logging module? [Y/n]
|
|
118
|
+
Install deployment module assets (Docker/CI)? [Y/n]
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
### Scaffold toggles vs RapidKit modules
|
|
122
|
+
|
|
123
|
+
- `enable_*` prompts (for Docker, CI, SQLite, etc.) control the starter assets generated by this kit.
|
|
124
|
+
- `install_*` prompts control which RapidKit modules are installed up front.
|
|
125
|
+
- You can always add modules later with `rapidkit add module <name>` if you skip them during scaffolding.
|
|
126
|
+
|
|
127
|
+
When you need deployment artefacts in an existing project, install the optional `deployment` module:
|
|
128
|
+
|
|
129
|
+
```bash
|
|
130
|
+
rapidkit add module deployment
|
|
131
|
+
rapidkit modules lock --overwrite
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
<!-- <<<inject:module-snippet>>> -->
|
|
135
|
+
|
|
136
|
+
## 📄 License
|
|
137
|
+
|
|
138
|
+
This project is licensed under the **{{ license }}** License - see the `LICENSE` file included at the project root for details.
|
|
139
|
+
|
|
140
|
+
## 🔒 Security & secrets
|
|
141
|
+
|
|
142
|
+
- Copy `.env.example` to `.env` and populate secrets (`SECRET_KEY`, DB credentials, etc.) before deploying.
|
|
143
|
+
- **Do not** commit real secrets or `.env` to git; `.gitignore` already contains `.env` to protect accidental commits.
|
|
144
|
+
- For production, tighten CORS and allowed hosts rather than using wildcard settings provided for convenience in dev.
|
|
145
|
+
- Run `make audit` (pip-audit) before releases to catch dependency CVEs early.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{% include 'common/env.example.j2' %}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
[tool.poetry]
|
|
2
|
+
name = "{{ project_name }}"
|
|
3
|
+
version = "{{ app_version }}"
|
|
4
|
+
description = "{{ description }}"
|
|
5
|
+
authors = ["{{ author }} <you@example.com>"]
|
|
6
|
+
license = "{{ license }}"
|
|
7
|
+
packages = [{ include = "src" }]
|
|
8
|
+
|
|
9
|
+
[tool.poetry.scripts]
|
|
10
|
+
dev = "src.cli:dev"
|
|
11
|
+
start = "src.cli:start"
|
|
12
|
+
build = "src.cli:build"
|
|
13
|
+
test = "src.cli:test"
|
|
14
|
+
lint = "src.cli:lint"
|
|
15
|
+
format = "src.cli:format"
|
|
16
|
+
help = "src.cli:help_cmd"
|
|
17
|
+
|
|
18
|
+
[tool.poetry.dependencies]
|
|
19
|
+
python = "^{{ python_version }}"
|
|
20
|
+
fastapi = "^0.128.0"
|
|
21
|
+
uvicorn = { extras = ["standard"], version = "^0.40.0" }
|
|
22
|
+
pydantic = "^2.12.5"
|
|
23
|
+
{% if has_settings -%}
|
|
24
|
+
pydantic-settings = { version = "^2.12.0", extras = ["yaml"] }
|
|
25
|
+
{% endif %}
|
|
26
|
+
# <<<inject:poetry-dependencies>>>
|
|
27
|
+
|
|
28
|
+
[tool.poetry.group.dev.dependencies]
|
|
29
|
+
pytest = "^9.0.2"
|
|
30
|
+
pytest-asyncio = "^1.3.0"
|
|
31
|
+
pytest-cov = "^7.0.0"
|
|
32
|
+
httpx = "^0.28.1"
|
|
33
|
+
ruff = "^0.14.10"
|
|
34
|
+
black = "^25.12.0"
|
|
35
|
+
isort = "^7.0.0"
|
|
36
|
+
mypy = "^1.19.1"
|
|
37
|
+
build = "^1.3.0"
|
|
38
|
+
|
|
39
|
+
# <<<inject:poetry-dev-dependencies>>>
|
|
40
|
+
|
|
41
|
+
[build-system]
|
|
42
|
+
requires = ["poetry-core"]
|
|
43
|
+
build-backend = "poetry.core.masonry.api"
|
|
44
|
+
|
|
45
|
+
[tool.pytest.ini_options]
|
|
46
|
+
markers = [
|
|
47
|
+
"integration: mark tests as integration tests",
|
|
48
|
+
"template_integration: mark template integration tests",
|
|
49
|
+
]
|
|
50
|
+
|
|
51
|
+
[tool.ruff]
|
|
52
|
+
line-length = 100
|
|
53
|
+
exclude = [".rapidkit/vendor"]
|
|
54
|
+
|
|
55
|
+
[tool.ruff.lint]
|
|
56
|
+
ignore = ["E501"]
|
|
57
|
+
|
|
58
|
+
[tool.mypy]
|
|
59
|
+
python_version = "{{ python_version }}"
|
|
60
|
+
ignore_missing_imports = true
|
|
61
|
+
warn_unused_configs = false
|
|
62
|
+
show_error_codes = true
|
|
63
|
+
# Ignore vendor snapshots and generated health shims from strict static checking
|
|
64
|
+
exclude = "(^\\.rapidkit/vendor/|src/health/|src/main.py$)"
|