cloudwright-ai-cli 0.1.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.
- cloudwright_ai_cli-0.1.0.dist-info/METADATA +42 -0
- cloudwright_ai_cli-0.1.0.dist-info/RECORD +28 -0
- cloudwright_ai_cli-0.1.0.dist-info/WHEEL +4 -0
- cloudwright_ai_cli-0.1.0.dist-info/entry_points.txt +2 -0
- cloudwright_cli/__init__.py +1 -0
- cloudwright_cli/__main__.py +5 -0
- cloudwright_cli/commands/__init__.py +0 -0
- cloudwright_cli/commands/analyze_cmd.py +117 -0
- cloudwright_cli/commands/catalog_cmd.py +148 -0
- cloudwright_cli/commands/chat.py +164 -0
- cloudwright_cli/commands/compare.py +75 -0
- cloudwright_cli/commands/cost.py +112 -0
- cloudwright_cli/commands/design.py +84 -0
- cloudwright_cli/commands/diff.py +88 -0
- cloudwright_cli/commands/drift_cmd.py +98 -0
- cloudwright_cli/commands/export.py +65 -0
- cloudwright_cli/commands/import_cmd.py +69 -0
- cloudwright_cli/commands/init_cmd.py +135 -0
- cloudwright_cli/commands/lint_cmd.py +91 -0
- cloudwright_cli/commands/modify_cmd.py +125 -0
- cloudwright_cli/commands/policy.py +88 -0
- cloudwright_cli/commands/refresh_cmd.py +104 -0
- cloudwright_cli/commands/score_cmd.py +80 -0
- cloudwright_cli/commands/validate.py +106 -0
- cloudwright_cli/main.py +66 -0
- cloudwright_cli/project.py +50 -0
- cloudwright_cli/py.typed +0 -0
- cloudwright_cli/utils.py +37 -0
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
"""Project directory support — finds and loads .cloudwright/ configuration."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from pathlib import Path
|
|
6
|
+
from typing import Any
|
|
7
|
+
|
|
8
|
+
import yaml
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def find_project_root(start: Path | None = None) -> Path | None:
|
|
12
|
+
"""Walk up from start (default: cwd) looking for .cloudwright/ directory."""
|
|
13
|
+
current = (start or Path.cwd()).resolve()
|
|
14
|
+
for parent in [current, *current.parents]:
|
|
15
|
+
if (parent / ".cloudwright").is_dir():
|
|
16
|
+
return parent
|
|
17
|
+
return None
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def load_project_config(project_root: Path) -> dict[str, Any]:
|
|
21
|
+
"""Load .cloudwright/config.yaml if it exists."""
|
|
22
|
+
config_path = project_root / ".cloudwright" / "config.yaml"
|
|
23
|
+
if config_path.exists():
|
|
24
|
+
return yaml.safe_load(config_path.read_text()) or {}
|
|
25
|
+
return {}
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def get_project_spec_path(project_root: Path) -> Path | None:
|
|
29
|
+
"""Return the path to .cloudwright/spec.yaml if it exists."""
|
|
30
|
+
spec_path = project_root / ".cloudwright" / "spec.yaml"
|
|
31
|
+
if spec_path.exists():
|
|
32
|
+
return spec_path
|
|
33
|
+
return None
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
def resolve_spec_path(spec_file: str | None) -> Path:
|
|
37
|
+
"""Resolve a spec file path — if None, try project directory."""
|
|
38
|
+
if spec_file:
|
|
39
|
+
return Path(spec_file)
|
|
40
|
+
|
|
41
|
+
root = find_project_root()
|
|
42
|
+
if root:
|
|
43
|
+
spec_path = get_project_spec_path(root)
|
|
44
|
+
if spec_path:
|
|
45
|
+
return spec_path
|
|
46
|
+
|
|
47
|
+
raise FileNotFoundError(
|
|
48
|
+
"No spec file specified and no .cloudwright/spec.yaml found. "
|
|
49
|
+
"Pass a spec file or run 'cloudwright init --project' to create a project."
|
|
50
|
+
)
|
cloudwright_cli/py.typed
ADDED
|
File without changes
|
cloudwright_cli/utils.py
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import json
|
|
4
|
+
|
|
5
|
+
import typer
|
|
6
|
+
from rich.console import Console
|
|
7
|
+
|
|
8
|
+
_err_console = Console(stderr=True)
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def handle_error(ctx: typer.Context, e: Exception) -> None:
|
|
12
|
+
"""Print a clean error message and exit 1."""
|
|
13
|
+
import yaml
|
|
14
|
+
|
|
15
|
+
verbose = ctx.obj.get("verbose", False) if ctx.obj else False
|
|
16
|
+
json_mode = ctx.obj.get("json", False) if ctx.obj else False
|
|
17
|
+
|
|
18
|
+
if isinstance(e, FileNotFoundError):
|
|
19
|
+
msg = f"File not found: {e}"
|
|
20
|
+
elif isinstance(e, yaml.YAMLError):
|
|
21
|
+
msg = f"Invalid YAML: {e}"
|
|
22
|
+
elif "validation" in type(e).__name__.lower():
|
|
23
|
+
msg = f"Invalid spec: {e}"
|
|
24
|
+
elif isinstance(e, ValueError):
|
|
25
|
+
msg = str(e)
|
|
26
|
+
else:
|
|
27
|
+
msg = f"Error: {e}"
|
|
28
|
+
|
|
29
|
+
if json_mode:
|
|
30
|
+
print(json.dumps({"error": msg}))
|
|
31
|
+
else:
|
|
32
|
+
_err_console.print(f"[red]Error:[/red] {msg}")
|
|
33
|
+
|
|
34
|
+
if verbose:
|
|
35
|
+
_err_console.print_exception()
|
|
36
|
+
|
|
37
|
+
raise typer.Exit(1)
|