codedna 0.2.3__py3-none-any.whl → 0.2.4__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 +1 -1
- codedna/ai.py +221 -0
- codedna/cli.py +150 -291
- {codedna-0.2.3.dist-info → codedna-0.2.4.dist-info}/METADATA +1 -1
- {codedna-0.2.3.dist-info → codedna-0.2.4.dist-info}/RECORD +8 -7
- {codedna-0.2.3.dist-info → codedna-0.2.4.dist-info}/WHEEL +0 -0
- {codedna-0.2.3.dist-info → codedna-0.2.4.dist-info}/entry_points.txt +0 -0
- {codedna-0.2.3.dist-info → codedna-0.2.4.dist-info}/licenses/LICENSE +0 -0
codedna/__init__.py
CHANGED
codedna/ai.py
ADDED
|
@@ -0,0 +1,221 @@
|
|
|
1
|
+
"""
|
|
2
|
+
AI Analiz Katmanı - Kullanici komut sonuclarini AI ile yorumlar.
|
|
3
|
+
|
|
4
|
+
Desteklenen provider'lar:
|
|
5
|
+
- Anthropic (Claude)
|
|
6
|
+
- MiniMax
|
|
7
|
+
- OpenAI
|
|
8
|
+
|
|
9
|
+
Key sadece analiz icin kullanilir, sohbet/tamamlama yok.
|
|
10
|
+
"""
|
|
11
|
+
import base64
|
|
12
|
+
import json
|
|
13
|
+
import os
|
|
14
|
+
import urllib.error
|
|
15
|
+
import urllib.request
|
|
16
|
+
from dataclasses import dataclass
|
|
17
|
+
from pathlib import Path
|
|
18
|
+
from typing import Optional
|
|
19
|
+
|
|
20
|
+
AI_CONFIG_PATH = Path.home() / ".codedna" / "ai_config.json"
|
|
21
|
+
|
|
22
|
+
# Provider listesi
|
|
23
|
+
PROVIDERS = ["anthropic", "minimax", "openai"]
|
|
24
|
+
|
|
25
|
+
# Default modeller
|
|
26
|
+
DEFAULT_MODELS = {
|
|
27
|
+
"anthropic": "claude-sonnet-4-20250514",
|
|
28
|
+
"minimax": "MiniMax-M2.5",
|
|
29
|
+
"openai": "gpt-4o-mini",
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
# Provider API endpoint
|
|
33
|
+
API_ENDPOINTS = {
|
|
34
|
+
"anthropic": "https://api.anthropic.com/v1/messages",
|
|
35
|
+
"minimax": "https://api.minimax.io/v1/text/chatcompletion_v2",
|
|
36
|
+
"openai": "https://api.openai.com/v1/chat/completions",
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
@dataclass
|
|
41
|
+
class AIConfig:
|
|
42
|
+
"""AI analiz konfigurasyonu."""
|
|
43
|
+
provider: str
|
|
44
|
+
api_key: str
|
|
45
|
+
model: str
|
|
46
|
+
enabled: bool = True
|
|
47
|
+
|
|
48
|
+
@classmethod
|
|
49
|
+
def load(cls) -> Optional["AIConfig"]:
|
|
50
|
+
"""Config dosyasindan yukle."""
|
|
51
|
+
if not AI_CONFIG_PATH.exists():
|
|
52
|
+
return None
|
|
53
|
+
try:
|
|
54
|
+
data = json.loads(AI_CONFIG_PATH.read_text())
|
|
55
|
+
return cls(
|
|
56
|
+
provider=data.get("provider", "anthropic"),
|
|
57
|
+
api_key=data.get("api_key", ""),
|
|
58
|
+
model=data.get("model", DEFAULT_MODELS.get(data.get("provider", "anthropic"), "")),
|
|
59
|
+
enabled=data.get("enabled", True),
|
|
60
|
+
)
|
|
61
|
+
except Exception:
|
|
62
|
+
return None
|
|
63
|
+
|
|
64
|
+
def save(self) -> None:
|
|
65
|
+
"""Config'i dosyaya yaz."""
|
|
66
|
+
AI_CONFIG_PATH.parent.mkdir(parents=True, exist_ok=True)
|
|
67
|
+
data = {
|
|
68
|
+
"provider": self.provider,
|
|
69
|
+
"api_key": self.api_key,
|
|
70
|
+
"model": self.model,
|
|
71
|
+
"enabled": self.enabled,
|
|
72
|
+
}
|
|
73
|
+
AI_CONFIG_PATH.write_text(json.dumps(data, ensure_ascii=False, indent=2))
|
|
74
|
+
try:
|
|
75
|
+
os.chmod(AI_CONFIG_PATH, 0o600)
|
|
76
|
+
except OSError:
|
|
77
|
+
pass
|
|
78
|
+
|
|
79
|
+
@classmethod
|
|
80
|
+
def clear(cls) -> None:
|
|
81
|
+
"""Config'i sil."""
|
|
82
|
+
if AI_CONFIG_PATH.exists():
|
|
83
|
+
AI_CONFIG_PATH.unlink()
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
def _call_anthropic(api_key: str, model: str, prompt: str) -> str:
|
|
87
|
+
"""Anthropic Claude API cagirisi."""
|
|
88
|
+
payload = {
|
|
89
|
+
"model": model,
|
|
90
|
+
"max_tokens": 500,
|
|
91
|
+
"messages": [
|
|
92
|
+
{"role": "user", "content": prompt}
|
|
93
|
+
],
|
|
94
|
+
}
|
|
95
|
+
req = urllib.request.Request(
|
|
96
|
+
API_ENDPOINTS["anthropic"],
|
|
97
|
+
data=json.dumps(payload).encode(),
|
|
98
|
+
headers={
|
|
99
|
+
"x-api-key": api_key,
|
|
100
|
+
"anthropic-version": "2023-06-01",
|
|
101
|
+
"Content-Type": "application/json",
|
|
102
|
+
},
|
|
103
|
+
method="POST",
|
|
104
|
+
)
|
|
105
|
+
with urllib.request.urlopen(req, timeout=30) as resp:
|
|
106
|
+
result = json.loads(resp.read())
|
|
107
|
+
# Response: {content: [{text: "..."}], ...}
|
|
108
|
+
return result.get("content", [{}])[0].get("text", "")
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
def _call_minimax(api_key: str, model: str, prompt: str) -> str:
|
|
112
|
+
"""MiniMax API cagirisi."""
|
|
113
|
+
payload = {
|
|
114
|
+
"model": model,
|
|
115
|
+
"messages": [
|
|
116
|
+
{"role": "system", "content": "Sen CodeDNA'nin AI analiz asistanisin. Kullanici komut ciktilarini yorumlarsin. Sohbet etme, sadece analiz ve oneriler sun."},
|
|
117
|
+
{"role": "user", "content": prompt}
|
|
118
|
+
],
|
|
119
|
+
}
|
|
120
|
+
req = urllib.request.Request(
|
|
121
|
+
API_ENDPOINTS["minimax"],
|
|
122
|
+
data=json.dumps(payload).encode(),
|
|
123
|
+
headers={
|
|
124
|
+
"Authorization": f"Bearer {api_key}",
|
|
125
|
+
"Content-Type": "application/json",
|
|
126
|
+
},
|
|
127
|
+
method="POST",
|
|
128
|
+
)
|
|
129
|
+
with urllib.request.urlopen(req, timeout=30) as resp:
|
|
130
|
+
result = json.loads(resp.read())
|
|
131
|
+
return result.get("choices", [{}])[0].get("message", {}).get("content", "")
|
|
132
|
+
|
|
133
|
+
|
|
134
|
+
def _call_openai(api_key: str, model: str, prompt: str) -> str:
|
|
135
|
+
"""OpenAI API cagirisi."""
|
|
136
|
+
payload = {
|
|
137
|
+
"model": model,
|
|
138
|
+
"max_tokens": 500,
|
|
139
|
+
"messages": [
|
|
140
|
+
{"role": "system", "content": "Sen CodeDNA'nin AI analiz asistanisin. Kullanici komut ciktilarini yorumlarsin. Sohbet etme, sadece analiz ve oneriler sun."},
|
|
141
|
+
{"role": "user", "content": prompt}
|
|
142
|
+
],
|
|
143
|
+
}
|
|
144
|
+
req = urllib.request.Request(
|
|
145
|
+
API_ENDPOINTS["openai"],
|
|
146
|
+
data=json.dumps(payload).encode(),
|
|
147
|
+
headers={
|
|
148
|
+
"Authorization": f"Bearer {api_key}",
|
|
149
|
+
"Content-Type": "application/json",
|
|
150
|
+
},
|
|
151
|
+
method="POST",
|
|
152
|
+
)
|
|
153
|
+
with urllib.request.urlopen(req, timeout=30) as resp:
|
|
154
|
+
result = json.loads(resp.read())
|
|
155
|
+
return result.get("choices", [{}])[0].get("message", {}).get("content", "")
|
|
156
|
+
|
|
157
|
+
|
|
158
|
+
def ai_analyze(command: str, output: str, config: Optional[AIConfig] = None) -> Optional[str]:
|
|
159
|
+
"""
|
|
160
|
+
Komut ciktisini AI ile analiz et.
|
|
161
|
+
|
|
162
|
+
Returns:
|
|
163
|
+
Analiz metni veya None (config yoksa / hata durumunda)
|
|
164
|
+
"""
|
|
165
|
+
if config is None:
|
|
166
|
+
config = AIConfig.load()
|
|
167
|
+
if config is None or not config.enabled or not config.api_key:
|
|
168
|
+
return None
|
|
169
|
+
|
|
170
|
+
# Plan kontrolu - sadece Pro+ kullanicilar AI analiz kullanabilir
|
|
171
|
+
try:
|
|
172
|
+
from codedna.plan import get_current_plan, Plan as PlanEnum
|
|
173
|
+
plan = get_current_plan()
|
|
174
|
+
if plan == PlanEnum.FREE:
|
|
175
|
+
return None # Free planda AI analiz yok
|
|
176
|
+
except Exception:
|
|
177
|
+
return None # Plan yuklenemedi, gosterme
|
|
178
|
+
|
|
179
|
+
# Prompt
|
|
180
|
+
prompt = f"""Sen CodeDNA'nin AI analiz katmanisin.
|
|
181
|
+
|
|
182
|
+
KOMUT: {command}
|
|
183
|
+
CIKTI: {output[:2000]}
|
|
184
|
+
|
|
185
|
+
Bu ciktiyi 3-4 cumlede analiz et:
|
|
186
|
+
1. Sonuc ne anlama geliyor? (iyi/kotu/notr)
|
|
187
|
+
2. Somut oneriler (numbered list, max 3)
|
|
188
|
+
3. Varsa sorun ve cozumu
|
|
189
|
+
|
|
190
|
+
Kurallar:
|
|
191
|
+
- Sohbet etme, sadece yorum
|
|
192
|
+
- Maksimum 100 kelime
|
|
193
|
+
- Turkce yanit ver
|
|
194
|
+
- Emoji kullanabilirsin (ama az)"""
|
|
195
|
+
|
|
196
|
+
try:
|
|
197
|
+
if config.provider == "anthropic":
|
|
198
|
+
return _call_anthropic(config.api_key, config.model, prompt)
|
|
199
|
+
elif config.provider == "minimax":
|
|
200
|
+
return _call_minimax(config.api_key, config.model, prompt)
|
|
201
|
+
elif config.provider == "openai":
|
|
202
|
+
return _call_openai(config.api_key, config.model, prompt)
|
|
203
|
+
else:
|
|
204
|
+
return None
|
|
205
|
+
except Exception as e:
|
|
206
|
+
return f"AI analiz hatasi: {type(e).__name__}"
|
|
207
|
+
|
|
208
|
+
|
|
209
|
+
def is_enabled() -> bool:
|
|
210
|
+
"""AI analiz aktif mi? (Sadece Pro+ uyeler)"""
|
|
211
|
+
config = AIConfig.load()
|
|
212
|
+
if config is None or not config.enabled or not config.api_key:
|
|
213
|
+
return False
|
|
214
|
+
try:
|
|
215
|
+
from codedna.plan import get_current_plan, Plan as PlanEnum
|
|
216
|
+
plan = get_current_plan()
|
|
217
|
+
if plan == PlanEnum.FREE:
|
|
218
|
+
return False
|
|
219
|
+
except Exception:
|
|
220
|
+
return False
|
|
221
|
+
return True
|
codedna/cli.py
CHANGED
|
@@ -45,7 +45,7 @@ def _version_callback(value: bool) -> None:
|
|
|
45
45
|
from importlib.metadata import version as _v
|
|
46
46
|
ver = _v("codedna")
|
|
47
47
|
except Exception:
|
|
48
|
-
ver = "0.2.
|
|
48
|
+
ver = "0.2.3"
|
|
49
49
|
console.print(f"codedna {ver}")
|
|
50
50
|
raise typer.Exit()
|
|
51
51
|
|
|
@@ -125,7 +125,7 @@ def init(
|
|
|
125
125
|
# ---------------------------------------------------------------------------
|
|
126
126
|
@app.command()
|
|
127
127
|
def doctor() -> None:
|
|
128
|
-
"""Sistem sağlık
|
|
128
|
+
"""Sistem sağlık kontrolü."""
|
|
129
129
|
console.print()
|
|
130
130
|
console.print(
|
|
131
131
|
Panel.fit(
|
|
@@ -138,36 +138,31 @@ def doctor() -> None:
|
|
|
138
138
|
|
|
139
139
|
kontroller = []
|
|
140
140
|
|
|
141
|
-
# 1. Python versiyonu
|
|
142
141
|
py_ver = f"{sys.version_info.major}.{sys.version_info.minor}.{sys.version_info.micro}"
|
|
143
142
|
py_ok = sys.version_info >= (3, 10)
|
|
144
|
-
kontroller.append(("Python versiyonu", f"v{py_ver}", py_ok, f"v{py_ver} (>=3.10
|
|
143
|
+
kontroller.append(("Python versiyonu", f"v{py_ver}", py_ok, f"v{py_ver} (>=3.10)" if py_ok else "ESKI"))
|
|
145
144
|
|
|
146
|
-
# 2. Git kurulu mu
|
|
147
145
|
import shutil
|
|
148
146
|
git_var = shutil.which("git")
|
|
149
147
|
git_ok = git_var is not None
|
|
150
|
-
kontroller.append(("Git binary", git_var or "yok", git_ok, f"bulundu
|
|
148
|
+
kontroller.append(("Git binary", git_var or "yok", git_ok, f"bulundu" if git_ok else "yok"))
|
|
151
149
|
|
|
152
|
-
# 3. Tree-sitter
|
|
153
150
|
try:
|
|
154
151
|
import tree_sitter
|
|
155
152
|
ts_ok = True
|
|
156
153
|
try:
|
|
157
154
|
ts_msg = f"v{tree_sitter.__version__}"
|
|
158
155
|
except AttributeError:
|
|
159
|
-
# Yeni versiyonlarda __version__ yok, paketten al
|
|
160
156
|
try:
|
|
161
157
|
from importlib.metadata import version as _v
|
|
162
158
|
ts_msg = f"v{_v('tree-sitter')}"
|
|
163
159
|
except Exception:
|
|
164
|
-
ts_msg = "yüklü
|
|
160
|
+
ts_msg = "yüklü"
|
|
165
161
|
except ImportError:
|
|
166
162
|
ts_ok = False
|
|
167
163
|
ts_msg = "yok"
|
|
168
|
-
kontroller.append(("Tree-sitter", ts_msg, ts_ok, ts_msg if ts_ok else "
|
|
164
|
+
kontroller.append(("Tree-sitter", ts_msg, ts_ok, ts_msg if ts_ok else "yüklü değil"))
|
|
169
165
|
|
|
170
|
-
# 4. FastAPI
|
|
171
166
|
try:
|
|
172
167
|
import fastapi
|
|
173
168
|
fa_ok = True
|
|
@@ -175,40 +170,35 @@ def doctor() -> None:
|
|
|
175
170
|
except ImportError:
|
|
176
171
|
fa_ok = False
|
|
177
172
|
fa_msg = "yok"
|
|
178
|
-
kontroller.append(("FastAPI", fa_msg, fa_ok, fa_msg if fa_ok else "
|
|
173
|
+
kontroller.append(("FastAPI", fa_msg, fa_ok, fa_msg if fa_ok else "yüklü değil"))
|
|
179
174
|
|
|
180
|
-
# 5. Auth DB
|
|
181
175
|
try:
|
|
182
176
|
from codedna.auth import _auth_db
|
|
183
177
|
db_path = _auth_db()
|
|
184
178
|
db_ok = db_path.exists()
|
|
185
|
-
kontroller.append(("Auth veritabanı", str(db_path), db_ok, f"var ({db_path.stat().st_size} bytes)" if db_ok else "yok
|
|
179
|
+
kontroller.append(("Auth veritabanı", str(db_path), db_ok, f"var ({db_path.stat().st_size} bytes)" if db_ok else "yok"))
|
|
186
180
|
except Exception as e:
|
|
187
181
|
kontroller.append(("Auth veritabanı", "hata", False, str(e)))
|
|
188
182
|
|
|
189
|
-
# 6. Plan
|
|
190
183
|
try:
|
|
191
184
|
from codedna.plan import get_current_plan
|
|
192
185
|
plan = get_current_plan()
|
|
193
|
-
|
|
194
|
-
kontroller.append(("Plan", plan.value.upper(), plan_ok, f"plan: {plan.value}"))
|
|
186
|
+
kontroller.append(("Plan", plan.value.upper(), True, f"plan: {plan.value}"))
|
|
195
187
|
except Exception as e:
|
|
196
188
|
kontroller.append(("Plan", "hata", False, str(e)))
|
|
197
189
|
|
|
198
|
-
# 7. Git hook (eğer git repo'daysak)
|
|
199
190
|
try:
|
|
200
191
|
from codedna.git_hook import find_git_root
|
|
201
192
|
git_root = find_git_root()
|
|
202
193
|
if git_root:
|
|
203
194
|
hook_path = git_root / ".git" / "hooks" / "post-commit"
|
|
204
195
|
hook_ok = hook_path.exists()
|
|
205
|
-
kontroller.append(("Post-commit hook",
|
|
196
|
+
kontroller.append(("Post-commit hook", "var" if hook_ok else "yok", hook_ok, "kurulmus" if hook_ok else "codedna init gerekli"))
|
|
206
197
|
else:
|
|
207
198
|
kontroller.append(("Post-commit hook", "—", True, "git repo disinda"))
|
|
208
199
|
except Exception as e:
|
|
209
200
|
kontroller.append(("Post-commit hook", "hata", False, str(e)))
|
|
210
201
|
|
|
211
|
-
# Tablo oluştur
|
|
212
202
|
tablo = Table(title="[bold]Sistem Durumu[/bold]", show_header=True, header_style="bold magenta", box=None)
|
|
213
203
|
tablo.add_column("Bileşen", style="cyan", no_wrap=True)
|
|
214
204
|
tablo.add_column("Durum", justify="center")
|
|
@@ -217,11 +207,9 @@ def doctor() -> None:
|
|
|
217
207
|
tum_ok = True
|
|
218
208
|
for ad, deger, ok, detay in kontroller:
|
|
219
209
|
if ok:
|
|
220
|
-
emoji = "[green]✓[/green]"
|
|
221
|
-
renk = "green"
|
|
210
|
+
emoji, renk = "[green]✓[/green]", "green"
|
|
222
211
|
else:
|
|
223
|
-
emoji = "[red]✗[/red]"
|
|
224
|
-
renk = "red"
|
|
212
|
+
emoji, renk = "[red]✗[/red]", "red"
|
|
225
213
|
tum_ok = False
|
|
226
214
|
tablo.add_row(ad, f"{emoji} [{renk}]{deger}[/{renk}]", detay)
|
|
227
215
|
|
|
@@ -230,9 +218,133 @@ def doctor() -> None:
|
|
|
230
218
|
if tum_ok:
|
|
231
219
|
console.print("[bold green]✓ Tüm sistem sağlıklı![/bold green]")
|
|
232
220
|
else:
|
|
233
|
-
console.print("[bold yellow]⚠ Bazı bileşenlerde sorun var.
|
|
221
|
+
console.print("[bold yellow]⚠ Bazı bileşenlerde sorun var.[/bold yellow]")
|
|
222
|
+
raise typer.Exit(1)
|
|
223
|
+
|
|
224
|
+
|
|
225
|
+
# ---------------------------------------------------------------------------
|
|
226
|
+
# codedna setup-ai — AI analiz katmanı (Pro+ plan gerekli)
|
|
227
|
+
# ---------------------------------------------------------------------------
|
|
228
|
+
@app.command(name="setup-ai")
|
|
229
|
+
def setup_ai(
|
|
230
|
+
clear: bool = typer.Option(False, "--clear", help="AI konfigürasyonunu sil"),
|
|
231
|
+
show: bool = typer.Option(False, "--show", help="Mevcut konfigürasyonu göster"),
|
|
232
|
+
enable_flag: bool = typer.Option(False, "--on", help="AI analizi etkinleştir"),
|
|
233
|
+
disable_flag: bool = typer.Option(False, "--off", help="AI analizi devre dışı bırak"),
|
|
234
|
+
) -> None:
|
|
235
|
+
"""AI analiz katmanı için API key ayarla (Anthropic, MiniMax, OpenAI). Pro+ plan gerekli."""
|
|
236
|
+
import getpass
|
|
237
|
+
from codedna.ai import AIConfig, AI_CONFIG_PATH, DEFAULT_MODELS, PROVIDERS
|
|
238
|
+
|
|
239
|
+
console.print()
|
|
240
|
+
console.print(
|
|
241
|
+
Panel.fit(
|
|
242
|
+
"[bold cyan]🧬 CodeDNA AI Setup[/bold cyan]\n"
|
|
243
|
+
"[dim]AI analiz katmanı — Pro+ plan gerekli[/dim]",
|
|
244
|
+
border_style="cyan",
|
|
245
|
+
)
|
|
246
|
+
)
|
|
247
|
+
console.print()
|
|
248
|
+
|
|
249
|
+
if clear:
|
|
250
|
+
AIConfig.clear()
|
|
251
|
+
console.print("[bold green]✓[/bold green] AI konfigürasyonu silindi.")
|
|
252
|
+
return
|
|
253
|
+
|
|
254
|
+
if show:
|
|
255
|
+
cfg = AIConfig.load()
|
|
256
|
+
if not cfg:
|
|
257
|
+
console.print("[yellow]AI konfigürasyonu yok.[/yellow]")
|
|
258
|
+
else:
|
|
259
|
+
masked = cfg.api_key[:8] + "..." + cfg.api_key[-4:] if len(cfg.api_key) > 12 else "***"
|
|
260
|
+
console.print(f"[bold]Provider:[/bold] {cfg.provider}")
|
|
261
|
+
console.print(f"[bold]Model:[/bold] {cfg.model}")
|
|
262
|
+
console.print(f"[bold]API Key:[/bold] {masked}")
|
|
263
|
+
console.print(f"[bold]Aktif:[/bold] {'Evet' if cfg.enabled else 'Hayır'}")
|
|
264
|
+
console.print(f"[bold]Config:[/bold] {AI_CONFIG_PATH}")
|
|
265
|
+
return
|
|
266
|
+
|
|
267
|
+
if enable_flag or disable_flag:
|
|
268
|
+
cfg = AIConfig.load()
|
|
269
|
+
if not cfg:
|
|
270
|
+
console.print("[red]Önce key ayarlayın: codedna setup-ai[/red]")
|
|
271
|
+
raise typer.Exit(1)
|
|
272
|
+
cfg.enabled = enable_flag
|
|
273
|
+
cfg.save()
|
|
274
|
+
status = "aktif" if enable_flag else "devre dışı"
|
|
275
|
+
console.print(f"[bold green]✓[/bold green] AI analiz {status}.")
|
|
276
|
+
return
|
|
277
|
+
|
|
278
|
+
# Plan kontrolu
|
|
279
|
+
try:
|
|
280
|
+
from codedna.plan import get_current_plan, Plan as PlanEnum
|
|
281
|
+
plan = get_current_plan()
|
|
282
|
+
if plan == PlanEnum.FREE:
|
|
283
|
+
console.print(
|
|
284
|
+
Panel.fit(
|
|
285
|
+
"[bold yellow]🔒 AI analiz Pro+ plan gerektirir.[/bold yellow]\n\n"
|
|
286
|
+
f"Mevcut plan: [cyan]{plan.value.upper()}[/cyan]\n\n"
|
|
287
|
+
"Demo: [cyan]codedna plan demo pro[/cyan]",
|
|
288
|
+
border_style="yellow",
|
|
289
|
+
)
|
|
290
|
+
)
|
|
291
|
+
raise typer.Exit(1)
|
|
292
|
+
except Exception as e:
|
|
293
|
+
console.print(f"[red]Plan hatası: {e}[/red]")
|
|
294
|
+
raise typer.Exit(1)
|
|
295
|
+
|
|
296
|
+
# Wizard
|
|
297
|
+
console.print("[bold]Provider seçin:[/bold]")
|
|
298
|
+
for i, p in enumerate(PROVIDERS, 1):
|
|
299
|
+
default = DEFAULT_MODELS.get(p, "")
|
|
300
|
+
console.print(f" [cyan]{i}[/cyan]. {p} [dim]({default})[/dim]")
|
|
301
|
+
console.print()
|
|
302
|
+
secim = typer.prompt("Numara", type=int, default=1)
|
|
303
|
+
if secim < 1 or secim > len(PROVIDERS):
|
|
304
|
+
console.print("[red]Geçersiz seçim.[/red]")
|
|
305
|
+
raise typer.Exit(1)
|
|
306
|
+
provider = PROVIDERS[secim - 1]
|
|
307
|
+
default_model = DEFAULT_MODELS[provider]
|
|
308
|
+
|
|
309
|
+
console.print()
|
|
310
|
+
console.print(f"[dim]API key girin ({provider}):[/dim]")
|
|
311
|
+
api_key = getpass.getpass("Key: ").strip()
|
|
312
|
+
if not api_key:
|
|
313
|
+
console.print("[red]Key boş olamaz.[/red]")
|
|
314
|
+
raise typer.Exit(1)
|
|
315
|
+
|
|
316
|
+
console.print()
|
|
317
|
+
model = typer.prompt(f"Model [varsayilan: {default_model}]", default=default_model)
|
|
318
|
+
|
|
319
|
+
console.print()
|
|
320
|
+
console.print("[dim]API bağlantısı test ediliyor...[/dim]")
|
|
321
|
+
try:
|
|
322
|
+
from codedna.ai import ai_analyze
|
|
323
|
+
test_config = AIConfig(provider=provider, api_key=api_key, model=model)
|
|
324
|
+
result = ai_analyze("test", "Bu bir test komutudur.", test_config)
|
|
325
|
+
if result and not result.startswith("AI analiz hatasi"):
|
|
326
|
+
console.print(f"[bold green]✓[/bold green] Bağlantı başarılı!")
|
|
327
|
+
else:
|
|
328
|
+
console.print(f"[bold red]✗[/bold red] Test başarısız: {result}")
|
|
329
|
+
raise typer.Exit(1)
|
|
330
|
+
except Exception as e:
|
|
331
|
+
console.print(f"[bold red]✗[/bold red] Hata: {e}")
|
|
234
332
|
raise typer.Exit(1)
|
|
235
333
|
|
|
334
|
+
config = AIConfig(provider=provider, api_key=api_key, model=model, enabled=True)
|
|
335
|
+
config.save()
|
|
336
|
+
console.print()
|
|
337
|
+
console.print(
|
|
338
|
+
Panel.fit(
|
|
339
|
+
f"[bold green]✓ AI analiz aktif![/bold green]\n\n"
|
|
340
|
+
f"Provider: {provider}\n"
|
|
341
|
+
f"Model: {model}\n"
|
|
342
|
+
f"Config: {AI_CONFIG_PATH}\n\n"
|
|
343
|
+
"[dim]Her komut çıktısından sonra AI analiz kutusu görünecek.[/dim]",
|
|
344
|
+
border_style="green",
|
|
345
|
+
)
|
|
346
|
+
)
|
|
347
|
+
|
|
236
348
|
|
|
237
349
|
@app.command()
|
|
238
350
|
def scan(
|
|
@@ -399,7 +511,7 @@ def status(
|
|
|
399
511
|
Panel(
|
|
400
512
|
f"[bold]Commit:[/bold] [dim]{commit_hash[:8]}[/dim] [dim]{mesaj}[/dim]\n"
|
|
401
513
|
f"[bold]Yazar:[/bold] {yazar}\n"
|
|
402
|
-
f"[bold]Değişen
|
|
514
|
+
f"[bold]Değişen dosyalar:[/bold] {len(sonuclar)}\n"
|
|
403
515
|
f"[bold]Ort. AI olasılığı:[/bold] [bold {risk_renk}]%{ort_ai*100:.0f} ({risk_etiketi})[/bold {risk_renk}]\n"
|
|
404
516
|
f"[bold]Anlama skoru:[/bold] {anlama_goster}",
|
|
405
517
|
title="[bold cyan]🧬 CodeDNA — Commit Skoru[/bold cyan]",
|
|
@@ -408,11 +520,6 @@ def status(
|
|
|
408
520
|
)
|
|
409
521
|
)
|
|
410
522
|
console.print("[dim]Commit skoru kaydedildi.[/dim]\n")
|
|
411
|
-
else:
|
|
412
|
-
console.print(
|
|
413
|
-
f"[bold]Commit:[/bold] [dim]{commit_hash[:8]}[/dim]\n"
|
|
414
|
-
"[dim]Bu commit'te desteklenen kod dosyası bulunamadı.[/dim]"
|
|
415
|
-
)
|
|
416
523
|
|
|
417
524
|
# Post-commit hook: korumalı modül ihlallerini kontrol et ve uyar (bloklama YOK)
|
|
418
525
|
if hook:
|
|
@@ -424,6 +531,12 @@ def status(
|
|
|
424
531
|
except Exception:
|
|
425
532
|
pass # Hook'u asla bozmaz
|
|
426
533
|
|
|
534
|
+
else:
|
|
535
|
+
console.print(
|
|
536
|
+
f"[bold]Commit:[/bold] [dim]{commit_hash[:8]}[/dim]\n"
|
|
537
|
+
"[dim]Bu commit'te desteklenen kod dosyası bulunamadı.[/dim]"
|
|
538
|
+
)
|
|
539
|
+
|
|
427
540
|
|
|
428
541
|
# ---------------------------------------------------------------------------
|
|
429
542
|
# codedna history
|
|
@@ -457,7 +570,7 @@ def history(
|
|
|
457
570
|
tablo.add_column("Commit", style="dim", min_width=10)
|
|
458
571
|
tablo.add_column("Yazar", min_width=15)
|
|
459
572
|
tablo.add_column("Tarih", min_width=17)
|
|
460
|
-
tablo.add_column("
|
|
573
|
+
tablo.add_column("Dosya", justify="right", min_width=6)
|
|
461
574
|
tablo.add_column("Anlama", justify="center", min_width=12)
|
|
462
575
|
|
|
463
576
|
for satir in satirlar:
|
|
@@ -1589,54 +1702,27 @@ def sprint_gecmisi(
|
|
|
1589
1702
|
def plan(
|
|
1590
1703
|
komut: Optional[str] = typer.Argument(
|
|
1591
1704
|
None,
|
|
1592
|
-
help="'activate'
|
|
1705
|
+
help="'activate' veya doğrudan lisans anahtarı",
|
|
1593
1706
|
),
|
|
1594
1707
|
anahtar: Optional[str] = typer.Argument(
|
|
1595
1708
|
None,
|
|
1596
|
-
help="Lisans anahtarı (activate
|
|
1709
|
+
help="Lisans anahtarı (activate ile birlikte kullanılır)",
|
|
1597
1710
|
),
|
|
1598
1711
|
) -> None:
|
|
1599
|
-
"""Mevcut planı göster
|
|
1712
|
+
"""Mevcut planı göster veya lisans anahtarı ile plan aktif et.
|
|
1600
1713
|
|
|
1601
1714
|
Kullanım:
|
|
1602
1715
|
codedna plan # mevcut planı göster
|
|
1603
|
-
codedna plan activate <KEY> # lisans aktif et
|
|
1604
|
-
codedna plan demo # Enterprise demo lisans aktif et (hızlı test)
|
|
1605
|
-
codedna plan demo pro # Pro demo lisans aktif et
|
|
1716
|
+
codedna plan activate <KEY> # lisans aktif et
|
|
1606
1717
|
codedna plan <KEY> # kısa yol
|
|
1607
1718
|
"""
|
|
1608
1719
|
from codedna.plan import (
|
|
1609
1720
|
Plan as PlanEnum,
|
|
1610
1721
|
get_current_plan,
|
|
1611
1722
|
activate_license,
|
|
1612
|
-
activate_demo_license,
|
|
1613
1723
|
get_plan_limits,
|
|
1614
1724
|
)
|
|
1615
1725
|
|
|
1616
|
-
# "demo [plan]" syntax'ı
|
|
1617
|
-
if komut == "demo":
|
|
1618
|
-
demo_plan_str = (anahtar or "enterprise").lower()
|
|
1619
|
-
try:
|
|
1620
|
-
demo_plan = PlanEnum(demo_plan_str)
|
|
1621
|
-
except ValueError:
|
|
1622
|
-
console.print(f"[bold red]Hata:[/bold red] Geçersiz plan: {demo_plan_str!r}")
|
|
1623
|
-
console.print("Geçerli planlar: free, pro, team, enterprise")
|
|
1624
|
-
raise typer.Exit(1)
|
|
1625
|
-
aktif_plan = activate_demo_license(demo_plan)
|
|
1626
|
-
console.print(
|
|
1627
|
-
Panel(
|
|
1628
|
-
f"[bold green]✓ Demo lisans aktif edildi![/bold green]\n\n"
|
|
1629
|
-
f"[bold]Plan:[/bold] [cyan]{aktif_plan.value.upper()}[/cyan]\n"
|
|
1630
|
-
f"[bold yellow]⚠️ Bu bir DEMO lisanstır — production için gerçek key gerekir.[/bold yellow]\n\n"
|
|
1631
|
-
f"Gerçek lisans için:\n"
|
|
1632
|
-
f"[dim]codedna plan activate CDNA-{demo_plan_str.upper()[:3]}-XXXX-XXXX-XXXX[/dim]",
|
|
1633
|
-
title="[bold cyan]🧬 CodeDNA — Demo Plan[/bold cyan]",
|
|
1634
|
-
border_style="cyan",
|
|
1635
|
-
padding=(1, 2),
|
|
1636
|
-
)
|
|
1637
|
-
)
|
|
1638
|
-
return
|
|
1639
|
-
|
|
1640
1726
|
# "activate <KEY>" veya doğrudan "<KEY>" syntax'ı destekle
|
|
1641
1727
|
lisans_anahtari: Optional[str] = None
|
|
1642
1728
|
if komut == "activate" and anahtar:
|
|
@@ -1830,233 +1916,6 @@ def uninstall(
|
|
|
1830
1916
|
raise typer.Exit(1)
|
|
1831
1917
|
|
|
1832
1918
|
|
|
1833
|
-
# ---------------------------------------------------------------------------
|
|
1834
|
-
# codedna natureco (Pro+ özellik — NatureCo CLI entegrasyonu)
|
|
1835
|
-
# ---------------------------------------------------------------------------
|
|
1836
|
-
@app.command()
|
|
1837
|
-
def natureco(
|
|
1838
|
-
komut: Optional[str] = typer.Argument(
|
|
1839
|
-
None,
|
|
1840
|
-
help="'connect', 'sync', 'auto-scan', 'status' veya doğrudan dosya yolu",
|
|
1841
|
-
),
|
|
1842
|
-
dosya: Optional[str] = typer.Argument(
|
|
1843
|
-
None,
|
|
1844
|
-
help="Dosya yolu (sync/auto-scan için)",
|
|
1845
|
-
),
|
|
1846
|
-
) -> None:
|
|
1847
|
-
"""NatureCo CLI ile entegre ol (Pro+ plan gerekir).
|
|
1848
|
-
|
|
1849
|
-
NatureCo CLI kod ürettiğinde otomatik CodeDNA analizi yap.
|
|
1850
|
-
|
|
1851
|
-
Kullanım:
|
|
1852
|
-
codedna natureco connect # NatureCo CLI'ya bağlan
|
|
1853
|
-
codedna natureco status # Bağlantı durumu
|
|
1854
|
-
codedna natureco sync <file> # Dosyayı tarat
|
|
1855
|
-
codedna natureco auto-scan # Post-hook: commit'te otomatik scan
|
|
1856
|
-
codedna natureco disconnect # Bağlantıyı kes
|
|
1857
|
-
"""
|
|
1858
|
-
from codedna.plan import get_current_plan, Plan as PlanEnum, is_feature_available
|
|
1859
|
-
|
|
1860
|
-
# Pro+ plan gerekli
|
|
1861
|
-
if not is_feature_available("natureco_integration"):
|
|
1862
|
-
plan = get_current_plan()
|
|
1863
|
-
console.print(
|
|
1864
|
-
Panel(
|
|
1865
|
-
f"[bold yellow]🔒 NatureCo entegrasyonu Pro+ plan gerektirir.[/bold yellow]\n\n"
|
|
1866
|
-
f"Mevcut planınız: [cyan]{plan.value.upper()}[/cyan]\n\n"
|
|
1867
|
-
f"Demo için:\n"
|
|
1868
|
-
f"[dim]codedna plan demo pro[/dim]\n\n"
|
|
1869
|
-
f"Upgrade:\n"
|
|
1870
|
-
f"[dim]https://codedna.dev/pricing[/dim]",
|
|
1871
|
-
title="[bold cyan]🧬 CodeDNA — NatureCo Integration[/bold cyan]",
|
|
1872
|
-
border_style="yellow",
|
|
1873
|
-
padding=(1, 2),
|
|
1874
|
-
)
|
|
1875
|
-
)
|
|
1876
|
-
raise typer.Exit(1)
|
|
1877
|
-
|
|
1878
|
-
if not komut or komut == "status":
|
|
1879
|
-
return _natureco_status()
|
|
1880
|
-
elif komut == "connect":
|
|
1881
|
-
return _natureco_connect()
|
|
1882
|
-
elif komut == "disconnect":
|
|
1883
|
-
return _natureco_disconnect()
|
|
1884
|
-
elif komut == "sync":
|
|
1885
|
-
return _natureco_sync(dosya)
|
|
1886
|
-
elif komut == "auto-scan":
|
|
1887
|
-
return _natureco_auto_scan()
|
|
1888
|
-
else:
|
|
1889
|
-
console.print(f"[bold red]Bilinmeyen komut:[/bold red] {komut!r}")
|
|
1890
|
-
console.print("Geçerli: connect, status, sync, auto-scan, disconnect")
|
|
1891
|
-
raise typer.Exit(1)
|
|
1892
|
-
|
|
1893
|
-
|
|
1894
|
-
def _natureco_config_path() -> Path:
|
|
1895
|
-
"""NatureCo entegrasyon ayar dosyası yolu."""
|
|
1896
|
-
return Path.home() / ".codedna" / "natureco.json"
|
|
1897
|
-
|
|
1898
|
-
|
|
1899
|
-
def _natureco_status() -> None:
|
|
1900
|
-
"""Bağlantı durumunu göster."""
|
|
1901
|
-
config_path = _natureco_config_path()
|
|
1902
|
-
if config_path.exists():
|
|
1903
|
-
import json as _json
|
|
1904
|
-
data = _json.loads(config_path.read_text())
|
|
1905
|
-
console.print(
|
|
1906
|
-
Panel(
|
|
1907
|
-
f"[bold green]✓ NatureCo CLI bağlı[/bold green]\n\n"
|
|
1908
|
-
f"[bold]Hook:[/bold] {'[green]Aktif[/green]' if data.get('auto_scan') else '[yellow]Pasif[/yellow]'}\n"
|
|
1909
|
-
f"[bold]Son sync:[/bold] {data.get('last_sync', 'Hiç')}\n"
|
|
1910
|
-
f"[bold]Toplam dosya:[/bold] {data.get('total_files', 0)}\n"
|
|
1911
|
-
f"[bold]Bağlandı:[/bold] {data.get('connected_at', 'Bilinmiyor')}",
|
|
1912
|
-
title="[bold cyan]🧬 CodeDNA ↔ NatureCo[/bold cyan]",
|
|
1913
|
-
border_style="green",
|
|
1914
|
-
padding=(1, 2),
|
|
1915
|
-
)
|
|
1916
|
-
)
|
|
1917
|
-
else:
|
|
1918
|
-
console.print(
|
|
1919
|
-
Panel(
|
|
1920
|
-
"[bold yellow]NatureCo CLI henüz bağlı değil.[/bold yellow]\n\n"
|
|
1921
|
-
"Bağlamak için:\n"
|
|
1922
|
-
"[dim]codedna natureco connect[/dim]",
|
|
1923
|
-
title="[bold cyan]🧬 CodeDNA ↔ NatureCo[/bold cyan]",
|
|
1924
|
-
border_style="yellow",
|
|
1925
|
-
padding=(1, 2),
|
|
1926
|
-
)
|
|
1927
|
-
)
|
|
1928
|
-
|
|
1929
|
-
|
|
1930
|
-
def _natureco_connect() -> None:
|
|
1931
|
-
"""NatureCo CLI ile bağlantı kur."""
|
|
1932
|
-
import json as _json
|
|
1933
|
-
import time as _time
|
|
1934
|
-
|
|
1935
|
-
config_path = _natureco_config_path()
|
|
1936
|
-
config_path.parent.mkdir(parents=True, exist_ok=True)
|
|
1937
|
-
|
|
1938
|
-
# NatureCo CLI yüklü mü kontrol et
|
|
1939
|
-
nc_path = None
|
|
1940
|
-
for p in ["/usr/local/bin/natureco", "/opt/homebrew/bin/natureco",
|
|
1941
|
-
str(Path.home() / ".npm-global/bin/natureco")]:
|
|
1942
|
-
if Path(p).exists():
|
|
1943
|
-
nc_path = p
|
|
1944
|
-
break
|
|
1945
|
-
|
|
1946
|
-
# PATH'te ara
|
|
1947
|
-
if not nc_path:
|
|
1948
|
-
import shutil
|
|
1949
|
-
nc_path = shutil.which("natureco")
|
|
1950
|
-
|
|
1951
|
-
if nc_path:
|
|
1952
|
-
console.print(f"[green]✓[/green] NatureCo CLI bulundu: [dim]{nc_path}[/dim]")
|
|
1953
|
-
else:
|
|
1954
|
-
console.print("[yellow]⚠[/yellow] NatureCo CLI PATH'te bulunamadı")
|
|
1955
|
-
console.print("[dim] Yine de entegrasyon kuruldu — NatureCo CLI kurulunca çalışacak[/dim]")
|
|
1956
|
-
|
|
1957
|
-
config = {
|
|
1958
|
-
"connected": True,
|
|
1959
|
-
"natureco_cli_path": nc_path,
|
|
1960
|
-
"auto_scan": True, # Varsayılan açık
|
|
1961
|
-
"last_sync": None,
|
|
1962
|
-
"total_files": 0,
|
|
1963
|
-
"connected_at": _time.strftime("%Y-%m-%d %H:%M:%S"),
|
|
1964
|
-
}
|
|
1965
|
-
config_path.write_text(_json.dumps(config, indent=2))
|
|
1966
|
-
|
|
1967
|
-
console.print(
|
|
1968
|
-
Panel(
|
|
1969
|
-
"[bold green]✓ NatureCo CLI bağlantısı kuruldu![/bold green]\n\n"
|
|
1970
|
-
"Artık NatureCo CLI ile üretilen her kod otomatik taranacak.\n\n"
|
|
1971
|
-
"[bold]Sonraki adımlar:[/bold]\n"
|
|
1972
|
-
"1. NatureCo CLI'da kod üretin (`natureco code`)\n"
|
|
1973
|
-
"2. CodeDNA otomatik scan yapar\n"
|
|
1974
|
-
"3. `codedna natureco status` ile durumu kontrol edin",
|
|
1975
|
-
title="[bold green]🧬 CodeDNA ↔ NatureCo Bağlandı[/bold green]",
|
|
1976
|
-
border_style="green",
|
|
1977
|
-
padding=(1, 2),
|
|
1978
|
-
)
|
|
1979
|
-
)
|
|
1980
|
-
|
|
1981
|
-
|
|
1982
|
-
def _natureco_disconnect() -> None:
|
|
1983
|
-
"""Bağlantıyı kes."""
|
|
1984
|
-
config_path = _natureco_config_path()
|
|
1985
|
-
if config_path.exists():
|
|
1986
|
-
config_path.unlink()
|
|
1987
|
-
console.print("[green]✓[/green] NatureCo bağlantısı kesildi.")
|
|
1988
|
-
else:
|
|
1989
|
-
console.print("[yellow]Zaten bağlı değil.[/yellow]")
|
|
1990
|
-
|
|
1991
|
-
|
|
1992
|
-
def _natureco_sync(dosya: Optional[str]) -> None:
|
|
1993
|
-
"""Bir dosyayı CodeDNA ile tara."""
|
|
1994
|
-
import json as _json
|
|
1995
|
-
import time as _time
|
|
1996
|
-
|
|
1997
|
-
if not dosya:
|
|
1998
|
-
console.print("[bold red]Hata:[/bold red] Dosya yolu gerekli")
|
|
1999
|
-
console.print("Kullanım: [dim]codedna natureco sync <dosya>[/dim]")
|
|
2000
|
-
raise typer.Exit(1)
|
|
2001
|
-
|
|
2002
|
-
file_path = Path(dosya)
|
|
2003
|
-
if not file_path.exists():
|
|
2004
|
-
console.print(f"[bold red]Hata:[/bold red] Dosya bulunamadı: {dosya}")
|
|
2005
|
-
raise typer.Exit(1)
|
|
2006
|
-
|
|
2007
|
-
# Repo kökünü bul
|
|
2008
|
-
kok = find_git_root() or Path.cwd()
|
|
2009
|
-
db_yolu = _get_db(kok)
|
|
2010
|
-
|
|
2011
|
-
# Scoring yap (analyzer kullanarak)
|
|
2012
|
-
from codedna.analyzer import analyze_file
|
|
2013
|
-
|
|
2014
|
-
console.print(f"[dim]Taranıyor:[/dim] {file_path.name}")
|
|
2015
|
-
result = analyze_file(file_path, single_commit_ratio=0.0)
|
|
2016
|
-
|
|
2017
|
-
if result:
|
|
2018
|
-
console.print(
|
|
2019
|
-
Panel(
|
|
2020
|
-
f"[bold green]✓ Tarama tamamlandı[/bold green]\n\n"
|
|
2021
|
-
f"[bold]Dosya:[/bold] {file_path.name}\n"
|
|
2022
|
-
f"[bold]AI olasılığı:[/bold] [cyan]%{result.ai_probability * 100:.0f}[/cyan]\n"
|
|
2023
|
-
f"[bold]Karmaşıklık:[/bold] {result.complexity_score:.1f}\n"
|
|
2024
|
-
f"[bold]Yorum oranı:[/bold] {result.comment_ratio * 100:.0f}%\n",
|
|
2025
|
-
title="[bold cyan]🧬 Tarama Sonucu[/bold cyan]",
|
|
2026
|
-
border_style="cyan",
|
|
2027
|
-
padding=(1, 2),
|
|
2028
|
-
)
|
|
2029
|
-
)
|
|
2030
|
-
|
|
2031
|
-
# Config'i güncelle
|
|
2032
|
-
config_path = _natureco_config_path()
|
|
2033
|
-
if config_path.exists():
|
|
2034
|
-
cfg = _json.loads(config_path.read_text())
|
|
2035
|
-
cfg["last_sync"] = _time.strftime("%Y-%m-%d %H:%M:%S")
|
|
2036
|
-
cfg["total_files"] = cfg.get("total_files", 0) + 1
|
|
2037
|
-
config_path.write_text(_json.dumps(cfg, indent=2))
|
|
2038
|
-
else:
|
|
2039
|
-
console.print("[yellow]Dosya analiz edilemedi.[/yellow]")
|
|
2040
|
-
|
|
2041
|
-
|
|
2042
|
-
def _natureco_auto_scan() -> None:
|
|
2043
|
-
"""Auto-scan hook'unu aktif/pasif yap."""
|
|
2044
|
-
import json as _json
|
|
2045
|
-
|
|
2046
|
-
config_path = _natureco_config_path()
|
|
2047
|
-
if not config_path.exists():
|
|
2048
|
-
console.print("[bold red]Hata:[/bold red] Önce connect gerekli")
|
|
2049
|
-
console.print("[dim]codedna natureco connect[/dim]")
|
|
2050
|
-
raise typer.Exit(1)
|
|
2051
|
-
|
|
2052
|
-
cfg = _json.loads(config_path.read_text())
|
|
2053
|
-
cfg["auto_scan"] = not cfg.get("auto_scan", False)
|
|
2054
|
-
config_path.write_text(_json.dumps(cfg, indent=2))
|
|
2055
|
-
|
|
2056
|
-
state = "[green]aktif[/green]" if cfg["auto_scan"] else "[yellow]pasif[/yellow]"
|
|
2057
|
-
console.print(f"[green]✓[/green] Auto-scan {state}")
|
|
2058
|
-
|
|
2059
|
-
|
|
2060
1919
|
# ---------------------------------------------------------------------------
|
|
2061
1920
|
# Yardımcı fonksiyonlar
|
|
2062
1921
|
# ---------------------------------------------------------------------------
|
|
@@ -2092,7 +1951,7 @@ def main() -> None:
|
|
|
2092
1951
|
from importlib.metadata import version as _v
|
|
2093
1952
|
ver = _v("codedna")
|
|
2094
1953
|
except Exception:
|
|
2095
|
-
ver =
|
|
1954
|
+
ver = "0.2.3"
|
|
2096
1955
|
console.print(f"codedna {ver}")
|
|
2097
1956
|
sys.exit(0)
|
|
2098
1957
|
app()
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: codedna
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.4
|
|
4
4
|
Summary: AI Code Transparency Tool - detect AI-written code and measure developer understanding
|
|
5
5
|
Project-URL: Homepage, https://codedna.dev
|
|
6
6
|
Project-URL: Repository, https://github.com/natureco-official/codedna
|
|
@@ -1,10 +1,11 @@
|
|
|
1
|
-
codedna/__init__.py,sha256=
|
|
1
|
+
codedna/__init__.py,sha256=7G00zlcjHJcAUQDtrKy_XkZJhBV3iF7ce-miIlhZJXA,93
|
|
2
|
+
codedna/ai.py,sha256=h7cwQ6ArGEHWOoMDOY7v9ARSRm_7dHyszGdRYfFiE9Q,6701
|
|
2
3
|
codedna/ai_fingerprint.py,sha256=xUiBF3jSjTqtu1xGAhbBbDx6PktQ7u_8KcSEz78fSSU,8107
|
|
3
4
|
codedna/analyzer.py,sha256=GgKd_2TCC1ZmroV6RApj8LPGAZsvrgqw9zYWdz3c0bI,7490
|
|
4
5
|
codedna/api.py,sha256=-X4GlQtuCqLPxerMc96KqDDtLM7XOXGCz9Hfhd9kgCM,50828
|
|
5
6
|
codedna/auth.py,sha256=0rPQTRX7I-6Kxg3xzYfZSiZIYJ5b7ERgbHqj6yIzL5s,11917
|
|
6
7
|
codedna/bus_factor.py,sha256=mgI4rRufMJmrLqTKibbrbHa3HrTaZdV9U80BMUZNRCw,8007
|
|
7
|
-
codedna/cli.py,sha256=
|
|
8
|
+
codedna/cli.py,sha256=bImIUXtNRnIlJrgswzhe9Wj8ZXr2bOS339l9SwUNJv4,72189
|
|
8
9
|
codedna/db.py,sha256=o2-kxPQRKnXkw_p-jeiwjH0ZJXvquFUwel75_Eh5z20,11098
|
|
9
10
|
codedna/git_hook.py,sha256=ZyLUStLFE94bKhMTMlDFkowisDPH1PS5wm7GBG6heEw,6382
|
|
10
11
|
codedna/interview.py,sha256=YVQeTx1zqdlRE1-Qe8IgLuEQz5-OwvesmMY3vTm-_xk,8661
|
|
@@ -20,8 +21,8 @@ codedna/integrations/__init__.py,sha256=f_K_JICrNyGALXzZ8YFCauWfZejOBJRlTeDTyX_2
|
|
|
20
21
|
codedna/integrations/github_bot.py,sha256=CdZ6VvqpkdGYrfgCoDI02vZka6ky231MwFgGcOfVVek,7841
|
|
21
22
|
codedna/integrations/jira.py,sha256=1SPcBjJ4SrHmnyimWpwM38jxnRh6BhQ-1rN5h1HF4W8,5334
|
|
22
23
|
codedna/integrations/lemonsqueezy.py,sha256=VtZq71YRHPfZzTiulQ4rWjks3lBLlPpke6XVRzRnha8,7611
|
|
23
|
-
codedna-0.2.
|
|
24
|
-
codedna-0.2.
|
|
25
|
-
codedna-0.2.
|
|
26
|
-
codedna-0.2.
|
|
27
|
-
codedna-0.2.
|
|
24
|
+
codedna-0.2.4.dist-info/METADATA,sha256=VWKXNQBBkrbM4hbbCsj1rtfgKvzQykAHXrXea8_sC3U,18957
|
|
25
|
+
codedna-0.2.4.dist-info/WHEEL,sha256=mffPy8wBnZQn2VnJUU5jE99KsxaSfiyMHV9Yt0aLVxs,87
|
|
26
|
+
codedna-0.2.4.dist-info/entry_points.txt,sha256=0pXR9iZgAwjwYbEGO3MSrlmYcrhMw6QXntKqq5KjWgM,45
|
|
27
|
+
codedna-0.2.4.dist-info/licenses/LICENSE,sha256=-XHiSAtpzZ_2gcli9hDggy41vDYoZrAqvLhiJ_5L35I,1065
|
|
28
|
+
codedna-0.2.4.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|