klapcontext 0.2.0__tar.gz → 0.2.1__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.
Files changed (44) hide show
  1. {klapcontext-0.2.0/src/klapcontext.egg-info → klapcontext-0.2.1}/PKG-INFO +1 -1
  2. {klapcontext-0.2.0 → klapcontext-0.2.1}/src/klapcontext/__init__.py +1 -1
  3. {klapcontext-0.2.0 → klapcontext-0.2.1}/src/klapcontext/context_builder.py +1 -1
  4. {klapcontext-0.2.0 → klapcontext-0.2.1}/src/klapcontext/detector.py +23 -2
  5. {klapcontext-0.2.0 → klapcontext-0.2.1}/src/klapcontext/frameworks/laravel.py +4 -1
  6. {klapcontext-0.2.0 → klapcontext-0.2.1/src/klapcontext.egg-info}/PKG-INFO +1 -1
  7. {klapcontext-0.2.0 → klapcontext-0.2.1}/tests/test_klapcontext.py +16 -0
  8. {klapcontext-0.2.0 → klapcontext-0.2.1}/LICENSE +0 -0
  9. {klapcontext-0.2.0 → klapcontext-0.2.1}/README.md +0 -0
  10. {klapcontext-0.2.0 → klapcontext-0.2.1}/pyproject.toml +0 -0
  11. {klapcontext-0.2.0 → klapcontext-0.2.1}/setup.cfg +0 -0
  12. {klapcontext-0.2.0 → klapcontext-0.2.1}/src/klapcontext/agent/__init__.py +0 -0
  13. {klapcontext-0.2.0 → klapcontext-0.2.1}/src/klapcontext/agent/capabilities.py +0 -0
  14. {klapcontext-0.2.0 → klapcontext-0.2.1}/src/klapcontext/agent/compiler.py +0 -0
  15. {klapcontext-0.2.0 → klapcontext-0.2.1}/src/klapcontext/agent/impact.py +0 -0
  16. {klapcontext-0.2.0 → klapcontext-0.2.1}/src/klapcontext/agent/intents.py +0 -0
  17. {klapcontext-0.2.0 → klapcontext-0.2.1}/src/klapcontext/agent/models.py +0 -0
  18. {klapcontext-0.2.0 → klapcontext-0.2.1}/src/klapcontext/agent/planner.py +0 -0
  19. {klapcontext-0.2.0 → klapcontext-0.2.1}/src/klapcontext/agent/verification.py +0 -0
  20. {klapcontext-0.2.0 → klapcontext-0.2.1}/src/klapcontext/agent/workflows.py +0 -0
  21. {klapcontext-0.2.0 → klapcontext-0.2.1}/src/klapcontext/agent_context.py +0 -0
  22. {klapcontext-0.2.0 → klapcontext-0.2.1}/src/klapcontext/cli.py +0 -0
  23. {klapcontext-0.2.0 → klapcontext-0.2.1}/src/klapcontext/evidence.py +0 -0
  24. {klapcontext-0.2.0 → klapcontext-0.2.1}/src/klapcontext/frameworks/__init__.py +0 -0
  25. {klapcontext-0.2.0 → klapcontext-0.2.1}/src/klapcontext/frameworks/base.py +0 -0
  26. {klapcontext-0.2.0 → klapcontext-0.2.1}/src/klapcontext/frameworks/fastapi.py +0 -0
  27. {klapcontext-0.2.0 → klapcontext-0.2.1}/src/klapcontext/frameworks/generic_php.py +0 -0
  28. {klapcontext-0.2.0 → klapcontext-0.2.1}/src/klapcontext/frameworks/node.py +0 -0
  29. {klapcontext-0.2.0 → klapcontext-0.2.1}/src/klapcontext/git.py +0 -0
  30. {klapcontext-0.2.0 → klapcontext-0.2.1}/src/klapcontext/graphify.py +0 -0
  31. {klapcontext-0.2.0 → klapcontext-0.2.1}/src/klapcontext/portal.py +0 -0
  32. {klapcontext-0.2.0 → klapcontext-0.2.1}/src/klapcontext/providers/__init__.py +0 -0
  33. {klapcontext-0.2.0 → klapcontext-0.2.1}/src/klapcontext/providers/base.py +0 -0
  34. {klapcontext-0.2.0 → klapcontext-0.2.1}/src/klapcontext/providers/code_intelligence.py +0 -0
  35. {klapcontext-0.2.0 → klapcontext-0.2.1}/src/klapcontext/providers/graphify.py +0 -0
  36. {klapcontext-0.2.0 → klapcontext-0.2.1}/src/klapcontext/providers/javascript_intelligence.py +0 -0
  37. {klapcontext-0.2.0 → klapcontext-0.2.1}/src/klapcontext/providers/python_intelligence.py +0 -0
  38. {klapcontext-0.2.0 → klapcontext-0.2.1}/src/klapcontext/semantic.py +0 -0
  39. {klapcontext-0.2.0 → klapcontext-0.2.1}/src/klapcontext/system.py +0 -0
  40. {klapcontext-0.2.0 → klapcontext-0.2.1}/src/klapcontext.egg-info/SOURCES.txt +0 -0
  41. {klapcontext-0.2.0 → klapcontext-0.2.1}/src/klapcontext.egg-info/dependency_links.txt +0 -0
  42. {klapcontext-0.2.0 → klapcontext-0.2.1}/src/klapcontext.egg-info/entry_points.txt +0 -0
  43. {klapcontext-0.2.0 → klapcontext-0.2.1}/src/klapcontext.egg-info/requires.txt +0 -0
  44. {klapcontext-0.2.0 → klapcontext-0.2.1}/src/klapcontext.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: klapcontext
