makima-cli 1.2.1__tar.gz → 1.2.2__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.
Files changed (32) hide show
  1. {makima_cli-1.2.1/makima_cli.egg-info → makima_cli-1.2.2}/PKG-INFO +1 -1
  2. makima_cli-1.2.2/makima/config.py +18 -0
  3. {makima_cli-1.2.1 → makima_cli-1.2.2}/makima/core/config_manager.py +52 -1
  4. makima_cli-1.2.2/makima/tools/git_tools.py +72 -0
  5. makima_cli-1.2.2/makima/tools/shell_tools.py +13 -0
  6. {makima_cli-1.2.1 → makima_cli-1.2.2}/makima/ui/app.py +43 -6
  7. {makima_cli-1.2.1 → makima_cli-1.2.2/makima_cli.egg-info}/PKG-INFO +1 -1
  8. {makima_cli-1.2.1 → makima_cli-1.2.2}/makima_cli.egg-info/SOURCES.txt +1 -0
  9. {makima_cli-1.2.1 → makima_cli-1.2.2}/pyproject.toml +1 -1
  10. makima_cli-1.2.1/makima/config.py +0 -38
  11. makima_cli-1.2.1/makima/tools/shell_tools.py +0 -20
  12. {makima_cli-1.2.1 → makima_cli-1.2.2}/LICENSE +0 -0
  13. {makima_cli-1.2.1 → makima_cli-1.2.2}/README.md +0 -0
  14. {makima_cli-1.2.1 → makima_cli-1.2.2}/makima/__init__.py +0 -0
  15. {makima_cli-1.2.1 → makima_cli-1.2.2}/makima/core/__init__.py +0 -0
  16. {makima_cli-1.2.1 → makima_cli-1.2.2}/makima/core/agent.py +0 -0
  17. {makima_cli-1.2.1 → makima_cli-1.2.2}/makima/core/context.py +0 -0
  18. {makima_cli-1.2.1 → makima_cli-1.2.2}/makima/core/memory.py +0 -0
  19. {makima_cli-1.2.1 → makima_cli-1.2.2}/makima/main.py +0 -0
  20. {makima_cli-1.2.1 → makima_cli-1.2.2}/makima/providers/base.py +0 -0
  21. {makima_cli-1.2.1 → makima_cli-1.2.2}/makima/providers/groq_provider.py +0 -0
  22. {makima_cli-1.2.1 → makima_cli-1.2.2}/makima/setup.py +0 -0
  23. {makima_cli-1.2.1 → makima_cli-1.2.2}/makima/test.py +0 -0
  24. {makima_cli-1.2.1 → makima_cli-1.2.2}/makima/tools/__init__.py +0 -0
  25. {makima_cli-1.2.1 → makima_cli-1.2.2}/makima/tools/file_tools.py +0 -0
  26. {makima_cli-1.2.1 → makima_cli-1.2.2}/makima/tools/registry.py +0 -0
  27. {makima_cli-1.2.1 → makima_cli-1.2.2}/makima/ui/__init__.py +0 -0
  28. {makima_cli-1.2.1 → makima_cli-1.2.2}/makima_cli.egg-info/dependency_links.txt +0 -0
  29. {makima_cli-1.2.1 → makima_cli-1.2.2}/makima_cli.egg-info/entry_points.txt +0 -0
  30. {makima_cli-1.2.1 → makima_cli-1.2.2}/makima_cli.egg-info/requires.txt +0 -0
  31. {makima_cli-1.2.1 → makima_cli-1.2.2}/makima_cli.egg-info/top_level.txt +0 -0
  32. {makima_cli-1.2.1 → makima_cli-1.2.2}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: makima-cli
3
- Version: 1.2.1
3
+ Version: 1.2.2
4
4
  Summary: AI coding assistant for your terminal
5
5
  Author: Kanhaiya
6
6
  License: MIT License
@@ -0,0 +1,18 @@
1
+
2
+ import os
3
+ import sys
4
+ import json
5
+ from pathlib import Path
6
+ from dotenv import load_dotenv
7
+ load_dotenv()
8
+
9
+ config_file = Path.home() / ".makima" / "config.json"
10
+ config = {}
11
+ if config_file.exists():
12
+ with open(config_file, "r") as f:
13
+ config = json.load(f)
14
+
15
+ GROQ_API_KEY = config.get("groq_api_key") or os.getenv("GROQ_API_KEY")
16
+ MODEL_NAME = config.get("model") or "qwen/qwen3.6-27b"
17
+ TOKEN_LIMIT = 6000
18
+ PROJECT_ROOT = sys.argv[1] if len(sys.argv) > 1 else os.getcwd()
@@ -122,4 +122,55 @@ def handle_config():
122
122
  if choice == "Change model":
123
123
  change_model()
124
124
  elif choice == "Change API key":
