aidp-cli 1.0.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.
aidp_cli/manifest.py ADDED
@@ -0,0 +1,229 @@
1
+ # Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved.
2
+
3
+ from __future__ import annotations
4
+
5
+ import json
6
+ from dataclasses import dataclass
7
+ from importlib import resources
8
+ from typing import Any
9
+
10
+
11
+ MANIFEST_FILENAME = "operation_manifest.json"
12
+
13
+
14
+ @dataclass(frozen=True)
15
+ class CommandField:
16
+ name: str
17
+ cli_name: str
18
+ original_name: str
19
+ location: str
20
+ required: bool
21
+ description: str = ""
22
+ type_name: str = ""
23
+ model_name: str = ""
24
+ enum_values: tuple[Any, ...] = ()
25
+
26
+
27
+ @dataclass(frozen=True)
28
+ class BodyField:
29
+ name: str
30
+ required: bool
31
+ type_name: str = ""
32
+ item_type: str = ""
33
+ model_name: str = ""
34
+ enum_values: tuple[Any, ...] = ()
35
+
36
+
37
+ @dataclass(frozen=True)
38
+ class BodyVariant:
39
+ discriminator_field: str
40
+ discriminator_value: Any
41
+ model_name: str
42
+
43
+
44
+ @dataclass(frozen=True)
45
+ class BodyModel:
46
+ name: str
47
+ fields: tuple[BodyField, ...]
48
+ required_fields: tuple[str, ...]
49
+ enum_fields: dict[str, tuple[Any, ...]]
50
+ variants: tuple[BodyVariant, ...] = ()
51
+
52
+
53
+ @dataclass(frozen=True)
54
+ class CommandDefinition:
55
+ name: str
56
+ sdk_method_name: str
57
+ operation_id: str
58
+ http_method: str
59
+ path: str
60
+ section: str
61
+ summary: str
62
+ description: str
63
+ deprecated: bool
64
+ fields: tuple[CommandField, ...]
65
+ body_field: CommandField | None
66
+ body_model: str
67
+ body_fields: tuple[BodyField, ...]
68
+ body_required_fields: tuple[str, ...]
69
+ body_enum_fields: dict[str, tuple[Any, ...]]
70
+ body_models: dict[str, BodyModel]
71
+
72
+
73
+ @dataclass(frozen=True)
74
+ class CommandGroup:
75
+ name: str
76
+ tag: str
77
+ client_class_name: str
78
+ description: str
79
+ commands: tuple[CommandDefinition, ...]
80
+
81
+
82
+ @dataclass(frozen=True)
83
+ class CommandManifest:
84
+ version: int
85
+ source_spec: str
86
+ source_spec_sha256: str
87
+ command_groups: tuple[CommandGroup, ...]
88
+
89
+
90
+ def load_command_manifest() -> CommandManifest:
91
+ try:
92
+ content = resources.files(__package__).joinpath(MANIFEST_FILENAME).read_text(encoding="utf-8")
93
+ except FileNotFoundError as exc:
94
+ raise RuntimeError(
95
+ "AIDP command manifest is missing. Regenerate the CLI package before running aidp."
96
+ ) from exc
97
+ try:
98
+ raw = json.loads(content)
99
+ if not isinstance(raw, dict):
100
+ raise TypeError("manifest root must be a JSON object")
101
+ if not isinstance(raw.get("commandGroups"), list):
102
+ raise TypeError("manifest commandGroups must be a list")
103
+ return manifest_from_dict(raw)
104
+ except (json.JSONDecodeError, KeyError, TypeError, ValueError) as exc:
105
+ raise RuntimeError(
106
+ "AIDP command manifest is invalid. Regenerate the CLI package before running aidp."
107
+ ) from exc
108
+
109
+
110
+ def manifest_from_dict(raw: dict[str, Any]) -> CommandManifest:
111
+ return CommandManifest(
112
+ version=int(raw.get("version", 0)),
113
+ source_spec=str(raw.get("sourceSpec", "")),
114
+ source_spec_sha256=str(raw.get("sourceSpecSha256", "")),
115
+ command_groups=tuple(group_from_dict(group) for group in raw.get("commandGroups", [])),
116
+ )
117
+
118
+
119
+ def group_from_dict(raw: dict[str, Any]) -> CommandGroup:
120
+ return CommandGroup(
121
+ name=str(raw["name"]),
122
+ tag=str(raw.get("tag", "")),
123
+ client_class_name=str(raw["clientClassName"]),
124
+ description=str(raw.get("description", "")),
125
+ commands=tuple(command_from_dict(command) for command in raw.get("commands", [])),
126
+ )
127
+
128
+
129
+ def command_from_dict(raw: dict[str, Any]) -> CommandDefinition:
130
+ fields = tuple(field_from_dict(field) for field in raw.get("fields", []))
131
+ body_field_name = raw.get("bodyField")
132
+ return CommandDefinition(
133
+ name=str(raw["name"]),
134
+ sdk_method_name=str(raw["sdkMethodName"]),
135
+ operation_id=str(raw.get("operationId", "")),
136
+ http_method=str(raw.get("httpMethod", "")),
137
+ path=str(raw.get("path", "")),
138
+ section=str(raw.get("section", "Available Commands")),
139
+ summary=str(raw.get("summary", "")),
140
+ description=str(raw.get("description", "")),
141
+ deprecated=bool(raw.get("deprecated", False)),
142
+ fields=fields,
143
+ body_field=next((field for field in fields if field.name == body_field_name), None),
144
+ body_model=str(raw.get("bodyModel", "")),
145
+ body_fields=tuple(body_field_from_dict(field) for field in raw.get("bodyFields", [])),
146
+ body_required_fields=tuple(str(field) for field in raw.get("bodyRequiredFields", [])),
147
+ body_enum_fields={
148
+ str(name): tuple(values)
149
+ for name, values in raw.get("bodyEnumFields", {}).items()
150
+ },
151
+ body_models={
152
+ str(name): body_model_from_dict(str(name), model)
153
+ for name, model in raw.get("bodyModels", {}).items()
154
+ },
155
+ )
156
+
157
+
158
+ def field_from_dict(raw: dict[str, Any]) -> CommandField:
159
+ return CommandField(
160
+ name=str(raw["name"]),
161
+ cli_name=str(raw["cliName"]),
162
+ original_name=str(raw.get("originalName", raw["name"])),
163
+ location=str(raw.get("in", "")),
164
+ required=bool(raw.get("required", False)),
165
+ description=str(raw.get("description", "")),
166
+ type_name=str(raw.get("type", "")),
167
+ model_name=str(raw.get("modelName", "")),
168
+ enum_values=tuple(raw.get("enumValues", [])),
169
+ )
170
+
171
+
172
+ def body_field_from_dict(raw: dict[str, Any]) -> BodyField:
173
+ return BodyField(
174
+ name=str(raw["name"]),
175
+ required=bool(raw.get("required", False)),
176
+ type_name=str(raw.get("type", "")),
177
+ item_type=str(raw.get("itemType", "")),
178
+ model_name=str(raw.get("modelName", "")),
179
+ enum_values=tuple(raw.get("enumValues", [])),
180
+ )
181
+
182
+
183
+ def body_model_from_dict(name: str, raw: dict[str, Any]) -> BodyModel:
184
+ return BodyModel(
185
+ name=name,
186
+ fields=tuple(body_field_from_dict(field) for field in raw.get("fields", [])),
187
+ required_fields=tuple(str(field) for field in raw.get("requiredFields", [])),
188
+ enum_fields={
189
+ str(field_name): tuple(values)
190
+ for field_name, values in raw.get("enumFields", {}).items()
191
+ },
192
+ variants=tuple(body_variant_from_dict(variant) for variant in raw.get("variants", [])),
193
+ )
194
+
195
+
196
+ def body_variant_from_dict(raw: dict[str, Any]) -> BodyVariant:
197
+ return BodyVariant(
198
+ discriminator_field=str(raw["discriminatorField"]),
199
+ discriminator_value=raw.get("discriminatorValue"),
200
+ model_name=str(raw["modelName"]),
201
+ )
202
+
203
+
204
+ def find_command_group(manifest: CommandManifest, name: str) -> CommandGroup | None:
205
+ normalized = normalize_lookup_name(name)
206
+ return next(
207
+ (
208
+ group
209
+ for group in manifest.command_groups
210
+ if normalize_lookup_name(group.name) == normalized
211
+ ),
212
+ None,
213
+ )
214
+
215
+
216
+ def find_command(group: CommandGroup, name: str) -> CommandDefinition | None:
217
+ normalized = normalize_lookup_name(name)
218
+ return next(
219
+ (
220
+ command
221
+ for command in group.commands
222
+ if normalize_lookup_name(command.name) == normalized
223
+ ),
224
+ None,
225
+ )
226
+
227
+
228
+ def normalize_lookup_name(value: str) -> str:
229
+ return value.replace("-", "").replace("_", "").lower()