codedna 0.2.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.
- codedna/__init__.py +4 -0
- codedna/ai_fingerprint.py +223 -0
- codedna/analyzer.py +245 -0
- codedna/api.py +1505 -0
- codedna/auth.py +372 -0
- codedna/bus_factor.py +259 -0
- codedna/cli.py +1965 -0
- codedna/db.py +336 -0
- codedna/git_hook.py +212 -0
- codedna/integrations/__init__.py +1 -0
- codedna/integrations/github_bot.py +259 -0
- codedna/integrations/jira.py +166 -0
- codedna/integrations/lemonsqueezy.py +236 -0
- codedna/interview.py +298 -0
- codedna/onboarding.py +195 -0
- codedna/plan.py +184 -0
- codedna/protection.py +211 -0
- codedna/rate_limit.py +83 -0
- codedna/scorer.py +221 -0
- codedna/sprint_health.py +187 -0
- codedna/survey.py +104 -0
- codedna/tech_debt.py +232 -0
- codedna-0.2.0.dist-info/METADATA +93 -0
- codedna-0.2.0.dist-info/RECORD +26 -0
- codedna-0.2.0.dist-info/WHEEL +4 -0
- codedna-0.2.0.dist-info/entry_points.txt +2 -0
codedna/survey.py
ADDED
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
"""Commit anlama anketi modülü."""
|
|
2
|
+
|
|
3
|
+
from typing import Optional
|
|
4
|
+
|
|
5
|
+
from rich.console import Console
|
|
6
|
+
from rich.panel import Panel
|
|
7
|
+
from rich.prompt import IntPrompt
|
|
8
|
+
from rich.text import Text
|
|
9
|
+
|
|
10
|
+
console = Console()
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def _skor_al(soru: str, soru_no: int) -> Optional[int]:
|
|
14
|
+
"""
|
|
15
|
+
1-5 arasında geçerli bir skor al.
|
|
16
|
+
|
|
17
|
+
Dönüş değerleri:
|
|
18
|
+
- int (1-5) : kullanıcı bir skor girdi
|
|
19
|
+
- None : kullanıcı bilerek atladı (0 veya Enter)
|
|
20
|
+
veya stdin okunamadı (EOFError — ortam sorunu)
|
|
21
|
+
|
|
22
|
+
EOFError, KeyboardInterrupt ayrı yakalanır:
|
|
23
|
+
- KeyboardInterrupt → sessizce None (kullanıcı Ctrl+C'ye bastı)
|
|
24
|
+
- EOFError → uyarı yaz + None (stdin bağlı değil, ortam sorunu)
|
|
25
|
+
"""
|
|
26
|
+
try:
|
|
27
|
+
deger = IntPrompt.ask(
|
|
28
|
+
f" [bold cyan]{soru_no}.[/bold cyan] {soru} [dim]\\[1-5][/dim]",
|
|
29
|
+
default=0,
|
|
30
|
+
)
|
|
31
|
+
if deger == 0:
|
|
32
|
+
return None
|
|
33
|
+
return max(1, min(5, deger))
|
|
34
|
+
except KeyboardInterrupt:
|
|
35
|
+
# Kullanıcı bilerek iptal etti — sessiz
|
|
36
|
+
return None
|
|
37
|
+
except EOFError:
|
|
38
|
+
# stdin okunamadı — kullanıcının bilerek yaptığı bir seçim değil.
|
|
39
|
+
# Sessiz yutma yerine bilgilendirici bir uyarı göster.
|
|
40
|
+
console.print(
|
|
41
|
+
" [dim red]⚠ Anket için terminal girdisi okunamadı "
|
|
42
|
+
"(stdin bağlı değil). Anket atlanıyor.[/dim red]"
|
|
43
|
+
)
|
|
44
|
+
return None
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
def run_survey(commit_hash: str) -> Optional[float]:
|
|
48
|
+
"""
|
|
49
|
+
Post-commit hook sonrası 3 soruluk anlama anketi çalıştır.
|
|
50
|
+
|
|
51
|
+
Args:
|
|
52
|
+
commit_hash: Anketin bağlandığı commit hash'i
|
|
53
|
+
|
|
54
|
+
Returns:
|
|
55
|
+
Ortalama anlama skoru (1.0-5.0), kullanıcı atlarsa None
|
|
56
|
+
"""
|
|
57
|
+
console.print()
|
|
58
|
+
console.print(
|
|
59
|
+
Panel(
|
|
60
|
+
Text.from_markup(
|
|
61
|
+
f"[bold yellow]CodeDNA[/bold yellow] — Commit [dim]{commit_hash[:8]}[/dim] için hızlı anlama anketi\n"
|
|
62
|
+
"[dim]Enter ile atlayabilirsin (0 = atla)[/dim]"
|
|
63
|
+
),
|
|
64
|
+
border_style="yellow",
|
|
65
|
+
padding=(0, 2),
|
|
66
|
+
)
|
|
67
|
+
)
|
|
68
|
+
|
|
69
|
+
sorular = [
|
|
70
|
+
"Bu değişikliği 3 ay sonra açıklayabilir misin?",
|
|
71
|
+
"Bir hata çıksa debug edebilir misin?",
|
|
72
|
+
"Başkası sorsa, nasıl çalıştığını anlatabilir misin?",
|
|
73
|
+
]
|
|
74
|
+
|
|
75
|
+
skorlar: list[int] = []
|
|
76
|
+
for i, soru in enumerate(sorular, start=1):
|
|
77
|
+
skor = _skor_al(soru, i)
|
|
78
|
+
if skor is None:
|
|
79
|
+
# Bilerek atladı veya EOFError zaten uyarı yazdı
|
|
80
|
+
console.print(" [dim]Anket atlandı.[/dim]")
|
|
81
|
+
return None
|
|
82
|
+
skorlar.append(skor)
|
|
83
|
+
|
|
84
|
+
if not skorlar:
|
|
85
|
+
return None
|
|
86
|
+
|
|
87
|
+
ortalama = sum(skorlar) / len(skorlar)
|
|
88
|
+
|
|
89
|
+
# Skora göre renk ve mesaj
|
|
90
|
+
if ortalama >= 4.0:
|
|
91
|
+
renk = "green"
|
|
92
|
+
etiket = "Harika 💪"
|
|
93
|
+
elif ortalama >= 2.5:
|
|
94
|
+
renk = "yellow"
|
|
95
|
+
etiket = "Orta seviye 🤔"
|
|
96
|
+
else:
|
|
97
|
+
renk = "red"
|
|
98
|
+
etiket = "Risk var ⚠️"
|
|
99
|
+
|
|
100
|
+
console.print(
|
|
101
|
+
f"\n Anlama skoru: [bold {renk}]{ortalama:.1f}/5[/bold {renk}] — {etiket}\n"
|
|
102
|
+
)
|
|
103
|
+
|
|
104
|
+
return ortalama
|
codedna/tech_debt.py
ADDED
|
@@ -0,0 +1,232 @@
|
|
|
1
|
+
"""Teknik borcu parasal değere çevirir."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from dataclasses import dataclass
|
|
6
|
+
from pathlib import Path
|
|
7
|
+
from typing import Optional
|
|
8
|
+
|
|
9
|
+
from codedna.db import get_connection, get_file_scores_for_commit, get_commit_history
|
|
10
|
+
|
|
11
|
+
# Varsayılan saatlik maliyet (USD)
|
|
12
|
+
_VARSAYILAN_SAATLIK = 75.0
|
|
13
|
+
|
|
14
|
+
# Risk eşikleri (aylık maliyet)
|
|
15
|
+
_KRITIK_ESIK = 100.0 # $/ay üzeri → KRİTİK
|
|
16
|
+
_YUKSEK_ESIK = 50.0 # $/ay üzeri → YÜKSEK
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
@dataclass
|
|
20
|
+
class DosyaBorcu:
|
|
21
|
+
"""Tek dosyanın teknik borç analizi."""
|
|
22
|
+
|
|
23
|
+
dosya_yolu: str
|
|
24
|
+
debt_saatleri: float # tahmini borç saati
|
|
25
|
+
aylik_maliyet_usd: float # amortismana yayılmış aylık maliyet
|
|
26
|
+
risk_seviyesi: str # KRİTİK / YÜKSEK / ORTA / DÜŞÜK
|
|
27
|
+
toplam_satir: int
|
|
28
|
+
ai_olasiligi: float
|
|
29
|
+
karmasiklik: float
|
|
30
|
+
anlama_skoru: Optional[float]
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
@dataclass
|
|
34
|
+
class RepoBorcu:
|
|
35
|
+
"""Repo geneli teknik borç özeti."""
|
|
36
|
+
|
|
37
|
+
toplam_debt_saatleri: float
|
|
38
|
+
toplam_aylik_maliyet_usd: float
|
|
39
|
+
en_pahali_5: list[DosyaBorcu]
|
|
40
|
+
toplam_dosya: int
|
|
41
|
+
saatlik_ucret: float
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
def _risk_hesapla(aylik_maliyet: float) -> str:
|
|
45
|
+
"""Aylık maliyete göre risk seviyesi döndür."""
|
|
46
|
+
if aylik_maliyet >= _KRITIK_ESIK:
|
|
47
|
+
return "KRİTİK"
|
|
48
|
+
elif aylik_maliyet >= _YUKSEK_ESIK:
|
|
49
|
+
return "YÜKSEK"
|
|
50
|
+
elif aylik_maliyet >= 20.0:
|
|
51
|
+
return "ORTA"
|
|
52
|
+
return "DÜŞÜK"
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
def _debt_saati_hesapla(
|
|
56
|
+
anlama_skoru: Optional[float],
|
|
57
|
+
ai_olasiligi: float,
|
|
58
|
+
karmasiklik: float,
|
|
59
|
+
toplam_satir: int,
|
|
60
|
+
) -> float:
|
|
61
|
+
"""
|
|
62
|
+
Dosya için teknik borç saatini hesapla.
|
|
63
|
+
|
|
64
|
+
Formül:
|
|
65
|
+
debt_hours = (
|
|
66
|
+
(1 - understanding_score/5) * 0.4 ← düşük anlama
|
|
67
|
+
+ ai_probability * 0.35 ← AI kodu
|
|
68
|
+
+ min(complexity/20, 1.0) * 0.25 ← karmaşıklık
|
|
69
|
+
) * (lines_of_code / 100) * 2
|
|
70
|
+
|
|
71
|
+
Anlama skoru yoksa 2.5/5 varsayılır.
|
|
72
|
+
"""
|
|
73
|
+
anlama = anlama_skoru if anlama_skoru is not None else 2.5
|
|
74
|
+
anlama_faktor = (1.0 - anlama / 5.0) * 0.40
|
|
75
|
+
ai_faktor = ai_olasiligi * 0.35
|
|
76
|
+
karmasiklik_faktor = min(karmasiklik / 20.0, 1.0) * 0.25
|
|
77
|
+
|
|
78
|
+
satir_carpan = (toplam_satir / 100.0) * 2.0
|
|
79
|
+
|
|
80
|
+
return (anlama_faktor + ai_faktor + karmasiklik_faktor) * satir_carpan
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
def calculate_file_debt(
|
|
84
|
+
file_path: str,
|
|
85
|
+
db_path: Path,
|
|
86
|
+
hourly_rate: float = _VARSAYILAN_SAATLIK,
|
|
87
|
+
) -> Optional[DosyaBorcu]:
|
|
88
|
+
"""
|
|
89
|
+
Tek dosya için teknik borç saatini ve dolar maliyetini hesapla.
|
|
90
|
+
Önce DB'den arar, bulamazsa dosyayı doğrudan analiz eder.
|
|
91
|
+
|
|
92
|
+
Args:
|
|
93
|
+
file_path: Dosya yolu (tam veya göreli)
|
|
94
|
+
db_path: SQLite veritabanı yolu
|
|
95
|
+
hourly_rate: Saatlik maliyet ($/saat)
|
|
96
|
+
|
|
97
|
+
Returns:
|
|
98
|
+
DosyaBorcu nesnesi veya dosya bulunamazsa None
|
|
99
|
+
"""
|
|
100
|
+
# Önce DB'den en son skoru bul
|
|
101
|
+
satir = None
|
|
102
|
+
try:
|
|
103
|
+
with get_connection(db_path) as conn:
|
|
104
|
+
satir = conn.execute(
|
|
105
|
+
"""
|
|
106
|
+
SELECT fs.ai_probability, fs.complexity_score, fs.understanding_score
|
|
107
|
+
FROM file_scores fs
|
|
108
|
+
JOIN commits c ON fs.commit_hash = c.commit_hash
|
|
109
|
+
WHERE fs.file_path = ?
|
|
110
|
+
ORDER BY c.timestamp DESC
|
|
111
|
+
LIMIT 1
|
|
112
|
+
""",
|
|
113
|
+
(file_path,),
|
|
114
|
+
).fetchone()
|
|
115
|
+
except Exception:
|
|
116
|
+
pass
|
|
117
|
+
|
|
118
|
+
# DB'den gelen değerleri al veya dosyayı doğrudan analiz et
|
|
119
|
+
if satir:
|
|
120
|
+
ai = float(satir["ai_probability"] or 0.0)
|
|
121
|
+
karmasiklik = float(satir["complexity_score"] or 1.0)
|
|
122
|
+
anlama = float(satir["understanding_score"]) if satir["understanding_score"] is not None else None
|
|
123
|
+
else:
|
|
124
|
+
# DB'de yok — tree-sitter ile doğrudan analiz et
|
|
125
|
+
p = Path(file_path)
|
|
126
|
+
if not p.exists():
|
|
127
|
+
return None
|
|
128
|
+
try:
|
|
129
|
+
from codedna.analyzer import analyze_file
|
|
130
|
+
sonuc = analyze_file(p)
|
|
131
|
+
if sonuc.desteklenmiyor or sonuc.hata:
|
|
132
|
+
return None
|
|
133
|
+
ai = sonuc.ai_probability
|
|
134
|
+
karmasiklik = sonuc.complexity_score
|
|
135
|
+
anlama = None
|
|
136
|
+
except Exception:
|
|
137
|
+
return None
|
|
138
|
+
|
|
139
|
+
# Satır sayısı
|
|
140
|
+
toplam_satir = 100
|
|
141
|
+
try:
|
|
142
|
+
p = Path(file_path)
|
|
143
|
+
if p.exists():
|
|
144
|
+
toplam_satir = len(p.read_text(errors="replace").splitlines())
|
|
145
|
+
except Exception:
|
|
146
|
+
pass
|
|
147
|
+
|
|
148
|
+
debt_saati = _debt_saati_hesapla(anlama, ai, karmasiklik, toplam_satir)
|
|
149
|
+
aylik_maliyet = debt_saati * hourly_rate / 12.0
|
|
150
|
+
|
|
151
|
+
return DosyaBorcu(
|
|
152
|
+
dosya_yolu=file_path,
|
|
153
|
+
debt_saatleri=round(debt_saati, 2),
|
|
154
|
+
aylik_maliyet_usd=round(aylik_maliyet, 2),
|
|
155
|
+
risk_seviyesi=_risk_hesapla(aylik_maliyet),
|
|
156
|
+
toplam_satir=toplam_satir,
|
|
157
|
+
ai_olasiligi=round(ai, 3),
|
|
158
|
+
karmasiklik=round(karmasiklik, 1),
|
|
159
|
+
anlama_skoru=round(anlama, 2) if anlama is not None else None,
|
|
160
|
+
)
|
|
161
|
+
|
|
162
|
+
|
|
163
|
+
def calculate_repo_debt(
|
|
164
|
+
repo_path: Path,
|
|
165
|
+
db_path: Path,
|
|
166
|
+
hourly_rate: float = _VARSAYILAN_SAATLIK,
|
|
167
|
+
) -> RepoBorcu:
|
|
168
|
+
"""
|
|
169
|
+
Repo geneli toplam teknik borç özeti hesapla.
|
|
170
|
+
|
|
171
|
+
Args:
|
|
172
|
+
repo_path: Git repo kök dizini
|
|
173
|
+
db_path: SQLite veritabanı yolu
|
|
174
|
+
hourly_rate: Saatlik maliyet ($/saat)
|
|
175
|
+
|
|
176
|
+
Returns:
|
|
177
|
+
RepoBorcu özet nesnesi
|
|
178
|
+
"""
|
|
179
|
+
# Repo dosyalarını tara — scan_repository artık sadece git izlenen
|
|
180
|
+
# dosyaları döndürüyor (.gitignore'dakiler dahil değil).
|
|
181
|
+
# DB yollarını KAYNAK olarak kullanmıyoruz: eski kirli veriler
|
|
182
|
+
# (build çıktıları vb.) hesaba katılmasın.
|
|
183
|
+
from codedna.scorer import scan_repository
|
|
184
|
+
taranan = scan_repository(repo_path, max_files=200)
|
|
185
|
+
tarama_yollari = {s.file_path for s in taranan}
|
|
186
|
+
|
|
187
|
+
# DB'deki anlama skorlarını sadece zenginleştirme için kullan —
|
|
188
|
+
# dosya listesini BELIRLEMEK için değil
|
|
189
|
+
tum_yollar = list(tarama_yollari)
|
|
190
|
+
|
|
191
|
+
dosya_borclar: list[DosyaBorcu] = []
|
|
192
|
+
for yol in tum_yollar:
|
|
193
|
+
# DB'de varsa DB'den al, yoksa taranan sonuçtan hesapla
|
|
194
|
+
borc = calculate_file_debt(yol, db_path, hourly_rate)
|
|
195
|
+
if borc is None:
|
|
196
|
+
# Taranan sonuçtan bulup hesapla
|
|
197
|
+
taranan_sonuc = next((s for s in taranan if s.file_path == yol), None)
|
|
198
|
+
if taranan_sonuc:
|
|
199
|
+
debt_saati = _debt_saati_hesapla(
|
|
200
|
+
None,
|
|
201
|
+
taranan_sonuc.ai_probability,
|
|
202
|
+
taranan_sonuc.complexity_score,
|
|
203
|
+
taranan_sonuc.total_lines,
|
|
204
|
+
)
|
|
205
|
+
aylik = debt_saati * hourly_rate / 12.0
|
|
206
|
+
borc = DosyaBorcu(
|
|
207
|
+
dosya_yolu=yol,
|
|
208
|
+
debt_saatleri=round(debt_saati, 2),
|
|
209
|
+
aylik_maliyet_usd=round(aylik, 2),
|
|
210
|
+
risk_seviyesi=_risk_hesapla(aylik),
|
|
211
|
+
toplam_satir=taranan_sonuc.total_lines,
|
|
212
|
+
ai_olasiligi=round(taranan_sonuc.ai_probability, 3),
|
|
213
|
+
karmasiklik=round(taranan_sonuc.complexity_score, 1),
|
|
214
|
+
anlama_skoru=None,
|
|
215
|
+
)
|
|
216
|
+
if borc:
|
|
217
|
+
dosya_borclar.append(borc)
|
|
218
|
+
|
|
219
|
+
# En pahalı 5 dosya
|
|
220
|
+
dosya_borclar.sort(key=lambda d: d.aylik_maliyet_usd, reverse=True)
|
|
221
|
+
en_pahali = dosya_borclar[:5]
|
|
222
|
+
|
|
223
|
+
toplam_saat = sum(d.debt_saatleri for d in dosya_borclar)
|
|
224
|
+
toplam_aylik = sum(d.aylik_maliyet_usd for d in dosya_borclar)
|
|
225
|
+
|
|
226
|
+
return RepoBorcu(
|
|
227
|
+
toplam_debt_saatleri=round(toplam_saat, 2),
|
|
228
|
+
toplam_aylik_maliyet_usd=round(toplam_aylik, 2),
|
|
229
|
+
en_pahali_5=en_pahali,
|
|
230
|
+
toplam_dosya=len(dosya_borclar),
|
|
231
|
+
saatlik_ucret=hourly_rate,
|
|
232
|
+
)
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: codedna
|
|
3
|
+
Version: 0.2.0
|
|
4
|
+
Summary: AI kod şeffaflık aracı — her commit'te AI yazım oranını ve anlama skorunu ölçer
|
|
5
|
+
Project-URL: Homepage, https://codedna.dev
|
|
6
|
+
Project-URL: Repository, https://github.com/natureco-official/codedna
|
|
7
|
+
Project-URL: Issues, https://github.com/natureco-official/codedna/issues
|
|
8
|
+
Project-URL: Changelog, https://github.com/natureco-official/codedna/blob/main/CHANGELOG.md
|
|
9
|
+
Author-email: NatureCo <hello@natureco.me>
|
|
10
|
+
License: MIT
|
|
11
|
+
Keywords: ai,code-analysis,developer-tools,devops,git,transparency
|
|
12
|
+
Classifier: Development Status :: 4 - Beta
|
|
13
|
+
Classifier: Environment :: Console
|
|
14
|
+
Classifier: Intended Audience :: Developers
|
|
15
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
16
|
+
Classifier: Operating System :: OS Independent
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
20
|
+
Classifier: Topic :: Software Development :: Quality Assurance
|
|
21
|
+
Requires-Python: >=3.10
|
|
22
|
+
Requires-Dist: bcrypt>=5.0.0
|
|
23
|
+
Requires-Dist: fastapi>=0.138.0
|
|
24
|
+
Requires-Dist: gitpython>=3.1.50
|
|
25
|
+
Requires-Dist: pyjwt>=2.13.0
|
|
26
|
+
Requires-Dist: rich>=15.0.0
|
|
27
|
+
Requires-Dist: tree-sitter-javascript>=0.25.0
|
|
28
|
+
Requires-Dist: tree-sitter-python>=0.25.0
|
|
29
|
+
Requires-Dist: tree-sitter-typescript>=0.23.2
|
|
30
|
+
Requires-Dist: tree-sitter>=0.25.2
|
|
31
|
+
Requires-Dist: typer>=0.26.7
|
|
32
|
+
Requires-Dist: uvicorn[standard]>=0.49.0
|
|
33
|
+
Provides-Extra: dashboard
|
|
34
|
+
Requires-Dist: next-cmd>=0.5.0; extra == 'dashboard'
|
|
35
|
+
Provides-Extra: dev
|
|
36
|
+
Requires-Dist: black>=24.0.0; extra == 'dev'
|
|
37
|
+
Requires-Dist: pytest-cov>=4.0.0; extra == 'dev'
|
|
38
|
+
Requires-Dist: pytest>=8.0.0; extra == 'dev'
|
|
39
|
+
Requires-Dist: ruff>=0.1.0; extra == 'dev'
|
|
40
|
+
Description-Content-Type: text/markdown
|
|
41
|
+
|
|
42
|
+
# 🧬 CodeDNA — AI Kod Şeffaflık Aracı
|
|
43
|
+
|
|
44
|
+
Her commit'te hangi kodun AI tarafından yazıldığını tespit eden, geliştiricinin o kodu gerçekten anlayıp anlamadığını ölçen ve takım genelinde "anlama borcu" haritası çıkaran CLI aracı.
|
|
45
|
+
|
|
46
|
+
## Kurulum
|
|
47
|
+
|
|
48
|
+
```bash
|
|
49
|
+
# Geliştirme ortamı için
|
|
50
|
+
uv pip install -e .
|
|
51
|
+
|
|
52
|
+
# veya
|
|
53
|
+
pip install codedna
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
## Kullanım
|
|
57
|
+
|
|
58
|
+
```bash
|
|
59
|
+
# Git hook'u kur ve veritabanını oluştur
|
|
60
|
+
codedna init
|
|
61
|
+
|
|
62
|
+
# Tüm repoyu tara
|
|
63
|
+
codedna scan
|
|
64
|
+
|
|
65
|
+
# Son commit skorunu göster
|
|
66
|
+
codedna status
|
|
67
|
+
|
|
68
|
+
# Geçmiş commit skorlarını listele
|
|
69
|
+
codedna history
|
|
70
|
+
|
|
71
|
+
# Hook'u kaldır
|
|
72
|
+
codedna uninstall
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
## Nasıl Çalışır?
|
|
76
|
+
|
|
77
|
+
`codedna scan` komutu her desteklenen dosyayı (`*.py`, `*.js`, `*.ts`, `*.jsx`, `*.tsx`) analiz eder:
|
|
78
|
+
|
|
79
|
+
| Metrik | Açıklama |
|
|
80
|
+
|--------|----------|
|
|
81
|
+
| `comment_ratio > 0.3` | AI kodu genelde aşırı yorum yazar → +0.20 |
|
|
82
|
+
| `avg_function_length > 50` | AI büyük fonksiyon blokları üretir → +0.15 |
|
|
83
|
+
| `single_commit_ratio > 0.7` | Toplu yapıştırma işareti → +0.30 |
|
|
84
|
+
| Yüksek karmaşıklık + tek commit | AI imzası → +0.25 |
|
|
85
|
+
|
|
86
|
+
## Gereksinimler
|
|
87
|
+
|
|
88
|
+
- Python 3.10+
|
|
89
|
+
- Git kurulu olmalı
|
|
90
|
+
# test
|
|
91
|
+
# test2
|
|
92
|
+
# test4
|
|
93
|
+
# test5
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
codedna/__init__.py,sha256=vwyeFcp7eBgr9Uxbpe7bEYAiYijK6CojD8OWLUA3kxY,93
|
|
2
|
+
codedna/ai_fingerprint.py,sha256=xUiBF3jSjTqtu1xGAhbBbDx6PktQ7u_8KcSEz78fSSU,8107
|
|
3
|
+
codedna/analyzer.py,sha256=GgKd_2TCC1ZmroV6RApj8LPGAZsvrgqw9zYWdz3c0bI,7490
|
|
4
|
+
codedna/api.py,sha256=-X4GlQtuCqLPxerMc96KqDDtLM7XOXGCz9Hfhd9kgCM,50828
|
|
5
|
+
codedna/auth.py,sha256=0rPQTRX7I-6Kxg3xzYfZSiZIYJ5b7ERgbHqj6yIzL5s,11917
|
|
6
|
+
codedna/bus_factor.py,sha256=mgI4rRufMJmrLqTKibbrbHa3HrTaZdV9U80BMUZNRCw,8007
|
|
7
|
+
codedna/cli.py,sha256=qgs7Gq3ACQ586G_iq7QVtmq7_n7jquZ-mGmGey1VPTY,72661
|
|
8
|
+
codedna/db.py,sha256=o2-kxPQRKnXkw_p-jeiwjH0ZJXvquFUwel75_Eh5z20,11098
|
|
9
|
+
codedna/git_hook.py,sha256=ZyLUStLFE94bKhMTMlDFkowisDPH1PS5wm7GBG6heEw,6382
|
|
10
|
+
codedna/interview.py,sha256=YVQeTx1zqdlRE1-Qe8IgLuEQz5-OwvesmMY3vTm-_xk,8661
|
|
11
|
+
codedna/onboarding.py,sha256=hENlLV2tzdKwdN1rYSk8UpPpWlC2JhqPxsF9qGVVccA,5879
|
|
12
|
+
codedna/plan.py,sha256=99lcUTtT9ikIAy59k_EyF38L-6utf4Hf-fjJ5ci0X4U,5614
|
|
13
|
+
codedna/protection.py,sha256=ci5O9HFzTiOckrMdILQuxfXVCRuozwKOBndjsvLFpw4,6302
|
|
14
|
+
codedna/rate_limit.py,sha256=1JBRFoasq-JT9T0aAObplvk04u7L97mZLuE3SeByZcg,2744
|
|
15
|
+
codedna/scorer.py,sha256=tDBKQ3-_kZPi-Az5vh16TvURBiR1X_Au8vaJTYpC5Jw,6986
|
|
16
|
+
codedna/sprint_health.py,sha256=R3PFrpjGUSAw1QmwLFrp7Fo-vufcJSiXqoS_Yw6zOEk,6164
|
|
17
|
+
codedna/survey.py,sha256=tNM1wbaTbe4Mi7cf-A3hnmVcWW7VIBGt--_fJ_oSir0,3099
|
|
18
|
+
codedna/tech_debt.py,sha256=3Y_NEuLtM9FAb6GtT88BYMT9zrPl8_gSgUVHop4m3XY,7551
|
|
19
|
+
codedna/integrations/__init__.py,sha256=f_K_JICrNyGALXzZ8YFCauWfZejOBJRlTeDTyX_2Ogk,45
|
|
20
|
+
codedna/integrations/github_bot.py,sha256=CdZ6VvqpkdGYrfgCoDI02vZka6ky231MwFgGcOfVVek,7841
|
|
21
|
+
codedna/integrations/jira.py,sha256=1SPcBjJ4SrHmnyimWpwM38jxnRh6BhQ-1rN5h1HF4W8,5334
|
|
22
|
+
codedna/integrations/lemonsqueezy.py,sha256=VtZq71YRHPfZzTiulQ4rWjks3lBLlPpke6XVRzRnha8,7611
|
|
23
|
+
codedna-0.2.0.dist-info/METADATA,sha256=s7WQVYZRkRVW6dKog1iR7A_BaMcK0Vq6glpqA62Y_Wg,2884
|
|
24
|
+
codedna-0.2.0.dist-info/WHEEL,sha256=mffPy8wBnZQn2VnJUU5jE99KsxaSfiyMHV9Yt0aLVxs,87
|
|
25
|
+
codedna-0.2.0.dist-info/entry_points.txt,sha256=0pXR9iZgAwjwYbEGO3MSrlmYcrhMw6QXntKqq5KjWgM,45
|
|
26
|
+
codedna-0.2.0.dist-info/RECORD,,
|