codeguardian-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.
Files changed (50) hide show
  1. CODEGUARDIAN/__init__.py +0 -0
  2. CODEGUARDIAN/analyzers/__init__.py +0 -0
  3. CODEGUARDIAN/analyzers/circular_dependency_analyzer.py +101 -0
  4. CODEGUARDIAN/analyzers/db_access_analyzer.py +55 -0
  5. CODEGUARDIAN/analyzers/dependency_analyzer.py +259 -0
  6. CODEGUARDIAN/analyzers/file_analyzer.py +96 -0
  7. CODEGUARDIAN/analyzers/function_analyzer.py +199 -0
  8. CODEGUARDIAN/analyzers/source_code_analyzer.py +169 -0
  9. CODEGUARDIAN/cli/__init__.py +0 -0
  10. CODEGUARDIAN/cli/commands.py +619 -0
  11. CODEGUARDIAN/config/__init__.py +0 -0
  12. CODEGUARDIAN/config/config_loader.py +76 -0
  13. CODEGUARDIAN/config/settings.py +2 -0
  14. CODEGUARDIAN/main.py +4 -0
  15. CODEGUARDIAN/reports/__init__.py +0 -0
  16. CODEGUARDIAN/reports/architecture_score.py +68 -0
  17. CODEGUARDIAN/reports/console_reporter.py +487 -0
  18. CODEGUARDIAN/reports/html_reporter.py +293 -0
  19. CODEGUARDIAN/reports/json_reporter.py +69 -0
  20. CODEGUARDIAN/reports/markdown_reporter.py +130 -0
  21. CODEGUARDIAN/reports/severity.py +15 -0
  22. CODEGUARDIAN/reports/statistics_reporter.py +183 -0
  23. CODEGUARDIAN/rules/__init__.py +0 -0
  24. CODEGUARDIAN/rules/architecture_rules.py +5 -0
  25. CODEGUARDIAN/rules/architecture_validator.py +69 -0
  26. CODEGUARDIAN/rules/controllers/user_controller.py +16 -0
  27. CODEGUARDIAN/src/__init__.py +0 -0
  28. CODEGUARDIAN/src/discovery/__init__.py +0 -0
  29. CODEGUARDIAN/src/discovery/finder.py +39 -0
  30. CODEGUARDIAN/src/extractor/__init__.py +0 -0
  31. CODEGUARDIAN/src/extractor/class_extractor.py +32 -0
  32. CODEGUARDIAN/src/extractor/function_extractor.py +17 -0
  33. CODEGUARDIAN/src/extractor/import_extractor.py +23 -0
  34. CODEGUARDIAN/src/extractor/python_class_extractor.py +13 -0
  35. CODEGUARDIAN/src/extractor/python_function_extractor.py +16 -0
  36. CODEGUARDIAN/src/extractor/python_imports_extractor.py +24 -0
  37. CODEGUARDIAN/src/main.py +65 -0
  38. CODEGUARDIAN/src/parser/__init__.py +0 -0
  39. CODEGUARDIAN/src/parser/ts_parser.py +14 -0
  40. CODEGUARDIAN/src/tree/Walker.py +10 -0
  41. CODEGUARDIAN/src/tree/__init__.py +0 -0
  42. CODEGUARDIAN/utils/__init__.py +0 -0
  43. CODEGUARDIAN/utils/ast_cache.py +47 -0
  44. CODEGUARDIAN/utils/file_cache.py +30 -0
  45. CODEGUARDIAN/utils/layer_utils.py +19 -0
  46. codeguardian_cli-1.0.0.dist-info/METADATA +43 -0
  47. codeguardian_cli-1.0.0.dist-info/RECORD +50 -0
  48. codeguardian_cli-1.0.0.dist-info/WHEEL +5 -0
  49. codeguardian_cli-1.0.0.dist-info/entry_points.txt +2 -0
  50. codeguardian_cli-1.0.0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,69 @@
