yncli 1.0.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.
- yncli/__init__.py +5 -0
- yncli/agent.py +277 -0
- yncli/built_in_skills/architect.md +10 -0
- yncli/built_in_skills/code_review.md +8 -0
- yncli/built_in_skills/debug_oracle.md +10 -0
- yncli/built_in_skills/debugger.md +11 -0
- yncli/built_in_skills/polyglot.md +17 -0
- yncli/built_in_skills/refactor_master.md +16 -0
- yncli/built_in_skills/security_auditor.md +18 -0
- yncli/built_in_skills/system_architect.md +10 -0
- yncli/built_in_skills/test_runner.md +14 -0
- yncli/built_in_skills/ultrabrain.md +21 -0
- yncli/clean_text.py +70 -0
- yncli/client.py +146 -0
- yncli/config.py +44 -0
- yncli/language_detector.py +206 -0
- yncli/main.py +137 -0
- yncli/skills_manager.py +61 -0
- yncli/system_prompt.py +102 -0
- yncli/tools/__init__.py +266 -0
- yncli/tools/file_tools.py +206 -0
- yncli/tools/polyglot_tools.py +133 -0
- yncli/tools/search_tools.py +68 -0
- yncli/tools/system_tools.py +140 -0
- yncli/tui.py +536 -0
- yncli/workspace_memory.py +97 -0
- yncli/workspace_scanner.py +99 -0
- yncli-1.0.0.dist-info/METADATA +63 -0
- yncli-1.0.0.dist-info/RECORD +32 -0
- yncli-1.0.0.dist-info/WHEEL +5 -0
- yncli-1.0.0.dist-info/entry_points.txt +2 -0
- yncli-1.0.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import os
|
|
2
|
+
import json
|
|
3
|
+
from pathlib import Path
|
|
4
|
+
from typing import Dict, Any, List
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class WorkspaceMemory:
|
|
8
|
+
"""
|
|
9
|
+
Maintains real-time in-depth memory and indexed source code of the active workspace.
|
|
10
|
+
"""
|
|
11
|
+
def __init__(self, workspace_dir: str = "."):
|
|
12
|
+
self.workspace_dir = str(Path(workspace_dir).resolve())
|
|
13
|
+
self.indexed_files: Dict[str, str] = {}
|
|
14
|
+
self.file_tree: List[str] = []
|
|
15
|
+
self.project_type: str = "general"
|
|
16
|
+
self.refresh()
|
|
17
|
+
|
|
18
|
+
def refresh(self) -> None:
|
|
19
|
+
cwd = Path(self.workspace_dir)
|
|
20
|
+
if not cwd.exists():
|
|
21
|
+
return
|
|
22
|
+
|
|
23
|
+
ignore_dirs = {
|
|
24
|
+
"node_modules", "venv", ".venv", "__pycache__", "target", "vendor",
|
|
25
|
+
"dist", "build", ".git", ".idea", ".vscode", "yncli.egg-info"
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
source_exts = {
|
|
29
|
+
".html", ".htm", ".css", ".js", ".jsx", ".ts", ".tsx", ".php",
|
|
30
|
+
".py", ".json", ".md", ".sql", ".yaml", ".yml", ".toml", ".rs", ".go"
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
self.indexed_files = {}
|
|
34
|
+
self.file_tree = []
|
|
35
|
+
|
|
36
|
+
try:
|
|
37
|
+
for root, dirs, files in os.walk(cwd):
|
|
38
|
+
dirs[:] = [d for d in dirs if d not in ignore_dirs and not d.startswith(".")]
|
|
39
|
+
rel_root = Path(root).relative_to(cwd)
|
|
40
|
+
|
|
41
|
+
for f in sorted(files):
|
|
42
|
+
if f.startswith(".") and f not in (".env", ".gitignore"):
|
|
43
|
+
continue
|
|
44
|
+
rel_f = rel_root / f if str(rel_root) != "." else Path(f)
|
|
45
|
+
posix_path = rel_f.as_posix()
|
|
46
|
+
self.file_tree.append(posix_path)
|
|
47
|
+
|
|
48
|
+
full_path = cwd / rel_f
|
|
49
|
+
ext = full_path.suffix.lower()
|
|
50
|
+
|
|
51
|
+
# Read all small project source files up to 25KB into memory
|
|
52
|
+
if (ext in source_exts or f in ("Dockerfile", "Makefile")) and len(self.indexed_files) < 20:
|
|
53
|
+
try:
|
|
54
|
+
size = full_path.stat().st_size
|
|
55
|
+
if 0 < size < 35000:
|
|
56
|
+
with open(full_path, "r", encoding="utf-8", errors="replace") as fp:
|
|
57
|
+
self.indexed_files[posix_path] = fp.read()
|
|
58
|
+
except Exception:
|
|
59
|
+
pass
|
|
60
|
+
except Exception:
|
|
61
|
+
pass
|
|
62
|
+
|
|
63
|
+
# Detect primary project type
|
|
64
|
+
fset = set(self.file_tree)
|
|
65
|
+
if "index.html" in fset or any(f.endswith(".html") for f in fset):
|
|
66
|
+
self.project_type = "Web Frontend (HTML/CSS/JS)"
|
|
67
|
+
elif "composer.json" in fset or "artisan" in fset or any(f.endswith(".php") for f in fset):
|
|
68
|
+
self.project_type = "PHP / Laravel"
|
|
69
|
+
elif "package.json" in fset:
|
|
70
|
+
self.project_type = "Node.js / JavaScript"
|
|
71
|
+
elif "requirements.txt" in fset or "pyproject.toml" in fset or any(f.endswith(".py") for f in fset):
|
|
72
|
+
self.project_type = "Python"
|
|
73
|
+
|
|
74
|
+
def get_context_for_prompt(self) -> str:
|
|
75
|
+
"""
|
|
76
|
+
Builds an exhaustive source code snapshot for the AI so it never needs to ask where files are.
|
|
77
|
+
"""
|
|
78
|
+
lines = []
|
|
79
|
+
lines.append(f"### WORKSPACE LOCATION: {self.workspace_dir}")
|
|
80
|
+
lines.append(f"### DETECTED PROJECT TYPE: {self.project_type}")
|
|
81
|
+
lines.append(f"### TOTAL WORKSPACE FILES ({len(self.file_tree)}):")
|
|
82
|
+
for f in self.file_tree[:30]:
|
|
83
|
+
lines.append(f" - {f}")
|
|
84
|
+
if len(self.file_tree) > 30:
|
|
85
|
+
lines.append(f" - ... ({len(self.file_tree) - 30} other files)")
|
|
86
|
+
|
|
87
|
+
if self.indexed_files:
|
|
88
|
+
lines.append("\n### COMPLETE PRE-LOADED PROJECT SOURCE FILES:")
|
|
89
|
+
for fname, content in self.indexed_files.items():
|
|
90
|
+
lines.append(f"\n========================================")
|
|
91
|
+
lines.append(f"FILE: `{fname}` ({len(content.splitlines())} lines)")
|
|
92
|
+
lines.append(f"========================================")
|
|
93
|
+
lines.append(content)
|
|
94
|
+
else:
|
|
95
|
+
lines.append("\n(No existing project source files found in workspace directory)")
|
|
96
|
+
|
|
97
|
+
return "\n".join(lines)
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import os
|
|
2
|
+
from pathlib import Path
|
|
3
|
+
from typing import Dict, Any, List
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
def scan_workspace_deep(workspace_dir: str = ".") -> Dict[str, Any]:
|
|
7
|
+
"""
|
|
8
|
+
Performs deep background workspace inspection, analyzing project structure,
|
|
9
|
+
key files, frameworks, and existing implementation state.
|
|
10
|
+
"""
|
|
11
|
+
cwd = Path(workspace_dir).resolve()
|
|
12
|
+
if not cwd.exists():
|
|
13
|
+
return {"summary": "Workspace directory not found.", "key_files": {}, "tree": []}
|
|
14
|
+
|
|
15
|
+
ignore_dirs = {
|
|
16
|
+
"node_modules", "venv", ".venv", "__pycache__", "target", "vendor",
|
|
17
|
+
"dist", "build", ".git", ".idea", ".vscode", "yncli.egg-info"
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
files_list: List[str] = []
|
|
21
|
+
dirs_list: List[str] = []
|
|
22
|
+
key_files_content: Dict[str, str] = {}
|
|
23
|
+
|
|
24
|
+
priority_files = [
|
|
25
|
+
"plan.md", "README.md", "package.json", "composer.json", "requirements.txt",
|
|
26
|
+
"index.html", "index.php", "main.py", "app.py", "Cargo.toml", "go.mod",
|
|
27
|
+
"style.css", "styles.css", "script.js", "app.js", "App.tsx", "App.jsx"
|
|
28
|
+
]
|
|
29
|
+
|
|
30
|
+
try:
|
|
31
|
+
for root, dirs, files in os.walk(cwd):
|
|
32
|
+
dirs[:] = [d for d in dirs if d not in ignore_dirs and not d.startswith(".")]
|
|
33
|
+
rel_root = Path(root).relative_to(cwd)
|
|
34
|
+
|
|
35
|
+
for d in dirs:
|
|
36
|
+
rel_d = rel_root / d if str(rel_root) != "." else Path(d)
|
|
37
|
+
dirs_list.append(f"{rel_d.as_posix()}/")
|
|
38
|
+
|
|
39
|
+
for f in sorted(files):
|
|
40
|
+
if f.startswith(".") and f not in (".env", ".gitignore"):
|
|
41
|
+
continue
|
|
42
|
+
rel_f = rel_root / f if str(rel_root) != "." else Path(f)
|
|
43
|
+
posix_path = rel_f.as_posix()
|
|
44
|
+
files_list.append(posix_path)
|
|
45
|
+
|
|
46
|
+
# Read key context files if small
|
|
47
|
+
if f in priority_files and len(key_files_content) < 6:
|
|
48
|
+
full_p = cwd / rel_f
|
|
49
|
+
try:
|
|
50
|
+
if full_p.stat().st_size < 30000:
|
|
51
|
+
with open(full_p, "r", encoding="utf-8", errors="replace") as fp:
|
|
52
|
+
snippet = fp.read(4000)
|
|
53
|
+
key_files_content[posix_path] = snippet
|
|
54
|
+
except Exception:
|
|
55
|
+
pass
|
|
56
|
+
except Exception as e:
|
|
57
|
+
return {"summary": f"Error scanning workspace: {e}", "key_files": {}, "tree": []}
|
|
58
|
+
|
|
59
|
+
return {
|
|
60
|
+
"cwd": str(cwd),
|
|
61
|
+
"total_files": len(files_list),
|
|
62
|
+
"total_dirs": len(dirs_list),
|
|
63
|
+
"files": files_list[:60],
|
|
64
|
+
"key_files": key_files_content
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
def format_workspace_context(scan_data: Dict[str, Any]) -> str:
|
|
69
|
+
"""
|
|
70
|
+
Formats the deep scan data into an executive architectural context for LLM system prompt.
|
|
71
|
+
"""
|
|
72
|
+
if not scan_data or "cwd" not in scan_data:
|
|
73
|
+
return "No workspace data available."
|
|
74
|
+
|
|
75
|
+
lines = []
|
|
76
|
+
lines.append(f"### Current Workspace: {scan_data['cwd']}")
|
|
77
|
+
lines.append(f"Total Detected Files: {scan_data.get('total_files', 0)} files")
|
|
78
|
+
|
|
79
|
+
files = scan_data.get("files", [])
|
|
80
|
+
if files:
|
|
81
|
+
lines.append("### Project File Structure:")
|
|
82
|
+
for f in files[:35]:
|
|
83
|
+
lines.append(f" - {f}")
|
|
84
|
+
if len(files) > 35:
|
|
85
|
+
lines.append(f" - ... ({len(files) - 35} more files)")
|
|
86
|
+
else:
|
|
87
|
+
lines.append("### Project File Structure: (Empty workspace directory)")
|
|
88
|
+
|
|
89
|
+
key_files = scan_data.get("key_files", {})
|
|
90
|
+
if key_files:
|
|
91
|
+
lines.append("\n### Key Project Files Overview:")
|
|
92
|
+
for fname, content in key_files.items():
|
|
93
|
+
lines.append(f"#### File: `{fname}`")
|
|
94
|
+
lines.append("```")
|
|
95
|
+
preview = "\n".join(content.splitlines()[:25])
|
|
96
|
+
lines.append(preview)
|
|
97
|
+
lines.append("```")
|
|
98
|
+
|
|
99
|
+
return "\n".join(lines)
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: yncli
|
|
3
|
+
Version: 1.0.0
|
|
4
|
+
Summary: Autonomous Polyglot AI Coding Agent & TUI
|
|
5
|
+
Author: YNCLI Team
|
|
6
|
+
Requires-Python: >=3.8
|
|
7
|
+
Description-Content-Type: text/markdown
|
|
8
|
+
Requires-Dist: rich>=13.7.0
|
|
9
|
+
Requires-Dist: prompt_toolkit>=3.0.40
|
|
10
|
+
Requires-Dist: requests>=2.31.0
|
|
11
|
+
Requires-Dist: duckduckgo-search>=6.0.0
|
|
12
|
+
Requires-Dist: beautifulsoup4>=4.12.0
|
|
13
|
+
Requires-Dist: pygments>=2.17.0
|
|
14
|
+
Dynamic: author
|
|
15
|
+
Dynamic: requires-python
|
|
16
|
+
|
|
17
|
+
# ⚡ YNCLI: World-Class Autonomous Polyglot AI Coding Agent & TUI
|
|
18
|
+
|
|
19
|
+
YNCLI adalah AI Coding Agent berbasis CLI/TUI mandiri yang mendukung:
|
|
20
|
+
- **Polyglot Coding Engine**: Menguasai Python, TypeScript/JavaScript, Rust, Go, C/C++, Java/Kotlin, C#/.NET, PHP, Ruby, Dart/Flutter, Swift, SQL, Shell, dan Web stack.
|
|
21
|
+
- **Dynamic Language & Framework Detection**: Otomatis mendeteksi arsitektur project dan menginjeksi idiomatic patterns ke dalam agent.
|
|
22
|
+
- **Autonomous ReAct Loop**: AI dapat membaca file, menulis file, melakukan surgical patch, mencari kode via grep, memvalidasi sintaks via compiler/linter, dan menjalankan perintah di terminal.
|
|
23
|
+
- **Real-Time Date & Environment Awareness**: Mengetahui waktu, tanggal, hari lokal secara real-time.
|
|
24
|
+
- **Thinking / Reasoning Visualizer**: Menampilkan penalaran model (seperti Gemini 3.7 Flash High / Claude 4.6 Thinking) secara live.
|
|
25
|
+
- **Real-time Web Search & Scraper**: DuckDuckGo search + HTML-to-markdown reader bawaan.
|
|
26
|
+
- **Dynamic Skills System**: Mode Architect, Debugger, Code Reviewer, Test Runner, dan Polyglot.
|
|
27
|
+
|
|
28
|
+
## Cara Menggunakan
|
|
29
|
+
|
|
30
|
+
Cukup ketik perintah berikut di PowerShell atau Command Prompt mana saja:
|
|
31
|
+
|
|
32
|
+
### 1. Masuk ke Mode TUI Interaktif:
|
|
33
|
+
```powershell
|
|
34
|
+
yncli
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
### 2. Mode Direct Execution (Quick Query):
|
|
38
|
+
```powershell
|
|
39
|
+
yncli "buatkan script rest api fastapi lengkap dengan jwt auth"
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
### 3. Opsi Tambahan:
|
|
43
|
+
```powershell
|
|
44
|
+
# Ganti model
|
|
45
|
+
yncli -m ag/claude-sonnet-4-6
|
|
46
|
+
|
|
47
|
+
# Aktifkan skill tertentu
|
|
48
|
+
yncli -s architect
|
|
49
|
+
|
|
50
|
+
# Lihat daftar model yang tersedia di endpoint
|
|
51
|
+
yncli --list-models
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
### Slash Commands di dalam TUI:
|
|
55
|
+
- `/model <nama>`: Ganti model AI aktif
|
|
56
|
+
- `/models`: Lihat semua model AI dari endpoint
|
|
57
|
+
- `/skill <nama>`: Aktifkan skill (polyglot, architect, debugger, code_review, test_runner)
|
|
58
|
+
- `/skills`: Lihat semua skill yang tersedia
|
|
59
|
+
- `/tools`: Lihat daftar tools coding yang aktif
|
|
60
|
+
- `/clear`: Reset memory percakapan
|
|
61
|
+
- `/history`: Lihat ringkasan percakapan
|
|
62
|
+
- `/save [file]`: Export percakapan ke Markdown
|
|
63
|
+
- `/exit`: Keluar
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
yncli/__init__.py,sha256=7VvDOot5C5ccdADH58Jrm2JlCKKecHmrG_Seq-s8N3U,80
|
|
2
|
+
yncli/agent.py,sha256=LRjtCtqWWlbQ-mxtCosTYNv63vH06L36OjMZ5aOBwAs,12388
|
|
3
|
+
yncli/clean_text.py,sha256=vw95KVDrBt5rug0AGeMpv4JOFMXB0DcmbBrOMuqVjjY,2034
|
|
4
|
+
yncli/client.py,sha256=xaPbnghCtOv4jTFkUuNwtPKtY66QnvalXljQPl18SFE,5428
|
|
5
|
+
yncli/config.py,sha256=onxEobwZkon6E8UVXMScFZ0gmf4LX1OX48zfM0Ooe0Y,1301
|
|
6
|
+
yncli/language_detector.py,sha256=qAD5gS0CqObtvA8akD6yTDJE2w712Bxuaffmoo0Msqk,9043
|
|
7
|
+
yncli/main.py,sha256=mrCaVHflCcH626xws2tdpRCoE1YTtz7W3dANq6q9zS8,3956
|
|
8
|
+
yncli/skills_manager.py,sha256=UpXaGRpgDRycx33Ps0NKrRCG06ONXd2WRzk8FRfNaWA,2377
|
|
9
|
+
yncli/system_prompt.py,sha256=b5M09FrbPW10oCu6VJixh7tXxMbQJkePT3BDX6m1CKY,5911
|
|
10
|
+
yncli/tui.py,sha256=aZPUbYTAid800to_HVRLsMStwLoUlM1obINtEfHuu2M,24031
|
|
11
|
+
yncli/workspace_memory.py,sha256=_nTJ10IY9yPjcQsIIeOBQpjmVfQT6E28wWLlv8stAlQ,4119
|
|
12
|
+
yncli/workspace_scanner.py,sha256=V-KJG8j92AbxO2fnbN8iFCm7TF_zp9W9aY-yzC7M0Ec,3720
|
|
13
|
+
yncli/built_in_skills/architect.md,sha256=zr6bf71DXsguHNLUxp31q4U214Zk2hz2O0DvnnKC2t0,714
|
|
14
|
+
yncli/built_in_skills/code_review.md,sha256=UYRyaidGYcV2x07jZYjd7eaDUKaVA6QgxojqmnDogzI,704
|
|
15
|
+
yncli/built_in_skills/debug_oracle.md,sha256=7eoCA5xcg1pyZe4BuQvegofVJvxOvHoQEcdVbFLJGLs,908
|
|
16
|
+
yncli/built_in_skills/debugger.md,sha256=q6dcCjtk84Khvi8LYXWh3jAlGZTqjtBR1rn7Vj9OOlA,793
|
|
17
|
+
yncli/built_in_skills/polyglot.md,sha256=ToqMfN0IHYzm6e9RodnqIagPKWaRmyQxdvr_a1hlbTA,1545
|
|
18
|
+
yncli/built_in_skills/refactor_master.md,sha256=hxxccZXVqlp9rEzP7Lr5yK0K3FS3NfdHWlD1nn1ZAto,1061
|
|
19
|
+
yncli/built_in_skills/security_auditor.md,sha256=TQahVOfz2VfwHtHEuyZIUQPAiU_2kL9EEtj8MSkJDEo,1242
|
|
20
|
+
yncli/built_in_skills/system_architect.md,sha256=j0sHJqQgCBpIWLTFAYkiNL5JSi04F_h1bQ3kW40wSqY,789
|
|
21
|
+
yncli/built_in_skills/test_runner.md,sha256=sS-FW5y5KcZ-lCDKKXUImSiBNKxmdmELY1G8vOQ1gBQ,793
|
|
22
|
+
yncli/built_in_skills/ultrabrain.md,sha256=JewfCyRwzt_oev-Khj0C4iGV4cxCMjTgrNgUIe-azAo,1583
|
|
23
|
+
yncli/tools/__init__.py,sha256=P5HmDzhcc0O6x3uLHq9Tvh-xWXhNRgcgZOhkTwrzxu8,11674
|
|
24
|
+
yncli/tools/file_tools.py,sha256=qghfoKGxq-XiedEOqU0P6GU6xhlbr0hOen8a5jLfqbQ,8577
|
|
25
|
+
yncli/tools/polyglot_tools.py,sha256=hm2EteZ3v9PgeuCDYszmYMW7Y__Xshn18kYaddaNw6g,5470
|
|
26
|
+
yncli/tools/search_tools.py,sha256=EUC8mk19En3rAfHmCTbXsE3gCkYh3E-WHGMw1vMKG-s,2344
|
|
27
|
+
yncli/tools/system_tools.py,sha256=4PYImZUYscxQS6_rGJspa4ttX-2HRNoChLue1oXtezM,4587
|
|
28
|
+
yncli-1.0.0.dist-info/METADATA,sha256=8JUTPQDL53qtWWJPqT9zmriNeadE5ZpYa98yHNfoYzk,2490
|
|
29
|
+
yncli-1.0.0.dist-info/WHEEL,sha256=YVMoNqKzERt-wjUZwJ33xBGAwnFl-4cqbYkTtWa4itE,91
|
|
30
|
+
yncli-1.0.0.dist-info/entry_points.txt,sha256=YvlvvcUrBuvBkCq7LZzQ-AKXY3jDnhUNFUvmhxFejyU,42
|
|
31
|
+
yncli-1.0.0.dist-info/top_level.txt,sha256=FBSylTcPyJt8Jur-0awK08GNAjtYqQHvRagrqMxEYIU,6
|
|
32
|
+
yncli-1.0.0.dist-info/RECORD,,
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
yncli
|