3
- Version: 0.2.0
3
+ Version: 0.2.1
4
4
  Summary: Make your repository understandable to humans and AI.
5
5
  Author: Willy Cordon
6
6
  License-Expression: Apache-2.0
@@ -1,3 +1,3 @@
1
1
  """KlapContext local engineering-context generator."""
2
2
 
3
- __version__ = "0.2.0"
3
+ __version__ = "0.2.1"
@@ -86,7 +86,7 @@ def _empty_raw() -> dict:
86
86
 
87
87
 
88
88
  def _semantic(root: Path, stack: dict) -> tuple[SemanticModel, dict]:
89
- if "Laravel" in stack["frameworks"]:
89
+ if "Laravel" in stack["frameworks"] or "Lumen" in stack["frameworks"]:
90
90
  model = LaravelAdapter().analyze(root)
91
91
  return model, model.metadata["raw"]
92
92
  if "FastAPI" in stack["frameworks"]:
@@ -8,16 +8,20 @@ from .evidence import Evidence
8
8
 
9
9
  def detect_project(root: Path) -> tuple[dict, list[Evidence]]:
10
10
  evidence: list[Evidence] = []
11
- stack = {"languages": [], "frameworks": [], "databases": [], "runtime": [], "infrastructure": []}
11
+ stack = {"languages": [], "frameworks": [], "databases": [], "runtime": [], "infrastructure": [], "package_managers": [], "project_type": "unknown"}
12
12
  def add(bucket: str, value: str, path: str, reason: str) -> None:
13
13
  if value not in stack[bucket]: stack[bucket].append(value)
14
14
  evidence.append(Evidence("file", path, reason, "CONFIRMED", 1.0))
15
15
  composer = root / "composer.json"
16
16
  if composer.exists():
17
17
  add("languages", "PHP", "composer.json", "Composer manifest detected")
18
+ stack["runtime"].append("PHP"); stack["package_managers"].append("composer")
18
19
  try: deps = {**json.loads(composer.read_text(encoding="utf-8")).get("require", {}), **json.loads(composer.read_text(encoding="utf-8")).get("require-dev", {})}
19
20
  except json.JSONDecodeError: deps = {}
20
21
  if "laravel/framework" in deps: add("frameworks", "Laravel", "composer.json", "laravel/framework dependency detected")
22
+ if "laravel/lumen-framework" in deps:
23
+ add("frameworks", "Lumen", "composer.json", "laravel/lumen-framework dependency detected")
24
+ stack["project_type"] = "backend-api"
21
25
  elif any(root.rglob("*.php")):