1
+ from CODEGUARDIAN.config.config_loader import (
2
+ ConfigLoader
3
+ )
4
+
5
+ from CODEGUARDIAN.utils.layer_utils import get_layer
6
+
7
+
8
+ class ArchitectureViolation:
9
+
10
+ def __init__(
11
+ self,
12
+ source_file,
13
+ source_layer,
14
+ target_layer
15
+ ):
16
+
17
+ self.source_file = source_file
18
+ self.source_layer = source_layer
19
+ self.target_layer = target_layer
20
+
21
+
22
+ class ArchitectureValidator:
23
+
24
+ def __init__(self):
25
+
26
+ config = ConfigLoader.load()
27
+
28
+ self.forbidden_dependencies = {
29
+
30
+ tuple(rule)
31
+
32
+ for rule in config[
33
+ "forbidden_dependencies"
34
+ ]
35
+ }
36
+
37
+
38
+
39
+ def validate(
40
+ self,
41
+ dependencies
42
+ ):
43
+
44
+ violations = []
45
+
46
+ for dep in dependencies:
47
+
48
+ source_layer = get_layer(
49
+ dep.source_file
50
+ )
51
+
52
+ target_layer = get_layer(
53
+ dep.target_module
54
+ )
55
+
56
+ if (
57
+ source_layer,
58
+ target_layer
59
+ ) in self.forbidden_dependencies:
60
+
61
+ violations.append(
62
+ ArchitectureViolation(
63
+ dep.source_file,
64
+ source_layer,
65
+ target_layer
66
+ )
67
+ )
68
+
69
+ return violations
@@ -0,0 +1,16 @@
1
+ from repositories.user_repository import UserRepository
2
+
3
+
4
+
5
+
6
+
7
+
8
+
9
+
10
+ class UserController:
11
+
12
+ def __init__(self):
13
+ self.repository = UserRepository()
14
+
15
+ def get_user(self):
16
+ return self.repository.get_user()
File without changes
File without changes
@@ -0,0 +1,39 @@
1
+ from pathlib import Path
2
+
3
+ IGNORE_DIRS = {
4
+ "venv",
5
+ ".venv",
6
+ ".git",
7
+ "__pycache__",
8
+ ".pytest_cache",
9
+ "node_modules",
10
+ "dist",
11
+ "build",
12
+ "tests",
13
+
14
+ }
15
+
16
+
17
+ def discover_files(project_path, extensions) -> list[Path]:
18
+
19
+
20
+
21
+ project_path = Path(project_path)
22
+
23
+ files = []
24
+
25
+ for file in project_path.rglob("*"):
26
+
27
+ if any(part in IGNORE_DIRS for part in file.parts):
28
+ continue
29
+
30
+ if file.name.startswith("test_"):
31
+ continue
32
+
33
+ if file.is_file() and file.suffix in extensions:
34
+ files.append(file)
35
+
36
+ return files
37
+
38
+
39
+
File without changes
@@ -0,0 +1,32 @@
1
+ from tree_sitter import Node
2
+
3
+ from CODEGUARDIAN.src.tree.Walker import walk
4
+
5
+
6
+
7
+ class ClassExtractor:
8
+ def __init__(self):
9
+ self.classes = []
10
+
11
+ def visit(self,node):
12
+ if node.type =="class_declaration":
13
+ name_node =node.child_by_field_name("name")
14
+
15
+ if name_node:
16
+ self.classes.append(name_node.text.decode("utf8"))
17
+
18
+
19
+
20
+
21
+ """
22
+ def extract_classes(node: Node, classes: list[str]) -> None:
23
+
24
+
25
+
26
+ if node.type == "class_declaration":
27
+ name_node = node.child_by_field_name("name")
28
+
29
+ if name_node:
30
+ classes.append(name_node.text.decode("utf8"))
31
+ """
32
+
@@ -0,0 +1,17 @@
1
+ from tree_sitter import Node
2
+
3
+ from CODEGUARDIAN.src.tree.Walker import walk
4
+
5
+
6
+ class functionExtractor:
7
+ def __init__(self):
8
+ self.function =[]
9
+
10
+ def visit(self,node):
11
+ if node.type =="function_declaration":
12
+ name_node =node.child_by_field_name("name")
13
+
14
+ if name_node:
15
+ self.function.append(name_node.text.decode("utf8"))
16
+
17
+
@@ -0,0 +1,23 @@
1
+ from tree_sitter import Node
2
+ from CODEGUARDIAN.src.tree.Walker import walk
3
+
4
+
5
+ class importExtractor:
6
+ def __init__(self):
7
+ self.imports =[]
8
+
9
+ def visit(self, node):
10
+
11
+ if node.type != "import_statement":
12
+ return
13
+
14
+ for child in node.children:
15
+
16
+ if child.type == "string":
17
+
18
+ self.imports.append(
19
+ child.text.decode("utf8").strip('"')
20
+ )
21
+
22
+
23
+
@@ -0,0 +1,13 @@
1
+ import ast
2
+
3
+
4
+ class PythonClassExtractor:
5
+
6
+ def __init__(self):
7
+
8
+ self.classes = []
9
+
10
+ def extract( self,tree):
11
+ for node in ast.walk(tree):
12
+ if isinstance(node,ast.ClassDef):
13
+ self.classes.append(node.name)
@@ -0,0 +1,16 @@
1
+ import ast
2
+
3
+
4
+ class PythonFunctionExtractor:
5
+
6
+ def __init__(self):
7
+
8
+ self.functions = []
9
+
10
+ def extract( self,tree):
11
+
12
+ for node in ast.walk(tree):
13
+
14
+ if isinstance(node,ast.FunctionDef):
15
+
16
+ self.functions.append( node.name)
@@ -0,0 +1,24 @@
1
+ import ast
2
+
3
+
4
+ class PythonImportExtractor:
5
+
6
+ def __init__(self):
7
+
8
+ self.imports = []
9
+
10
+ def extract(self,tree):
11
+
12
+ for node in ast.walk(tree):
13
+
14
+ if isinstance(node,ast.Import):
15
+
16
+ for alias in node.names:
17
+
18
+ self.imports.append(alias.name)
19
+
20
+ elif isinstance(node,ast.ImportFrom):
21
+
22
+ if node.module:
23
+
24
+ self.imports.append(node.module)
@@ -0,0 +1,65 @@
1
+ from pathlib import Path
2
+
3
+ from CODEGUARDIAN.src.parser.ts_parser import parse_typescript
4
+
5
+ from CODEGUARDIAN.src.discovery.finder import discover_files
6
+
7
+ from CODEGUARDIAN.src.extractor.class_extractor import ClassExtractor
8
+
9
+ from CODEGUARDIAN.src.extractor.import_extractor import importExtractor
10
+
11
+ from CODEGUARDIAN.src.extractor.function_extractor import functionExtractor
12
+ from CODEGUARDIAN.src.tree.Walker import walk
13
+
14
+
15
+
16
+ project = Path("")
17
+
18
+
19
+ files = discover_files(
20
+ project,
21
+ {".ts", ".js",}
22
+ )
23
+
24
+ print("Discovered files:")
25
+
26
+ for file in files:
27
+ print(file)
28
+ source = file.read_text(encoding="utf8")
29
+
30
+ tree = parse_typescript(source)
31
+
32
+
33
+
34
+ extractor = ClassExtractor()
35
+
36
+ walk(tree.root_node, extractor.visit)
37
+
38
+ print(extractor.classes)
39
+
40
+
41
+ extractor = functionExtractor()
42
+
43
+ walk(tree.root_node, extractor.visit)
44
+
45
+ print(extractor.function)
46
+
47
+ extractor = importExtractor()
48
+
49
+ walk(tree.root_node, extractor.visit)
50
+ print(extractor.imports)
51
+
52
+
53
+
54
+
55
+
56
+ """classes = []
57
+ extract_classes(tree.root_node, classes)
58
+
59
+ print("\nClasses Found:")
60
+
61
+ for class_name in classes:
62
+ print(f"- {class_name}")
63
+ """
64
+
65
+
File without changes
@@ -0,0 +1,14 @@
1
+ from tree_sitter import Language, Parser
2
+ from tree_sitter_typescript import language_typescript
3
+
4
+
5
+ def parse_typescript(source_code: str):
6
+ parser = Parser()
7
+
8
+ language = Language(language_typescript())
9
+
10
+ parser.language = language
11
+
12
+ tree = parser.parse(bytes(source_code, "utf8"))
13
+
14
+ return tree
@@ -0,0 +1,10 @@
1
+ from tree_sitter import Node
2
+
3
+
4
+
5
+ def walk(node , callbreak):
6
+ callbreak(node)
7
+
8
+
9
+ for child in node.children:
10
+ walk(child,callbreak)
File without changes
File without changes
@@ -0,0 +1,47 @@
1
+ import ast
2
+
3
+ from pathlib import Path
4
+
5
+ from CODEGUARDIAN.src.parser.ts_parser import parse_typescript
6
+
7
+
8
+ class ASTCache:
9
+
10
+ _cache = {}
11
+
12
+ @classmethod
13
+ def get_tree(
14
+ cls,
15
+ file_path,
16
+ source
17
+ ):
18
+
19
+ file_path = str(
20
+ Path(file_path).resolve()
21
+ )
22
+
23
+ cached_data = cls._cache.get(
24
+ file_path
25
+ )
26
+
27
+ if (
28
+ cached_data is not None
29
+ and cached_data["source"] == source
30
+ ):
31
+
32
+ return cached_data["tree"]
33
+
34
+ if file_path.endswith(".py"):
35
+
36
+ tree = ast.parse(source)
37
+
38
+ else:
39
+
40
+ tree = parse_typescript(source)
41
+
42
+ cls._cache[file_path] = {
43
+ "source": source,
44
+ "tree": tree
45
+ }
46
+
47
+ return tree
@@ -0,0 +1,30 @@
1
+ from pathlib import Path
2
+
3
+ from CODEGUARDIAN.src.discovery.finder import discover_files
4
+
5
+
6
+ class FileCache:
7
+
8
+ _cache = {}
9
+
10
+ @classmethod
11
+ def get_files(cls, project_path, extensions):
12
+
13
+ key = (
14
+ str(Path(project_path).resolve()),
15
+ tuple(sorted(extensions))
16
+ )
17
+
18
+ if key not in cls._cache:
19
+
20
+
21
+
22
+
23
+ cls._cache[key] = discover_files(
24
+ Path(project_path),
25
+ extensions
26
+ )
27
+
28
+
29
+
30
+ return cls._cache[key]
@@ -0,0 +1,19 @@
1
+ def get_layer(
2
+ module_name
3
+ ):
4
+
5
+ parts = module_name.split(".")
6
+
7
+ for part in parts:
8
+
9
+ if part in {
10
+
11
+ "controllers",
12
+ "services",
13
+ "repositories"
14
+
15
+ }:
16
+
17
+ return part
18
+
19
+ return None
@@ -0,0 +1,43 @@
1
+ Metadata-Version: 2.4
2
+ Name: codeguardian-cli
3
+ Version: 1.0.0
4
+ Summary: Architecture and code quality analyzer
5
+ Requires-Python: >=3.10
6
+ Description-Content-Type: text/markdown
7
+ Requires-Dist: rich
8
+ Requires-Dist: typer
9
+
10
+ ## Developer Note
11
+
12
+ While developing CodeGuardian itself, the pre-commit hook may block commits because the repository contains sample files with intentional architecture violations and circular dependencies.
13
+
14
+ To temporarily disable the hook:
15
+
16
+ ### Windows (PowerShell)
17
+
18
+ ```powershell
19
+ Rename-Item .git\hooks\pre-commit pre-commit.bak
20
+ ```
21
+
22
+ ### Linux/macOS
23
+
24
+ ```bash
25
+ mv .git/hooks/pre-commit .git/hooks/pre-commit.bak
26
+ ```
27
+
28
+ After committing, restore the hook:
29
+
30
+ ### Windows (PowerShell)
31
+
32
+ ```powershell
33
+ Rename-Item .git\hooks\pre-commit.bak pre-commit
34
+ ```
35
+
36
+
37
+
38
+ or reinstall it:
39
+
40
+ ```bash
41
+ python install_hook.py
42
+ ```
43
+
@@ -0,0 +1,50 @@
1
+ CODEGUARDIAN/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2
+ CODEGUARDIAN/main.py,sha256=wr-jlLMp2sb9q7L7Yk5nS5oQJO5syaG-rb7YTp4qKKc,79
3
+ CODEGUARDIAN/analyzers/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
4
+ CODEGUARDIAN/analyzers/circular_dependency_analyzer.py,sha256=zPYVW6rljEJ4EIhlPsXWZ3hrgfTzGW4QMRxwDEeKiLE,1961
5
+ CODEGUARDIAN/analyzers/db_access_analyzer.py,sha256=atn4XZt8zTKlOOQLQd6Uist72JipDUUBF8hwaadk1lk,935
6
+ CODEGUARDIAN/analyzers/dependency_analyzer.py,sha256=LCWOyXxWy4A0YLCRZI9RoRrDEFuAlWk3wjZGJUjvQao,5307
7
+ CODEGUARDIAN/analyzers/file_analyzer.py,sha256=Ui4kNcYB3TQ_kZhaz_4qNFqsOQJwW5eMiDgkoCxGtSo,1765
8
+ CODEGUARDIAN/analyzers/function_analyzer.py,sha256=xswjsPxBDnQFj6ObXkHlP-avLpb8tn226MG1tICj8Sw,3702
9
+ CODEGUARDIAN/analyzers/source_code_analyzer.py,sha256=RFfGLXUCjwDXL-ZpA54pteEyXt7wH2XiZ01CIQT7fxs,3519
10
+ CODEGUARDIAN/cli/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
11
+ CODEGUARDIAN/cli/commands.py,sha256=yluS6NrSpQBgcGLqh33rQ1vq23X_MnIADqe3ZIgh_1s,12398
12
+ CODEGUARDIAN/config/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
13
+ CODEGUARDIAN/config/config_loader.py,sha256=0CiM_t2Lz4bDWtuiN94GSjOLjAQ7liO_qZTqJP-HbB0,1368
14
+ CODEGUARDIAN/config/settings.py,sha256=C74NzVbZCW9-iDx9GD2kHd9Es4nxUmvnJDhl4kDtJEI,44
15
+ CODEGUARDIAN/reports/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
16
+ CODEGUARDIAN/reports/architecture_score.py,sha256=ExfHjKWiNyQt5Vo6W5q3pQdojAMnQxJoqI6AlxKCf7Y,1362
17
+ CODEGUARDIAN/reports/console_reporter.py,sha256=688Y4IQdy3Xz_14hWQaGlNAXJZ-m_I3mvE8rJWK3eTY,10543
18
+ CODEGUARDIAN/reports/html_reporter.py,sha256=PvyoXGRKh-X4meLD3zuSdaG6lnIq2_xOPQY4ko2uNU4,4825
19
+ CODEGUARDIAN/reports/json_reporter.py,sha256=u1GS5boc4Esl6qR_nFwtHnWgdXnbnancfWevOpUAUS0,1435
20
+ CODEGUARDIAN/reports/markdown_reporter.py,sha256=wYre14mcVDv6j6S_HFm9agmTpsNvcyhDbFdQeG2gWlE,3149
21
+ CODEGUARDIAN/reports/severity.py,sha256=3SLkg782ImYfDa3SQ7p31v_s-Vby3JHRwB9rvVMUvdc,237
22
+ CODEGUARDIAN/reports/statistics_reporter.py,sha256=i6koszOWRFYxQIjWS54StLtJgBQ8j0qP_PgVKaj2H2A,3773
23
+ CODEGUARDIAN/rules/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
24
+ CODEGUARDIAN/rules/architecture_rules.py,sha256=QyzXlXBFMkUJKX2SAVzE75faZWRJ7RQ5r7ZqCklw70k,116
25
+ CODEGUARDIAN/rules/architecture_validator.py,sha256=fcxW2BuzTPlJ3UbGOZnodJI5QpLSXriXkCWXI_KS034,1314
26
+ CODEGUARDIAN/rules/controllers/user_controller.py,sha256=To6ZzyBi5cV7AZBD8DjG-u7oAkHdhc81pnaU4n7NPPI,220
27
+ CODEGUARDIAN/src/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
28
+ CODEGUARDIAN/src/main.py,sha256=8Es65AMa5M27CpwNMt5dGZahoNND2P7CJLyiWnYqoz0,1130
29
+ CODEGUARDIAN/src/discovery/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
30
+ CODEGUARDIAN/src/discovery/finder.py,sha256=_RMNm-9nmHOTkq7D1TUafkVmJ8KUgDHhO5NDkulx_LM,619
31
+ CODEGUARDIAN/src/extractor/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
32
+ CODEGUARDIAN/src/extractor/class_extractor.py,sha256=PkI9d4i0J_ZFl8_DphL4q1WR_ohSbQ3VLBILhjJmvGA,628
33
+ CODEGUARDIAN/src/extractor/function_extractor.py,sha256=T34m0zvHW1XQ2c_eBI98VjuTSH6DkQqBJGlUvvSPEX4,381
34
+ CODEGUARDIAN/src/extractor/import_extractor.py,sha256=0-YGjSHBOaU8EV7xqumjE3QF0XiySfatCnUB9n8dsnk,418
35
+ CODEGUARDIAN/src/extractor/python_class_extractor.py,sha256=2-Gt1uSkST8LQowjpC_LQMfHVX2QYZoPR261RzrEfl8,251
36
+ CODEGUARDIAN/src/extractor/python_function_extractor.py,sha256=b9-UVGDPqzp4fYOIl7Ce_os9FFN5etRZifF1rmzAwL4,265
37
+ CODEGUARDIAN/src/extractor/python_imports_extractor.py,sha256=IplPaD2-bbzerqxzfOY8Af8ao2cX0MXTLmlACQnGK-E,437
38
+ CODEGUARDIAN/src/parser/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
39
+ CODEGUARDIAN/src/parser/ts_parser.py,sha256=SYR75w6-WhNB3lE_hZM9r0X8cuOP-2HA0M3lasVkNes,309
40
+ CODEGUARDIAN/src/tree/Walker.py,sha256=vReF3xk40Wb4VuM1W_hLfZrUaIsLQwyTywPF98VkwCI,143
41
+ CODEGUARDIAN/src/tree/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
42
+ CODEGUARDIAN/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
43
+ CODEGUARDIAN/utils/ast_cache.py,sha256=XVbOWW_Iw-I3bge8mI923WfYCyEn9GZCyMWkYLe8_aI,777
44
+ CODEGUARDIAN/utils/file_cache.py,sha256=BCjiSAwZZYOq_pV57yWvrzBov8yPlkG_ZHsnSdaBZr8,510
45
+ CODEGUARDIAN/utils/layer_utils.py,sha256=QpUawYG8f5qjtIuXP0QBKEI_-W9kgHX9F2X_AvzrehM,248
46
+ codeguardian_cli-1.0.0.dist-info/METADATA,sha256=z5REWcSWKYkmSgEC3_SWzf4x8CXqXQ9ATBoMM-P7DN8,819
47
+ codeguardian_cli-1.0.0.dist-info/WHEEL,sha256=K260EYznzXsJYBQGqmI8VTxEdiZYNvDZwW9cBh9-_MA,91
48
+ codeguardian_cli-1.0.0.dist-info/entry_points.txt,sha256=I4OdLGA4ilsjlUDtu9NrmkswYu8vIjIpMaLL8koX11g,55
49
+ codeguardian_cli-1.0.0.dist-info/top_level.txt,sha256=FCCh2epuHzvBi_N-MJr-PFIPrWydRx1kRSDBVAdYbOw,13
50
+ codeguardian_cli-1.0.0.dist-info/RECORD,,
@@ -0,0 +1,5 @@
1
+ Wheel-Version: 1.0
2
+ Generator: setuptools (83.0.0)
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
5
+
@@ -0,0 +1,2 @@
1
+ [console_scripts]
2
+ codeguardian = CODEGUARDIAN.main:app
@@ -0,0 +1 @@
1
+ CODEGUARDIAN