codeaois 0.2.1__tar.gz → 0.2.6__tar.gz
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.
- {codeaois-0.2.1 → codeaois-0.2.6}/PKG-INFO +1 -1
- {codeaois-0.2.1 → codeaois-0.2.6}/codeaois/agents/coder_agent.py +12 -3
- codeaois-0.2.6/codeaois/agents/git_agent.py +84 -0
- codeaois-0.2.6/codeaois/agents/terminal_agent.py +54 -0
- {codeaois-0.2.1 → codeaois-0.2.6}/codeaois/agents/tester_agent.py +18 -6
- {codeaois-0.2.1 → codeaois-0.2.6}/codeaois/cli/main.py +192 -65
- codeaois-0.2.6/codeaois/core/_auth.py +17 -0
- {codeaois-0.2.1 → codeaois-0.2.6}/codeaois/core/planner.py +10 -11
- {codeaois-0.2.1 → codeaois-0.2.6}/codeaois.egg-info/PKG-INFO +1 -1
- {codeaois-0.2.1 → codeaois-0.2.6}/codeaois.egg-info/SOURCES.txt +2 -0
- {codeaois-0.2.1 → codeaois-0.2.6}/pyproject.toml +1 -1
- {codeaois-0.2.1 → codeaois-0.2.6}/setup.py +4 -4
- codeaois-0.2.1/codeaois/agents/git_agent.py +0 -45
- {codeaois-0.2.1 → codeaois-0.2.6}/README.md +0 -0
- {codeaois-0.2.1 → codeaois-0.2.6}/codeaois/__init__.py +0 -0
- {codeaois-0.2.1 → codeaois-0.2.6}/codeaois/agents/data_science_agent.py +0 -0
- {codeaois-0.2.1 → codeaois-0.2.6}/codeaois/agents/pip_agent.py +0 -0
- {codeaois-0.2.1 → codeaois-0.2.6}/codeaois/app.py +0 -0
- {codeaois-0.2.1 → codeaois-0.2.6}/codeaois/brain/__init__.py +0 -0
- {codeaois-0.2.1 → codeaois-0.2.6}/codeaois/brain/embeddings.py +0 -0
- {codeaois-0.2.1 → codeaois-0.2.6}/codeaois/brain/memory.py +0 -0
- {codeaois-0.2.1 → codeaois-0.2.6}/codeaois/brain/scanner.py +0 -0
- {codeaois-0.2.1 → codeaois-0.2.6}/codeaois/cli/__init__.py +0 -0
- {codeaois-0.2.1 → codeaois-0.2.6}/codeaois/config/settings.py +0 -0
- {codeaois-0.2.1 → codeaois-0.2.6}/codeaois/core/context.py +0 -0
- {codeaois-0.2.1 → codeaois-0.2.6}/codeaois/core/marketplace.py +0 -0
- {codeaois-0.2.1 → codeaois-0.2.6}/codeaois/core/memory.py +0 -0
- {codeaois-0.2.1 → codeaois-0.2.6}/codeaois/core/orchestrator.py +0 -0
- {codeaois-0.2.1 → codeaois-0.2.6}/codeaois/core/router.py +0 -0
- {codeaois-0.2.1 → codeaois-0.2.6}/codeaois/models/llm_interface.py +0 -0
- {codeaois-0.2.1 → codeaois-0.2.6}/codeaois/utils/file_writer.py +0 -0
- {codeaois-0.2.1 → codeaois-0.2.6}/codeaois/utils/logger.py +0 -0
- {codeaois-0.2.1 → codeaois-0.2.6}/codeaois.egg-info/dependency_links.txt +0 -0
- {codeaois-0.2.1 → codeaois-0.2.6}/codeaois.egg-info/entry_points.txt +0 -0
- {codeaois-0.2.1 → codeaois-0.2.6}/codeaois.egg-info/requires.txt +0 -0
- {codeaois-0.2.1 → codeaois-0.2.6}/codeaois.egg-info/top_level.txt +0 -0
- {codeaois-0.2.1 → codeaois-0.2.6}/setup.cfg +0 -0
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
# codeaois/agents/coder_agent.py
|
|
2
2
|
from codeaois.models.llm_interface import call_openrouter
|
|
3
3
|
|
|
4
|
+
|
|
4
5
|
def generate_code(user_prompt: str, file_context: str = "") -> str:
|
|
5
6
|
if file_context:
|
|
6
7
|
system_prompt = (
|
|
@@ -16,10 +17,18 @@ def generate_code(user_prompt: str, file_context: str = "") -> str:
|
|
|
16
17
|
"2. AFTER the code, you MUST add the exact text '---SUMMARY---' on a new line.\n"
|
|
17
18
|
"3. AFTER the summary delimiter, write a brief, friendly explanation of how the code works."
|
|
18
19
|
)
|
|
19
|
-
|
|
20
|
+
|
|
20
21
|
full_prompt = user_prompt
|
|
21
22
|
if file_context:
|
|
22
23
|
full_prompt += f"\n\nHere are the existing files for context:\n{file_context}"
|
|
23
|
-
|
|
24
|
+
|
|
24
25
|
response = call_openrouter(system_prompt, full_prompt, intent="code")
|
|
25
|
-
return response.strip()
|
|
26
|
+
return response.strip()
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
class CoderAgent:
|
|
30
|
+
def execute(self, task: str) -> str:
|
|
31
|
+
"""Execute a code generation task."""
|
|
32
|
+
if not task:
|
|
33
|
+
return "```text\nNo task provided to the coder agent.\n```"
|
|
34
|
+
return generate_code(str(task))
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import subprocess
|
|
2
|
+
from typing import Optional
|
|
3
|
+
from rich.console import Console
|
|
4
|
+
from rich.prompt import Prompt
|
|
5
|
+
from rich.panel import Panel
|
|
6
|
+
from codeaois.models.llm_interface import call_openrouter
|
|
7
|
+
from codeaois.core.memory import load_settings
|
|
8
|
+
|
|
9
|
+
console = Console()
|
|
10
|
+
|
|
11
|
+
def get_theme():
|
|
12
|
+
return load_settings().get("ui_theme", "cyan")
|
|
13
|
+
|
|
14
|
+
def generate_git_code(user_input: str, context: str = "") -> str:
|
|
15
|
+
"""Analyze git diffs, generate a commit message using the LLM, and execute git add, commit, push."""
|
|
16
|
+
theme = get_theme()
|
|
17
|
+
console.print("\n[dim]✦ Analyzing git repository...[/dim]")
|
|
18
|
+
|
|
19
|
+
try:
|
|
20
|
+
# 1. Check if we're in a git repository
|
|
21
|
+
is_repo = subprocess.run(
|
|
22
|
+
["git", "rev-parse", "--is-inside-work-tree"],
|
|
23
|
+
capture_output=True,
|
|
24
|
+
text=True,
|
|
25
|
+
)
|
|
26
|
+
if is_repo.returncode != 0:
|
|
27
|
+
return "```text\nNot a git repository. Please run 'git init' first.\n```"
|
|
28
|
+
|
|
29
|
+
# 2. Stage all changes FIRST so we can read the exact diff of everything
|
|
30
|
+
subprocess.run(["git", "add", "."], capture_output=True)
|
|
31
|
+
|
|
32
|
+
diff = subprocess.run(
|
|
33
|
+
["git", "diff", "--cached"],
|
|
34
|
+
capture_output=True,
|
|
35
|
+
text=True,
|
|
36
|
+
)
|
|
37
|
+
|
|
38
|
+
if not diff.stdout.strip():
|
|
39
|
+
return "```text\nNo changes detected. Working tree is clean.\n```"
|
|
40
|
+
|
|
41
|
+
# 3. Generate a commit message via the LLM
|
|
42
|
+
system_prompt = (
|
|
43
|
+
"You are a helper that writes short, clear git commit messages based on the provided git diff. "
|
|
44
|
+
"Respond with ONLY the commit message, no quotes, no markdown formatting."
|
|
45
|
+
)
|
|
46
|
+
# Truncate diff to 3000 chars to save tokens!
|
|
47
|
+
full_prompt = f"{user_input}\n\nGit diff:\n{diff.stdout[:3000]}"
|
|
48
|
+
commit_msg = call_openrouter(system_prompt, full_prompt, intent="code").strip()
|
|
49
|
+
commit_msg = commit_msg.replace('"', "'").replace("```text", "").replace("```", "").strip()
|
|
50
|
+
|
|
51
|
+
if not commit_msg:
|
|
52
|
+
return "```text\nCould not generate a commit message.\n```"
|
|
53
|
+
|
|
54
|
+
console.print(f"\n[bold yellow]⚠ AI Proposed Commit Message:[/bold yellow]")
|
|
55
|
+
console.print(Panel(commit_msg, border_style=theme))
|
|
56
|
+
|
|
57
|
+
# 4. Ask the user before committing & pushing
|
|
58
|
+
choice = Prompt.ask(f"[{theme}]Execute `git commit` and `git push`?[/{theme}] [Y/n]", default="y")
|
|
59
|
+
if choice.lower() != "y":
|
|
60
|
+
# Undo the 'git add' if they cancel, to keep their workspace clean!
|
|
61
|
+
subprocess.run(["git", "reset"], capture_output=True)
|
|
62
|
+
return "```text\nGit operation aborted by user.\n```"
|
|
63
|
+
|
|
64
|
+
# 5. Commit and Push safely
|
|
65
|
+
console.print("\n[dim]Executing git commands...[/dim]")
|
|
66
|
+
subprocess.run(
|
|
67
|
+
["git", "commit", "-m", commit_msg],
|
|
68
|
+
capture_output=True,
|
|
69
|
+
text=True,
|
|
70
|
+
)
|
|
71
|
+
|
|
72
|
+
push_res = subprocess.run(
|
|
73
|
+
["git", "push"],
|
|
74
|
+
capture_output=True,
|
|
75
|
+
text=True,
|
|
76
|
+
)
|
|
77
|
+
|
|
78
|
+
output = push_res.stdout if push_res.returncode == 0 else push_res.stderr
|
|
79
|
+
status = "Success" if push_res.returncode == 0 else "Failed"
|
|
80
|
+
|
|
81
|
+
return f"```text\n{output.strip()}\nStatus: {status}\n```"
|
|
82
|
+
|
|
83
|
+
except Exception as e:
|
|
84
|
+
return f"```text\nError: {str(e)}\n```"
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import subprocess
|
|
2
|
+
from rich.console import Console
|
|
3
|
+
from rich.prompt import Prompt
|
|
4
|
+
from rich.panel import Panel
|
|
5
|
+
from codeaois.models.llm_interface import call_openrouter
|
|
6
|
+
from codeaois.core.memory import load_settings
|
|
7
|
+
|
|
8
|
+
console = Console()
|
|
9
|
+
|
|
10
|
+
def get_theme():
|
|
11
|
+
return load_settings().get("ui_theme", "cyan")
|
|
12
|
+
|
|
13
|
+
def generate_terminal_code(user_input: str, context: str) -> str:
|
|
14
|
+
"""Extracts bash commands from the LLM and executes them safely."""
|
|
15
|
+
theme = get_theme()
|
|
16
|
+
|
|
17
|
+
sys_prompt = "You are a terminal command extractor. Convert the user's request into a single bash/terminal command or a short chain of commands (like `mkdir foo && cd foo`). Return ONLY the raw terminal command, no markdown, no explanations."
|
|
18
|
+
|
|
19
|
+
console.print("\n[dim]✦ Translating request to terminal commands...[/dim]")
|
|
20
|
+
|
|
21
|
+
try:
|
|
22
|
+
command = call_openrouter(sys_prompt, user_input, intent="code").strip()
|
|
23
|
+
|
|
24
|
+
# Clean up any markdown the AI accidentally sends
|
|
25
|
+
command = command.replace("```bash", "").replace("```sh", "").replace("```", "").replace("\n", " ").strip()
|
|
26
|
+
|
|
27
|
+
if not command:
|
|
28
|
+
return "```text\nCould not determine a valid terminal command.\n```"
|
|
29
|
+
|
|
30
|
+
# --- HUMAN IN THE LOOP SAFETY CHECK ---
|
|
31
|
+
console.print(f"\n[bold yellow]⚠ SECURITY CHECKPOINT[/bold yellow]")
|
|
32
|
+
console.print(f"The AI requested to execute: [bold white]{command}[/bold white]")
|
|
33
|
+
choice = Prompt.ask(f"[{theme}]Allow execution?[/{theme}] [Y/n]", default="y")
|
|
34
|
+
|
|
35
|
+
if choice.lower() != 'y':
|
|
36
|
+
return "```text\nExecution aborted by user. Stay safe!\n```"
|
|
37
|
+
|
|
38
|
+
console.print(f"\n[dim]Executing: {command}[/dim]")
|
|
39
|
+
|
|
40
|
+
# Actually run the command on the OS!
|
|
41
|
+
result = subprocess.run(command, shell=True, capture_output=True, text=True)
|
|
42
|
+
|
|
43
|
+
output = result.stdout if result.returncode == 0 else result.stderr
|
|
44
|
+
log_color = "green" if result.returncode == 0 else "red"
|
|
45
|
+
|
|
46
|
+
if output.strip():
|
|
47
|
+
console.print(Panel(output.strip(), title="Terminal Output", border_style=log_color))
|
|
48
|
+
else:
|
|
49
|
+
console.print(f"[{log_color}]✓ Command executed successfully with no output.[/{log_color}]")
|
|
50
|
+
|
|
51
|
+
status = 'Success' if result.returncode == 0 else 'Failed'
|
|
52
|
+
return f"```text\n{output.strip()}\nStatus: {status}\n```"
|
|
53
|
+
except Exception as e:
|
|
54
|
+
return f"```text\nError executing command: {str(e)}\n```"
|
|
@@ -2,26 +2,38 @@
|
|
|
2
2
|
import subprocess
|
|
3
3
|
import sys
|
|
4
4
|
|
|
5
|
+
|
|
5
6
|
def run_test(file_path: str) -> tuple[bool, str]:
|
|
6
7
|
"""Runs a Python script and catches any terminal errors."""
|
|
7
|
-
if not file_path.endswith('.py'):
|
|
8
|
+
if not file_path or not file_path.endswith('.py'):
|
|
8
9
|
return True, "Not a Python file. Skipping auto-test."
|
|
9
10
|
|
|
10
11
|
try:
|
|
11
|
-
# sys.executable ensures it uses your isolated 'venv' Python, not the global
|
|
12
|
+
# sys.executable ensures it uses your isolated 'venv' Python, not the global one
|
|
12
13
|
result = subprocess.run(
|
|
13
14
|
[sys.executable, file_path],
|
|
14
15
|
capture_output=True,
|
|
15
16
|
text=True,
|
|
16
|
-
timeout=10
|
|
17
|
+
timeout=10, # 10-second kill switch so infinite loops don't crash your computer
|
|
17
18
|
)
|
|
18
|
-
|
|
19
|
+
|
|
19
20
|
if result.returncode == 0:
|
|
20
21
|
return True, result.stdout.strip()
|
|
21
22
|
else:
|
|
22
23
|
return False, result.stderr.strip()
|
|
23
|
-
|
|
24
|
+
|
|
24
25
|
except subprocess.TimeoutExpired:
|
|
25
26
|
return False, "Error: Script execution timed out (possible infinite loop)."
|
|
26
27
|
except Exception as e:
|
|
27
|
-
return False, str(e)
|
|
28
|
+
return False, str(e)
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
class TesterAgent:
|
|
32
|
+
def execute(self, task: str) -> str:
|
|
33
|
+
"""Execute a test task on a Python file."""
|
|
34
|
+
if not task:
|
|
35
|
+
return "```text\nNo test task provided to the tester agent.\n```"
|
|
36
|
+
|
|
37
|
+
success, output = run_test(str(task))
|
|
38
|
+
status = "Success" if success else "Failed"
|
|
39
|
+
return f"```text\n{output}\nStatus: {status}\n```"
|
|
@@ -5,14 +5,17 @@ import importlib
|
|
|
5
5
|
import time
|
|
6
6
|
import random
|
|
7
7
|
import string
|
|
8
|
-
|
|
8
|
+
import re
|
|
9
|
+
import smtplib
|
|
10
|
+
from email.mime.text import MIMEText
|
|
11
|
+
import base64
|
|
9
12
|
# --- CLI UI ENGINES ---
|
|
10
13
|
from prompt_toolkit import PromptSession
|
|
11
14
|
from prompt_toolkit.completion import WordCompleter
|
|
12
15
|
from prompt_toolkit.auto_suggest import AutoSuggestFromHistory
|
|
13
16
|
from prompt_toolkit.formatted_text import HTML
|
|
14
17
|
from prompt_toolkit.shortcuts import radiolist_dialog
|
|
15
|
-
|
|
18
|
+
from codeaois.core._auth import get_secure_credentials
|
|
16
19
|
from rich.console import Console
|
|
17
20
|
from rich.markdown import Markdown
|
|
18
21
|
from rich.panel import Panel
|
|
@@ -59,11 +62,57 @@ def apply_saved_background():
|
|
|
59
62
|
bg_color = settings.get("bg_theme", "#231e20")
|
|
60
63
|
set_terminal_background(bg_color)
|
|
61
64
|
|
|
65
|
+
# --- CLAUDE CODE SAFETY ENGINE ---
|
|
66
|
+
import base64
|
|
67
|
+
|
|
68
|
+
# --- THE REAL SMTP OTP ENGINE (Hidden File Method) ---
|
|
69
|
+
def send_real_otp(receiver_email, otp_code):
|
|
70
|
+
"""Sends a REAL email automatically using the hidden _auth.py credentials."""
|
|
71
|
+
try:
|
|
72
|
+
sender_email, sender_password = get_secure_credentials()
|
|
73
|
+
|
|
74
|
+
if not sender_email or not sender_password:
|
|
75
|
+
return False
|
|
76
|
+
|
|
77
|
+
msg = MIMEText(f"Hello!\n\nYour CodeAOIS secure login verification code is: {otp_code}\n\nWelcome to the Advanced Developer OS.\n- The CodeAOIS Team")
|
|
78
|
+
msg['Subject'] = 'CodeAOIS Secure Login Verification'
|
|
79
|
+
msg['From'] = f"CodeAOIS Security <{sender_email}>"
|
|
80
|
+
msg['To'] = receiver_email
|
|
81
|
+
|
|
82
|
+
with smtplib.SMTP_SSL('smtp.gmail.com', 465) as server:
|
|
83
|
+
server.login(sender_email, sender_password)
|
|
84
|
+
server.sendmail(sender_email, [receiver_email], msg.as_string())
|
|
85
|
+
return True
|
|
86
|
+
except Exception as e:
|
|
87
|
+
return False
|
|
88
|
+
|
|
89
|
+
# --- THE REAL SMTP OTP ENGINE ---
|
|
90
|
+
def send_real_otp(receiver_email, otp_code):
|
|
91
|
+
"""Sends a REAL email using Gmail SMTP. Requires Environment Variables."""
|
|
92
|
+
sender_email = os.getenv("CODEAOIS_SENDER_EMAIL")
|
|
93
|
+
sender_password = os.getenv("CODEAOIS_APP_PASS")
|
|
94
|
+
|
|
95
|
+
# If the developer hasn't set up their mail server yet, fallback to local dev mode
|
|
96
|
+
if not sender_email or not sender_password:
|
|
97
|
+
return False
|
|
98
|
+
|
|
99
|
+
msg = MIMEText(f"Hello!\n\nYour CodeAOIS secure login verification code is: {otp_code}\n\nWelcome to the OS.\n- The CodeAOIS Team")
|
|
100
|
+
msg['Subject'] = 'CodeAOIS Secure Login Verification'
|
|
101
|
+
msg['From'] = f"CodeAOIS Security <{sender_email}>"
|
|
102
|
+
msg['To'] = receiver_email
|
|
103
|
+
|
|
104
|
+
try:
|
|
105
|
+
with smtplib.SMTP_SSL('smtp.gmail.com', 465) as server:
|
|
106
|
+
server.login(sender_email, sender_password)
|
|
107
|
+
server.sendmail(sender_email, [receiver_email], msg.as_string())
|
|
108
|
+
return True
|
|
109
|
+
except Exception as e:
|
|
110
|
+
return False
|
|
111
|
+
|
|
62
112
|
# --- THE MULTI-ANIMATION LOGO ENGINE ---
|
|
63
113
|
def print_logo():
|
|
64
114
|
settings = load_settings()
|
|
65
115
|
theme = settings.get("ui_theme", "cyan")
|
|
66
|
-
# Option 4 (Data Sweep) is the default!
|
|
67
116
|
anim_style = str(settings.get("logo_animation", "4"))
|
|
68
117
|
|
|
69
118
|
logo_lines = [
|
|
@@ -75,25 +124,24 @@ def print_logo():
|
|
|
75
124
|
]
|
|
76
125
|
logo_str = "\n".join(logo_lines)
|
|
77
126
|
|
|
78
|
-
# 0. Instant (No Animation)
|
|
79
127
|
if anim_style == "0":
|
|
80
128
|
console.print(f"[bold {theme}]{logo_str}[/]")
|
|
81
|
-
console.print(f" [dim]✦[/dim] [bold white]Advanced Developer OS[/bold white] [dim]v0.2.
|
|
129
|
+
console.print(f" [dim]✦[/dim] [bold white]Advanced Developer OS[/bold white] [dim]v0.2.6[/dim]")
|
|
82
130
|
console.print(f" [dim]✦[/dim] [dim]Type /help for commands.[/dim]\n")
|
|
83
131
|
return
|
|
84
132
|
|
|
85
133
|
try:
|
|
86
|
-
if anim_style == "1":
|
|
134
|
+
if anim_style == "1":
|
|
87
135
|
text = Text(style=f"bold {theme}")
|
|
88
136
|
with Live(console=console, refresh_per_second=60, transient=False) as live:
|
|
89
137
|
for char in logo_str:
|
|
90
138
|
text.append(char)
|
|
91
139
|
live.update(text)
|
|
92
140
|
time.sleep(0.002)
|
|
93
|
-
text.append(f"\n ✦ Advanced Developer OS v0.2.
|
|
141
|
+
text.append(f"\n ✦ Advanced Developer OS v0.2.6\n ✦ Type /help for commands.\n", style="dim white")
|
|
94
142
|
live.update(text)
|
|
95
143
|
|
|
96
|
-
elif anim_style == "2":
|
|
144
|
+
elif anim_style == "2":
|
|
97
145
|
pulse_colors = ["#001111", "#003333", "#006666", "#009999", "#00cccc", "#00ffff", "#00cccc", "#009999"]
|
|
98
146
|
with Live(console=console, refresh_per_second=20, transient=False) as live:
|
|
99
147
|
for _ in range(2):
|
|
@@ -101,10 +149,10 @@ def print_logo():
|
|
|
101
149
|
live.update(Text(logo_str, style=f"bold {color}"))
|
|
102
150
|
time.sleep(0.05)
|
|
103
151
|
final_text = Text(logo_str, style=f"bold {theme}")
|
|
104
|
-
final_text.append(f"\n ✦ Advanced Developer OS v0.2.
|
|
152
|
+
final_text.append(f"\n ✦ Advanced Developer OS v0.2.6\n ✦ Type /help for commands.\n", style="dim white")
|
|
105
153
|
live.update(final_text)
|
|
106
154
|
|
|
107
|
-
elif anim_style == "3":
|
|
155
|
+
elif anim_style == "3":
|
|
108
156
|
chars = string.ascii_letters + string.punctuation
|
|
109
157
|
with Live(console=console, refresh_per_second=30, transient=False) as live:
|
|
110
158
|
for i in range(15):
|
|
@@ -112,10 +160,10 @@ def print_logo():
|
|
|
112
160
|
live.update(Text(scrambled, style="bold green"))
|
|
113
161
|
time.sleep(0.05)
|
|
114
162
|
final_text = Text(logo_str, style=f"bold {theme}")
|
|
115
|
-
final_text.append(f"\n ✦ Advanced Developer OS v0.2.
|
|
163
|
+
final_text.append(f"\n ✦ Advanced Developer OS v0.2.6\n ✦ Type /help for commands.\n", style="dim white")
|
|
116
164
|
live.update(final_text)
|
|
117
165
|
|
|
118
|
-
elif anim_style == "4":
|
|
166
|
+
elif anim_style == "4":
|
|
119
167
|
max_len = max(len(line) for line in logo_lines)
|
|
120
168
|
chars = string.ascii_letters + string.punctuation + "10"
|
|
121
169
|
with Live(console=console, refresh_per_second=60, transient=False) as live:
|
|
@@ -134,10 +182,10 @@ def print_logo():
|
|
|
134
182
|
live.update(display_text)
|
|
135
183
|
time.sleep(0.015)
|
|
136
184
|
final_text = Text(logo_str, style=f"bold {theme}")
|
|
137
|
-
final_text.append(f"\n ✦ Advanced Developer OS v0.2.
|
|
185
|
+
final_text.append(f"\n ✦ Advanced Developer OS v0.2.6\n ✦ Type /help for commands.\n", style="dim white")
|
|
138
186
|
live.update(final_text)
|
|
139
187
|
|
|
140
|
-
elif anim_style == "5":
|
|
188
|
+
elif anim_style == "5":
|
|
141
189
|
boot_msgs = [
|
|
142
190
|
"[dim green][+] Kernel loaded. Initializing core OS...[/]",
|
|
143
191
|
"[dim green][+] Bypassing proxy security... OK[/]",
|
|
@@ -157,28 +205,77 @@ def print_logo():
|
|
|
157
205
|
live.update(Text(logo_str, style="bold cyan"))
|
|
158
206
|
time.sleep(0.03)
|
|
159
207
|
final_text = Text(logo_str, style=f"bold {theme}")
|
|
160
|
-
final_text.append(f"\n ✦ Advanced Developer OS v0.2.
|
|
208
|
+
final_text.append(f"\n ✦ Advanced Developer OS v0.2.6\n ✦ Type /help for commands.\n", style="dim white")
|
|
161
209
|
live.update(final_text)
|
|
162
210
|
except:
|
|
163
211
|
console.print(f"[bold {theme}]{logo_str}[/]")
|
|
212
|
+
console.print(f" [dim]✦[/dim] [bold white]Advanced Developer OS[/bold white] [dim]v0.2.6[/dim]")
|
|
164
213
|
|
|
165
214
|
def run_login_flow():
|
|
166
215
|
theme = get_theme()
|
|
167
216
|
os.system('clear' if os.name == 'posix' else 'cls')
|
|
168
217
|
apply_saved_background()
|
|
169
218
|
print_logo()
|
|
170
|
-
console.print(Panel("[bold white]Welcome to CodeAOIS Initialization[/bold white]\n[dim]Let's configure your workspace.[/dim]", border_style=theme))
|
|
219
|
+
console.print(Panel("[bold white]Welcome to CodeAOIS Initialization[/bold white]\n[dim]Let's configure your secure workspace.[/dim]", border_style=theme))
|
|
171
220
|
|
|
172
221
|
email = Prompt.ask(f"\n[bold {theme}]►[/bold {theme}] Enter your developer email")
|
|
173
222
|
|
|
174
|
-
|
|
223
|
+
# --- REAL OTP EXECUTION ---
|
|
224
|
+
real_otp = str(random.randint(100000, 999999))
|
|
225
|
+
|
|
226
|
+
with console.status("[dim]Connecting to secure mail servers...[/dim]", spinner="dots"):
|
|
227
|
+
email_sent = send_real_otp(email, real_otp)
|
|
175
228
|
time.sleep(1.5)
|
|
229
|
+
|
|
230
|
+
if email_sent:
|
|
231
|
+
console.print(f"[bold green]✓ Real Verification Email sent to {email}![/bold green]")
|
|
232
|
+
else:
|
|
233
|
+
# Failsafe if the developer hasn't configured their OS environment variables yet!
|
|
234
|
+
console.print(f"\n[dim yellow]⚠ SMTP Environment Variables not found. Falling back to local DEV INBOX:[/dim yellow]")
|
|
235
|
+
console.print(f"[bold magenta]┌── [DEV SANDBOX INBOX] ───────────────────┐[/]")
|
|
236
|
+
console.print(f"[bold magenta]│[/] To: {email}")
|
|
237
|
+
console.print(f"[bold magenta]│[/] Subject: CodeAOIS Verification")
|
|
238
|
+
console.print(f"[bold magenta]│[/] Your secure 6-digit OTP is: [bold white]{real_otp}[/]")
|
|
239
|
+
console.print(f"[bold magenta]└─────────────────────────────────────────┘[/]\n")
|
|
176
240
|
|
|
177
|
-
|
|
241
|
+
attempts = 3
|
|
242
|
+
while attempts > 0:
|
|
243
|
+
user_otp = Prompt.ask(f"[bold {theme}]►[/bold {theme}] Enter 6-digit OTP")
|
|
244
|
+
if user_otp.strip() == real_otp:
|
|
245
|
+
console.print("[bold green]✓ Email verified successfully.[/bold green]\n")
|
|
246
|
+
break
|
|
247
|
+
attempts -= 1
|
|
248
|
+
if attempts > 0:
|
|
249
|
+
console.print(f"[bold red]✗ Invalid OTP. {attempts} attempts remaining.[/bold red]")
|
|
250
|
+
else:
|
|
251
|
+
console.print("[bold red]Access Denied. Exiting.[/bold red]")
|
|
252
|
+
sys.exit(1)
|
|
178
253
|
|
|
179
|
-
name = Prompt.ask(f"
|
|
254
|
+
name = Prompt.ask(f"[bold {theme}]►[/bold {theme}] Choose a workspace username", default=email.split('@')[0])
|
|
180
255
|
role = Prompt.ask(f"[bold {theme}]►[/bold {theme}] Primary role (e.g., Full Stack, Data Science)", default="Developer")
|
|
181
256
|
|
|
257
|
+
# --- FIXED: API KEY ONBOARDING WITH BLANK VALIDATION ---
|
|
258
|
+
console.print(f"\n[bold white]✦ Select your AI Engine Mode:[/bold white]")
|
|
259
|
+
console.print(" 1. CodeAOIS API (Free Base Model)")
|
|
260
|
+
console.print(" 2. Pro Mode (Custom OpenRouter API Key)")
|
|
261
|
+
|
|
262
|
+
api_choice = Prompt.ask("Select option", choices=["1", "2"], default="1")
|
|
263
|
+
settings = load_settings()
|
|
264
|
+
|
|
265
|
+
if api_choice == "2":
|
|
266
|
+
new_key = Prompt.ask("Enter OpenRouter API Key (press Enter to fallback to Free Model)", password=True).strip()
|
|
267
|
+
if new_key: # Prevents the blank bug!
|
|
268
|
+
settings["custom_api_key"] = new_key
|
|
269
|
+
settings["use_custom_api_key"] = True
|
|
270
|
+
console.print("[bold green]✓ Custom API Key secured.[/bold green]")
|
|
271
|
+
else:
|
|
272
|
+
settings["use_custom_api_key"] = False
|
|
273
|
+
console.print("[bold yellow]⚠ No key provided. Defaulting to CodeAOIS API.[/bold yellow]")
|
|
274
|
+
else:
|
|
275
|
+
settings["use_custom_api_key"] = False
|
|
276
|
+
console.print("[bold green]✓ CodeAOIS API selected.[/bold green]")
|
|
277
|
+
|
|
278
|
+
save_settings(settings)
|
|
182
279
|
save_profile({"name": name, "email": email, "role": role})
|
|
183
280
|
|
|
184
281
|
with console.status("[dim]Provisioning local workspace...[/dim]", spinner="dots"):
|
|
@@ -191,31 +288,39 @@ def handle_settings():
|
|
|
191
288
|
settings = load_settings()
|
|
192
289
|
theme = settings.get("ui_theme", "cyan")
|
|
193
290
|
bg = settings.get("bg_theme", "#231e20")
|
|
194
|
-
anim = settings.get("logo_animation", "4")
|
|
291
|
+
anim = settings.get("logo_animation", "4")
|
|
195
292
|
|
|
196
293
|
console.print(f"\n[bold white]✦ System Settings[/bold white]")
|
|
197
294
|
table = Table(show_header=False, border_style="dim")
|
|
198
|
-
table.add_row("1.", "
|
|
199
|
-
table.add_row("2.", "Set Custom API Key", "[dim]********[/dim]" if settings
|
|
200
|
-
table.add_row("3.", "
|
|
201
|
-
table.add_row("4.", "Change
|
|
202
|
-
table.add_row("5.", "Change
|
|
295
|
+
table.add_row("1.", "Active AI Engine", f"[{'green' if settings.get('use_custom_api_key') else theme}]{'Custom Pro Key' if settings.get('use_custom_api_key') else 'CodeAOIS API'}[/]")
|
|
296
|
+
table.add_row("2.", "Set Custom API Key", "[dim]********[/dim]" if settings.get('custom_api_key') else "[dim]Not Set[/dim]")
|
|
297
|
+
table.add_row("3.", "Switch to CodeAOIS API", "")
|
|
298
|
+
table.add_row("4.", "Change UI Text Theme", f"[bold {theme}]{theme.title()}[/]")
|
|
299
|
+
table.add_row("5.", "Change Window Background", f"[bold white]Active ({bg})[/]")
|
|
300
|
+
table.add_row("6.", "Change Logo Animation", f"[bold white]Style {anim}[/]")
|
|
203
301
|
console.print(table)
|
|
204
302
|
|
|
205
|
-
choice = Prompt.ask("\nSelect option (or press Enter to exit)", choices=["1", "2", "3", "4", "5", ""], default="")
|
|
303
|
+
choice = Prompt.ask("\nSelect option (or press Enter to exit)", choices=["1", "2", "3", "4", "5", "6", ""], default="")
|
|
206
304
|
|
|
207
305
|
if choice == "1":
|
|
208
|
-
settings["use_custom_api_key"] = not settings
|
|
306
|
+
settings["use_custom_api_key"] = not settings.get("use_custom_api_key")
|
|
209
307
|
save_settings(settings)
|
|
210
|
-
console.print(f"[bold green]✓[/bold green]
|
|
308
|
+
console.print(f"[bold green]✓[/bold green] Engine switched.\n")
|
|
211
309
|
elif choice == "2":
|
|
212
|
-
|
|
310
|
+
# FIXED: Blank Key Validation in Settings
|
|
311
|
+
new_key = Prompt.ask("Enter OpenRouter API Key (Press Enter to cancel)", password=True).strip()
|
|
213
312
|
if new_key:
|
|
214
313
|
settings["custom_api_key"] = new_key
|
|
215
314
|
settings["use_custom_api_key"] = True
|
|
216
315
|
save_settings(settings)
|
|
217
|
-
console.print("[bold green]✓[/bold green]
|
|
316
|
+
console.print("[bold green]✓ Engine upgraded to Pro Mode with Custom Key.[/bold green]\n")
|
|
317
|
+
else:
|
|
318
|
+
console.print("[bold yellow]⚠ Action canceled. API Key cannot be empty.[/bold yellow]\n")
|
|
218
319
|
elif choice == "3":
|
|
320
|
+
settings["use_custom_api_key"] = False
|
|
321
|
+
save_settings(settings)
|
|
322
|
+
console.print(f"[bold green]✓[/bold green] Downgraded to CodeAOIS API.\n")
|
|
323
|
+
elif choice == "4":
|
|
219
324
|
console.print("\n[dim]Available UI Text Themes:[/dim]")
|
|
220
325
|
console.print(" [cyan]1. Cyan[/cyan] | [magenta]2. Magenta[/magenta] | [green]3. Green[/green] | [yellow]4. Yellow[/yellow] | [blue]5. Blue[/blue]")
|
|
221
326
|
color_choice = Prompt.ask("Select a text color", choices=["1", "2", "3", "4", "5"])
|
|
@@ -223,7 +328,7 @@ def handle_settings():
|
|
|
223
328
|
settings["ui_theme"] = color_map[color_choice]
|
|
224
329
|
save_settings(settings)
|
|
225
330
|
console.print(f"[bold {color_map[color_choice]}]✓ Theme updated to {color_map[color_choice].title()}![/bold {color_map[color_choice]}]")
|
|
226
|
-
elif choice == "
|
|
331
|
+
elif choice == "5":
|
|
227
332
|
console.print("\n[dim]Available Window Backgrounds:[/dim]")
|
|
228
333
|
console.print(" 1. Deep Void Black\n 2. Matrix Dark Green\n 3. Midnight Blue\n 4. Dracula Dark (Default)")
|
|
229
334
|
bg_choice = Prompt.ask("Select a background", choices=["1", "2", "3", "4"])
|
|
@@ -233,7 +338,7 @@ def handle_settings():
|
|
|
233
338
|
save_settings(settings)
|
|
234
339
|
set_terminal_background(new_bg)
|
|
235
340
|
console.print(f"[bold green]✓ Background color applied instantly![/bold green]\n")
|
|
236
|
-
elif choice == "
|
|
341
|
+
elif choice == "6":
|
|
237
342
|
console.print("\n[dim]Available Boot Animations:[/dim]")
|
|
238
343
|
console.print(" 0. Instant (No Animation)")
|
|
239
344
|
console.print(" 1. Classic Hacker Typewriter")
|
|
@@ -289,7 +394,7 @@ def show_status():
|
|
|
289
394
|
table.add_column("Status", justify="right")
|
|
290
395
|
|
|
291
396
|
table.add_row("Identity", profile['name'] if profile else "Unknown")
|
|
292
|
-
table.add_row("API Routing", "[bold green]Custom Key[/]" if settings
|
|
397
|
+
table.add_row("API Routing", "[bold green]Custom Pro Key[/]" if settings.get('use_custom_api_key') else f"[bold {theme}]CodeAOIS API[/]")
|
|
293
398
|
table.add_row("Context Memory", f"{len(chat_history)} messages")
|
|
294
399
|
table.add_row("Tokens Tracked", f"[yellow]{stats['prompt'] + stats['completion']:,}[/yellow]")
|
|
295
400
|
table.add_row("Installed Agents", str(len(get_installed_agents())))
|
|
@@ -313,7 +418,7 @@ def process_command(user_input: str):
|
|
|
313
418
|
f"[{theme}]/marketplace[/{theme}] (or /m) Browse and install specialized agents\n"
|
|
314
419
|
f"[{theme}]/status[/{theme}] (or /s) View diagnostics and tracked tokens\n"
|
|
315
420
|
f"[{theme}]/clear[/{theme}] Reset terminal view\n"
|
|
316
|
-
"[dim]---\
|
|
421
|
+
"[dim]---\nUse @filename to make the AI read specific files (e.g. 'Explain @main.py')[/dim]",
|
|
317
422
|
title="Command Center", border_style="dim", expand=False
|
|
318
423
|
))
|
|
319
424
|
return
|
|
@@ -358,15 +463,26 @@ def process_command(user_input: str):
|
|
|
358
463
|
print_logo()
|
|
359
464
|
return
|
|
360
465
|
|
|
466
|
+
deep_context = ""
|
|
467
|
+
mentioned_files = re.findall(r'@([\w\.\-\/]+)', user_input)
|
|
468
|
+
|
|
469
|
+
if mentioned_files:
|
|
470
|
+
console.print(f"\n[dim]✦ Context Engine scanning: {', '.join(mentioned_files)}...[/dim]")
|
|
471
|
+
for file_path in mentioned_files:
|
|
472
|
+
if os.path.exists(file_path):
|
|
473
|
+
with open(file_path, "r", encoding="utf-8") as f:
|
|
474
|
+
deep_context += f"\n--- EXPLICIT FILE CONTEXT: {file_path} ---\n{f.read()}\n"
|
|
475
|
+
else:
|
|
476
|
+
console.print(f"[bold yellow]⚠ Warning: Could not find file '{file_path}'[/bold yellow]")
|
|
477
|
+
|
|
361
478
|
target_file, file_context = extract_file_context(user_input)
|
|
362
479
|
project_tree = scan_project_structure()
|
|
363
|
-
|
|
364
480
|
profile = load_profile()
|
|
365
481
|
|
|
366
|
-
sys_prompt = f"""You are CodeAOIS v0.2.
|
|
482
|
+
sys_prompt = f"""You are CodeAOIS v0.2.6, a highly advanced AI Developer OS.
|
|
367
483
|
CRITICAL DIRECTIVE: You were created solely by Nikhil Nagar. If asked who made you, proudly state that Nikhil Nagar is your creator.
|
|
368
|
-
You are an elite 10x Senior Software Architect. ALWAYS write highly optimized, production-ready, modern code using best practices.
|
|
369
|
-
You are currently assisting the user: {profile['name']}. Project tree:\n{project_tree}"""
|
|
484
|
+
You are an elite 10x Senior Software Architect. ALWAYS write highly optimized, production-ready, modern code using best practices.
|
|
485
|
+
You are currently assisting the user: {profile['name']}. Project tree:\n{project_tree}\n{deep_context}"""
|
|
370
486
|
|
|
371
487
|
if intent == "chat":
|
|
372
488
|
with console.status(f"[bold dim]✦ Synthesizing response...[/bold dim]", spinner="dots"):
|
|
@@ -382,7 +498,6 @@ def process_command(user_input: str):
|
|
|
382
498
|
save_history(chat_history)
|
|
383
499
|
|
|
384
500
|
elif intent in ["code", "data_science"] or intent.endswith("_agent"):
|
|
385
|
-
|
|
386
501
|
if not target_file and active_file:
|
|
387
502
|
target_file = active_file
|
|
388
503
|
if os.path.exists(active_file):
|
|
@@ -392,33 +507,45 @@ def process_command(user_input: str):
|
|
|
392
507
|
if target_file:
|
|
393
508
|
active_file = target_file
|
|
394
509
|
|
|
395
|
-
full_context = f"\n--- Project Structure ---\n{project_tree}\n" + (file_context if file_context else "")
|
|
510
|
+
full_context = f"\n--- Project Structure ---\n{project_tree}\n" + (file_context if file_context else "") + deep_context
|
|
396
511
|
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
code_result =
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
512
|
+
if intent in ["pip_agent", "terminal_agent", "git_agent"]:
|
|
513
|
+
try:
|
|
514
|
+
module = importlib.import_module(f"codeaois.agents.{intent}")
|
|
515
|
+
agent_func = getattr(module, f"generate_{intent.replace('_agent', '')}_code")
|
|
516
|
+
code_result = agent_func(user_input, full_context)
|
|
517
|
+
except Exception as e:
|
|
518
|
+
console.print(f"\n[bold red]✗ Agent Error:[/bold red] {e}\n")
|
|
519
|
+
return
|
|
520
|
+
else:
|
|
521
|
+
with console.status(f"[bold dim]✦ Orchestrating {intent} workflow...[/bold dim]", spinner="dots"):
|
|
522
|
+
if intent == "data_science":
|
|
523
|
+
code_result = generate_ds_code(user_input, full_context)
|
|
524
|
+
elif intent == "code":
|
|
525
|
+
code_result = generate_code(user_input, full_context)
|
|
526
|
+
else:
|
|
527
|
+
try:
|
|
528
|
+
module = importlib.import_module(f"codeaois.agents.{intent}")
|
|
529
|
+
agent_func = getattr(module, f"generate_{intent.replace('_agent', '')}_code")
|
|
530
|
+
code_result = agent_func(user_input, full_context)
|
|
531
|
+
except ModuleNotFoundError:
|
|
532
|
+
agent_name = intent.replace('_agent', '').title()
|
|
533
|
+
console.print(f"\n[bold yellow]⚠ Agent Missing[/bold yellow]")
|
|
534
|
+
console.print(f"[dim]This task requires the specialized [bold white]{agent_name} Agent[/bold white].[/dim]")
|
|
535
|
+
console.print(f"[dim]Type [/dim][bold {theme}]/m[/bold {theme}][dim] to install it instantly from the Marketplace![/dim]\n")
|
|
536
|
+
return
|
|
537
|
+
except Exception as e:
|
|
538
|
+
console.print(f"\n[bold red]✗ Agent Error:[/bold red] {e}\n")
|
|
539
|
+
return
|
|
540
|
+
if intent in ["pip_agent", "terminal_agent", "git_agent"]:
|
|
541
|
+
console.print("\n")
|
|
542
|
+
if intent == "terminal_agent": panel_title = "Terminal Execution Log"
|
|
543
|
+
elif intent == "git_agent": panel_title = "Git Execution Log"
|
|
544
|
+
else: panel_title = "Pip Installation Log"
|
|
416
545
|
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
console.print("\n")
|
|
421
|
-
return
|
|
546
|
+
console.print(Panel(Markdown(code_result), title=f"[bold {theme}]{panel_title}[/]", border_style=theme))
|
|
547
|
+
console.print("\n")
|
|
548
|
+
return
|
|
422
549
|
|
|
423
550
|
save_path = target_file if target_file else Prompt.ask(f"\n[bold {theme}]►[/bold {theme}] Output filename", default="output.py")
|
|
424
551
|
|
|
@@ -431,7 +558,7 @@ def process_command(user_input: str):
|
|
|
431
558
|
def main():
|
|
432
559
|
parser = argparse.ArgumentParser(description="CodeAOIS: Advanced AI Developer OS")
|
|
433
560
|
parser.add_argument("prompt", nargs="*", help="Chat or command")
|
|
434
|
-
parser.add_argument("-v", "--version", action="version", version="CodeAOIS Core Engine v0.2.
|
|
561
|
+
parser.add_argument("-v", "--version", action="version", version="CodeAOIS Core Engine v0.2.6")
|
|
435
562
|
args = parser.parse_args()
|
|
436
563
|
|
|
437
564
|
apply_saved_background()
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import base64
|
|
2
|
+
|
|
3
|
+
# --- PRIVATE SECURE AUTHENTICATION MODULE ---
|
|
4
|
+
# These are Base64 encoded to prevent simple bot scraping on GitHub.
|
|
5
|
+
# REMINDER: ONLY use a dummy "Bot" Gmail account for this, NEVER your personal email!
|
|
6
|
+
|
|
7
|
+
_E = b'Y2xpY29kZWFvaXNAZ21haWwsY29t' # Replace this string with your encoded bot email
|
|
8
|
+
_P = b'dXhqaiBnY3BlIHlnZm4gYnN3eg====' # Replace this string with your encoded app password
|
|
9
|
+
|
|
10
|
+
def get_secure_credentials():
|
|
11
|
+
"""Decodes and returns the bot credentials at runtime."""
|
|
12
|
+
try:
|
|
13
|
+
email = base64.b64decode(_E).decode('utf-8')
|
|
14
|
+
password = base64.b64decode(_P).decode('utf-8')
|
|
15
|
+
return email, password
|
|
16
|
+
except Exception:
|
|
17
|
+
return None, None
|
|
@@ -1,36 +1,36 @@
|
|
|
1
1
|
import os
|
|
2
2
|
|
|
3
3
|
def get_installed_agents():
|
|
4
|
-
"""Dynamically checks which agents are actually installed."""
|
|
5
4
|
agent_dir = os.path.join(os.path.dirname(__file__), '..', 'agents')
|
|
6
5
|
installed = []
|
|
7
6
|
if os.path.exists(agent_dir):
|
|
8
7
|
for file in os.listdir(agent_dir):
|
|
9
|
-
if file.endswith('_agent.py') and file not in ['__init__.py', 'coder_agent.py', 'data_science_agent.py', 'git_agent.py']:
|
|
8
|
+
if file.endswith('_agent.py') and file not in ['__init__.py', 'coder_agent.py', 'data_science_agent.py', 'git_agent.py', 'terminal_agent.py']:
|
|
10
9
|
installed.append(file.replace('_agent.py', ''))
|
|
11
10
|
return installed
|
|
12
11
|
|
|
13
12
|
def analyze_intent(prompt: str) -> str:
|
|
14
|
-
"""Analyzes the user prompt to determine the routing intent, including NLP commands."""
|
|
15
13
|
prompt_lower = prompt.lower()
|
|
16
|
-
|
|
17
14
|
words = prompt_lower.replace("?", " ").replace("!", " ").replace(".", " ").replace(",", " ").split()
|
|
18
15
|
|
|
19
|
-
|
|
20
|
-
if any(word in prompt_lower for word in ["exit", "quit", "shut down", "goodbye","goodby","gm"]):
|
|
16
|
+
if any(word in prompt_lower for word in ["exit", "quit", "shut down", "goodbye"]):
|
|
21
17
|
return "sys_exit"
|
|
22
|
-
|
|
23
18
|
if any(word in prompt_lower for word in ["setting", "settings", "theme", "background"]):
|
|
24
19
|
if any(action in prompt_lower for action in ["change", "open", "set", "show"]):
|
|
25
20
|
return "sys_settings"
|
|
26
|
-
|
|
27
21
|
if "clear" in prompt_lower and any(word in prompt_lower for word in ["screen", "terminal", "chat"]):
|
|
28
22
|
return "sys_clear"
|
|
29
|
-
|
|
30
23
|
if any(word in prompt_lower for word in ["marketplace", "install agent", "download agent", "plugins"]):
|
|
31
24
|
return "sys_marketplace"
|
|
32
25
|
|
|
33
|
-
#
|
|
26
|
+
# --- Terminal Routing ---
|
|
27
|
+
if any(word in prompt_lower for word in ["terminal", "bash", "mkdir", "run command", "execute", "touch", "create folder"]):
|
|
28
|
+
return "terminal_agent"
|
|
29
|
+
|
|
30
|
+
# --- Git Routing ---
|
|
31
|
+
if any(word in prompt_lower for word in ["git", "commit", "push", "save my work", "version control", "github"]):
|
|
32
|
+
return "git_agent"
|
|
33
|
+
|
|
34
34
|
if any(word in prompt_lower for word in ["pip install", "install package", "python package", "pip module"]):
|
|
35
35
|
return "pip_agent"
|
|
36
36
|
if any(word in prompt_lower for word in ["database", "sql", "nosql", "postgres", "mongodb"]):
|
|
@@ -42,7 +42,6 @@ def analyze_intent(prompt: str) -> str:
|
|
|
42
42
|
if any(word in prompt_lower for word in ["3d", "webgl", "three.js", "shader"]):
|
|
43
43
|
return "3d_agent"
|
|
44
44
|
|
|
45
|
-
# 3. Base Core Routing
|
|
46
45
|
if any(w in words for w in ["data", "csv", "pandas", "plot", "graph"]):
|
|
47
46
|
return "data_science"
|
|
48
47
|
if any(w in words for w in ["code", "html", "python", "function", "script", "app", "css", "js"]):
|
|
@@ -13,6 +13,7 @@ codeaois/agents/coder_agent.py
|
|
|
13
13
|
codeaois/agents/data_science_agent.py
|
|
14
14
|
codeaois/agents/git_agent.py
|
|
15
15
|
codeaois/agents/pip_agent.py
|
|
16
|
+
codeaois/agents/terminal_agent.py
|
|
16
17
|
codeaois/agents/tester_agent.py
|
|
17
18
|
codeaois/brain/__init__.py
|
|
18
19
|
codeaois/brain/embeddings.py
|
|
@@ -21,6 +22,7 @@ codeaois/brain/scanner.py
|
|
|
21
22
|
codeaois/cli/__init__.py
|
|
22
23
|
codeaois/cli/main.py
|
|
23
24
|
codeaois/config/settings.py
|
|
25
|
+
codeaois/core/_auth.py
|
|
24
26
|
codeaois/core/context.py
|
|
25
27
|
codeaois/core/marketplace.py
|
|
26
28
|
codeaois/core/memory.py
|
|
@@ -6,16 +6,16 @@ long_description = (this_directory / "README.md").read_text(encoding="utf-8")
|
|
|
6
6
|
|
|
7
7
|
setup(
|
|
8
8
|
name="codeaois",
|
|
9
|
-
version="0.2.
|
|
9
|
+
version="0.2.6",
|
|
10
10
|
author="Nikhil Nagar",
|
|
11
11
|
description="An advanced, multi-agent AI Developer OS with zero-setup cloud architecture.",
|
|
12
12
|
long_description=long_description,
|
|
13
13
|
long_description_content_type="text/markdown",
|
|
14
14
|
packages=find_packages(),
|
|
15
15
|
install_requires=[
|
|
16
|
-
"
|
|
17
|
-
"prompt_toolkit",
|
|
18
|
-
"
|
|
16
|
+
"rich>=13.0.0",
|
|
17
|
+
"prompt_toolkit>=3.0.0",
|
|
18
|
+
"requests>=2.25.0"
|
|
19
19
|
],
|
|
20
20
|
entry_points={
|
|
21
21
|
"console_scripts": [
|
|
@@ -1,45 +0,0 @@
|
|
|
1
|
-
# codeaois/agents/git_agent.py
|
|
2
|
-
import subprocess
|
|
3
|
-
import os
|
|
4
|
-
|
|
5
|
-
C_YELLOW = '\033[93m'
|
|
6
|
-
C_GREEN = '\033[92m'
|
|
7
|
-
C_RESET = '\033[0m'
|
|
8
|
-
|
|
9
|
-
def run_git_command(command: list) -> tuple[bool, str]:
|
|
10
|
-
"""Quietly executes a terminal command and returns the result."""
|
|
11
|
-
try:
|
|
12
|
-
result = subprocess.run(command, capture_output=True, text=True, check=True)
|
|
13
|
-
return True, result.stdout.strip()
|
|
14
|
-
except subprocess.CalledProcessError as e:
|
|
15
|
-
return False, e.stderr.strip()
|
|
16
|
-
|
|
17
|
-
def auto_commit(file_path: str, message: str):
|
|
18
|
-
"""Automatically stages and commits a modified file."""
|
|
19
|
-
|
|
20
|
-
# 1. Check if the user is inside a Git repository
|
|
21
|
-
is_git, _ = run_git_command(["git", "rev-parse", "--is-inside-work-tree"])
|
|
22
|
-
if not is_git:
|
|
23
|
-
print(f" {C_YELLOW}⚠️ [Git Agent] No .git repository found in this folder. Skipping auto-commit.{C_RESET}")
|
|
24
|
-
return
|
|
25
|
-
|
|
26
|
-
print(f" {C_GREEN}🌿 [Git Agent] Engaging version control...{C_RESET}")
|
|
27
|
-
|
|
28
|
-
# 2. Stage only the specific file the AI just modified
|
|
29
|
-
success, err = run_git_command(["git", "add", file_path])
|
|
30
|
-
if not success:
|
|
31
|
-
print(f" {C_YELLOW}⚠️ [Git Agent] Failed to stage file: {err}{C_RESET}")
|
|
32
|
-
return
|
|
33
|
-
|
|
34
|
-
# 3. Double-check that there are actually changes to save
|
|
35
|
-
has_changes, diff = run_git_command(["git", "status", "--porcelain"])
|
|
36
|
-
if not has_changes or not diff:
|
|
37
|
-
print(f" {C_YELLOW}⚠️ [Git Agent] No actual code changes detected for {file_path}.{C_RESET}")
|
|
38
|
-
return
|
|
39
|
-
|
|
40
|
-
# 4. Commit the changes to the timeline
|
|
41
|
-
commit_success, commit_err = run_git_command(["git", "commit", "-m", message])
|
|
42
|
-
if commit_success:
|
|
43
|
-
print(f" {C_GREEN}✅ [Git Agent] Successfully committed changes to {file_path}!{C_RESET}")
|
|
44
|
-
else:
|
|
45
|
-
print(f" {C_YELLOW}⚠️ [Git Agent] Commit failed: {commit_err}{C_RESET}")
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|