22
26
  # A standalone PHP repository has no Composer manifest to identify it,
23
27
  # but language analysis can still provide a useful generic model.
@@ -26,16 +30,33 @@ def detect_project(root: Path) -> tuple[dict, list[Evidence]]:
26
30
  package = root / "package.json"
27
31
  if package.exists():
28
32
  add("languages", "JavaScript", "package.json", "npm manifest detected")
33
+ stack["runtime"].append("Node.js"); stack["package_managers"].append("npm")
29
34
  try: deps = {**json.loads(package.read_text(encoding="utf-8")).get("dependencies", {}), **json.loads(package.read_text(encoding="utf-8")).get("devDependencies", {})}
30
35
  except json.JSONDecodeError: deps = {}
31
36
  for name, label in (("next", "Next.js"), ("vue", "Vue"), ("react", "React"), ("express", "Express"), ("@nestjs/core", "NestJS")):
32
37
  if name in deps: add("frameworks", label, "package.json", f"{name} dependency detected")
38
+ if any(root.rglob("*.ts")) or any(root.rglob("*.tsx")): add("languages", "TypeScript", "package.json", "TypeScript source detected")
33
39
  if (root / "pyproject.toml").exists() or (root / "requirements.txt").exists():
34
40
  python_manifest = root / "pyproject.toml" if (root / "pyproject.toml").exists() else root / "requirements.txt"
35
41
  add("languages", "Python", python_manifest.name, "Python manifest detected")
42
+ stack["runtime"].append("Python"); stack["package_managers"].append("pip")
36
43
  if "fastapi" in python_manifest.read_text(encoding="utf-8", errors="ignore").casefold(): add("frameworks", "FastAPI", python_manifest.name, "FastAPI dependency detected")
37
44
  if (root / "manage.py").exists(): add("frameworks", "Django", "manage.py", "Django entry point detected")
38
- if list(root.glob("*.csproj")): add("languages", "C#", next(root.glob("*.csproj")).name, ".NET project detected")
45
+ if list(root.glob("*.csproj")):
46
+ add("languages", "C#", next(root.glob("*.csproj")).name, ".NET project detected"); stack["runtime"].append(".NET"); stack["package_managers"].append("NuGet")
47
+ if (root / "Program.cs").exists(): add("frameworks", ".NET Web API", "Program.cs", "ASP.NET entry point detected")
48
+ if (root / "go.mod").exists():
49
+ add("languages", "Go", "go.mod", "Go module detected"); stack["runtime"].append("Go"); stack["package_managers"].append("go modules")
50
+ if (root / "Cargo.toml").exists():
51
+ add("languages", "Rust", "Cargo.toml", "Rust manifest detected"); stack["runtime"].append("Rust"); stack["package_managers"].append("cargo")
52
+ if (root / "pom.xml").exists() or (root / "build.gradle").exists() or (root / "build.gradle.kts").exists():
53
+ manifest = "pom.xml" if (root / "pom.xml").exists() else "build.gradle" if (root / "build.gradle").exists() else "build.gradle.kts"
54
+ add("languages", "Java", manifest, "Java build manifest detected"); stack["runtime"].append("JVM"); stack["package_managers"].append("maven" if manifest == "pom.xml" else "gradle")
55
+ # Keep generic analysis useful for small repositories without a manifest.
56
+ for suffix, language in (("*.py", "Python"), ("*.js", "JavaScript"), ("*.ts", "TypeScript"), ("*.java", "Java"), ("*.go", "Go"), ("*.rs", "Rust")):
57
+ if language not in stack["languages"] and any(root.rglob(suffix)):
58
+ first = next(root.rglob(suffix)); add("languages", language, first.relative_to(root).as_posix(), f"{language} source file detected")
59
+ if any(name in stack["frameworks"] for name in ("Laravel", "Lumen", "FastAPI", "Express", "NestJS", ".NET Web API")): stack["project_type"] = "backend-api"
39
60
  if (root / "Dockerfile").exists(): add("infrastructure", "Docker", "Dockerfile", "Dockerfile detected")
40
61
  if list(root.glob("docker-compose*")) or list(root.glob("compose*")): add("infrastructure", "Docker Compose", "docker-compose", "Compose configuration detected")
