arclith-cli 0.19.0__tar.gz → 0.21.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {arclith_cli-0.19.0 → arclith_cli-0.21.0}/PKG-INFO +41 -10
- {arclith_cli-0.19.0 → arclith_cli-0.21.0}/README.md +39 -8
- arclith_cli-0.21.0/arclith_cli/__init__.py +1 -0
- {arclith_cli-0.19.0 → arclith_cli-0.21.0}/arclith_cli/adapter_templates.py +2 -1
- {arclith_cli-0.19.0 → arclith_cli-0.21.0}/arclith_cli/capabilities.py +5 -0
- {arclith_cli-0.19.0 → arclith_cli-0.21.0}/arclith_cli/capability_models.py +41 -0
- arclith_cli-0.21.0/arclith_cli/catalogs/channels.py +197 -0
- {arclith_cli-0.19.0 → arclith_cli-0.21.0}/arclith_cli/catalogs/persistence.py +14 -79
- arclith_cli-0.21.0/arclith_cli/catalogs/repository_facets.py +94 -0
- arclith_cli-0.21.0/arclith_cli/catalogs/repository_postgresql.py +107 -0
- {arclith_cli-0.19.0 → arclith_cli-0.21.0}/arclith_cli/core_scaffold.py +155 -40
- {arclith_cli-0.19.0 → arclith_cli-0.21.0}/arclith_cli/init_project.py +1 -1
- {arclith_cli-0.19.0 → arclith_cli-0.21.0}/arclith_cli/main.py +41 -3
- {arclith_cli-0.19.0 → arclith_cli-0.21.0}/arclith_cli/project_paths.py +18 -3
- {arclith_cli-0.19.0 → arclith_cli-0.21.0}/arclith_cli/recipe.py +14 -1
- arclith_cli-0.21.0/arclith_cli/scaffold_interactive.py +105 -0
- arclith_cli-0.21.0/arclith_cli/scaffold_templates.py +140 -0
- {arclith_cli-0.19.0 → arclith_cli-0.21.0}/pyproject.toml +2 -2
- {arclith_cli-0.19.0 → arclith_cli-0.21.0}/tests/e2e_manual.sh +1 -1
- arclith_cli-0.21.0/tests/test_adapter_templates.py +20 -0
- {arclith_cli-0.19.0 → arclith_cli-0.21.0}/tests/test_add_adapter.py +172 -7
- {arclith_cli-0.19.0 → arclith_cli-0.21.0}/tests/test_capabilities.py +176 -0
- arclith_cli-0.21.0/tests/test_core_scaffold.py +566 -0
- {arclith_cli-0.19.0 → arclith_cli-0.21.0}/tests/test_e2e_scaffold.py +3 -1
- {arclith_cli-0.19.0 → arclith_cli-0.21.0}/tests/test_embedding_capability.py +3 -3
- {arclith_cli-0.19.0 → arclith_cli-0.21.0}/tests/test_project_paths.py +1 -0
- {arclith_cli-0.19.0 → arclith_cli-0.21.0}/tests/test_recipe.py +2 -2
- arclith_cli-0.21.0/tests/test_scaffold_cli.py +216 -0
- {arclith_cli-0.19.0 → arclith_cli-0.21.0}/tests/test_vector_store_capability.py +1 -1
- {arclith_cli-0.19.0 → arclith_cli-0.21.0}/uv.lock +4 -3
- arclith_cli-0.19.0/arclith_cli/__init__.py +0 -1
- arclith_cli-0.19.0/tests/test_core_scaffold.py +0 -248
- {arclith_cli-0.19.0 → arclith_cli-0.21.0}/.gitignore +0 -0
- {arclith_cli-0.19.0 → arclith_cli-0.21.0}/LICENSE +0 -0
- {arclith_cli-0.19.0 → arclith_cli-0.21.0}/Makefile +0 -0
- {arclith_cli-0.19.0 → arclith_cli-0.21.0}/arclith_cli/adapter_config.py +0 -0
- {arclith_cli-0.19.0 → arclith_cli-0.21.0}/arclith_cli/adapter_generator.py +0 -0
- {arclith_cli-0.19.0 → arclith_cli-0.21.0}/arclith_cli/adapter_parameters.py +0 -0
- {arclith_cli-0.19.0 → arclith_cli-0.21.0}/arclith_cli/adapter_rendering.py +0 -0
- {arclith_cli-0.19.0 → arclith_cli-0.21.0}/arclith_cli/adapter_selection.py +0 -0
- {arclith_cli-0.19.0 → arclith_cli-0.21.0}/arclith_cli/add_adapter.py +0 -0
- {arclith_cli-0.19.0 → arclith_cli-0.21.0}/arclith_cli/catalogs/__init__.py +0 -0
- {arclith_cli-0.19.0 → arclith_cli-0.21.0}/arclith_cli/catalogs/ai.py +0 -0
- {arclith_cli-0.19.0 → arclith_cli-0.21.0}/arclith_cli/catalogs/core.py +0 -0
- {arclith_cli-0.19.0 → arclith_cli-0.21.0}/arclith_cli/catalogs/observability.py +0 -0
- {arclith_cli-0.19.0 → arclith_cli-0.21.0}/arclith_cli/catalogs/security.py +0 -0
- {arclith_cli-0.19.0 → arclith_cli-0.21.0}/arclith_cli/catalogs/transports.py +0 -0
- {arclith_cli-0.19.0 → arclith_cli-0.21.0}/arclith_cli/entity_scanner.py +0 -0
- {arclith_cli-0.19.0 → arclith_cli-0.21.0}/arclith_cli/export_config.py +0 -0
- {arclith_cli-0.19.0 → arclith_cli-0.21.0}/arclith_cli/new_project.py +0 -0
- {arclith_cli-0.19.0 → arclith_cli-0.21.0}/arclith_cli/recipe_cli.py +0 -0
- {arclith_cli-0.19.0 → arclith_cli-0.21.0}/arclith_cli/recipe_models.py +0 -0
- {arclith_cli-0.19.0 → arclith_cli-0.21.0}/arclith_cli/rename.py +0 -0
- {arclith_cli-0.19.0 → arclith_cli-0.21.0}/arclith_cli/runtime_templates.py +0 -0
- {arclith_cli-0.19.0 → arclith_cli-0.21.0}/arclith_cli/scaffold.py +0 -0
- {arclith_cli-0.19.0 → arclith_cli-0.21.0}/arclith_cli/updater.py +0 -0
- {arclith_cli-0.19.0 → arclith_cli-0.21.0}/tests/__init__.py +0 -0
- {arclith_cli-0.19.0 → arclith_cli-0.21.0}/tests/test_rename.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: arclith-cli
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.21.0
|
|
4
4
|
Summary: CLI scaffolding tool for arclith — hexagonal architecture framework
|
|
5
5
|
Author-email: Killian KOPP <killiankopp@gmail.com>
|
|
6
6
|
License: Apache License
|
|
@@ -186,7 +186,7 @@ License: Apache License
|
|
|
186
186
|
License-File: LICENSE
|
|
187
187
|
Keywords: arclith,cli,ddd,hexagonal-architecture,scaffold
|
|
188
188
|
Requires-Python: >=3.13
|
|
189
|
-
Requires-Dist: arclith>=0.
|
|
189
|
+
Requires-Dist: arclith>=0.24.0
|
|
190
190
|
Requires-Dist: httpx>=0.27.0
|
|
191
191
|
Requires-Dist: rich>=13.0.0
|
|
192
192
|
Requires-Dist: typer>=0.15.0
|
|
@@ -252,7 +252,10 @@ template est régénéré côté CLI pour appliquer le contrat `runtime/docker-i
|
|
|
252
252
|
|
|
253
253
|
### `add-entity` — Ajouter une entité métier
|
|
254
254
|
|
|
255
|
-
Crée
|
|
255
|
+
Crée un squelette minimal et guidé dans `src/<package>/domain/models/`. Le fichier
|
|
256
|
+
signale où déclarer les champs et invariants, rappelle les champs déjà fournis par
|
|
257
|
+
`Entity` et renvoie vers les guides Arclith et Pydantic. L'exemple `Field(...)`
|
|
258
|
+
reste commenté, donc aucun import inutilisé n'est ajouté.
|
|
256
259
|
|
|
257
260
|
```bash
|
|
258
261
|
cd my-recipe-service
|
|
@@ -265,21 +268,41 @@ Fichier généré :
|
|
|
265
268
|
src/<package>/domain/models/shopping_item.py
|
|
266
269
|
```
|
|
267
270
|
|
|
268
|
-
La commande ne génère aucun CRUD, aucun port repository, aucun adapter et aucun
|
|
271
|
+
La commande ne génère aucun CRUD, aucun port repository, aucun adapter et aucun
|
|
272
|
+
endpoint. Elle pose seulement le point d'ancrage du modèle métier ; le
|
|
273
|
+
développeur complète ensuite les champs et invariants de l'entité.
|
|
269
274
|
|
|
270
275
|
---
|
|
271
276
|
|
|
272
277
|
### `add-usecase` — Ajouter un cas d'usage
|
|
273
278
|
|
|
274
|
-
Crée
|
|
275
|
-
cas d'usage dans `src/<package>/application/use_cases/`.
|
|
279
|
+
Crée un port inbound guidé dans `src/<package>/domain/ports/inbound/`, puis le
|
|
280
|
+
cas d'usage dans `src/<package>/application/use_cases/`. Sans option de liaison,
|
|
281
|
+
la commande interactive propose les entités détectées par analyse AST, la
|
|
282
|
+
création d'une nouvelle entité ou un cas d'usage transverse.
|
|
276
283
|
|
|
277
284
|
```bash
|
|
278
285
|
cd my-recipe-service
|
|
286
|
+
|
|
287
|
+
# Mode interactif : choisir une entité détectée, en créer une ou rester transverse
|
|
279
288
|
arclith-cli add-usecase PlanShoppingList
|
|
280
|
-
|
|
289
|
+
|
|
290
|
+
# Modes directs, complets pour les agents et la CI
|
|
291
|
+
arclith-cli add-usecase CreateTodo --entity Todo
|
|
292
|
+
arclith-cli add-usecase CreateRecipe --new-entity Recipe
|
|
293
|
+
arclith-cli add-usecase RunMaintenance --no-entity
|
|
281
294
|
```
|
|
282
295
|
|
|
296
|
+
| Option | Effet |
|
|
297
|
+
|---|---|
|
|
298
|
+
| `--entity Todo` | lie le use case à une entité détectée et échoue si elle est absente |
|
|
299
|
+
| `--new-entity Todo` | crée l'entité si nécessaire, puis génère le use case lié |
|
|
300
|
+
| `--no-entity` | génère un `Command`, un `Result` et un use case transverse sans repository |
|
|
301
|
+
|
|
302
|
+
Ces options sont mutuellement exclusives. `--new-entity` réutilise une entité
|
|
303
|
+
valide déjà présente, mais refuse un fichier homonyme qui ne déclare pas la
|
|
304
|
+
classe `Entity` attendue.
|
|
305
|
+
|
|
283
306
|
Fichier généré :
|
|
284
307
|
|
|
285
308
|
```text
|
|
@@ -287,9 +310,17 @@ src/<package>/domain/ports/inbound/plan_shopping_list.py
|
|
|
287
310
|
src/<package>/application/use_cases/plan_shopping_list.py
|
|
288
311
|
```
|
|
289
312
|
|
|
290
|
-
Le nom peut être fourni en PascalCase, snake_case ou kebab-case. Le suffixe
|
|
291
|
-
|
|
292
|
-
|
|
313
|
+
Le nom peut être fourni en PascalCase, snake_case ou kebab-case. Le suffixe
|
|
314
|
+
`UseCase` est normalisé : `PlanShoppingListUseCase` et
|
|
315
|
+
`plan-shopping-list-use-case` génèrent tous les deux
|
|
316
|
+
`PlanShoppingListUseCase`.
|
|
317
|
+
|
|
318
|
+
Pour une entité principale, le squelette injecte explicitement
|
|
319
|
+
`Repository[Entity]` et type `execute` avec un `Command` Pydantic et l'entité en
|
|
320
|
+
retour. Le mode transverse génère plutôt un `Command` et un `Result` Pydantic,
|
|
321
|
+
sans repository implicite. Aucun mode ne câble FastAPI, FastMCP ou LangGraph.
|
|
322
|
+
Les exemples complets et les règles de séparation sont dans le
|
|
323
|
+
[deep dive du scaffold CLI](https://karned-rekipe.github.io/arclith/deep-dives/cli-scaffold/).
|
|
293
324
|
|
|
294
325
|
---
|
|
295
326
|
|
|
@@ -58,7 +58,10 @@ template est régénéré côté CLI pour appliquer le contrat `runtime/docker-i
|
|
|
58
58
|
|
|
59
59
|
### `add-entity` — Ajouter une entité métier
|
|
60
60
|
|
|
61
|
-
Crée
|
|
61
|
+
Crée un squelette minimal et guidé dans `src/<package>/domain/models/`. Le fichier
|
|
62
|
+
signale où déclarer les champs et invariants, rappelle les champs déjà fournis par
|
|
63
|
+
`Entity` et renvoie vers les guides Arclith et Pydantic. L'exemple `Field(...)`
|
|
64
|
+
reste commenté, donc aucun import inutilisé n'est ajouté.
|
|
62
65
|
|
|
63
66
|
```bash
|
|
64
67
|
cd my-recipe-service
|
|
@@ -71,21 +74,41 @@ Fichier généré :
|
|
|
71
74
|
src/<package>/domain/models/shopping_item.py
|
|
72
75
|
```
|
|
73
76
|
|
|
74
|
-
La commande ne génère aucun CRUD, aucun port repository, aucun adapter et aucun
|
|
77
|
+
La commande ne génère aucun CRUD, aucun port repository, aucun adapter et aucun
|
|
78
|
+
endpoint. Elle pose seulement le point d'ancrage du modèle métier ; le
|
|
79
|
+
développeur complète ensuite les champs et invariants de l'entité.
|
|
75
80
|
|
|
76
81
|
---
|
|
77
82
|
|
|
78
83
|
### `add-usecase` — Ajouter un cas d'usage
|
|
79
84
|
|
|
80
|
-
Crée
|
|
81
|
-
cas d'usage dans `src/<package>/application/use_cases/`.
|
|
85
|
+
Crée un port inbound guidé dans `src/<package>/domain/ports/inbound/`, puis le
|
|
86
|
+
cas d'usage dans `src/<package>/application/use_cases/`. Sans option de liaison,
|
|
87
|
+
la commande interactive propose les entités détectées par analyse AST, la
|
|
88
|
+
création d'une nouvelle entité ou un cas d'usage transverse.
|
|
82
89
|
|
|
83
90
|
```bash
|
|
84
91
|
cd my-recipe-service
|
|
92
|
+
|
|
93
|
+
# Mode interactif : choisir une entité détectée, en créer une ou rester transverse
|
|
85
94
|
arclith-cli add-usecase PlanShoppingList
|
|
86
|
-
|
|
95
|
+
|
|
96
|
+
# Modes directs, complets pour les agents et la CI
|
|
97
|
+
arclith-cli add-usecase CreateTodo --entity Todo
|
|
98
|
+
arclith-cli add-usecase CreateRecipe --new-entity Recipe
|
|
99
|
+
arclith-cli add-usecase RunMaintenance --no-entity
|
|
87
100
|
```
|
|
88
101
|
|
|
102
|
+
| Option | Effet |
|
|
103
|
+
|---|---|
|
|
104
|
+
| `--entity Todo` | lie le use case à une entité détectée et échoue si elle est absente |
|
|
105
|
+
| `--new-entity Todo` | crée l'entité si nécessaire, puis génère le use case lié |
|
|
106
|
+
| `--no-entity` | génère un `Command`, un `Result` et un use case transverse sans repository |
|
|
107
|
+
|
|
108
|
+
Ces options sont mutuellement exclusives. `--new-entity` réutilise une entité
|
|
109
|
+
valide déjà présente, mais refuse un fichier homonyme qui ne déclare pas la
|
|
110
|
+
classe `Entity` attendue.
|
|
111
|
+
|
|
89
112
|
Fichier généré :
|
|
90
113
|
|
|
91
114
|
```text
|
|
@@ -93,9 +116,17 @@ src/<package>/domain/ports/inbound/plan_shopping_list.py
|
|
|
93
116
|
src/<package>/application/use_cases/plan_shopping_list.py
|
|
94
117
|
```
|
|
95
118
|
|
|
96
|
-
Le nom peut être fourni en PascalCase, snake_case ou kebab-case. Le suffixe
|
|
97
|
-
|
|
98
|
-
|
|
119
|
+
Le nom peut être fourni en PascalCase, snake_case ou kebab-case. Le suffixe
|
|
120
|
+
`UseCase` est normalisé : `PlanShoppingListUseCase` et
|
|
121
|
+
`plan-shopping-list-use-case` génèrent tous les deux
|
|
122
|
+
`PlanShoppingListUseCase`.
|
|
123
|
+
|
|
124
|
+
Pour une entité principale, le squelette injecte explicitement
|
|
125
|
+
`Repository[Entity]` et type `execute` avec un `Command` Pydantic et l'entité en
|
|
126
|
+
retour. Le mode transverse génère plutôt un `Command` et un `Result` Pydantic,
|
|
127
|
+
sans repository implicite. Aucun mode ne câble FastAPI, FastMCP ou LangGraph.
|
|
128
|
+
Les exemples complets et les règles de séparation sont dans le
|
|
129
|
+
[deep dive du scaffold CLI](https://karned-rekipe.github.io/arclith/deep-dives/cli-scaffold/).
|
|
99
130
|
|
|
100
131
|
---
|
|
101
132
|
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = "0.21.0"
|
|
@@ -205,7 +205,8 @@ _repository_registry: RepositoryRegistry[{pascal}, {pascal}Repository] = (
|
|
|
205
205
|
|
|
206
206
|
|
|
207
207
|
def build_{snake}_service(arclith: Arclith) -> tuple[{pascal}Service, Logger]:
|
|
208
|
-
|
|
208
|
+
adapter = arclith.config.adapters.repository_adapter_for({pascal})
|
|
209
|
+
arclith.logger.info("🗄️ Repository adapter selected", adapter=adapter)
|
|
209
210
|
repo: {pascal}Repository = arclith.repository({pascal}, registry=_repository_registry)
|
|
210
211
|
return {pascal}Service(repo, arclith.logger, arclith.config.soft_delete.retention_days), arclith.logger
|
|
211
212
|
"""
|
|
@@ -3,6 +3,7 @@ from __future__ import annotations
|
|
|
3
3
|
from typing import Any
|
|
4
4
|
|
|
5
5
|
from arclith_cli.capability_models import (
|
|
6
|
+
AdapterFacets,
|
|
6
7
|
AdapterProfileSpec,
|
|
7
8
|
AdapterSpec,
|
|
8
9
|
CapabilitySpec,
|
|
@@ -18,6 +19,7 @@ from arclith_cli.catalogs.ai import (
|
|
|
18
19
|
EMBEDDING_CAPABILITY,
|
|
19
20
|
LLM_CAPABILITY,
|
|
20
21
|
)
|
|
22
|
+
from arclith_cli.catalogs.channels import CHANNEL_CAPABILITY
|
|
21
23
|
from arclith_cli.catalogs.core import (
|
|
22
24
|
CACHE_CAPABILITY,
|
|
23
25
|
LOGGER_CAPABILITY,
|
|
@@ -48,9 +50,11 @@ __all__ = [
|
|
|
48
50
|
"AGENT_PERSISTENCE_CAPABILITY",
|
|
49
51
|
"API_CAPABILITY",
|
|
50
52
|
"AUTH_CAPABILITY",
|
|
53
|
+
"AdapterFacets",
|
|
51
54
|
"AdapterProfileSpec",
|
|
52
55
|
"AdapterSpec",
|
|
53
56
|
"CACHE_CAPABILITY",
|
|
57
|
+
"CHANNEL_CAPABILITY",
|
|
54
58
|
"CAPABILITY_CATALOG",
|
|
55
59
|
"COMMAND_BUS_CAPABILITY",
|
|
56
60
|
"CapabilitySpec",
|
|
@@ -91,6 +95,7 @@ CAPABILITY_CATALOG = (
|
|
|
91
95
|
PROBE_CAPABILITY,
|
|
92
96
|
HTTP_CAPABILITY,
|
|
93
97
|
COMMAND_BUS_CAPABILITY,
|
|
98
|
+
CHANNEL_CAPABILITY,
|
|
94
99
|
RUNTIME_CAPABILITY,
|
|
95
100
|
AUTH_CAPABILITY,
|
|
96
101
|
TENANT_CAPABILITY,
|
|
@@ -5,6 +5,16 @@ from typing import Any, Literal
|
|
|
5
5
|
|
|
6
6
|
ParameterKind = Literal["string", "boolean"]
|
|
7
7
|
LayerKind = Literal["inbound", "outbound", "bidirectional", "runtime"]
|
|
8
|
+
StorageModel = Literal[
|
|
9
|
+
"memory",
|
|
10
|
+
"document",
|
|
11
|
+
"relational_json",
|
|
12
|
+
"embedded_analytics",
|
|
13
|
+
"relational_structured",
|
|
14
|
+
]
|
|
15
|
+
RuntimeKind = Literal["in_process", "file", "server"]
|
|
16
|
+
TransactionSupport = Literal["none", "limited", "strong"]
|
|
17
|
+
SchemaStrategy = Literal["flexible", "json_table", "structured_tables"]
|
|
8
18
|
|
|
9
19
|
|
|
10
20
|
@dataclass(frozen=True)
|
|
@@ -70,6 +80,30 @@ class AdapterProfileSpec:
|
|
|
70
80
|
return {"name": self.name, "parameters": dict(self.parameters)}
|
|
71
81
|
|
|
72
82
|
|
|
83
|
+
@dataclass(frozen=True)
|
|
84
|
+
class AdapterFacets:
|
|
85
|
+
storage_model: StorageModel
|
|
86
|
+
runtime: RuntimeKind
|
|
87
|
+
production_ready: bool
|
|
88
|
+
multi_process: bool
|
|
89
|
+
transactions: TransactionSupport
|
|
90
|
+
schema_strategy: SchemaStrategy
|
|
91
|
+
recommended_for: tuple[str, ...]
|
|
92
|
+
limits: tuple[str, ...]
|
|
93
|
+
|
|
94
|
+
def to_dict(self) -> dict[str, Any]:
|
|
95
|
+
return {
|
|
96
|
+
"storage_model": self.storage_model,
|
|
97
|
+
"runtime": self.runtime,
|
|
98
|
+
"production_ready": self.production_ready,
|
|
99
|
+
"multi_process": self.multi_process,
|
|
100
|
+
"transactions": self.transactions,
|
|
101
|
+
"schema_strategy": self.schema_strategy,
|
|
102
|
+
"recommended_for": list(self.recommended_for),
|
|
103
|
+
"limits": list(self.limits),
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
|
|
73
107
|
@dataclass(frozen=True)
|
|
74
108
|
class AdapterSpec:
|
|
75
109
|
name: str
|
|
@@ -90,6 +124,7 @@ class AdapterSpec:
|
|
|
90
124
|
profiles: tuple[AdapterProfileSpec, ...] = ()
|
|
91
125
|
dependency_extra: str | None = None
|
|
92
126
|
entity_scoped: bool = True
|
|
127
|
+
facets: AdapterFacets | None = None
|
|
93
128
|
|
|
94
129
|
def has_config(self) -> bool:
|
|
95
130
|
return self.config_path is not None and bool(self.config_template)
|
|
@@ -137,6 +172,7 @@ class AdapterSpec:
|
|
|
137
172
|
"profiles": [profile.to_dict() for profile in self.profiles],
|
|
138
173
|
"dependency_extra": self.dependency_extra,
|
|
139
174
|
"entity_scoped": self.entity_scoped,
|
|
175
|
+
"facets": self.facets.to_dict() if self.facets is not None else None,
|
|
140
176
|
}
|
|
141
177
|
|
|
142
178
|
|
|
@@ -169,6 +205,7 @@ class CapabilitySpec:
|
|
|
169
205
|
|
|
170
206
|
|
|
171
207
|
__all__ = [
|
|
208
|
+
"AdapterFacets",
|
|
172
209
|
"AdapterProfileSpec",
|
|
173
210
|
"AdapterSpec",
|
|
174
211
|
"CapabilitySpec",
|
|
@@ -176,5 +213,9 @@ __all__ = [
|
|
|
176
213
|
"LayerKind",
|
|
177
214
|
"ParameterKind",
|
|
178
215
|
"ParameterSpec",
|
|
216
|
+
"RuntimeKind",
|
|
217
|
+
"SchemaStrategy",
|
|
179
218
|
"SecretMappingSpec",
|
|
219
|
+
"StorageModel",
|
|
220
|
+
"TransactionSupport",
|
|
180
221
|
]
|
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
from arclith_cli.capability_models import (
|
|
2
|
+
AdapterSpec,
|
|
3
|
+
CapabilitySpec,
|
|
4
|
+
ParameterSpec,
|
|
5
|
+
SecretMappingSpec,
|
|
6
|
+
)
|
|
7
|
+
|
|
8
|
+
CHANNEL_CAPABILITY = CapabilitySpec(
|
|
9
|
+
name="channel",
|
|
10
|
+
layer="bidirectional",
|
|
11
|
+
description="Messages conversationnels entrants et sortants normalisés.",
|
|
12
|
+
activation_config_key=None,
|
|
13
|
+
adapters=(
|
|
14
|
+
AdapterSpec(
|
|
15
|
+
name="memory",
|
|
16
|
+
capability="channel",
|
|
17
|
+
layer="bidirectional",
|
|
18
|
+
description="Fake déterministe en mémoire pour tests et prototypes locaux.",
|
|
19
|
+
config_path="config/adapters/bidirectional/memory.yaml",
|
|
20
|
+
config_template="""\
|
|
21
|
+
enabled: true
|
|
22
|
+
""",
|
|
23
|
+
entity_scoped=False,
|
|
24
|
+
),
|
|
25
|
+
AdapterSpec(
|
|
26
|
+
name="webhook",
|
|
27
|
+
capability="channel",
|
|
28
|
+
layer="bidirectional",
|
|
29
|
+
description="Webhook HTTP générique signé, idempotent et provider-neutral.",
|
|
30
|
+
config_path="config/adapters/bidirectional/webhook.yaml",
|
|
31
|
+
config_template="""\
|
|
32
|
+
enabled: true
|
|
33
|
+
path: "{path}"
|
|
34
|
+
secret: null
|
|
35
|
+
signature_header: "{signature_header}"
|
|
36
|
+
timestamp_header: "{timestamp_header}"
|
|
37
|
+
signature_tolerance_seconds: {signature_tolerance_seconds}
|
|
38
|
+
idempotency_header: "{idempotency_header}"
|
|
39
|
+
event_ttl_seconds: {event_ttl_seconds}
|
|
40
|
+
max_payload_bytes: {max_payload_bytes}
|
|
41
|
+
metadata_allowlist: []
|
|
42
|
+
response_mode: "{response_mode}"
|
|
43
|
+
callback_url: {callback_url}
|
|
44
|
+
callback_allowed_host: {callback_allowed_host}
|
|
45
|
+
callback_timeout_seconds: {callback_timeout_seconds}
|
|
46
|
+
""",
|
|
47
|
+
secret_mappings=(
|
|
48
|
+
SecretMappingSpec(
|
|
49
|
+
field_path="adapters.channel.webhook.secret",
|
|
50
|
+
secret_key="ARCLITH_WEBHOOK_SECRET",
|
|
51
|
+
),
|
|
52
|
+
),
|
|
53
|
+
parameters=(
|
|
54
|
+
ParameterSpec(
|
|
55
|
+
name="path",
|
|
56
|
+
kind="string",
|
|
57
|
+
prompt="Route HTTP statique du webhook",
|
|
58
|
+
default="/channels/webhook",
|
|
59
|
+
),
|
|
60
|
+
ParameterSpec(
|
|
61
|
+
name="signature_header",
|
|
62
|
+
kind="string",
|
|
63
|
+
prompt="Header de signature HMAC",
|
|
64
|
+
default="X-Arclith-Signature",
|
|
65
|
+
),
|
|
66
|
+
ParameterSpec(
|
|
67
|
+
name="timestamp_header",
|
|
68
|
+
kind="string",
|
|
69
|
+
prompt="Header du timestamp signé",
|
|
70
|
+
default="X-Arclith-Timestamp",
|
|
71
|
+
),
|
|
72
|
+
ParameterSpec(
|
|
73
|
+
name="signature_tolerance_seconds",
|
|
74
|
+
kind="string",
|
|
75
|
+
prompt="Tolérance de fraîcheur HMAC en secondes",
|
|
76
|
+
default="300",
|
|
77
|
+
),
|
|
78
|
+
ParameterSpec(
|
|
79
|
+
name="idempotency_header",
|
|
80
|
+
kind="string",
|
|
81
|
+
prompt="Header de l'identifiant stable de l'événement",
|
|
82
|
+
default="X-Arclith-Event-Id",
|
|
83
|
+
),
|
|
84
|
+
ParameterSpec(
|
|
85
|
+
name="event_ttl_seconds",
|
|
86
|
+
kind="string",
|
|
87
|
+
prompt="Durée de déduplication en secondes",
|
|
88
|
+
default="86400",
|
|
89
|
+
),
|
|
90
|
+
ParameterSpec(
|
|
91
|
+
name="max_payload_bytes",
|
|
92
|
+
kind="string",
|
|
93
|
+
prompt="Taille maximale du payload en octets",
|
|
94
|
+
default="1048576",
|
|
95
|
+
),
|
|
96
|
+
ParameterSpec(
|
|
97
|
+
name="response_mode",
|
|
98
|
+
kind="string",
|
|
99
|
+
prompt="Mode de réponse HTTP",
|
|
100
|
+
default="sync",
|
|
101
|
+
choices=("sync", "accepted", "callback"),
|
|
102
|
+
),
|
|
103
|
+
ParameterSpec(
|
|
104
|
+
name="callback_url",
|
|
105
|
+
kind="string",
|
|
106
|
+
prompt="URL HTTPS du callback côté serveur (null hors mode callback)",
|
|
107
|
+
default="null",
|
|
108
|
+
),
|
|
109
|
+
ParameterSpec(
|
|
110
|
+
name="callback_allowed_host",
|
|
111
|
+
kind="string",
|
|
112
|
+
prompt="Hostname exact autorisé pour le callback (null hors mode callback)",
|
|
113
|
+
default="null",
|
|
114
|
+
),
|
|
115
|
+
ParameterSpec(
|
|
116
|
+
name="callback_timeout_seconds",
|
|
117
|
+
kind="string",
|
|
118
|
+
prompt="Timeout du callback sortant en secondes",
|
|
119
|
+
default="5.0",
|
|
120
|
+
),
|
|
121
|
+
),
|
|
122
|
+
dependency_extra="channel",
|
|
123
|
+
entity_scoped=False,
|
|
124
|
+
),
|
|
125
|
+
AdapterSpec(
|
|
126
|
+
name="slack",
|
|
127
|
+
capability="channel",
|
|
128
|
+
layer="bidirectional",
|
|
129
|
+
description="Slack Events API signé avec réponses chat.postMessage.",
|
|
130
|
+
config_path="config/adapters/bidirectional/slack.yaml",
|
|
131
|
+
config_template="""\
|
|
132
|
+
enabled: true
|
|
133
|
+
path: "{path}"
|
|
134
|
+
signing_secret: null
|
|
135
|
+
bot_token: null
|
|
136
|
+
workspace_id: {workspace_id}
|
|
137
|
+
allowed_channel_ids: []
|
|
138
|
+
signature_tolerance_seconds: {signature_tolerance_seconds}
|
|
139
|
+
event_ttl_seconds: {event_ttl_seconds}
|
|
140
|
+
max_payload_bytes: {max_payload_bytes}
|
|
141
|
+
request_timeout_seconds: {request_timeout_seconds}
|
|
142
|
+
""",
|
|
143
|
+
secret_mappings=(
|
|
144
|
+
SecretMappingSpec(
|
|
145
|
+
field_path="adapters.channel.slack.signing_secret",
|
|
146
|
+
secret_key="ARCLITH_SLACK_SIGNING_SECRET",
|
|
147
|
+
),
|
|
148
|
+
SecretMappingSpec(
|
|
149
|
+
field_path="adapters.channel.slack.bot_token",
|
|
150
|
+
secret_key="ARCLITH_SLACK_BOT_TOKEN",
|
|
151
|
+
),
|
|
152
|
+
),
|
|
153
|
+
parameters=(
|
|
154
|
+
ParameterSpec(
|
|
155
|
+
name="path",
|
|
156
|
+
kind="string",
|
|
157
|
+
prompt="Route HTTP statique des événements Slack",
|
|
158
|
+
default="/channels/slack/events",
|
|
159
|
+
),
|
|
160
|
+
ParameterSpec(
|
|
161
|
+
name="workspace_id",
|
|
162
|
+
kind="string",
|
|
163
|
+
prompt="Workspace Slack exact autorisé (null pour tout accepter)",
|
|
164
|
+
default="null",
|
|
165
|
+
),
|
|
166
|
+
ParameterSpec(
|
|
167
|
+
name="signature_tolerance_seconds",
|
|
168
|
+
kind="string",
|
|
169
|
+
prompt="Tolérance de fraîcheur de signature en secondes",
|
|
170
|
+
default="300",
|
|
171
|
+
),
|
|
172
|
+
ParameterSpec(
|
|
173
|
+
name="event_ttl_seconds",
|
|
174
|
+
kind="string",
|
|
175
|
+
prompt="Durée de déduplication des event_id en secondes",
|
|
176
|
+
default="86400",
|
|
177
|
+
),
|
|
178
|
+
ParameterSpec(
|
|
179
|
+
name="max_payload_bytes",
|
|
180
|
+
kind="string",
|
|
181
|
+
prompt="Taille maximale du payload en octets",
|
|
182
|
+
default="1048576",
|
|
183
|
+
),
|
|
184
|
+
ParameterSpec(
|
|
185
|
+
name="request_timeout_seconds",
|
|
186
|
+
kind="string",
|
|
187
|
+
prompt="Timeout de chat.postMessage en secondes",
|
|
188
|
+
default="5.0",
|
|
189
|
+
),
|
|
190
|
+
),
|
|
191
|
+
dependency_extra="channel",
|
|
192
|
+
entity_scoped=False,
|
|
193
|
+
),
|
|
194
|
+
),
|
|
195
|
+
)
|
|
196
|
+
|
|
197
|
+
__all__ = ["CHANNEL_CAPABILITY"]
|
|
@@ -6,6 +6,15 @@ from arclith_cli.capability_models import (
|
|
|
6
6
|
ParameterSpec,
|
|
7
7
|
SecretMappingSpec,
|
|
8
8
|
)
|
|
9
|
+
from arclith_cli.catalogs.repository_facets import (
|
|
10
|
+
DUCKDB_FACETS,
|
|
11
|
+
MARIADB_FACETS,
|
|
12
|
+
MEMORY_FACETS,
|
|
13
|
+
MONGODB_FACETS,
|
|
14
|
+
)
|
|
15
|
+
from arclith_cli.catalogs.repository_postgresql import (
|
|
16
|
+
POSTGRESQL_REPOSITORY_ADAPTER,
|
|
17
|
+
)
|
|
9
18
|
|
|
10
19
|
REPOSITORY_CAPABILITY = CapabilitySpec(
|
|
11
20
|
name="repository",
|
|
@@ -18,6 +27,7 @@ REPOSITORY_CAPABILITY = CapabilitySpec(
|
|
|
18
27
|
capability="repository",
|
|
19
28
|
layer="outbound",
|
|
20
29
|
description="Stockage volatile en mémoire pour dev, tests et smoke locaux.",
|
|
30
|
+
facets=MEMORY_FACETS,
|
|
21
31
|
),
|
|
22
32
|
AdapterSpec(
|
|
23
33
|
name="mongodb",
|
|
@@ -57,6 +67,7 @@ multitenant: {multitenant} # true = uri/db_name résolus par requête via JWT
|
|
|
57
67
|
default=False,
|
|
58
68
|
),
|
|
59
69
|
),
|
|
70
|
+
facets=MONGODB_FACETS,
|
|
60
71
|
),
|
|
61
72
|
AdapterSpec(
|
|
62
73
|
name="duckdb",
|
|
@@ -76,6 +87,7 @@ path: {path}
|
|
|
76
87
|
default="data/",
|
|
77
88
|
),
|
|
78
89
|
),
|
|
90
|
+
facets=DUCKDB_FACETS,
|
|
79
91
|
),
|
|
80
92
|
AdapterSpec(
|
|
81
93
|
name="mariadb",
|
|
@@ -142,86 +154,9 @@ multitenant: false
|
|
|
142
154
|
default="",
|
|
143
155
|
),
|
|
144
156
|
),
|
|
157
|
+
facets=MARIADB_FACETS,
|
|
145
158
|
),
|
|
146
|
-
|
|
147
|
-
name="postgresql",
|
|
148
|
-
capability="repository",
|
|
149
|
-
layer="outbound",
|
|
150
|
-
description="Repository PostgreSQL async optionnel, pilote par SQLAlchemy et asyncpg, avec payload JSONB generique.",
|
|
151
|
-
config_path="config/adapters/outbound/postgresql.yaml",
|
|
152
|
-
config_template="""\
|
|
153
|
-
url: null # à mapper via config/secrets.yaml ou resolver env/vault si vous fournissez une URL complète
|
|
154
|
-
host: {host}
|
|
155
|
-
port: {port}
|
|
156
|
-
database: {database}
|
|
157
|
-
user: {user}
|
|
158
|
-
password: null # à mapper via config/secrets.yaml ou resolver env/vault
|
|
159
|
-
schema: {schema}
|
|
160
|
-
driver: {driver}
|
|
161
|
-
table_prefix: "{table_prefix}"
|
|
162
|
-
multitenant: {multitenant}
|
|
163
|
-
""",
|
|
164
|
-
secret_mappings=(
|
|
165
|
-
SecretMappingSpec(
|
|
166
|
-
field_path="adapters.postgresql.url",
|
|
167
|
-
secret_key="POSTGRESQL_URL",
|
|
168
|
-
),
|
|
169
|
-
SecretMappingSpec(
|
|
170
|
-
field_path="adapters.postgresql.password",
|
|
171
|
-
secret_key="POSTGRESQL_PASSWORD",
|
|
172
|
-
),
|
|
173
|
-
),
|
|
174
|
-
parameters=(
|
|
175
|
-
ParameterSpec(
|
|
176
|
-
name="host",
|
|
177
|
-
kind="string",
|
|
178
|
-
prompt="host",
|
|
179
|
-
default="127.0.0.1",
|
|
180
|
-
),
|
|
181
|
-
ParameterSpec(
|
|
182
|
-
name="port",
|
|
183
|
-
kind="string",
|
|
184
|
-
prompt="port",
|
|
185
|
-
default="5432",
|
|
186
|
-
),
|
|
187
|
-
ParameterSpec(
|
|
188
|
-
name="database",
|
|
189
|
-
kind="string",
|
|
190
|
-
prompt="database",
|
|
191
|
-
default_from_project_name=True,
|
|
192
|
-
),
|
|
193
|
-
ParameterSpec(
|
|
194
|
-
name="user",
|
|
195
|
-
kind="string",
|
|
196
|
-
prompt="user",
|
|
197
|
-
default="app",
|
|
198
|
-
),
|
|
199
|
-
ParameterSpec(
|
|
200
|
-
name="schema",
|
|
201
|
-
kind="string",
|
|
202
|
-
prompt="schema",
|
|
203
|
-
default="public",
|
|
204
|
-
),
|
|
205
|
-
ParameterSpec(
|
|
206
|
-
name="driver",
|
|
207
|
-
kind="string",
|
|
208
|
-
prompt="driver",
|
|
209
|
-
default="asyncpg",
|
|
210
|
-
),
|
|
211
|
-
ParameterSpec(
|
|
212
|
-
name="table_prefix",
|
|
213
|
-
kind="string",
|
|
214
|
-
prompt="table_prefix",
|
|
215
|
-
default="",
|
|
216
|
-
),
|
|
217
|
-
ParameterSpec(
|
|
218
|
-
name="multitenant",
|
|
219
|
-
kind="boolean",
|
|
220
|
-
prompt="multitenant",
|
|
221
|
-
default=False,
|
|
222
|
-
),
|
|
223
|
-
),
|
|
224
|
-
),
|
|
159
|
+
POSTGRESQL_REPOSITORY_ADAPTER,
|
|
225
160
|
),
|
|
226
161
|
)
|
|
227
162
|
|