makima-cli 0.2.0__tar.gz → 1.2.1__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.
- makima_cli-1.2.1/LICENSE +21 -0
- makima_cli-1.2.1/PKG-INFO +80 -0
- {makima_cli-0.2.0 → makima_cli-1.2.1}/README.md +1 -1
- {makima_cli-0.2.0 → makima_cli-1.2.1}/makima/__init__.py +0 -0
- makima_cli-1.2.1/makima/config.py +38 -0
- {makima_cli-0.2.0 → makima_cli-1.2.1}/makima/core/__init__.py +0 -0
- makima_cli-1.2.1/makima/core/agent.py +157 -0
- makima_cli-1.2.1/makima/core/config_manager.py +125 -0
- {makima_cli-0.2.0 → makima_cli-1.2.1}/makima/core/context.py +0 -0
- {makima_cli-0.2.0 → makima_cli-1.2.1}/makima/core/memory.py +0 -0
- makima_cli-1.2.1/makima/main.py +14 -0
- {makima_cli-0.2.0 → makima_cli-1.2.1}/makima/providers/base.py +0 -0
- {makima_cli-0.2.0 → makima_cli-1.2.1}/makima/providers/groq_provider.py +17 -2
- {makima_cli-0.2.0 → makima_cli-1.2.1}/makima/setup.py +51 -3
- makima_cli-1.2.1/makima/test.py +49 -0
- {makima_cli-0.2.0 → makima_cli-1.2.1}/makima/tools/__init__.py +0 -0
- {makima_cli-0.2.0 → makima_cli-1.2.1}/makima/tools/file_tools.py +0 -0
- {makima_cli-0.2.0 → makima_cli-1.2.1}/makima/tools/registry.py +0 -0
- makima_cli-1.2.1/makima/tools/shell_tools.py +20 -0
- makima_cli-1.2.1/makima/ui/__init__.py +0 -0
- makima_cli-1.2.1/makima/ui/app.py +138 -0
- makima_cli-1.2.1/makima_cli.egg-info/PKG-INFO +80 -0
- {makima_cli-0.2.0 → makima_cli-1.2.1}/makima_cli.egg-info/SOURCES.txt +5 -0
- {makima_cli-0.2.0 → makima_cli-1.2.1}/makima_cli.egg-info/dependency_links.txt +0 -0
- {makima_cli-0.2.0 → makima_cli-1.2.1}/makima_cli.egg-info/entry_points.txt +0 -0
- {makima_cli-0.2.0 → makima_cli-1.2.1}/makima_cli.egg-info/requires.txt +1 -0
- {makima_cli-0.2.0 → makima_cli-1.2.1}/makima_cli.egg-info/top_level.txt +0 -0
- {makima_cli-0.2.0 → makima_cli-1.2.1}/pyproject.toml +2 -1
- {makima_cli-0.2.0 → makima_cli-1.2.1}/setup.cfg +0 -0
- makima_cli-0.2.0/PKG-INFO +0 -55
- makima_cli-0.2.0/makima/config.py +0 -20
- makima_cli-0.2.0/makima/core/agent.py +0 -133
- makima_cli-0.2.0/makima/main.py +0 -8
- makima_cli-0.2.0/makima/tools/shell_tools.py +0 -20
- makima_cli-0.2.0/makima_cli.egg-info/PKG-INFO +0 -55
makima_cli-1.2.1/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Kanhaiya kumar
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: makima-cli
|
|
3
|
+
Version: 1.2.1
|
|
4
|
+
Summary: AI coding assistant for your terminal
|
|
5
|
+
Author: Kanhaiya
|
|
6
|
+
License: MIT License
|
|
7
|
+
|
|
8
|
+
Copyright (c) 2026 Kanhaiya kumar
|
|
9
|
+
|
|
10
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
11
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
12
|
+
in the Software without restriction, including without limitation the rights
|
|
13
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
14
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
15
|
+
furnished to do so, subject to the following conditions:
|
|
16
|
+
|
|
17
|
+
The above copyright notice and this permission notice shall be included in all
|
|
18
|
+
copies or substantial portions of the Software.
|
|
19
|
+
|
|
20
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
21
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
22
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
23
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
24
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
25
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
26
|
+
SOFTWARE.
|
|
27
|
+
|
|
28
|
+
Requires-Python: >=3.10
|
|
29
|
+
Description-Content-Type: text/markdown
|
|
30
|
+
License-File: LICENSE
|
|
31
|
+
Requires-Dist: groq
|
|
32
|
+
Requires-Dist: python-dotenv
|
|
33
|
+
Requires-Dist: gitpython
|
|
34
|
+
Requires-Dist: rich
|
|
35
|
+
Requires-Dist: pyfiglet
|
|
36
|
+
Requires-Dist: questionary
|
|
37
|
+
Dynamic: license-file
|
|
38
|
+
|
|
39
|
+
# Makima CLI 🤖
|
|
40
|
+
|
|
41
|
+
An AI-powered coding assistant that runs in your terminal. Point it at any codebase and ask questions, make edits, and run commands — all from a clean CLI interface.
|
|
42
|
+
|
|
43
|
+
## Features
|
|
44
|
+
|
|
45
|
+
- Understands your entire codebase
|
|
46
|
+
- Answers questions about your code
|
|
47
|
+
- Edits files with auto git backup before changes
|
|
48
|
+
- Creates new files
|
|
49
|
+
- Runs terminal commands with confirmation
|
|
50
|
+
- Works on any project
|
|
51
|
+
- Clean terminal UI with syntax highlighting
|
|
52
|
+
|
|
53
|
+
## Install
|
|
54
|
+
|
|
55
|
+
git clone https://github.com/kanhaiya-ML/makima-cli.git
|
|
56
|
+
cd makima-cli
|
|
57
|
+
pip install -r requirements.txt
|
|
58
|
+
|
|
59
|
+
## Setup
|
|
60
|
+
|
|
61
|
+
Create a .env file in the project root:
|
|
62
|
+
GROQ_API_KEY=your_key_here
|
|
63
|
+
|
|
64
|
+
Get a free API key at https://console.groq.com
|
|
65
|
+
|
|
66
|
+
## Usage
|
|
67
|
+
|
|
68
|
+
Point it at any project:
|
|
69
|
+
python main.py /path/to/your/project
|
|
70
|
+
|
|
71
|
+
Or run from inside a project folder:
|
|
72
|
+
cd your-project
|
|
73
|
+
python /path/to/makima-cli/main.py
|
|
74
|
+
|
|
75
|
+
## Built With
|
|
76
|
+
|
|
77
|
+
- Python
|
|
78
|
+
- Groq API
|
|
79
|
+
- Rich
|
|
80
|
+
- GitPython
|
|
@@ -14,7 +14,7 @@ An AI-powered coding assistant that runs in your terminal. Point it at any codeb
|
|
|
14
14
|
|
|
15
15
|
## Install
|
|
16
16
|
|
|
17
|
-
git clone https://github.com/
|
|
17
|
+
git clone https://github.com/kanhaiya-ML/makima-cli.git
|
|
18
18
|
cd makima-cli
|
|
19
19
|
pip install -r requirements.txt
|
|
20
20
|
|
|
File without changes
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
# import os
|
|
2
|
+
# import sys
|
|
3
|
+
# from makima.setup import setup_api_key,setup_model
|
|
4
|
+
# from dotenv import load_dotenv
|
|
5
|
+
# load_dotenv()
|
|
6
|
+
|
|
7
|
+
# GROQ_API_KEY = setup_api_key()
|
|
8
|
+
# # GROQ_API_KEY = os.getenv("GROQ_API_KEY")
|
|
9
|
+
# MODEL_NAME = setup_model()
|
|
10
|
+
# TOKEN_LIMIT = 10000
|
|
11
|
+
# # PROJECT_ROOT = os.getcwd()
|
|
12
|
+
# PROJECT_ROOT = sys.argv[1] if len(sys.argv) > 1 else os.getcwd()
|
|
13
|
+
|
|
14
|
+
# if not GROQ_API_KEY:
|
|
15
|
+
# print("Error: GROQ_API_KEY not set.")
|
|
16
|
+
# print("Run this command first:")
|
|
17
|
+
# print(' Windows: setx GROQ_API_KEY "your-key-here"')
|
|
18
|
+
# print(' Linux/Mac: export GROQ_API_KEY="your-key-here"')
|
|
19
|
+
# print("Get a free key at: https://console.groq.com")
|
|
20
|
+
# sys.exit(1)
|
|
21
|
+
|
|
22
|
+
import os
|
|
23
|
+
import sys
|
|
24
|
+
import json
|
|
25
|
+
from pathlib import Path
|
|
26
|
+
from dotenv import load_dotenv
|
|
27
|
+
load_dotenv()
|
|
28
|
+
|
|
29
|
+
config_file = Path.home() / ".makima" / "config.json"
|
|
30
|
+
config = {}
|
|
31
|
+
if config_file.exists():
|
|
32
|
+
with open(config_file, "r") as f:
|
|
33
|
+
config = json.load(f)
|
|
34
|
+
|
|
35
|
+
GROQ_API_KEY = config.get("groq_api_key") or os.getenv("GROQ_API_KEY")
|
|
36
|
+
MODEL_NAME = config.get("model") or "qwen/qwen3.6-27b"
|
|
37
|
+
TOKEN_LIMIT = 6000
|
|
38
|
+
PROJECT_ROOT = sys.argv[1] if len(sys.argv) > 1 else os.getcwd()
|
|
File without changes
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
import json
|
|
2
|
+
from makima.config import PROJECT_ROOT,MODEL_NAME
|
|
3
|
+
from makima.core.context import ContextManager
|
|
4
|
+
from makima.core.memory import Memory
|
|
5
|
+
from makima.tools import TOOL_REGISTRY
|
|
6
|
+
from makima.tools.registry import TOOL_SCHEMAS
|
|
7
|
+
from makima.providers.groq_provider import GroqProvider
|
|
8
|
+
from rich.console import Console
|
|
9
|
+
from makima.core.config_manager import handle_config
|
|
10
|
+
|
|
11
|
+
console = Console()
|
|
12
|
+
|
|
13
|
+
ctx = ContextManager()
|
|
14
|
+
context = ctx.build_context()
|
|
15
|
+
|
|
16
|
+
SYSTEM_PROMPT = f"""
|
|
17
|
+
You are a coding assistant. The project is at: {PROJECT_ROOT}
|
|
18
|
+
|
|
19
|
+
Rules:
|
|
20
|
+
- Always use list_files first to find exact paths
|
|
21
|
+
- Always use read_file before editing any file
|
|
22
|
+
- Use full absolute paths always
|
|
23
|
+
- Be concise and direct
|
|
24
|
+
- old_str must be an exact match of multiple lines from the file
|
|
25
|
+
- Never explain what you are about to do. Never say "Let me..." or "I'll first...".
|
|
26
|
+
- Just call the tool immediately and silently.
|
|
27
|
+
- Only speak in plain text when you have a FINAL answer for the user.
|
|
28
|
+
- Call only ONE tool per response. Wait for the tool result before calling the next tool.
|
|
29
|
+
- Never output multiple tool calls in one response.
|
|
30
|
+
"""
|
|
31
|
+
|
|
32
|
+
import pyfiglet
|
|
33
|
+
from rich.panel import Panel
|
|
34
|
+
from rich.text import Text
|
|
35
|
+
from rich.rule import Rule
|
|
36
|
+
from rich.markdown import Markdown
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
def run_agent():
|
|
40
|
+
provider = GroqProvider()
|
|
41
|
+
memory = Memory(system_prompt=SYSTEM_PROMPT)
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
ascii_art = pyfiglet.figlet_format("Makima", font="big")
|
|
45
|
+
console.print(f"[bold #FF6B35]{ascii_art}[/]")
|
|
46
|
+
|
|
47
|
+
# info line underneath, no box
|
|
48
|
+
console.print(f"[dim] Your AI Coding Assistant[/]")
|
|
49
|
+
console.print(f"[green] Project :[/] {PROJECT_ROOT}")
|
|
50
|
+
console.print(f"[green] Files :[/] {len(ctx.files)} files loaded")
|
|
51
|
+
console.print(f"[green] Model :[/] {MODEL_NAME}")
|
|
52
|
+
console.print(f"[dim] Type 'exit' to quit[/]")
|
|
53
|
+
console.print(Rule(style="#FF6B35")) # clean horizontal line separator
|
|
54
|
+
console.print()
|
|
55
|
+
|
|
56
|
+
try:
|
|
57
|
+
|
|
58
|
+
while True:
|
|
59
|
+
user_input = console.input("[bold blue]You:[/] ")
|
|
60
|
+
if user_input.strip() == "exit":
|
|
61
|
+
break
|
|
62
|
+
|
|
63
|
+
if user_input.strip() == "/config":
|
|
64
|
+
handle_config()
|
|
65
|
+
continue
|
|
66
|
+
|
|
67
|
+
memory.add_user(user_input)
|
|
68
|
+
|
|
69
|
+
while True:
|
|
70
|
+
try:
|
|
71
|
+
with console.status("[yellow]thinking...[/]"):
|
|
72
|
+
stream = provider.stream_chat(
|
|
73
|
+
messages=memory.get(),
|
|
74
|
+
tools=TOOL_SCHEMAS
|
|
75
|
+
)
|
|
76
|
+
chunks = list(stream)
|
|
77
|
+
except Exception as e:
|
|
78
|
+
console.print(f"[red]Error: {e}[/]")
|
|
79
|
+
break
|
|
80
|
+
|
|
81
|
+
#variables to collect the response
|
|
82
|
+
text_buffer = ""
|
|
83
|
+
tool_name = ""
|
|
84
|
+
tool_args = ""
|
|
85
|
+
tool_call_id = ""
|
|
86
|
+
is_tool_call = False
|
|
87
|
+
|
|
88
|
+
# console.print("[bold green]Agent:[/] ", end="")
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
for chunk in chunks:
|
|
92
|
+
delta = chunk.choices[0].delta
|
|
93
|
+
|
|
94
|
+
#text chunk
|
|
95
|
+
if delta.content:
|
|
96
|
+
# print(delta.content, end="", flush=True)
|
|
97
|
+
text_buffer += delta.content
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
# tool call chunk
|
|
101
|
+
if delta.tool_calls:
|
|
102
|
+
is_tool_call = True
|
|
103
|
+
tc = delta.tool_calls[0]
|
|
104
|
+
if tc.id:
|
|
105
|
+
tool_call_id = tc.id
|
|
106
|
+
if tc.function.name:
|
|
107
|
+
tool_name += tc.function.name
|
|
108
|
+
if tc.function.arguments:
|
|
109
|
+
tool_args += tc.function.arguments
|
|
110
|
+
|
|
111
|
+
# print()
|
|
112
|
+
|
|
113
|
+
if is_tool_call:
|
|
114
|
+
console.print(f"[dim]⚡ {tool_name}[/]")
|
|
115
|
+
args = json.loads(tool_args)
|
|
116
|
+
|
|
117
|
+
# confirmation for run_command only
|
|
118
|
+
if tool_name == "run_command":
|
|
119
|
+
console.print(f"[yellow]Command: {args.get('cmd')}[/]")
|
|
120
|
+
confirm = console.input("[bold]Run this? (y/n):[/] ").strip().lower()
|
|
121
|
+
if confirm != "y":
|
|
122
|
+
memory.add_raw({
|
|
123
|
+
"role": "assistant",
|
|
124
|
+
"tool_calls": [{
|
|
125
|
+
"id": tool_call_id,
|
|
126
|
+
"type": "function",
|
|
127
|
+
"function": {
|
|
128
|
+
"name": tool_name,
|
|
129
|
+
"arguments": tool_args
|
|
130
|
+
}
|
|
131
|
+
}]
|
|
132
|
+
})
|
|
133
|
+
memory.add_tool_result(tool_call_id, "Command cancelled by user")
|
|
134
|
+
continue
|
|
135
|
+
|
|
136
|
+
tool_fn = TOOL_REGISTRY.get(tool_name)
|
|
137
|
+
with console.status(f"[yellow]calling {tool_name}...[/]"):
|
|
138
|
+
result = tool_fn(**args) if tool_fn else "Unknown tool"
|
|
139
|
+
memory.add_raw({
|
|
140
|
+
"role": "assistant",
|
|
141
|
+
"tool_calls": [{
|
|
142
|
+
"id": tool_call_id,
|
|
143
|
+
"type": "function",
|
|
144
|
+
"function": {
|
|
145
|
+
"name": tool_name,
|
|
146
|
+
"arguments": tool_args
|
|
147
|
+
}
|
|
148
|
+
}]
|
|
149
|
+
})
|
|
150
|
+
memory.add_tool_result(tool_call_id, str(result))
|
|
151
|
+
else:
|
|
152
|
+
console.print("[bold green]Agent:[/]")
|
|
153
|
+
console.print(Markdown(text_buffer))
|
|
154
|
+
memory.add_assistant(text_buffer)
|
|
155
|
+
break
|
|
156
|
+
except KeyboardInterrupt:
|
|
157
|
+
console.print("\n[dim]Goodbye![/]")
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
from pathlib import Path
|
|
2
|
+
import json
|
|
3
|
+
from makima.setup import validate_key
|
|
4
|
+
import questionary
|
|
5
|
+
from rich.console import Console
|
|
6
|
+
console = Console()
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def show_config():
|
|
10
|
+
config_dir = Path.home() / ".makima"
|
|
11
|
+
config_file = config_dir / "config.json"
|
|
12
|
+
|
|
13
|
+
try:
|
|
14
|
+
with open(config_file,"r") as f:
|
|
15
|
+
data = json.load(f)
|
|
16
|
+
model = data.get("model")
|
|
17
|
+
key = data.get("groq_api_key")
|
|
18
|
+
console.print("Current setting:")
|
|
19
|
+
console.print(f"Model: {model}")
|
|
20
|
+
console.print(f"Key: {key[:8]}****")
|
|
21
|
+
# console.print("What do you want to change?")
|
|
22
|
+
# options = questionary.select(
|
|
23
|
+
# "What do you want to change?",
|
|
24
|
+
# choices = [
|
|
25
|
+
# "Change Model",
|
|
26
|
+
# "Change API key",
|
|
27
|
+
# "Cancel"
|
|
28
|
+
# ]
|
|
29
|
+
# )
|
|
30
|
+
|
|
31
|
+
except Exception as e:
|
|
32
|
+
return f"Somthing went wrong! {e}"
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
def change_model():
|
|
36
|
+
config_dir = Path.home() / ".makima"
|
|
37
|
+
config_file = config_dir / "config.json"
|
|
38
|
+
|
|
39
|
+
if config_file.exists():
|
|
40
|
+
with open(config_file,"r") as f:
|
|
41
|
+
data = json.load(f)
|
|
42
|
+
model = data.get("model")
|
|
43
|
+
if model:
|
|
44
|
+
console.print(f"Selected Model: {model}")
|
|
45
|
+
|
|
46
|
+
model = questionary.select(
|
|
47
|
+
"Select a model: ",
|
|
48
|
+
choices = [
|
|
49
|
+
"llama-3.3-70b",
|
|
50
|
+
"qwen/qwen3.6-27b",
|
|
51
|
+
"gemma2-9b"
|
|
52
|
+
]
|
|
53
|
+
).ask()
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
existing = {}
|
|
57
|
+
if config_file.exists():
|
|
58
|
+
with open(config_file,"r") as f:
|
|
59
|
+
existing = json.load(f)
|
|
60
|
+
|
|
61
|
+
existing["model"] = model
|
|
62
|
+
|
|
63
|
+
with open(config_file,"w") as f:
|
|
64
|
+
json.dump(existing,f)
|
|
65
|
+
|
|
66
|
+
console.print(f"[bold green]✓ Model changed to: {model}[/]")
|
|
67
|
+
return model
|
|
68
|
+
|
|
69
|
+
# if model:
|
|
70
|
+
# console.print(f"[bold green]✓ Model Selected: {model} [/]")
|
|
71
|
+
# config_dir.mkdir(exist_ok=True)
|
|
72
|
+
# with open(config_file,"w") as f:
|
|
73
|
+
# json.dump({"model":model}, f)
|
|
74
|
+
# return model
|
|
75
|
+
# else:
|
|
76
|
+
# console.print("[bold red]✗ Please Select in Given models.[/]")
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
def change_api_key():
|
|
81
|
+
config_dir = Path.home() / ".makima"
|
|
82
|
+
config_file = config_dir / "config.json"
|
|
83
|
+
|
|
84
|
+
if config_file.exists():
|
|
85
|
+
with open(config_file,"r") as f:
|
|
86
|
+
data = json.load(f)
|
|
87
|
+
key = data.get("groq_api_key")
|
|
88
|
+
if key:
|
|
89
|
+
console.print(f"Already Setted API key: {key}")
|
|
90
|
+
|
|
91
|
+
while True:
|
|
92
|
+
|
|
93
|
+
key = console.input("[bold yellow]Enter your Groq API key:[/] ").strip()
|
|
94
|
+
|
|
95
|
+
with console.status("[yellow]Authenticating...[/]"):
|
|
96
|
+
valid = validate_key(key)
|
|
97
|
+
|
|
98
|
+
if valid:
|
|
99
|
+
console.print("[bold green]✓ Connected to Groq[/]")
|
|
100
|
+
config_dir.mkdir(exist_ok=True)
|
|
101
|
+
existing = {}
|
|
102
|
+
if config_file.exists():
|
|
103
|
+
with open(config_file, "r") as f:
|
|
104
|
+
existing = json.load(f)
|
|
105
|
+
existing["groq_api_key"] = key
|
|
106
|
+
with open(config_file, "w") as f:
|
|
107
|
+
json.dump(existing, f)
|
|
108
|
+
return key
|
|
109
|
+
else:
|
|
110
|
+
console.print("[bold red]✗ Invalid key. Try again.[/]")
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
def handle_config():
|
|
115
|
+
show_config()
|
|
116
|
+
|
|
117
|
+
choice = questionary.select(
|
|
118
|
+
"What do you want to change?",
|
|
119
|
+
choices=["Change model", "Change API key", "Cancel"]
|
|
120
|
+
).ask()
|
|
121
|
+
|
|
122
|
+
if choice == "Change model":
|
|
123
|
+
change_model()
|
|
124
|
+
elif choice == "Change API key":
|
|
125
|
+
change_api_key()
|
|
File without changes
|
|
File without changes
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
from makima.core.agent import run_agent
|
|
2
|
+
import sys
|
|
3
|
+
from makima.ui.app import run_ui
|
|
4
|
+
from makima.setup import setup_api_key, setup_model
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
def main():
|
|
8
|
+
# run_agent()
|
|
9
|
+
setup_model()
|
|
10
|
+
setup_api_key()
|
|
11
|
+
run_ui()
|
|
12
|
+
|
|
13
|
+
if __name__ == "__main__":
|
|
14
|
+
main()
|
|
File without changes
|
|
@@ -1,11 +1,26 @@
|
|
|
1
1
|
from groq import Groq
|
|
2
2
|
from makima.providers.base import LLMProvider
|
|
3
|
-
from makima.config import
|
|
3
|
+
from makima.config import MODEL_NAME
|
|
4
|
+
import os
|
|
5
|
+
import json
|
|
6
|
+
from pathlib import Path
|
|
4
7
|
|
|
5
8
|
class GroqProvider(LLMProvider):
|
|
6
9
|
|
|
7
10
|
def __init__(self):
|
|
8
|
-
|
|
11
|
+
# read fresh from config file
|
|
12
|
+
key = self._load_key()
|
|
13
|
+
self.client = Groq(api_key=key)
|
|
14
|
+
|
|
15
|
+
def _load_key(self):
|
|
16
|
+
config_file = Path.home() / ".makima" / "config.json"
|
|
17
|
+
if config_file.exists():
|
|
18
|
+
with open(config_file, "r") as f:
|
|
19
|
+
data = json.load(f)
|
|
20
|
+
key = data.get("groq_api_key")
|
|
21
|
+
if key:
|
|
22
|
+
return key
|
|
23
|
+
return os.getenv("GROQ_API_KEY")
|
|
9
24
|
|
|
10
25
|
def chat(self, messages: list, tools: list) -> object:
|
|
11
26
|
return self.client.chat.completions.create(
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
from pathlib import Path
|
|
2
2
|
from groq import Groq
|
|
3
3
|
import json
|
|
4
|
+
import questionary
|
|
4
5
|
from rich.console import Console
|
|
5
6
|
console = Console()
|
|
6
7
|
|
|
@@ -26,8 +27,9 @@ def setup_api_key():
|
|
|
26
27
|
if config_file.exists():
|
|
27
28
|
with open(config_file, "r") as f:
|
|
28
29
|
data = json.load(f)
|
|
29
|
-
key = data
|
|
30
|
-
|
|
30
|
+
key = data.get("groq_api_key")
|
|
31
|
+
if key and validate_key(key):
|
|
32
|
+
return key
|
|
31
33
|
|
|
32
34
|
import os
|
|
33
35
|
env_key = os.getenv("GROQ_API_KEY")
|
|
@@ -50,4 +52,50 @@ def setup_api_key():
|
|
|
50
52
|
json.dump({"groq_api_key": key}, f)
|
|
51
53
|
return key
|
|
52
54
|
else:
|
|
53
|
-
console.print("[bold red]✗ Invalid key. Try again.[/]")
|
|
55
|
+
console.print("[bold red]✗ Invalid key. Try again.[/]")
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
def setup_model():
|
|
60
|
+
config_dir = Path.home() / ".makima"
|
|
61
|
+
config_file = config_dir / "config.json"
|
|
62
|
+
|
|
63
|
+
if config_file.exists():
|
|
64
|
+
with open(config_file,"r") as f:
|
|
65
|
+
data = json.load(f)
|
|
66
|
+
model = data.get("model")
|
|
67
|
+
if model:
|
|
68
|
+
return model
|
|
69
|
+
|
|
70
|
+
model = questionary.select(
|
|
71
|
+
"Select a model: ",
|
|
72
|
+
choices = [
|
|
73
|
+
"llama-3.3-70b",
|
|
74
|
+
"qwen/qwen3.6-27b",
|
|
75
|
+
"gemma2-9b"
|
|
76
|
+
]
|
|
77
|
+
).ask()
|
|
78
|
+
|
|
79
|
+
existing = {}
|
|
80
|
+
if config_file.exists():
|
|
81
|
+
with open(config_file,"r") as f:
|
|
82
|
+
existing = json.load(f)
|
|
83
|
+
|
|
84
|
+
existing["model"] = model
|
|
85
|
+
|
|
86
|
+
config_dir.mkdir(exist_ok=True)
|
|
87
|
+
with open(config_file,"w") as f:
|
|
88
|
+
json.dump(existing,f)
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
if model:
|
|
92
|
+
console.print(f"[bold green]✓ Model Selected: {model} [/]")
|
|
93
|
+
config_dir.mkdir(exist_ok=True)
|
|
94
|
+
with open(config_file,"w") as f:
|
|
95
|
+
json.dump({"model":model}, f)
|
|
96
|
+
return model
|
|
97
|
+
else:
|
|
98
|
+
console.print("[bold red]✗ Please Select in Given models.[/]")
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
from textual.app import App
|
|
2
|
+
from textual.widgets import Header, Footer, Input, RichLog
|
|
3
|
+
from rich.text import Text
|
|
4
|
+
|
|
5
|
+
from makima.providers.groq_provider import GroqProvider
|
|
6
|
+
from makima.core.memory import Memory
|
|
7
|
+
|
|
8
|
+
SYSTEM_PROMPT = "..."
|
|
9
|
+
class Makima(App):
|
|
10
|
+
|
|
11
|
+
def on_mount(self):
|
|
12
|
+
self.provider = GroqProvider()
|
|
13
|
+
self.memory = Memory(system_prompt=SYSTEM_PROMPT)
|
|
14
|
+
|
|
15
|
+
def compose(self):
|
|
16
|
+
yield Header()
|
|
17
|
+
|
|
18
|
+
yield RichLog(id="chat")
|
|
19
|
+
|
|
20
|
+
yield Input(
|
|
21
|
+
placeholder="Ask Makima...",
|
|
22
|
+
id="input"
|
|
23
|
+
)
|
|
24
|
+
|
|
25
|
+
yield Footer()
|
|
26
|
+
|
|
27
|
+
def on_input_submitted(self, event: Input.Submitted):
|
|
28
|
+
chat = self.query_one("#chat", RichLog)
|
|
29
|
+
|
|
30
|
+
user_input = event.value.strip()
|
|
31
|
+
|
|
32
|
+
if not user_input:
|
|
33
|
+
return
|
|
34
|
+
|
|
35
|
+
chat.write(
|
|
36
|
+
Text(f"You: {user_input}",style="bold cyan")
|
|
37
|
+
)
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
event.input.value = ""
|
|
41
|
+
|
|
42
|
+
chat.write(
|
|
43
|
+
Text("Makima: Hello! I'm alive", style="bold green")
|
|
44
|
+
)
|
|
45
|
+
# chat.write("[bold green]Makima:[/] Hello! I'm alive")
|
|
46
|
+
|
|
47
|
+
if __name__ == "__main__":
|
|
48
|
+
app = Makima()
|
|
49
|
+
app.run()
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import subprocess
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
def run_command(cmd):
|
|
5
|
+
# print(f"Commands going to Run: {cmd}")
|
|
6
|
+
# User_answer = input("Run This? (Y/N): ")
|
|
7
|
+
# User_answer = User_answer.lower()
|
|
8
|
+
|
|
9
|
+
# if User_answer != "y":
|
|
10
|
+
# return "Command cancelled"
|
|
11
|
+
|
|
12
|
+
result = subprocess.run(
|
|
13
|
+
cmd,
|
|
14
|
+
shell=True,
|
|
15
|
+
capture_output=True,
|
|
16
|
+
text=True,
|
|
17
|
+
timeout=30
|
|
18
|
+
)
|
|
19
|
+
|
|
20
|
+
return result.stdout + result.stderr
|
|
File without changes
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
from textual.app import App, ComposeResult
|
|
2
|
+
from textual.widgets import Header, Footer, Input, RichLog
|
|
3
|
+
from makima.config import PROJECT_ROOT
|
|
4
|
+
from makima.tools import TOOL_REGISTRY
|
|
5
|
+
from makima.tools.registry import TOOL_SCHEMAS
|
|
6
|
+
from makima.core.config_manager import handle_config
|
|
7
|
+
|
|
8
|
+
import asyncio
|
|
9
|
+
import json
|
|
10
|
+
|
|
11
|
+
from makima.providers.groq_provider import GroqProvider
|
|
12
|
+
from makima.core.memory import Memory
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
SYSTEM_PROMPT = f"""
|
|
16
|
+
You are a coding assistant. The project is at: {PROJECT_ROOT}
|
|
17
|
+
|
|
18
|
+
Rules:
|
|
19
|
+
- Always use list_files first to find exact paths
|
|
20
|
+
- Always use read_file before editing any file
|
|
21
|
+
- Use full absolute paths always
|
|
22
|
+
- Be concise and direct
|
|
23
|
+
- old_str must be an exact match of multiple lines from the file
|
|
24
|
+
- Never explain what you are about to do. Never say "Let me..." or "I'll first...".
|
|
25
|
+
- Just call the tool immediately and silently.
|
|
26
|
+
- Only speak in plain text when you have a FINAL answer for the user.
|
|
27
|
+
- Call only ONE tool per response. Wait for the tool result before calling the next tool.
|
|
28
|
+
- Never output multiple tool calls in one response.
|
|
29
|
+
"""
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
class MakimaApp(App):
|
|
33
|
+
CSS_PATH = "app.tcss"
|
|
34
|
+
|
|
35
|
+
def __init__(self):
|
|
36
|
+
super().__init__()
|
|
37
|
+
self.memory = Memory(system_prompt=SYSTEM_PROMPT)
|
|
38
|
+
self.provider = GroqProvider()
|
|
39
|
+
|
|
40
|
+
def compose(self) -> ComposeResult:
|
|
41
|
+
yield Header()
|
|
42
|
+
yield RichLog(id="chat",markup=True, highlight=True)
|
|
43
|
+
yield Input(placeholder="Ask anything... (type 'exit' to quit)")
|
|
44
|
+
yield Footer()
|
|
45
|
+
|
|
46
|
+
def on_mount(self):
|
|
47
|
+
# focus the input so user can type immediately
|
|
48
|
+
self.query_one(Input).focus()
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
async def on_input_submitted(self, event: Input.Submitted) -> None:
|
|
52
|
+
user_input = event.value.strip()
|
|
53
|
+
|
|
54
|
+
if not user_input:
|
|
55
|
+
return
|
|
56
|
+
|
|
57
|
+
chat = self.query_one(RichLog)
|
|
58
|
+
input_box = self.query_one(Input)
|
|
59
|
+
|
|
60
|
+
chat.write(f"[bold blue]You:[/] {user_input}")
|
|
61
|
+
input_box.clear()
|
|
62
|
+
|
|
63
|
+
if user_input == "exit":
|
|
64
|
+
self.exit()
|
|
65
|
+
return
|
|
66
|
+
|
|
67
|
+
if user_input == "/config":
|
|
68
|
+
# config runs in background thread
|
|
69
|
+
await asyncio.to_thread(handle_config)
|
|
70
|
+
return
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
# show thinking indicator
|
|
74
|
+
chat.write("[dim]thinking...[/]")
|
|
75
|
+
|
|
76
|
+
# run agent in background thread
|
|
77
|
+
response = await asyncio.to_thread(self.process_message, user_input)
|
|
78
|
+
|
|
79
|
+
# remove "thinking..." and show response
|
|
80
|
+
from rich.markdown import Markdown
|
|
81
|
+
chat.write(Markdown(f"[bold green]Agent:[/] {response}"))
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
def process_message(self, user_input):
|
|
85
|
+
self.memory.add_user(user_input)
|
|
86
|
+
|
|
87
|
+
while True:
|
|
88
|
+
stream = self.provider.stream_chat(
|
|
89
|
+
messages=self.memory.get(),
|
|
90
|
+
tools=TOOL_SCHEMAS
|
|
91
|
+
)
|
|
92
|
+
chunks = list(stream)
|
|
93
|
+
|
|
94
|
+
# collect chunks
|
|
95
|
+
text_buffer = ""
|
|
96
|
+
tool_name = ""
|
|
97
|
+
tool_args = ""
|
|
98
|
+
tool_call_id = ""
|
|
99
|
+
is_tool_call = False
|
|
100
|
+
|
|
101
|
+
for chunk in chunks:
|
|
102
|
+
delta = chunk.choices[0].delta
|
|
103
|
+
if delta.content:
|
|
104
|
+
text_buffer += delta.content
|
|
105
|
+
if delta.tool_calls:
|
|
106
|
+
is_tool_call = True
|
|
107
|
+
tc = delta.tool_calls[0]
|
|
108
|
+
if tc.id:
|
|
109
|
+
tool_call_id = tc.id
|
|
110
|
+
if tc.function.name:
|
|
111
|
+
tool_name += tc.function.name
|
|
112
|
+
if tc.function.arguments:
|
|
113
|
+
tool_args += tc.function.arguments
|
|
114
|
+
|
|
115
|
+
if is_tool_call:
|
|
116
|
+
args = json.loads(tool_args)
|
|
117
|
+
tool_fn = TOOL_REGISTRY.get(tool_name)
|
|
118
|
+
result = tool_fn(**args) if tool_fn else "Unknown tool"
|
|
119
|
+
|
|
120
|
+
self.memory.add_raw({
|
|
121
|
+
"role": "assistant",
|
|
122
|
+
"tool_calls": [{
|
|
123
|
+
"id": tool_call_id,
|
|
124
|
+
"type": "function",
|
|
125
|
+
"function": {
|
|
126
|
+
"name": tool_name,
|
|
127
|
+
"arguments": tool_args
|
|
128
|
+
}
|
|
129
|
+
}]
|
|
130
|
+
})
|
|
131
|
+
self.memory.add_tool_result(tool_call_id, str(result))
|
|
132
|
+
|
|
133
|
+
else:
|
|
134
|
+
self.memory.add_assistant(text_buffer)
|
|
135
|
+
return text_buffer
|
|
136
|
+
def run_ui():
|
|
137
|
+
app = MakimaApp()
|
|
138
|
+
app.run()
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: makima-cli
|
|
3
|
+
Version: 1.2.1
|
|
4
|
+
Summary: AI coding assistant for your terminal
|
|
5
|
+
Author: Kanhaiya
|
|
6
|
+
License: MIT License
|
|
7
|
+
|
|
8
|
+
Copyright (c) 2026 Kanhaiya kumar
|
|
9
|
+
|
|
10
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
11
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
12
|
+
in the Software without restriction, including without limitation the rights
|
|
13
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
14
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
15
|
+
furnished to do so, subject to the following conditions:
|
|
16
|
+
|
|
17
|
+
The above copyright notice and this permission notice shall be included in all
|
|
18
|
+
copies or substantial portions of the Software.
|
|
19
|
+
|
|
20
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
21
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
22
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
23
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
24
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
25
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
26
|
+
SOFTWARE.
|
|
27
|
+
|
|
28
|
+
Requires-Python: >=3.10
|
|
29
|
+
Description-Content-Type: text/markdown
|
|
30
|
+
License-File: LICENSE
|
|
31
|
+
Requires-Dist: groq
|
|
32
|
+
Requires-Dist: python-dotenv
|
|
33
|
+
Requires-Dist: gitpython
|
|
34
|
+
Requires-Dist: rich
|
|
35
|
+
Requires-Dist: pyfiglet
|
|
36
|
+
Requires-Dist: questionary
|
|
37
|
+
Dynamic: license-file
|
|
38
|
+
|
|
39
|
+
# Makima CLI 🤖
|
|
40
|
+
|
|
41
|
+
An AI-powered coding assistant that runs in your terminal. Point it at any codebase and ask questions, make edits, and run commands — all from a clean CLI interface.
|
|
42
|
+
|
|
43
|
+
## Features
|
|
44
|
+
|
|
45
|
+
- Understands your entire codebase
|
|
46
|
+
- Answers questions about your code
|
|
47
|
+
- Edits files with auto git backup before changes
|
|
48
|
+
- Creates new files
|
|
49
|
+
- Runs terminal commands with confirmation
|
|
50
|
+
- Works on any project
|
|
51
|
+
- Clean terminal UI with syntax highlighting
|
|
52
|
+
|
|
53
|
+
## Install
|
|
54
|
+
|
|
55
|
+
git clone https://github.com/kanhaiya-ML/makima-cli.git
|
|
56
|
+
cd makima-cli
|
|
57
|
+
pip install -r requirements.txt
|
|
58
|
+
|
|
59
|
+
## Setup
|
|
60
|
+
|
|
61
|
+
Create a .env file in the project root:
|
|
62
|
+
GROQ_API_KEY=your_key_here
|
|
63
|
+
|
|
64
|
+
Get a free API key at https://console.groq.com
|
|
65
|
+
|
|
66
|
+
## Usage
|
|
67
|
+
|
|
68
|
+
Point it at any project:
|
|
69
|
+
python main.py /path/to/your/project
|
|
70
|
+
|
|
71
|
+
Or run from inside a project folder:
|
|
72
|
+
cd your-project
|
|
73
|
+
python /path/to/makima-cli/main.py
|
|
74
|
+
|
|
75
|
+
## Built With
|
|
76
|
+
|
|
77
|
+
- Python
|
|
78
|
+
- Groq API
|
|
79
|
+
- Rich
|
|
80
|
+
- GitPython
|
|
@@ -1,11 +1,14 @@
|
|
|
1
|
+
LICENSE
|
|
1
2
|
README.md
|
|
2
3
|
pyproject.toml
|
|
3
4
|
makima/__init__.py
|
|
4
5
|
makima/config.py
|
|
5
6
|
makima/main.py
|
|
6
7
|
makima/setup.py
|
|
8
|
+
makima/test.py
|
|
7
9
|
makima/core/__init__.py
|
|
8
10
|
makima/core/agent.py
|
|
11
|
+
makima/core/config_manager.py
|
|
9
12
|
makima/core/context.py
|
|
10
13
|
makima/core/memory.py
|
|
11
14
|
makima/providers/base.py
|
|
@@ -14,6 +17,8 @@ makima/tools/__init__.py
|
|
|
14
17
|
makima/tools/file_tools.py
|
|
15
18
|
makima/tools/registry.py
|
|
16
19
|
makima/tools/shell_tools.py
|
|
20
|
+
makima/ui/__init__.py
|
|
21
|
+
makima/ui/app.py
|
|
17
22
|
makima_cli.egg-info/PKG-INFO
|
|
18
23
|
makima_cli.egg-info/SOURCES.txt
|
|
19
24
|
makima_cli.egg-info/dependency_links.txt
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "makima-cli"
|
|
7
|
-
version = "
|
|
7
|
+
version = "1.2.1"
|
|
8
8
|
description = "AI coding assistant for your terminal"
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
license = {file = "LICENSE"}
|
|
@@ -18,6 +18,7 @@ dependencies = [
|
|
|
18
18
|
"gitpython",
|
|
19
19
|
"rich",
|
|
20
20
|
"pyfiglet",
|
|
21
|
+
"questionary",
|
|
21
22
|
]
|
|
22
23
|
|
|
23
24
|
[project.scripts]
|
|
File without changes
|
makima_cli-0.2.0/PKG-INFO
DELETED
|
@@ -1,55 +0,0 @@
|
|
|
1
|
-
Metadata-Version: 2.4
|
|
2
|
-
Name: makima-cli
|
|
3
|
-
Version: 0.2.0
|
|
4
|
-
Summary: AI coding assistant for your terminal
|
|
5
|
-
Author: Kanhaiya
|
|
6
|
-
Requires-Python: >=3.10
|
|
7
|
-
Description-Content-Type: text/markdown
|
|
8
|
-
Requires-Dist: groq
|
|
9
|
-
Requires-Dist: python-dotenv
|
|
10
|
-
Requires-Dist: gitpython
|
|
11
|
-
Requires-Dist: rich
|
|
12
|
-
Requires-Dist: pyfiglet
|
|
13
|
-
|
|
14
|
-
# Makima CLI 🤖
|
|
15
|
-
|
|
16
|
-
An AI-powered coding assistant that runs in your terminal. Point it at any codebase and ask questions, make edits, and run commands — all from a clean CLI interface.
|
|
17
|
-
|
|
18
|
-
## Features
|
|
19
|
-
|
|
20
|
-
- Understands your entire codebase
|
|
21
|
-
- Answers questions about your code
|
|
22
|
-
- Edits files with auto git backup before changes
|
|
23
|
-
- Creates new files
|
|
24
|
-
- Runs terminal commands with confirmation
|
|
25
|
-
- Works on any project
|
|
26
|
-
- Clean terminal UI with syntax highlighting
|
|
27
|
-
|
|
28
|
-
## Install
|
|
29
|
-
|
|
30
|
-
git clone https://github.com/yourusername/makima-cli.git
|
|
31
|
-
cd makima-cli
|
|
32
|
-
pip install -r requirements.txt
|
|
33
|
-
|
|
34
|
-
## Setup
|
|
35
|
-
|
|
36
|
-
Create a .env file in the project root:
|
|
37
|
-
GROQ_API_KEY=your_key_here
|
|
38
|
-
|
|
39
|
-
Get a free API key at https://console.groq.com
|
|
40
|
-
|
|
41
|
-
## Usage
|
|
42
|
-
|
|
43
|
-
Point it at any project:
|
|
44
|
-
python main.py /path/to/your/project
|
|
45
|
-
|
|
46
|
-
Or run from inside a project folder:
|
|
47
|
-
cd your-project
|
|
48
|
-
python /path/to/makima-cli/main.py
|
|
49
|
-
|
|
50
|
-
## Built With
|
|
51
|
-
|
|
52
|
-
- Python
|
|
53
|
-
- Groq API
|
|
54
|
-
- Rich
|
|
55
|
-
- GitPython
|
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
import os
|
|
2
|
-
import sys
|
|
3
|
-
from makima.setup import setup_api_key
|
|
4
|
-
from dotenv import load_dotenv
|
|
5
|
-
load_dotenv()
|
|
6
|
-
|
|
7
|
-
GROQ_API_KEY = setup_api_key()
|
|
8
|
-
# GROQ_API_KEY = os.getenv("GROQ_API_KEY")
|
|
9
|
-
MODEL_NAME = "qwen/qwen3.6-27b"
|
|
10
|
-
TOKEN_LIMIT = 10000
|
|
11
|
-
# PROJECT_ROOT = os.getcwd()
|
|
12
|
-
PROJECT_ROOT = sys.argv[1] if len(sys.argv) > 1 else os.getcwd()
|
|
13
|
-
|
|
14
|
-
if not GROQ_API_KEY:
|
|
15
|
-
print("Error: GROQ_API_KEY not set.")
|
|
16
|
-
print("Run this command first:")
|
|
17
|
-
print(' Windows: setx GROQ_API_KEY "your-key-here"')
|
|
18
|
-
print(' Linux/Mac: export GROQ_API_KEY="your-key-here"')
|
|
19
|
-
print("Get a free key at: https://console.groq.com")
|
|
20
|
-
sys.exit(1)
|
|
@@ -1,133 +0,0 @@
|
|
|
1
|
-
import json
|
|
2
|
-
from makima.config import PROJECT_ROOT,MODEL_NAME
|
|
3
|
-
from makima.core.context import ContextManager
|
|
4
|
-
from makima.core.memory import Memory
|
|
5
|
-
from makima.tools import TOOL_REGISTRY
|
|
6
|
-
from makima.tools.registry import TOOL_SCHEMAS
|
|
7
|
-
from makima.providers.groq_provider import GroqProvider
|
|
8
|
-
from rich.console import Console
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
console = Console()
|
|
12
|
-
|
|
13
|
-
ctx = ContextManager()
|
|
14
|
-
context = ctx.build_context()
|
|
15
|
-
|
|
16
|
-
SYSTEM_PROMPT = f"""
|
|
17
|
-
You are a coding assistant. The project is at: {PROJECT_ROOT}
|
|
18
|
-
|
|
19
|
-
Rules:
|
|
20
|
-
- Always use list_files first to find exact paths
|
|
21
|
-
- Always use read_file before editing any file
|
|
22
|
-
- Use full absolute paths always
|
|
23
|
-
- Be concise and direct
|
|
24
|
-
- old_str must be an exact match of multiple lines from the file
|
|
25
|
-
- Never explain what you are about to do. Never say "Let me..." or "I'll first...".
|
|
26
|
-
- Just call the tool immediately and silently.
|
|
27
|
-
- Only speak in plain text when you have a FINAL answer for the user.
|
|
28
|
-
- Call only ONE tool per response. Wait for the tool result before calling the next tool.
|
|
29
|
-
- Never output multiple tool calls in one response.
|
|
30
|
-
"""
|
|
31
|
-
|
|
32
|
-
import pyfiglet
|
|
33
|
-
from rich.panel import Panel
|
|
34
|
-
from rich.text import Text
|
|
35
|
-
from rich.rule import Rule
|
|
36
|
-
from rich.markdown import Markdown
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
def run_agent():
|
|
40
|
-
provider = GroqProvider()
|
|
41
|
-
memory = Memory(system_prompt=SYSTEM_PROMPT)
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
ascii_art = pyfiglet.figlet_format("Makima", font="big")
|
|
45
|
-
console.print(f"[bold #FF6B35]{ascii_art}[/]")
|
|
46
|
-
|
|
47
|
-
# info line underneath, no box
|
|
48
|
-
console.print(f"[dim] Your AI Coding Assistant[/]")
|
|
49
|
-
console.print(f"[green] Project :[/] {PROJECT_ROOT}")
|
|
50
|
-
console.print(f"[green] Files :[/] {len(ctx.files)} files loaded")
|
|
51
|
-
console.print(f"[green] Model :[/] {MODEL_NAME}")
|
|
52
|
-
console.print(f"[dim] Type 'exit' to quit[/]")
|
|
53
|
-
console.print(Rule(style="#FF6B35")) # clean horizontal line separator
|
|
54
|
-
console.print()
|
|
55
|
-
|
|
56
|
-
while True:
|
|
57
|
-
user_input = console.input("[bold blue]You:[/] ")
|
|
58
|
-
if user_input.strip() == "exit":
|
|
59
|
-
break
|
|
60
|
-
|
|
61
|
-
memory.add_user(user_input)
|
|
62
|
-
|
|
63
|
-
while True:
|
|
64
|
-
try:
|
|
65
|
-
with console.status("[yellow]thinking...[/]"):
|
|
66
|
-
stream = provider.stream_chat(
|
|
67
|
-
messages=memory.get(),
|
|
68
|
-
tools=TOOL_SCHEMAS
|
|
69
|
-
)
|
|
70
|
-
chunks = list(stream)
|
|
71
|
-
except Exception as e:
|
|
72
|
-
console.print(f"[red]Error: {e}[/]")
|
|
73
|
-
break
|
|
74
|
-
|
|
75
|
-
#variables to collect the response
|
|
76
|
-
text_buffer = ""
|
|
77
|
-
tool_name = ""
|
|
78
|
-
tool_args = ""
|
|
79
|
-
tool_call_id = ""
|
|
80
|
-
is_tool_call = False
|
|
81
|
-
|
|
82
|
-
# console.print("[bold green]Agent:[/] ", end="")
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
for chunk in chunks:
|
|
86
|
-
delta = chunk.choices[0].delta
|
|
87
|
-
|
|
88
|
-
#text chunk
|
|
89
|
-
if delta.content:
|
|
90
|
-
# print(delta.content, end="", flush=True)
|
|
91
|
-
text_buffer += delta.content
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
# tool call chunk
|
|
95
|
-
if delta.tool_calls:
|
|
96
|
-
is_tool_call = True
|
|
97
|
-
tc = delta.tool_calls[0]
|
|
98
|
-
if tc.id:
|
|
99
|
-
tool_call_id = tc.id
|
|
100
|
-
if tc.function.name:
|
|
101
|
-
tool_name += tc.function.name
|
|
102
|
-
if tc.function.arguments:
|
|
103
|
-
tool_args += tc.function.arguments
|
|
104
|
-
|
|
105
|
-
# print()
|
|
106
|
-
|
|
107
|
-
if is_tool_call:
|
|
108
|
-
console.print(f"[dim]⚡ {tool_name}[/]")
|
|
109
|
-
|
|
110
|
-
with console.status(f"[yellow]calling {tool_name}...[/]"):
|
|
111
|
-
args = json.loads(tool_args)
|
|
112
|
-
tool_fn = TOOL_REGISTRY.get(tool_name)
|
|
113
|
-
result = tool_fn(**args) if tool_fn else "Unknown tool"
|
|
114
|
-
|
|
115
|
-
# build the assistant message manually for memory
|
|
116
|
-
memory.add_raw({
|
|
117
|
-
"role": "assistant",
|
|
118
|
-
"tool_calls": [{
|
|
119
|
-
"id": tool_call_id,
|
|
120
|
-
"type": "function",
|
|
121
|
-
"function": {
|
|
122
|
-
"name": tool_name,
|
|
123
|
-
"arguments": tool_args
|
|
124
|
-
}
|
|
125
|
-
}]
|
|
126
|
-
})
|
|
127
|
-
memory.add_tool_result(tool_call_id, str(result))
|
|
128
|
-
|
|
129
|
-
else:
|
|
130
|
-
console.print("[bold green]Agent:[/]")
|
|
131
|
-
console.print(Markdown(text_buffer))
|
|
132
|
-
memory.add_assistant(text_buffer)
|
|
133
|
-
break
|
makima_cli-0.2.0/makima/main.py
DELETED
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
import subprocess
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
def run_command(cmd):
|
|
5
|
-
print(f"Commands going to Run: {cmd}")
|
|
6
|
-
User_answer = input("Run This? (Y/N): ")
|
|
7
|
-
User_answer = User_answer.lower()
|
|
8
|
-
|
|
9
|
-
if User_answer != "y":
|
|
10
|
-
return "Command cancelled"
|
|
11
|
-
|
|
12
|
-
result = subprocess.run(
|
|
13
|
-
cmd,
|
|
14
|
-
shell=True,
|
|
15
|
-
capture_output=True,
|
|
16
|
-
text=True,
|
|
17
|
-
timeout=30
|
|
18
|
-
)
|
|
19
|
-
|
|
20
|
-
return result.stdout + result.stderr
|
|
@@ -1,55 +0,0 @@
|
|
|
1
|
-
Metadata-Version: 2.4
|
|
2
|
-
Name: makima-cli
|
|
3
|
-
Version: 0.2.0
|
|
4
|
-
Summary: AI coding assistant for your terminal
|
|
5
|
-
Author: Kanhaiya
|
|
6
|
-
Requires-Python: >=3.10
|
|
7
|
-
Description-Content-Type: text/markdown
|
|
8
|
-
Requires-Dist: groq
|
|
9
|
-
Requires-Dist: python-dotenv
|
|
10
|
-
Requires-Dist: gitpython
|
|
11
|
-
Requires-Dist: rich
|
|
12
|
-
Requires-Dist: pyfiglet
|
|
13
|
-
|
|
14
|
-
# Makima CLI 🤖
|
|
15
|
-
|
|
16
|
-
An AI-powered coding assistant that runs in your terminal. Point it at any codebase and ask questions, make edits, and run commands — all from a clean CLI interface.
|
|
17
|
-
|
|
18
|
-
## Features
|
|
19
|
-
|
|
20
|
-
- Understands your entire codebase
|
|
21
|
-
- Answers questions about your code
|
|
22
|
-
- Edits files with auto git backup before changes
|
|
23
|
-
- Creates new files
|
|
24
|
-
- Runs terminal commands with confirmation
|
|
25
|
-
- Works on any project
|
|
26
|
-
- Clean terminal UI with syntax highlighting
|
|
27
|
-
|
|
28
|
-
## Install
|
|
29
|
-
|
|
30
|
-
git clone https://github.com/yourusername/makima-cli.git
|
|
31
|
-
cd makima-cli
|
|
32
|
-
pip install -r requirements.txt
|
|
33
|
-
|
|
34
|
-
## Setup
|
|
35
|
-
|
|
36
|
-
Create a .env file in the project root:
|
|
37
|
-
GROQ_API_KEY=your_key_here
|
|
38
|
-
|
|
39
|
-
Get a free API key at https://console.groq.com
|
|
40
|
-
|
|
41
|
-
## Usage
|
|
42
|
-
|
|
43
|
-
Point it at any project:
|
|
44
|
-
python main.py /path/to/your/project
|
|
45
|
-
|
|
46
|
-
Or run from inside a project folder:
|
|
47
|
-
cd your-project
|
|
48
|
-
python /path/to/makima-cli/main.py
|
|
49
|
-
|
|
50
|
-
## Built With
|
|
51
|
-
|
|
52
|
-
- Python
|
|
53
|
-
- Groq API
|
|
54
|
-
- Rich
|
|
55
|
-
- GitPython
|