adl-toolkit 0.0.0-stage → 0.1.1

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 (104) hide show
  1. package/INSTALL_TOOLKIT.md +163 -0
  2. package/README.md +269 -2
  3. package/adl_drift/__init__.py +6 -0
  4. package/adl_drift/cli/__init__.py +1 -0
  5. package/adl_drift/cli/commands.py +993 -0
  6. package/adl_drift/cli/main.py +744 -0
  7. package/adl_drift/cortex/__init__.py +1 -0
  8. package/adl_drift/cortex/embeddings.py +96 -0
  9. package/adl_drift/cortex/memory.py +1749 -0
  10. package/adl_drift/cortex/patterns.py +89 -0
  11. package/adl_drift/cortex/telemetry.py +192 -0
  12. package/adl_drift/detectors/__init__.py +1 -0
  13. package/adl_drift/detectors/async_patterns.py +115 -0
  14. package/adl_drift/detectors/base.py +121 -0
  15. package/adl_drift/detectors/config.py +122 -0
  16. package/adl_drift/detectors/data_access.py +128 -0
  17. package/adl_drift/detectors/decorators.py +122 -0
  18. package/adl_drift/detectors/dynamic_patterns.py +260 -0
  19. package/adl_drift/detectors/errors.py +134 -0
  20. package/adl_drift/detectors/imports.py +132 -0
  21. package/adl_drift/detectors/logging_patterns.py +108 -0
  22. package/adl_drift/detectors/routes.py +257 -0
  23. package/adl_drift/detectors/security.py +236 -0
  24. package/adl_drift/detectors/taint.py +406 -0
  25. package/adl_drift/detectors/tests.py +95 -0
  26. package/adl_drift/detectors/type_conventions.py +81 -0
  27. package/adl_drift/graph/__init__.py +1 -0
  28. package/adl_drift/graph/builder.py +2670 -0
  29. package/adl_drift/graph/cfg.py +461 -0
  30. package/adl_drift/graph/cluster.py +40 -0
  31. package/adl_drift/graph/edges.py +86 -0
  32. package/adl_drift/graph/node.py +90 -0
  33. package/adl_drift/harness/__init__.py +10 -0
  34. package/adl_drift/harness/setup.py +832 -0
  35. package/adl_drift/harness/skills/drift-antigravity.md +19 -0
  36. package/adl_drift/harness/skills/drift-generic.md +19 -0
  37. package/adl_drift/harness/skills/drift.md +25 -0
  38. package/adl_drift/harness/watch.py +84 -0
  39. package/adl_drift/lang/__init__.py +8 -0
  40. package/adl_drift/lang/base.py +464 -0
  41. package/adl_drift/lang/java/__init__.py +6 -0
  42. package/adl_drift/lang/java/backend.py +97 -0
  43. package/adl_drift/lang/java/cfg.py +1424 -0
  44. package/adl_drift/lang/java/config.py +707 -0
  45. package/adl_drift/lang/java/detectors/__init__.py +29 -0
  46. package/adl_drift/lang/java/detectors/additional.py +445 -0
  47. package/adl_drift/lang/java/detectors/base.py +154 -0
  48. package/adl_drift/lang/java/detectors/data_access.py +148 -0
  49. package/adl_drift/lang/java/detectors/imports.py +53 -0
  50. package/adl_drift/lang/java/detectors/routes.py +159 -0
  51. package/adl_drift/lang/java/detectors/security.py +386 -0
  52. package/adl_drift/lang/java/detectors/tests.py +74 -0
  53. package/adl_drift/lang/java/extractor.py +582 -0
  54. package/adl_drift/lang/java/ids.py +99 -0
  55. package/adl_drift/lang/java/parser.py +49 -0
  56. package/adl_drift/lang/java/resolution/__init__.py +1 -0
  57. package/adl_drift/lang/java/resolution/constants.py +1619 -0
  58. package/adl_drift/lang/java/resolution/constructors.py +278 -0
  59. package/adl_drift/lang/java/resolution/context.py +305 -0
  60. package/adl_drift/lang/java/resolution/dispatch.py +540 -0
  61. package/adl_drift/lang/java/resolution/functional.py +1318 -0
  62. package/adl_drift/lang/java/resolution/generated.py +95 -0
  63. package/adl_drift/lang/java/resolution/model.py +153 -0
  64. package/adl_drift/lang/java/resolution/orchestration.py +866 -0
  65. package/adl_drift/lang/java/resolution/overloads.py +1275 -0
  66. package/adl_drift/lang/java/resolution/scopes.py +1111 -0
  67. package/adl_drift/lang/java/resolution/types.py +2947 -0
  68. package/adl_drift/lang/java/resolver.py +1401 -0
  69. package/adl_drift/lang/java/scopes.py +69 -0
  70. package/adl_drift/lang/java/taint.py +500 -0
  71. package/adl_drift/lang/java/type_provenance.py +342 -0
  72. package/adl_drift/lang/python/__init__.py +8 -0
  73. package/adl_drift/lang/python/backend.py +94 -0
  74. package/adl_drift/lang/python/cfg.py +537 -0
  75. package/adl_drift/lang/python/extractor.py +454 -0
  76. package/adl_drift/lang/python/parser.py +41 -0
  77. package/adl_drift/lang/python/resolver.py +1789 -0
  78. package/adl_drift/lang/python/taint.py +365 -0
  79. package/adl_drift/lang/registry.py +117 -0
  80. package/adl_drift/parser/__init__.py +1 -0
  81. package/adl_drift/parser/cache.py +38 -0
  82. package/adl_drift/parser/core.py +33 -0
  83. package/adl_drift/parser/extractor.py +17 -0
  84. package/adl_drift/parser/literal_eval.py +326 -0
  85. package/adl_drift/scanner/__init__.py +1 -0
  86. package/adl_drift/scanner/discovery.py +338 -0
  87. package/adl_drift/scanner/incremental.py +261 -0
  88. package/adl_drift/scanner/parallel.py +224 -0
  89. package/adl_drift/server/__init__.py +1 -0
  90. package/adl_drift/server/handlers.py +2849 -0
  91. package/adl_drift/server/mcp_server.py +127 -0
  92. package/adl_drift/server/mcp_stdio.py +335 -0
  93. package/adl_drift/server/protocol.py +71 -0
  94. package/adl_drift/server/static/index.html +696 -0
  95. package/adl_drift/server/web.py +350 -0
  96. package/adl_drift/utils/__init__.py +1 -0
  97. package/adl_drift/utils/config.py +77 -0
  98. package/adl_drift/utils/fswalk.py +52 -0
  99. package/adl_drift/utils/types.py +345 -0
  100. package/bin/adl-drift.mjs +35 -0
  101. package/bin/adl-toolkit.mjs +488 -0
  102. package/package.json +29 -4
  103. package/pyproject.toml +49 -0
  104. package/scripts/install_toolkit.py +3584 -0
