tarang 4.4.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.
- tarang/__init__.py +23 -0
- tarang/cli.py +1168 -0
- tarang/client/__init__.py +19 -0
- tarang/client/api_client.py +701 -0
- tarang/client/auth.py +178 -0
- tarang/context/__init__.py +41 -0
- tarang/context/bm25.py +218 -0
- tarang/context/chunker.py +984 -0
- tarang/context/graph.py +464 -0
- tarang/context/indexer.py +514 -0
- tarang/context/retriever.py +270 -0
- tarang/context/skeleton.py +282 -0
- tarang/context_collector.py +449 -0
- tarang/executor/__init__.py +6 -0
- tarang/executor/diff_apply.py +246 -0
- tarang/executor/linter.py +184 -0
- tarang/stream.py +1346 -0
- tarang/ui/__init__.py +7 -0
- tarang/ui/console.py +407 -0
- tarang/ui/diff_viewer.py +146 -0
- tarang/ui/formatter.py +1151 -0
- tarang/ui/keyboard.py +197 -0
- tarang/ws/__init__.py +14 -0
- tarang/ws/client.py +464 -0
- tarang/ws/executor.py +638 -0
- tarang/ws/handlers.py +590 -0
- tarang-4.4.0.dist-info/METADATA +102 -0
- tarang-4.4.0.dist-info/RECORD +31 -0
- tarang-4.4.0.dist-info/WHEEL +5 -0
- tarang-4.4.0.dist-info/entry_points.txt +2 -0
- tarang-4.4.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Shadow Linter - Run linting after applying changes.
|
|
3
|
+
|
|
4
|
+
Auto-detects project type and runs appropriate linters.
|
|
5
|
+
"""
|
|
6
|
+
from __future__ import annotations
|
|
7
|
+
|
|
8
|
+
import shutil
|
|
9
|
+
import subprocess
|
|
10
|
+
from dataclasses import dataclass, field
|
|
11
|
+
from pathlib import Path
|
|
12
|
+
from typing import Dict, List, Optional
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
@dataclass
|
|
16
|
+
class LintResult:
|
|
17
|
+
"""Result of linting."""
|
|
18
|
+
success: bool
|
|
19
|
+
errors: List[str] = field(default_factory=list)
|
|
20
|
+
warnings: List[str] = field(default_factory=list)
|
|
21
|
+
tool: str = "none"
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
class ShadowLinter:
|
|
25
|
+
"""
|
|
26
|
+
Run linting in the background after applying changes.
|
|
27
|
+
|
|
28
|
+
Auto-detects project type and runs appropriate linter.
|
|
29
|
+
"""
|
|
30
|
+
|
|
31
|
+
LINTER_CONFIGS: Dict[str, Dict] = {
|
|
32
|
+
"python": {
|
|
33
|
+
"detect": ["pyproject.toml", "setup.py", "requirements.txt"],
|
|
34
|
+
"commands": [
|
|
35
|
+
["python", "-m", "py_compile", "{file}"], # Syntax check
|
|
36
|
+
["ruff", "check", "{file}"], # Fast linter
|
|
37
|
+
]
|
|
38
|
+
},
|
|
39
|
+
"javascript": {
|
|
40
|
+
"detect": ["package.json"],
|
|
41
|
+
"commands": [
|
|
42
|
+
["npx", "eslint", "{file}"],
|
|
43
|
+
]
|
|
44
|
+
},
|
|
45
|
+
"typescript": {
|
|
46
|
+
"detect": ["tsconfig.json"],
|
|
47
|
+
"commands": [
|
|
48
|
+
["npx", "tsc", "--noEmit"],
|
|
49
|
+
]
|
|
50
|
+
},
|
|
51
|
+
"rust": {
|
|
52
|
+
"detect": ["Cargo.toml"],
|
|
53
|
+
"commands": [
|
|
54
|
+
["cargo", "check"],
|
|
55
|
+
]
|
|
56
|
+
},
|
|
57
|
+
"go": {
|
|
58
|
+
"detect": ["go.mod"],
|
|
59
|
+
"commands": [
|
|
60
|
+
["go", "vet", "{file}"],
|
|
61
|
+
]
|
|
62
|
+
},
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
def __init__(self, project_root: Path):
|
|
66
|
+
self.project_root = project_root
|
|
67
|
+
self.project_type = self._detect_project_type()
|
|
68
|
+
|
|
69
|
+
def lint_file(self, file_path: str) -> LintResult:
|
|
70
|
+
"""
|
|
71
|
+
Run linters on a modified file.
|
|
72
|
+
|
|
73
|
+
Args:
|
|
74
|
+
file_path: Path to file (relative to project root)
|
|
75
|
+
|
|
76
|
+
Returns:
|
|
77
|
+
LintResult with errors/warnings
|
|
78
|
+
"""
|
|
79
|
+
if not self.project_type:
|
|
80
|
+
return LintResult(success=True, tool="none")
|
|
81
|
+
|
|
82
|
+
config = self.LINTER_CONFIGS.get(self.project_type, {})
|
|
83
|
+
commands = config.get("commands", [])
|
|
84
|
+
|
|
85
|
+
errors = []
|
|
86
|
+
warnings = []
|
|
87
|
+
|
|
88
|
+
for cmd_template in commands:
|
|
89
|
+
cmd = [
|
|
90
|
+
part.replace("{file}", file_path)
|
|
91
|
+
for part in cmd_template
|
|
92
|
+
]
|
|
93
|
+
|
|
94
|
+
# Check if command exists
|
|
95
|
+
if not shutil.which(cmd[0]):
|
|
96
|
+
continue
|
|
97
|
+
|
|
98
|
+
try:
|
|
99
|
+
result = subprocess.run(
|
|
100
|
+
cmd,
|
|
101
|
+
cwd=self.project_root,
|
|
102
|
+
capture_output=True,
|
|
103
|
+
timeout=60
|
|
104
|
+
)
|
|
105
|
+
|
|
106
|
+
if result.returncode != 0:
|
|
107
|
+
output = result.stderr.decode() or result.stdout.decode()
|
|
108
|
+
errors.append(f"{cmd[0]}: {output}")
|
|
109
|
+
|
|
110
|
+
except subprocess.TimeoutExpired:
|
|
111
|
+
warnings.append(f"{cmd[0]} timed out")
|
|
112
|
+
except FileNotFoundError:
|
|
113
|
+
continue
|
|
114
|
+
|
|
115
|
+
return LintResult(
|
|
116
|
+
success=len(errors) == 0,
|
|
117
|
+
errors=errors,
|
|
118
|
+
warnings=warnings,
|
|
119
|
+
tool=self.project_type,
|
|
120
|
+
)
|
|
121
|
+
|
|
122
|
+
def lint_build(self) -> LintResult:
|
|
123
|
+
"""
|
|
124
|
+
Run full project build/check.
|
|
125
|
+
|
|
126
|
+
Returns:
|
|
127
|
+
LintResult with build errors/warnings
|
|
128
|
+
"""
|
|
129
|
+
build_commands = {
|
|
130
|
+
"python": ["python", "-m", "py_compile"],
|
|
131
|
+
"javascript": ["npm", "run", "build"],
|
|
132
|
+
"typescript": ["npm", "run", "build"],
|
|
133
|
+
"rust": ["cargo", "build"],
|
|
134
|
+
"go": ["go", "build", "./..."],
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
if self.project_type not in build_commands:
|
|
138
|
+
return LintResult(success=True, tool="none")
|
|
139
|
+
|
|
140
|
+
cmd = build_commands[self.project_type]
|
|
141
|
+
|
|
142
|
+
# Check if command exists
|
|
143
|
+
if not shutil.which(cmd[0]):
|
|
144
|
+
return LintResult(success=True, tool="none")
|
|
145
|
+
|
|
146
|
+
try:
|
|
147
|
+
result = subprocess.run(
|
|
148
|
+
cmd,
|
|
149
|
+
cwd=self.project_root,
|
|
150
|
+
capture_output=True,
|
|
151
|
+
timeout=300
|
|
152
|
+
)
|
|
153
|
+
|
|
154
|
+
errors = []
|
|
155
|
+
if result.returncode != 0:
|
|
156
|
+
errors = [result.stderr.decode() or result.stdout.decode()]
|
|
157
|
+
|
|
158
|
+
return LintResult(
|
|
159
|
+
success=result.returncode == 0,
|
|
160
|
+
errors=errors,
|
|
161
|
+
warnings=[],
|
|
162
|
+
tool=cmd[0],
|
|
163
|
+
)
|
|
164
|
+
|
|
165
|
+
except subprocess.TimeoutExpired:
|
|
166
|
+
return LintResult(
|
|
167
|
+
success=False,
|
|
168
|
+
errors=["Build timed out"],
|
|
169
|
+
tool=cmd[0],
|
|
170
|
+
)
|
|
171
|
+
except Exception as e:
|
|
172
|
+
return LintResult(
|
|
173
|
+
success=False,
|
|
174
|
+
errors=[str(e)],
|
|
175
|
+
tool="build",
|
|
176
|
+
)
|
|
177
|
+
|
|
178
|
+
def _detect_project_type(self) -> Optional[str]:
|
|
179
|
+
"""Detect project type from marker files."""
|
|
180
|
+
for project_type, config in self.LINTER_CONFIGS.items():
|
|
181
|
+
for marker in config.get("detect", []):
|
|
182
|
+
if (self.project_root / marker).exists():
|
|
183
|
+
return project_type
|
|
184
|
+
return None
|