125
- change_api_key()
125
+ change_api_key()
126
+
127
+
128
+ from makima.tools.git_tools import get_git_diff, generate_commit_message, clean_message
129
+ import subprocess
130
+ import os
131
+
132
+ def commit_only(message):
133
+ message = clean_message(message)
134
+ cmd = f'git add -A && git commit -m "{message}"'
135
+ result = subprocess.run(cmd, shell=True, text=True, capture_output=True)
136
+ if result.returncode == 0:
137
+ return "✓ Committed locally"
138
+ return f"✗ Failed: {result.stderr}"
139
+
140
+
141
+ def analyze_changes():
142
+ diff = get_git_diff()
143
+
144
+ if not diff.strip():
145
+ return None, None
146
+ message = generate_commit_message(diff)
147
+ return diff, message
148
+
149
+
150
+ def handle_commit():
151
+ diff = get_git_diff()
152
+
153
+ if not diff.strip():
154
+ console.print("[yellow]No changes to commit.[/]")
155
+ return
156
+
157
+ commit_message = generate_commit_message(diff=diff)
158
+ console.print(f"[white] {commit_message}")
159
+
160
+ # choice = questionary.select(
161
+ # "What action you want?: ",
162
+ # choices = [
163
+ # "commit_and_push",
164
+ # "commit only",
165
+ # "cancle"
166
+ # ]
167
+ # ).ask()
168
+
169
+ # if choice == "commit_and_push":
170
+ # result = commit_and_push(message=commit_message)
171
+ # console.print(f"[green]{result}[/]")
172
+ # elif choice == "commit only":
173
+ # result = commit_only(diff)
174
+ # console.print(f"[green]{result}[/]")
175
+
176
+
@@ -0,0 +1,72 @@
1
+ import subprocess
2
+ from groq import Groq
3
+ from makima.config import GROQ_API_KEY, PROJECT_ROOT
4
+ import re
5
+
6
+
7
+ def get_git_diff():
8
+ diff = subprocess.run("git diff", shell=True, text=True, capture_output=True)
9
+ status = subprocess.run("git status", shell=True, text=True, capture_output=True)
10
+
11
+ return f"STATUS:\n{status.stdout}\n\nDIFF:\n{diff.stdout}"
12
+
13
+
14
+ def generate_commit_message(diff):
15
+ prompt = f"""Generate ONE git commit message for this diff.
16
+ Format: type(scope): description
17
+ Types: feat/fix/refactor/docs/chore
18
+ Rules: max 72 chars, no quotes, no backticks, no explanation
19
+ Return ONLY the commit message line, nothing else.
20
+
21
+ {diff[:3000]}"""
22
+
23
+ try:
24
+ client = Groq(api_key=GROQ_API_KEY)
25
+ result = client.chat.completions.create(
26
+ model="qwen/qwen3.6-27b",
27
+ messages=[{
28
+ "role": "user",
29
+ "content": prompt
30
+ }]
31
+ )
32
+ except Exception as e:
33
+ print(f"Message Generator Failed!\n {e}")
34
+ return f"Failed to generate message: {e}"
35
+
36
+ content = result.choices[0].message.content
37
+ if "</think>" in content:
38
+ content = content.split("</think>")[-1].strip()
39
+ content = re.sub(r'[`\n]', '', content).strip()
40
+ return content
41
+
42
+
43
+ def commit_and_push(message):
44
+ try:
45
+ message = clean_message(message)
46
+ cmd = f'git add -A && git commit -m "{message}" && git push origin main'
47
+ result = subprocess.run(
48
+ cmd,
49
+ shell=True,
50
+ text=True,
51
+ capture_output=True,
52
+ timeout=120,
53
+ cwd=PROJECT_ROOT
54
+ )
55
+ if result.returncode == 0:
56
+ return f"✓ Committed and pushed: {message}"
57
+ else:
58
+ return f"✗ Failed: {result.stderr}"
59
+ except Exception as e:
60
+ return f"✗ Error: {e}"
61
+
62
+
63
+
64
+ def clean_message(message):
65
+ # remove thinking blocks
66
+ if "</think>" in message:
67
+ message = message.split("</think>")[-1].strip()
68
+ # remove backticks, quotes, special shell characters
69
+ message = re.sub(r'[`"\'\n]', '', message)
70
+ # remove any remaining markdown
71
+ message = message.strip()
72
+ return message
@@ -0,0 +1,13 @@
1
+ import subprocess
2
+
3
+
4
+ def run_command(cmd):
5
+ result = subprocess.run(
6
+ cmd,
7
+ shell=True,
8
+ capture_output=True,
9
+ text=True,
10
+ timeout=30
11
+ )
12
+
13
+ return result.stdout + result.stderr
@@ -3,14 +3,17 @@ from textual.widgets import Header, Footer, Input, RichLog
3
3
  from makima.config import PROJECT_ROOT