41
62
  if (root / ".github" / "workflows").exists(): add("infrastructure", "GitHub Actions", ".github/workflows", "GitHub Actions workflows detected")
@@ -61,7 +61,7 @@ def _routes(root: Path) -> tuple[list[dict], list[dict]]:
61
61
  directory = root / "routes"
62
62
  if not directory.is_dir():
63
63
  return routes, scheduled
64
- route_pattern = re.compile(r"Route::(get|post|put|patch|delete|options|any)\s*\(\s*['\"]([^'\"]+)['\"]\s*,\s*(.+?)\);", re.S | re.I)
64
+ route_pattern = re.compile(r"(?:Route|\$app|\$router)(?:::|->)(get|post|put|patch|delete|options|any)\s*\(\s*['\"]([^'\"]+)['\"]\s*,\s*(.+?)\);", re.S | re.I)
65
65
  resource_pattern = re.compile(r"Route::(?:api)?resource\s*\(\s*['\"]([^'\"]+)['\"]\s*,\s*([A-Za-z_]\w*(?:\\[A-Za-z_]\w*)*)::class", re.I)
66
66
  schedule_pattern = re.compile(r"Schedule::(?:command|job)\s*\(\s*['\"]([^'\"]+)['\"]\s*\).*?->([A-Za-z]\w*)\s*\(", re.S)
67
67
  for file in directory.glob("*.php"):
@@ -69,6 +69,9 @@ def _routes(root: Path) -> tuple[list[dict], list[dict]]:
69
69
  for match in route_pattern.finditer(text):
70
70
  method, uri, target = match.groups()
71
71
  handler = _symbol(target)
72
+ if not handler:
73
+ callback = re.search(r"['\"]([A-Za-z_]\w*)@([A-Za-z_]\w*)['\"]", target)
74
+ handler = f"{callback.group(1)}::{callback.group(2)}" if callback else None
72
75
  name = f"{method.upper()} /{uri.lstrip('/')}"
73
76
  routes.append({"type": "http", "method": method.upper(), "uri": "/" + uri.lstrip("/"), "name": name, "path": str(file.relative_to(root)), "source": str(file.relative_to(root)), "line": text.count("\n", 0, match.start()) + 1, "target": handler, "handler": handler, "middleware": [], "status": "CONFIRMED", "evidence": _e(root, file, match.start(), "Declaración de ruta Laravel", symbol=name)})
74
77
  for match in resource_pattern.finditer(text):
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: klapcontext
3
- Version: 0.2.0
3
+ Version: 0.2.1
4
4
  Summary: Make your repository understandable to humans and AI.
5
5
  Author: Willy Cordon
6
6
  License-Expression: Apache-2.0
@@ -37,6 +37,22 @@ def test_detector_collects_confirmed_evidence(tmp_path):
37
37
  assert all(item.status == "CONFIRMED" for item in evidence)
38
38
 
39
39
 
40
+ def test_detector_identifies_manifest_and_source_languages(tmp_path):
41
+ (tmp_path / "go.mod").write_text("module example")
42
+ (tmp_path / "src").mkdir(); (tmp_path / "src" / "main.ts").write_text("export {}")
43
+ stack, _ = detect_project(tmp_path)
44
+ assert {"Go", "TypeScript"} <= set(stack["languages"])
45
+ assert "go modules" in stack["package_managers"]
46
+
47
+
48
+ def test_lumen_detection_and_route_adapter():
49
+ root = Path(__file__).parent / "fixtures" / "lumen_semantic"
50
+ stack, _ = detect_project(root)
51
+ assert "Lumen" in stack["frameworks"]
52
+ context = build(root, {"nodes": []})
53
+ assert context["system_model"]["routes"][0]["name"] == "POST /api/v1/call-vtex"
54
+
55
+
40
56
  def test_portal_has_dashboard_and_real_views(tmp_path):
41
57
  context = build(fixture_repo(tmp_path), {"nodes": [{"name": "UserController", "path": "app/Http/UserController.php", "type": "controller"}]})
42
58
  page = render_portal(context, render_agent(context), ["graph.html"])
File without changes
File without changes
File without changes
File without changes