@@ -0,0 +1,95 @@
1
+ """Test framework detector — pytest + unittest."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from pathlib import Path
6
+ from typing import List
7
+
8
+ from tree_sitter import Node, Tree
9
+
10
+ from adl_drift.detectors.base import BaseDetector
11
+ from adl_drift.utils.types import Pattern, PatternCategory
12
+
13
+
14
+ class TestDetector(BaseDetector):
15
+ """Flags test functions, fixtures, and unittest.TestCase classes."""
16
+
17
+ @property
18
+ def category(self) -> PatternCategory:
19
+ return PatternCategory.TESTS
20
+
21
+ def detect(self, tree: Tree, source_bytes: bytes, file_path: Path) -> List[Pattern]:
22
+ patterns: List[Pattern] = []
23
+ in_test_file = self._is_test_file(file_path)
24
+
25
+ for node in self._walk(tree.root_node):
26
+ if node.type == "function_definition":
27
+ name = self._name(node, source_bytes)
28
+ if not name:
29
+ continue
30
+ decorators = self._decorators(node, source_bytes)
31
+
32
+ if any("fixture" in d for d in decorators):
33
+ patterns.append(self._make_pattern(
34
+ name="pytest_fixture",
35
+ description=f"pytest fixture: {name}",
36
+ node=node, file_path=file_path, confidence=0.95,
37
+ metadata={"framework": "pytest", "function": name},
38
+ ))
39
+ elif name.startswith("test_") and in_test_file:
40
+ patterns.append(self._make_pattern(
41
+ name="pytest_test",
42
+ description=f"pytest test function: {name}",
43
+ node=node, file_path=file_path, confidence=0.9,
44
+ metadata={"framework": "pytest", "function": name},
45
+ ))
46
+ elif node.type == "class_definition":
47
+ bases = self._superclass_text(node, source_bytes)
48
+ if any("TestCase" in b for b in bases):
49
+ name = self._name(node, source_bytes) or "<anon>"
50
+ patterns.append(self._make_pattern(
51
+ name="unittest_testcase",
52
+ description=f"unittest.TestCase class: {name}",
53
+ node=node, file_path=file_path, confidence=0.95,
54
+ metadata={"framework": "unittest", "class": name,
55
+ "bases": bases},
56
+ ))
57
+ return patterns
58
+
59
+ def _name(self, node: Node, source: bytes):
60
+ nn = node.child_by_field_name("name")
61
+ return self.parser.node_text(nn, source) if nn else None
62
+
63
+ def _decorators(self, node: Node, source: bytes) -> List[str]:
64
+ out: List[str] = []
65
+ sib = node.prev_sibling
66
+ while sib and sib.type == "decorator":
67
+ out.append(self.parser.node_text(sib, source).strip())
68
+ sib = sib.prev_sibling
69
+ if node.parent and node.parent.type == "decorated_definition":
70
+ for c in node.parent.children:
71
+ if c.type == "decorator":
72
+ txt = self.parser.node_text(c, source).strip()
73
+ if txt not in out:
74
+ out.append(txt)
75
+ return out
76
+
77
+ def _superclass_text(self, node: Node, source: bytes) -> List[str]:
78
+ sc = node.child_by_field_name("superclasses")
79
+ if not sc:
80
+ return []
81
+ out: List[str] = []
82
+ for c in sc.children:
83
+ if c.type in ("identifier", "attribute"):
84
+ out.append(self.parser.node_text(c, source).strip())
85
+ return out
86
+
87
+ @staticmethod
88
+ def _is_test_file(file_path: Path) -> bool:
89
+ n = file_path.name
90
+ return n.startswith("test_") or n.endswith("_test.py") or "tests" in file_path.parts
91
+
92
+ def _walk(self, node: Node):
93
+ yield node
94
+ for child in node.children:
95
+ yield from self._walk(child)
@@ -0,0 +1,81 @@
1
+ """Type-annotation coverage detector.
2
+
3
+ Per-file pattern: ratio of annotated params/returns. One Pattern per scanned
4
+ file with coverage % in metadata. Depends on P1.3 (Symbol.param_types /
5
+ return_type populated).
6
+ """
7
+
8
+ from __future__ import annotations
9
+
10
+ from pathlib import Path
11
+ from typing import List
12
+
13
+ from tree_sitter import Node, Tree
14
+
15
+ from adl_drift.detectors.base import BaseDetector
16
+ from adl_drift.utils.types import Pattern, PatternCategory
17
+
18
+
19
+ class TypeConventionDetector(BaseDetector):
20
+ """Computes type-annotation coverage for a file."""
21
+
22
+ @property
23
+ def category(self) -> PatternCategory:
24
+ return PatternCategory.TYPES
25
+
26
+ def detect(self, tree: Tree, source_bytes: bytes, file_path: Path) -> List[Pattern]:
27
+ total_params = 0
28
+ typed_params = 0
29
+ total_funcs = 0
30
+ typed_returns = 0
31
+
32
+ for node in self._walk(tree.root_node):
33
+ if node.type != "function_definition":
34
+ continue
35
+ total_funcs += 1
36
+ params_node = node.child_by_field_name("parameters")
37
+ if params_node is not None:
38
+ for child in params_node.children:
39
+ ct = child.type
40
+ if ct == "identifier":
41
+ text = self.parser.node_text(child, source_bytes)
42
+ if text in ("self", "cls"):
43
+ continue
44
+ total_params += 1
45
+ elif ct == "default_parameter":
46
+ total_params += 1
47
+ elif ct in ("typed_parameter", "typed_default_parameter"):
48
+ total_params += 1
49
+ typed_params += 1
50
+ if node.child_by_field_name("return_type") is not None:
51
+ typed_returns += 1
52
+
53
+ if total_funcs == 0:
54
+ return []
55
+
56
+ param_cov = typed_params / total_params if total_params else 1.0
57
+ return_cov = typed_returns / total_funcs
58
+
59
+ return [self._make_pattern(
60
+ name="type_coverage",
61
+ description=(
62
+ f"type coverage — params {typed_params}/{total_params} "
63
+ f"({param_cov:.0%}), returns {typed_returns}/{total_funcs} "
64
+ f"({return_cov:.0%})"
65
+ ),
66
+ node=tree.root_node, file_path=file_path,
67
+ confidence=0.95,
68
+ metadata={
69
+ "total_params": total_params,
70
+ "typed_params": typed_params,
71
+ "param_coverage": round(param_cov, 3),
72
+ "total_functions": total_funcs,
73
+ "typed_returns": typed_returns,
74
+ "return_coverage": round(return_cov, 3),
75
+ },
76
+ )]
77
+
78
+ def _walk(self, node: Node):
79
+ yield node
80
+ for child in node.children:
81
+ yield from self._walk(child)
@@ -0,0 +1 @@
1
+ """Call graph and dependency analysis."""