4
4
  from makima.tools import TOOL_REGISTRY
5
5
  from makima.tools.registry import TOOL_SCHEMAS
6
- from makima.core.config_manager import handle_config
7
-
6
+ from makima.core.config_manager import handle_config, analyze_changes, commit_only
7
+ from makima.tools.git_tools import commit_and_push
8
+ from rich.text import Text
8
9
  import asyncio
9
10
  import json
10
11
 
11
12
  from makima.providers.groq_provider import GroqProvider
12
13
  from makima.core.memory import Memory
13
14
 
15
+ from pathlib import Path
16
+
14
17
 
15
18
  SYSTEM_PROMPT = f"""
16
19
  You are a coding assistant. The project is at: {PROJECT_ROOT}
@@ -30,12 +33,14 @@ Rules:
30
33
 
31
34
 
32
35
  class MakimaApp(App):
33
- CSS_PATH = "app.tcss"
36
+ CSS_PATH = Path(__file__).parent / "app.tcss"
34
37
 
35
38
  def __init__(self):
36
39
  super().__init__()
37
40
  self.memory = Memory(system_prompt=SYSTEM_PROMPT)
38
41
  self.provider = GroqProvider()
42
+ self.pending_commit = None
43
+
39
44
 
40
45
  def compose(self) -> ComposeResult:
41
46
  yield Header()
@@ -57,7 +62,7 @@ class MakimaApp(App):
57
62
  chat = self.query_one(RichLog)
58
63
  input_box = self.query_one(Input)
59
64
 
60
- chat.write(f"[bold blue]You:[/] {user_input}")
65
+ chat.write(Text.from_markup(f"[bold blue]You:[/] {user_input}"))
61
66
  input_box.clear()
62
67
 
63
68
  if user_input == "exit":
@@ -69,16 +74,48 @@ class MakimaApp(App):
69
74
  await asyncio.to_thread(handle_config)
70
75
  return
71
76
 
77
+ if user_input == "/commit":
78
+ chat.write("[dim]Analyzing changes...[/]")
79
+ diff, message = await asyncio.to_thread(analyze_changes)
80
+
81
+ if not diff:
82
+ chat.write("[yellow]No changes to commit.[/]")
83
+ return
84
+
85
+ chat.write(Text.from_markup(f"[white]Generated message: {message}[/]"))
86
+ chat.write(Text.from_markup(f"[yellow]Type 'push' to commit and push, 'commit' to commit only, or 'cancel'[/]"))
87
+
88
+ self.pending_commit = {"diff": diff, "message": message}
89
+ return
90
+
91
+ if user_input == "push" and self.pending_commit:
92
+ result = await asyncio.to_thread(commit_and_push, self.pending_commit["message"])
93
+ chat.write(Text.from_markup(f"[green]{result}[/]"))
94
+ self.pending_commit = None
95
+ return
96
+
97
+ if user_input == "commit" and self.pending_commit:
98
+ result = await asyncio.to_thread(commit_only, self.pending_commit["message"])
99
+ chat.write(f"[green]{result}[/]")
100
+ self.pending_commit = None
101
+ return
102
+
103
+ if user_input == "cancel" and self.pending_commit:
104
+ chat.write("[yellow]Commit cancelled.[/]")
105
+ self.pending_commit = None
106
+ return
107
+
72
108
 
73
109
  # show thinking indicator
74
- chat.write("[dim]thinking...[/]")
110
+ chat.write(Text.from_markup("[dim]thinking...[/]"))
75
111
 
76
112
  # run agent in background thread
77
113
  response = await asyncio.to_thread(self.process_message, user_input)
78
114
 
79
115
  # remove "thinking..." and show response
80
116
  from rich.markdown import Markdown
81
- chat.write(Markdown(f"[bold green]Agent:[/] {response}"))
117
+ chat.write(Text.from_markup(f"[bold green]Agent:[/]"))
118
+ chat.write(Markdown(response))
82
119
 
83
120
 
84
121
  def process_message(self, user_input):
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: makima-cli
3
- Version: 1.2.1
3
+ Version: 1.2.2
4
4
  Summary: AI coding assistant for your terminal
5
5
  Author: Kanhaiya
6
6
  License: MIT License
@@ -15,6 +15,7 @@ makima/providers/base.py
15
15
  makima/providers/groq_provider.py
16
16
  makima/tools/__init__.py
17
17
  makima/tools/file_tools.py
18
+ makima/tools/git_tools.py
18
19
  makima/tools/registry.py
19
20
  makima/tools/shell_tools.py
20
21
  makima/ui/__init__.py
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "makima-cli"
7
- version = "1.2.1"
7
+ version = "1.2.2"
8
8
  description = "AI coding assistant for your terminal"
9
9
  readme = "README.md"
10
10
  license = {file = "LICENSE"}
@@ -1,38 +0,0 @@
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()
@@ -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
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes