tzamuncode 0.1.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.
- tzamuncode/__init__.py +10 -0
- tzamuncode/agents/__init__.py +1 -0
- tzamuncode/agents/coder.py +144 -0
- tzamuncode/agents/tools.py +159 -0
- tzamuncode/auth/__init__.py +1 -0
- tzamuncode/auth/auth_manager.py +159 -0
- tzamuncode/cli/__init__.py +1 -0
- tzamuncode/cli/agentic_commands.py +131 -0
- tzamuncode/cli/auth_commands.py +125 -0
- tzamuncode/cli/commands.py +203 -0
- tzamuncode/cli/enhanced_chat.py +312 -0
- tzamuncode/cli/interactive_chat.py +323 -0
- tzamuncode/cli/main.py +444 -0
- tzamuncode/cli/realtime_chat.py +965 -0
- tzamuncode/cli/realtime_chat_methods.py +200 -0
- tzamuncode/cli/tui_chat.py +323 -0
- tzamuncode/config/__init__.py +1 -0
- tzamuncode/models/__init__.py +1 -0
- tzamuncode/models/ollama.py +124 -0
- tzamuncode/models/vllm_client.py +121 -0
- tzamuncode/utils/__init__.py +1 -0
- tzamuncode/utils/file_ops.py +59 -0
- tzamuncode/utils/project_scanner.py +193 -0
- tzamuncode-0.1.0.dist-info/METADATA +200 -0
- tzamuncode-0.1.0.dist-info/RECORD +29 -0
- tzamuncode-0.1.0.dist-info/WHEEL +5 -0
- tzamuncode-0.1.0.dist-info/entry_points.txt +3 -0
- tzamuncode-0.1.0.dist-info/licenses/LICENSE +21 -0
- tzamuncode-0.1.0.dist-info/top_level.txt +1 -0
tzamuncode/__init__.py
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"""Agentic AI module for TzamunCode"""
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Agentic Coder - Advanced AI coding agent with file access and tool calling
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
from typing import List, Dict, Optional, Any
|
|
6
|
+
from pathlib import Path
|
|
7
|
+
import json
|
|
8
|
+
|
|
9
|
+
from langchain.agents import initialize_agent, Tool, AgentType
|
|
10
|
+
from langchain.memory import ConversationBufferMemory
|
|
11
|
+
from langchain_community.llms import Ollama
|
|
12
|
+
|
|
13
|
+
from ..utils.file_ops import FileManager
|
|
14
|
+
from ..utils.project_scanner import ProjectScanner
|
|
15
|
+
from .tools import create_tools
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class AgenticCoder:
|
|
19
|
+
"""
|
|
20
|
+
Advanced AI coding agent with file access and autonomous capabilities.
|
|
21
|
+
|
|
22
|
+
Similar to Claude Code, this agent can:
|
|
23
|
+
- Read and write files autonomously
|
|
24
|
+
- Scan project structure
|
|
25
|
+
- Edit multiple files
|
|
26
|
+
- Execute git operations
|
|
27
|
+
- Search codebase
|
|
28
|
+
- Plan multi-step tasks
|
|
29
|
+
"""
|
|
30
|
+
|
|
31
|
+
def __init__(
|
|
32
|
+
self,
|
|
33
|
+
model: str = "qwen2.5:32b",
|
|
34
|
+
base_url: str = "http://localhost:11434",
|
|
35
|
+
workspace: Optional[str] = None
|
|
36
|
+
):
|
|
37
|
+
self.model = model
|
|
38
|
+
self.base_url = base_url
|
|
39
|
+
self.workspace = Path(workspace) if workspace else Path.cwd()
|
|
40
|
+
|
|
41
|
+
# Initialize components
|
|
42
|
+
self.file_manager = FileManager()
|
|
43
|
+
self.project_scanner = ProjectScanner(self.workspace)
|
|
44
|
+
|
|
45
|
+
# Initialize LLM
|
|
46
|
+
self.llm = Ollama(
|
|
47
|
+
model=model,
|
|
48
|
+
base_url=base_url,
|
|
49
|
+
temperature=0.7
|
|
50
|
+
)
|
|
51
|
+
|
|
52
|
+
# Create tools
|
|
53
|
+
self.tools = create_tools(
|
|
54
|
+
file_manager=self.file_manager,
|
|
55
|
+
project_scanner=self.project_scanner,
|
|
56
|
+
workspace=self.workspace
|
|
57
|
+
)
|
|
58
|
+
|
|
59
|
+
# Initialize memory
|
|
60
|
+
self.memory = ConversationBufferMemory(
|
|
61
|
+
memory_key="chat_history",
|
|
62
|
+
return_messages=True
|
|
63
|
+
)
|
|
64
|
+
|
|
65
|
+
# Initialize agent
|
|
66
|
+
self.agent = initialize_agent(
|
|
67
|
+
tools=self.tools,
|
|
68
|
+
llm=self.llm,
|
|
69
|
+
agent=AgentType.STRUCTURED_CHAT_ZERO_SHOT_REACT_DESCRIPTION,
|
|
70
|
+
verbose=True,
|
|
71
|
+
memory=self.memory,
|
|
72
|
+
handle_parsing_errors=True,
|
|
73
|
+
max_iterations=10
|
|
74
|
+
)
|
|
75
|
+
|
|
76
|
+
def execute(self, instruction: str) -> Dict[str, Any]:
|
|
77
|
+
"""
|
|
78
|
+
Execute an instruction using the agentic AI.
|
|
79
|
+
|
|
80
|
+
The agent will autonomously:
|
|
81
|
+
- Scan project if needed
|
|
82
|
+
- Read relevant files
|
|
83
|
+
- Plan the changes
|
|
84
|
+
- Edit multiple files
|
|
85
|
+
- Provide summary
|
|
86
|
+
|
|
87
|
+
Args:
|
|
88
|
+
instruction: What to do (e.g., "Add authentication to this Flask app")
|
|
89
|
+
|
|
90
|
+
Returns:
|
|
91
|
+
Dict with result, files_changed, and summary
|
|
92
|
+
"""
|
|
93
|
+
# Add context about workspace
|
|
94
|
+
context = f"""You are working in: {self.workspace}
|
|
95
|
+
|
|
96
|
+
Available tools:
|
|
97
|
+
- read_file: Read any file in the project
|
|
98
|
+
- write_file: Write/create files
|
|
99
|
+
- list_files: List files in directories
|
|
100
|
+
- search_code: Search for code patterns
|
|
101
|
+
- git_status: Check git status
|
|
102
|
+
- scan_project: Understand project structure
|
|
103
|
+
|
|
104
|
+
Instruction: {instruction}
|
|
105
|
+
|
|
106
|
+
Think step by step:
|
|
107
|
+
1. Understand what needs to be done
|
|
108
|
+
2. Scan project structure if needed
|
|
109
|
+
3. Read relevant files
|
|
110
|
+
4. Plan the changes
|
|
111
|
+
5. Make the changes
|
|
112
|
+
6. Summarize what was done
|
|
113
|
+
"""
|
|
114
|
+
|
|
115
|
+
try:
|
|
116
|
+
result = self.agent.run(context)
|
|
117
|
+
|
|
118
|
+
return {
|
|
119
|
+
"success": True,
|
|
120
|
+
"result": result,
|
|
121
|
+
"workspace": str(self.workspace)
|
|
122
|
+
}
|
|
123
|
+
except Exception as e:
|
|
124
|
+
return {
|
|
125
|
+
"success": False,
|
|
126
|
+
"error": str(e),
|
|
127
|
+
"workspace": str(self.workspace)
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
def chat(self, message: str) -> str:
|
|
131
|
+
"""
|
|
132
|
+
Chat with the agent while maintaining context.
|
|
133
|
+
|
|
134
|
+
Args:
|
|
135
|
+
message: User message
|
|
136
|
+
|
|
137
|
+
Returns:
|
|
138
|
+
Agent response
|
|
139
|
+
"""
|
|
140
|
+
return self.agent.run(message)
|
|
141
|
+
|
|
142
|
+
def reset_memory(self):
|
|
143
|
+
"""Reset conversation memory"""
|
|
144
|
+
self.memory.clear()
|
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Tool definitions for the agentic coder
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
from langchain.tools import Tool
|
|
6
|
+
from pathlib import Path
|
|
7
|
+
from typing import List
|
|
8
|
+
import subprocess
|
|
9
|
+
import os
|
|
10
|
+
|
|
11
|
+
from ..utils.file_ops import FileManager
|
|
12
|
+
from ..utils.project_scanner import ProjectScanner
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def create_tools(
|
|
16
|
+
file_manager: FileManager,
|
|
17
|
+
project_scanner: ProjectScanner,
|
|
18
|
+
workspace: Path
|
|
19
|
+
) -> List[Tool]:
|
|
20
|
+
"""Create tools for the agent"""
|
|
21
|
+
|
|
22
|
+
def read_file_tool(file_path: str) -> str:
|
|
23
|
+
"""Read a file from the project"""
|
|
24
|
+
try:
|
|
25
|
+
full_path = workspace / file_path
|
|
26
|
+
return file_manager.read_file(str(full_path))
|
|
27
|
+
except Exception as e:
|
|
28
|
+
return f"Error reading file: {e}"
|
|
29
|
+
|
|
30
|
+
def write_file_tool(args: str) -> str:
|
|
31
|
+
"""
|
|
32
|
+
Write content to a file.
|
|
33
|
+
Args should be: file_path|||content
|
|
34
|
+
"""
|
|
35
|
+
try:
|
|
36
|
+
parts = args.split("|||", 1)
|
|
37
|
+
if len(parts) != 2:
|
|
38
|
+
return "Error: Use format 'file_path|||content'"
|
|
39
|
+
|
|
40
|
+
file_path, content = parts
|
|
41
|
+
full_path = workspace / file_path.strip()
|
|
42
|
+
file_manager.write_file(str(full_path), content.strip())
|
|
43
|
+
return f"Successfully wrote to {file_path}"
|
|
44
|
+
except Exception as e:
|
|
45
|
+
return f"Error writing file: {e}"
|
|
46
|
+
|
|
47
|
+
def list_files_tool(directory: str = ".") -> str:
|
|
48
|
+
"""List files in a directory"""
|
|
49
|
+
try:
|
|
50
|
+
dir_path = workspace / directory
|
|
51
|
+
files = file_manager.list_files(str(dir_path))
|
|
52
|
+
return "\n".join(files[:50]) # Limit to 50 files
|
|
53
|
+
except Exception as e:
|
|
54
|
+
return f"Error listing files: {e}"
|
|
55
|
+
|
|
56
|
+
def search_code_tool(pattern: str) -> str:
|
|
57
|
+
"""Search for code pattern in project"""
|
|
58
|
+
try:
|
|
59
|
+
result = subprocess.run(
|
|
60
|
+
["grep", "-r", "-n", pattern, str(workspace)],
|
|
61
|
+
capture_output=True,
|
|
62
|
+
text=True,
|
|
63
|
+
timeout=10
|
|
64
|
+
)
|
|
65
|
+
output = result.stdout[:2000] # Limit output
|
|
66
|
+
return output if output else "No matches found"
|
|
67
|
+
except Exception as e:
|
|
68
|
+
return f"Error searching: {e}"
|
|
69
|
+
|
|
70
|
+
def git_status_tool(_: str = "") -> str:
|
|
71
|
+
"""Check git status"""
|
|
72
|
+
try:
|
|
73
|
+
result = subprocess.run(
|
|
74
|
+
["git", "status", "--short"],
|
|
75
|
+
cwd=workspace,
|
|
76
|
+
capture_output=True,
|
|
77
|
+
text=True,
|
|
78
|
+
timeout=5
|
|
79
|
+
)
|
|
80
|
+
return result.stdout if result.stdout else "No changes"
|
|
81
|
+
except Exception as e:
|
|
82
|
+
return f"Error checking git: {e}"
|
|
83
|
+
|
|
84
|
+
def scan_project_tool(_: str = "") -> str:
|
|
85
|
+
"""Scan and understand project structure"""
|
|
86
|
+
try:
|
|
87
|
+
structure = project_scanner.scan()
|
|
88
|
+
return f"""Project Structure:
|
|
89
|
+
Files: {structure['total_files']}
|
|
90
|
+
Directories: {structure['total_dirs']}
|
|
91
|
+
Languages: {', '.join(structure['languages'])}
|
|
92
|
+
|
|
93
|
+
Key files:
|
|
94
|
+
{chr(10).join(structure['key_files'][:10])}
|
|
95
|
+
"""
|
|
96
|
+
except Exception as e:
|
|
97
|
+
return f"Error scanning project: {e}"
|
|
98
|
+
|
|
99
|
+
def execute_command_tool(command: str) -> str:
|
|
100
|
+
"""Execute a shell command (use with caution)"""
|
|
101
|
+
try:
|
|
102
|
+
# Whitelist safe commands
|
|
103
|
+
safe_commands = ['ls', 'pwd', 'cat', 'grep', 'find', 'git']
|
|
104
|
+
cmd_parts = command.split()
|
|
105
|
+
if not cmd_parts or cmd_parts[0] not in safe_commands:
|
|
106
|
+
return f"Error: Command '{cmd_parts[0] if cmd_parts else 'empty'}' not allowed"
|
|
107
|
+
|
|
108
|
+
result = subprocess.run(
|
|
109
|
+
command,
|
|
110
|
+
shell=True,
|
|
111
|
+
cwd=workspace,
|
|
112
|
+
capture_output=True,
|
|
113
|
+
text=True,
|
|
114
|
+
timeout=10
|
|
115
|
+
)
|
|
116
|
+
return result.stdout[:1000] # Limit output
|
|
117
|
+
except Exception as e:
|
|
118
|
+
return f"Error executing command: {e}"
|
|
119
|
+
|
|
120
|
+
# Create tool list
|
|
121
|
+
tools = [
|
|
122
|
+
Tool(
|
|
123
|
+
name="read_file",
|
|
124
|
+
func=read_file_tool,
|
|
125
|
+
description="Read a file from the project. Input: file path relative to project root"
|
|
126
|
+
),
|
|
127
|
+
Tool(
|
|
128
|
+
name="write_file",
|
|
129
|
+
func=write_file_tool,
|
|
130
|
+
description="Write content to a file. Input: 'file_path|||content' (use ||| as separator)"
|
|
131
|
+
),
|
|
132
|
+
Tool(
|
|
133
|
+
name="list_files",
|
|
134
|
+
func=list_files_tool,
|
|
135
|
+
description="List files in a directory. Input: directory path (default: current directory)"
|
|
136
|
+
),
|
|
137
|
+
Tool(
|
|
138
|
+
name="search_code",
|
|
139
|
+
func=search_code_tool,
|
|
140
|
+
description="Search for a pattern in the codebase. Input: search pattern"
|
|
141
|
+
),
|
|
142
|
+
Tool(
|
|
143
|
+
name="git_status",
|
|
144
|
+
func=git_status_tool,
|
|
145
|
+
description="Check git status. Input: empty string"
|
|
146
|
+
),
|
|
147
|
+
Tool(
|
|
148
|
+
name="scan_project",
|
|
149
|
+
func=scan_project_tool,
|
|
150
|
+
description="Scan and understand project structure. Input: empty string"
|
|
151
|
+
),
|
|
152
|
+
Tool(
|
|
153
|
+
name="execute_command",
|
|
154
|
+
func=execute_command_tool,
|
|
155
|
+
description="Execute a safe shell command. Input: command to execute"
|
|
156
|
+
),
|
|
157
|
+
]
|
|
158
|
+
|
|
159
|
+
return tools
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"""Authentication module for TzamunCode"""
|
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Authentication Manager for TzamunCode
|
|
3
|
+
Supports username/password and API key authentication with TzamunAI
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
import requests
|
|
7
|
+
import json
|
|
8
|
+
from pathlib import Path
|
|
9
|
+
from typing import Optional, Dict
|
|
10
|
+
import hashlib
|
|
11
|
+
from datetime import datetime, timedelta
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class AuthManager:
|
|
15
|
+
"""Manage authentication for TzamunCode CLI"""
|
|
16
|
+
|
|
17
|
+
CONFIG_DIR = Path.home() / ".tzamuncode"
|
|
18
|
+
CONFIG_FILE = CONFIG_DIR / "auth.json"
|
|
19
|
+
TZAMUN_API_BASE = "http://192.168.1.141:3008" # Local Tzamun backend
|
|
20
|
+
|
|
21
|
+
def __init__(self):
|
|
22
|
+
self.CONFIG_DIR.mkdir(exist_ok=True)
|
|
23
|
+
self.auth_data = self.load_auth()
|
|
24
|
+
|
|
25
|
+
def load_auth(self) -> Dict:
|
|
26
|
+
"""Load authentication data from config file"""
|
|
27
|
+
if self.CONFIG_FILE.exists():
|
|
28
|
+
try:
|
|
29
|
+
with open(self.CONFIG_FILE, 'r') as f:
|
|
30
|
+
return json.load(f)
|
|
31
|
+
except:
|
|
32
|
+
return {}
|
|
33
|
+
return {}
|
|
34
|
+
|
|
35
|
+
def save_auth(self, auth_data: Dict):
|
|
36
|
+
"""Save authentication data to config file"""
|
|
37
|
+
with open(self.CONFIG_FILE, 'w') as f:
|
|
38
|
+
json.dump(auth_data, f, indent=2)
|
|
39
|
+
# Secure the file (only owner can read/write)
|
|
40
|
+
self.CONFIG_FILE.chmod(0o600)
|
|
41
|
+
|
|
42
|
+
def is_authenticated(self) -> bool:
|
|
43
|
+
"""Check if user is authenticated"""
|
|
44
|
+
if not self.auth_data:
|
|
45
|
+
return False
|
|
46
|
+
|
|
47
|
+
# Check if token is expired
|
|
48
|
+
if 'expires_at' in self.auth_data:
|
|
49
|
+
expires_at = datetime.fromisoformat(self.auth_data['expires_at'])
|
|
50
|
+
if datetime.now() > expires_at:
|
|
51
|
+
return False
|
|
52
|
+
|
|
53
|
+
return 'api_key' in self.auth_data or 'token' in self.auth_data
|
|
54
|
+
|
|
55
|
+
def login_with_credentials(self, username: str, password: str) -> bool:
|
|
56
|
+
"""
|
|
57
|
+
Login with username and password
|
|
58
|
+
|
|
59
|
+
Args:
|
|
60
|
+
username: TzamunAI username
|
|
61
|
+
password: TzamunAI password
|
|
62
|
+
|
|
63
|
+
Returns:
|
|
64
|
+
True if login successful
|
|
65
|
+
"""
|
|
66
|
+
try:
|
|
67
|
+
# Call TzamunAI login API
|
|
68
|
+
response = requests.post(
|
|
69
|
+
f"{self.TZAMUN_API_BASE}/api/auth/login",
|
|
70
|
+
json={
|
|
71
|
+
"username": username,
|
|
72
|
+
"password": password
|
|
73
|
+
},
|
|
74
|
+
timeout=10
|
|
75
|
+
)
|
|
76
|
+
|
|
77
|
+
if response.status_code == 200:
|
|
78
|
+
data = response.json()
|
|
79
|
+
|
|
80
|
+
# Save auth token
|
|
81
|
+
self.auth_data = {
|
|
82
|
+
'type': 'credentials',
|
|
83
|
+
'username': username,
|
|
84
|
+
'token': data.get('token'),
|
|
85
|
+
'expires_at': (datetime.now() + timedelta(days=30)).isoformat()
|
|
86
|
+
}
|
|
87
|
+
self.save_auth(self.auth_data)
|
|
88
|
+
return True
|
|
89
|
+
|
|
90
|
+
return False
|
|
91
|
+
|
|
92
|
+
except Exception as e:
|
|
93
|
+
print(f"Login error: {e}")
|
|
94
|
+
return False
|
|
95
|
+
|
|
96
|
+
def login_with_api_key(self, api_key: str) -> bool:
|
|
97
|
+
"""
|
|
98
|
+
Login with TzamunAI API key
|
|
99
|
+
|
|
100
|
+
Args:
|
|
101
|
+
api_key: TzamunAI API key (from TCHub)
|
|
102
|
+
|
|
103
|
+
Returns:
|
|
104
|
+
True if API key is valid
|
|
105
|
+
"""
|
|
106
|
+
try:
|
|
107
|
+
# Validate API key with TzamunAI
|
|
108
|
+
response = requests.get(
|
|
109
|
+
f"{self.TZAMUN_API_BASE}/api/v1/tchub/validate",
|
|
110
|
+
headers={
|
|
111
|
+
'X-API-Key': api_key
|
|
112
|
+
},
|
|
113
|
+
timeout=10
|
|
114
|
+
)
|
|
115
|
+
|
|
116
|
+
if response.status_code == 200:
|
|
117
|
+
# Save API key
|
|
118
|
+
self.auth_data = {
|
|
119
|
+
'type': 'api_key',
|
|
120
|
+
'api_key': api_key,
|
|
121
|
+
'validated_at': datetime.now().isoformat()
|
|
122
|
+
}
|
|
123
|
+
self.save_auth(self.auth_data)
|
|
124
|
+
return True
|
|
125
|
+
|
|
126
|
+
return False
|
|
127
|
+
|
|
128
|
+
except Exception as e:
|
|
129
|
+
print(f"API key validation error: {e}")
|
|
130
|
+
return False
|
|
131
|
+
|
|
132
|
+
def logout(self):
|
|
133
|
+
"""Logout and clear authentication data"""
|
|
134
|
+
self.auth_data = {}
|
|
135
|
+
if self.CONFIG_FILE.exists():
|
|
136
|
+
self.CONFIG_FILE.unlink()
|
|
137
|
+
|
|
138
|
+
def get_auth_header(self) -> Dict[str, str]:
|
|
139
|
+
"""Get authentication header for API requests"""
|
|
140
|
+
if not self.is_authenticated():
|
|
141
|
+
return {}
|
|
142
|
+
|
|
143
|
+
if self.auth_data.get('type') == 'api_key':
|
|
144
|
+
return {'X-API-Key': self.auth_data['api_key']}
|
|
145
|
+
elif self.auth_data.get('type') == 'credentials':
|
|
146
|
+
return {'Authorization': f"Bearer {self.auth_data['token']}"}
|
|
147
|
+
|
|
148
|
+
return {}
|
|
149
|
+
|
|
150
|
+
def get_user_info(self) -> Dict:
|
|
151
|
+
"""Get current user information"""
|
|
152
|
+
if not self.is_authenticated():
|
|
153
|
+
return {}
|
|
154
|
+
|
|
155
|
+
return {
|
|
156
|
+
'type': self.auth_data.get('type'),
|
|
157
|
+
'username': self.auth_data.get('username', 'API Key User'),
|
|
158
|
+
'authenticated': True
|
|
159
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"""CLI module for TzamunCode"""
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Agentic commands - Advanced AI operations with autonomous file access
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
from rich.console import Console
|
|
6
|
+
from rich.panel import Panel
|
|
7
|
+
from rich.markdown import Markdown
|
|
8
|
+
from rich.prompt import Confirm
|
|
9
|
+
from rich.live import Live
|
|
10
|
+
from rich.status import Status
|
|
11
|
+
from typing import Optional
|
|
12
|
+
import sys
|
|
13
|
+
|
|
14
|
+
from ..agents.coder import AgenticCoder
|
|
15
|
+
|
|
16
|
+
console = Console()
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def agentic_command(
|
|
20
|
+
instruction: str,
|
|
21
|
+
model: str = "qwen2.5:32b",
|
|
22
|
+
workspace: Optional[str] = None,
|
|
23
|
+
auto_apply: bool = False
|
|
24
|
+
):
|
|
25
|
+
"""
|
|
26
|
+
Execute an instruction using agentic AI with autonomous file access.
|
|
27
|
+
|
|
28
|
+
This is similar to Claude Code - the AI can:
|
|
29
|
+
- Scan your project
|
|
30
|
+
- Read files autonomously
|
|
31
|
+
- Write/edit multiple files
|
|
32
|
+
- Execute git operations
|
|
33
|
+
- Plan multi-step tasks
|
|
34
|
+
|
|
35
|
+
Args:
|
|
36
|
+
instruction: What to do (e.g., "Add authentication to this Flask app")
|
|
37
|
+
model: Model to use
|
|
38
|
+
workspace: Project directory (default: current directory)
|
|
39
|
+
auto_apply: Apply changes without confirmation
|
|
40
|
+
"""
|
|
41
|
+
console.print(f"\n[bold blue]TzamunCode Agentic Mode[/bold blue]")
|
|
42
|
+
console.print(f"[dim]Model: {model}[/dim]")
|
|
43
|
+
console.print(f"[dim]Workspace: {workspace or 'current directory'}[/dim]\n")
|
|
44
|
+
|
|
45
|
+
console.print(Panel(
|
|
46
|
+
f"[bold]Instruction:[/bold]\n{instruction}\n\n"
|
|
47
|
+
"[dim]The AI will autonomously:\n"
|
|
48
|
+
"β’ Scan project structure\n"
|
|
49
|
+
"β’ Read relevant files\n"
|
|
50
|
+
"β’ Plan changes\n"
|
|
51
|
+
"β’ Edit multiple files\n"
|
|
52
|
+
"β’ Provide summary[/dim]",
|
|
53
|
+
border_style="blue"
|
|
54
|
+
))
|
|
55
|
+
|
|
56
|
+
if not auto_apply:
|
|
57
|
+
if not Confirm.ask("\n[bold]Allow AI to access and modify files?[/bold]"):
|
|
58
|
+
console.print("[dim]Cancelled[/dim]")
|
|
59
|
+
return
|
|
60
|
+
|
|
61
|
+
# Initialize agentic coder
|
|
62
|
+
with console.status("[bold blue]Initializing AI agent...", spinner="dots"):
|
|
63
|
+
try:
|
|
64
|
+
agent = AgenticCoder(
|
|
65
|
+
model=model,
|
|
66
|
+
workspace=workspace
|
|
67
|
+
)
|
|
68
|
+
except Exception as e:
|
|
69
|
+
console.print(f"[bold red]Error:[/bold red] Failed to initialize agent: {e}")
|
|
70
|
+
return
|
|
71
|
+
|
|
72
|
+
console.print("[bold green]β[/bold green] Agent initialized\n")
|
|
73
|
+
|
|
74
|
+
# Execute instruction
|
|
75
|
+
console.print("[bold blue]AI is working...[/bold blue]\n")
|
|
76
|
+
|
|
77
|
+
try:
|
|
78
|
+
with Live(console=console, refresh_per_second=4) as live:
|
|
79
|
+
result = agent.execute(instruction)
|
|
80
|
+
|
|
81
|
+
if result['success']:
|
|
82
|
+
console.print("\n[bold green]β Task completed![/bold green]\n")
|
|
83
|
+
console.print(Panel(
|
|
84
|
+
Markdown(result['result']),
|
|
85
|
+
title="[bold blue]Summary[/bold blue]",
|
|
86
|
+
border_style="green"
|
|
87
|
+
))
|
|
88
|
+
else:
|
|
89
|
+
console.print(f"\n[bold red]β Error:[/bold red] {result.get('error', 'Unknown error')}")
|
|
90
|
+
|
|
91
|
+
except KeyboardInterrupt:
|
|
92
|
+
console.print("\n[dim]Interrupted by user[/dim]")
|
|
93
|
+
except Exception as e:
|
|
94
|
+
console.print(f"\n[bold red]Error:[/bold red] {e}")
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
def project_command(workspace: Optional[str] = None):
|
|
98
|
+
"""
|
|
99
|
+
Analyze and understand the project structure.
|
|
100
|
+
|
|
101
|
+
Args:
|
|
102
|
+
workspace: Project directory (default: current directory)
|
|
103
|
+
"""
|
|
104
|
+
from ..utils.project_scanner import ProjectScanner
|
|
105
|
+
from pathlib import Path
|
|
106
|
+
|
|
107
|
+
workspace_path = Path(workspace) if workspace else Path.cwd()
|
|
108
|
+
|
|
109
|
+
console.print(f"\n[bold blue]Scanning Project:[/bold blue] {workspace_path}\n")
|
|
110
|
+
|
|
111
|
+
with console.status("[bold blue]Analyzing project...", spinner="dots"):
|
|
112
|
+
scanner = ProjectScanner(workspace_path)
|
|
113
|
+
structure = scanner.scan()
|
|
114
|
+
project_type = scanner.get_project_type()
|
|
115
|
+
|
|
116
|
+
# Display results
|
|
117
|
+
console.print(Panel.fit(
|
|
118
|
+
f"""[bold]Project Analysis[/bold]
|
|
119
|
+
|
|
120
|
+
[bold cyan]Type:[/bold cyan] {project_type}
|
|
121
|
+
[bold cyan]Total Files:[/bold cyan] {structure['total_files']}
|
|
122
|
+
[bold cyan]Total Directories:[/bold cyan] {structure['total_dirs']}
|
|
123
|
+
[bold cyan]Languages:[/bold cyan] {', '.join(structure['languages']) if structure['languages'] else 'None detected'}
|
|
124
|
+
|
|
125
|
+
[bold]Key Files:[/bold]
|
|
126
|
+
{chr(10).join(' β’ ' + f for f in structure['key_files'][:15])}
|
|
127
|
+
{f" ... and {len(structure['key_files']) - 15} more" if len(structure['key_files']) > 15 else ""}
|
|
128
|
+
""",
|
|
129
|
+
border_style="blue",
|
|
130
|
+
title="[bold blue]Project Structure[/bold blue]"
|
|
131
|
+
))
|