tzamuncode 0.1.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
tzamuncode/cli/main.py ADDED
@@ -0,0 +1,444 @@
1
+ """
2
+ TzamunCode CLI - Main Entry Point
3
+ """
4
+
5
+ import typer
6
+ from rich.console import Console
7
+ from rich.panel import Panel
8
+ from rich.markdown import Markdown
9
+ from rich.prompt import Confirm
10
+ from typing import Optional
11
+ import sys
12
+
13
+ from ..models.ollama import OllamaClient
14
+ from ..utils.file_ops import FileManager
15
+ from .commands import chat_command, generate_command, edit_command, explain_command
16
+ from .agentic_commands import agentic_command, project_command
17
+
18
+ app = typer.Typer(
19
+ name="tzamuncode",
20
+ help="TzamunCode - AI Coding Assistant powered by local models πŸš€",
21
+ add_completion=False,
22
+ )
23
+
24
+ console = Console()
25
+
26
+ def version_callback(value: bool):
27
+ if value:
28
+ from .. import __version__
29
+ console.print(f"[bold blue]TzamunCode[/bold blue] version {__version__}")
30
+ console.print("Built with ❀️ in Saudi Arabia πŸ‡ΈπŸ‡¦")
31
+ raise typer.Exit()
32
+
33
+ @app.callback(invoke_without_command=True)
34
+ def main(
35
+ ctx: typer.Context,
36
+ version: Optional[bool] = typer.Option(
37
+ None,
38
+ "--version",
39
+ "-v",
40
+ callback=version_callback,
41
+ is_eager=True,
42
+ help="Show version and exit"
43
+ )
44
+ ):
45
+ """
46
+ TzamunCode - AI Coding Assistant
47
+
48
+ Privacy-first AI coding assistant powered by local models.
49
+ """
50
+ # If no subcommand provided, show interactive backend selection
51
+ if ctx.invoked_subcommand is None:
52
+ from rich.prompt import Prompt
53
+ from .realtime_chat import RealtimeChat
54
+ from ..auth.auth_manager import AuthManager
55
+
56
+ # Check authentication
57
+ auth = AuthManager()
58
+ if not auth.is_authenticated():
59
+ console.print("\n[bold yellow]πŸ” Authentication Required[/bold yellow]\n")
60
+ console.print("[dim]Please login to use TzamunCode[/dim]\n")
61
+ console.print("Run: [cyan]tzamuncode login[/cyan]\n")
62
+ return
63
+
64
+ console.print("\n[bold cyan]πŸš€ TzamunCode AI Assistant[/bold cyan]\n")
65
+ console.print("Select AI Backend:\n")
66
+ console.print(" [bold]1[/bold]. ⚑ [cyan]vLLM[/cyan] - Fast inference (Qwen 2.5 7B)")
67
+ console.print(" [bold]2[/bold]. πŸ¦™ [green]Ollama[/green] - Powerful models (Qwen 2.5 32B)")
68
+
69
+ choice = Prompt.ask("\nChoose backend", choices=["1", "2"], default="2")
70
+
71
+ if choice == "1":
72
+ console.print("\nβœ… Starting with [cyan]vLLM[/cyan] backend...\n")
73
+ chat = RealtimeChat(model="qwen2.5-7b-instruct", use_vllm=True)
74
+ else:
75
+ console.print("\nβœ… Starting with [green]Ollama[/green] backend...\n")
76
+ chat = RealtimeChat(model="qwen2.5:32b", use_vllm=False)
77
+
78
+ chat.run()
79
+
80
+ @app.command()
81
+ def chat(
82
+ model: str = typer.Option(
83
+ "qwen2.5:32b",
84
+ "--model",
85
+ "-m",
86
+ help="Model to use for chat"
87
+ ),
88
+ system: Optional[str] = typer.Option(
89
+ None,
90
+ "--system",
91
+ "-s",
92
+ help="System prompt"
93
+ ),
94
+ vllm: bool = typer.Option(
95
+ False,
96
+ "--vllm",
97
+ help="Use vLLM backend (faster)"
98
+ )
99
+ ):
100
+ """
101
+ Start an interactive chat session with TzamunCode AI.
102
+
103
+ Features:
104
+ - Beautiful UI with welcome screen
105
+ - Type '/' to see all commands
106
+ - '/models' to switch models
107
+ - '/settings' to view settings
108
+ - '/help' for help
109
+
110
+ Examples:
111
+ tzamuncode chat
112
+ tzamuncode chat --model deepseek-coder-v2
113
+ tzc chat -m qwen2.5:32b
114
+ """
115
+ from .realtime_chat import run_realtime_chat
116
+ from ..auth.auth_manager import AuthManager
117
+
118
+ # Check authentication
119
+ auth = AuthManager()
120
+ if not auth.is_authenticated():
121
+ console.print("\n[bold yellow]πŸ” Authentication Required[/bold yellow]\n")
122
+ console.print("[dim]Please login to use TzamunCode[/dim]\n")
123
+ console.print("Run: [cyan]tzamuncode login[/cyan]\n")
124
+ return
125
+
126
+ if vllm and model == 'qwen2.5:32b':
127
+ model = 'qwen2.5-7b-instruct'
128
+ run_realtime_chat(model=model, system=system, use_vllm=vllm)
129
+
130
+ @app.command()
131
+ def generate(
132
+ prompt: str = typer.Argument(..., help="What to generate"),
133
+ model: str = typer.Option(
134
+ "qwen2.5:32b",
135
+ "--model",
136
+ "-m",
137
+ help="Model to use"
138
+ ),
139
+ output: Optional[str] = typer.Option(
140
+ None,
141
+ "--output",
142
+ "-o",
143
+ help="Output file or directory"
144
+ )
145
+ ):
146
+ """
147
+ Generate code based on a prompt.
148
+
149
+ Examples:
150
+ tzamuncode generate "Create a Flask REST API"
151
+ tzamuncode generate "Add unit tests" --output tests/
152
+ tzc generate "Python web scraper" -o scraper.py
153
+ """
154
+ generate_command(prompt=prompt, model=model, output=output)
155
+
156
+ @app.command()
157
+ def edit(
158
+ file_path: str = typer.Argument(..., help="File to edit"),
159
+ instruction: str = typer.Argument(..., help="What to change"),
160
+ model: str = typer.Option(
161
+ "qwen2.5:32b",
162
+ "--model",
163
+ "-m",
164
+ help="Model to use"
165
+ ),
166
+ apply: bool = typer.Option(
167
+ False,
168
+ "--apply",
169
+ "-a",
170
+ help="Apply changes without confirmation"
171
+ )
172
+ ):
173
+ """
174
+ Edit a file using AI.
175
+
176
+ Examples:
177
+ tzamuncode edit app.py "Add error handling"
178
+ tzamuncode edit . "Add type hints to all functions"
179
+ tzc edit main.py "Refactor to use async" --apply
180
+ """
181
+ edit_command(file_path=file_path, instruction=instruction, model=model, apply=apply)
182
+
183
+ @app.command()
184
+ def explain(
185
+ file_path: str = typer.Argument(..., help="File to explain"),
186
+ model: str = typer.Option(
187
+ "qwen2.5:32b",
188
+ "--model",
189
+ "-m",
190
+ help="Model to use"
191
+ ),
192
+ detailed: bool = typer.Option(
193
+ False,
194
+ "--detailed",
195
+ "-d",
196
+ help="Provide detailed explanation"
197
+ )
198
+ ):
199
+ """
200
+ Explain code in a file.
201
+
202
+ Examples:
203
+ tzamuncode explain complex_function.py
204
+ tzamuncode explain auth.py --detailed
205
+ tzc explain main.py -d
206
+ """
207
+ explain_command(file_path=file_path, model=model, detailed=detailed)
208
+
209
+ @app.command()
210
+ def code(
211
+ instruction: str = typer.Argument(..., help="What to do"),
212
+ model: str = typer.Option(
213
+ "qwen2.5:32b",
214
+ "--model",
215
+ "-m",
216
+ help="Model to use"
217
+ ),
218
+ workspace: Optional[str] = typer.Option(
219
+ None,
220
+ "--workspace",
221
+ "-w",
222
+ help="Project directory (default: current)"
223
+ ),
224
+ apply: bool = typer.Option(
225
+ False,
226
+ "--apply",
227
+ "-a",
228
+ help="Auto-apply changes without confirmation"
229
+ )
230
+ ):
231
+ """
232
+ Agentic AI mode - AI autonomously accesses files and writes code.
233
+
234
+ Similar to Claude Code, the AI will:
235
+ - Scan your project structure
236
+ - Read files autonomously
237
+ - Edit multiple files
238
+ - Execute git operations
239
+ - Plan and execute multi-step tasks
240
+
241
+ Examples:
242
+ tzamuncode code "Add authentication to this Flask app"
243
+ tzamuncode code "Refactor all Python files to use async/await"
244
+ tzc code "Add unit tests for all functions" --apply
245
+ """
246
+ agentic_command(
247
+ instruction=instruction,
248
+ model=model,
249
+ workspace=workspace,
250
+ auto_apply=apply
251
+ )
252
+
253
+ @app.command()
254
+ def project(
255
+ workspace: Optional[str] = typer.Option(
256
+ None,
257
+ "--workspace",
258
+ "-w",
259
+ help="Project directory (default: current)"
260
+ )
261
+ ):
262
+ """
263
+ Analyze and understand project structure.
264
+
265
+ Examples:
266
+ tzamuncode project
267
+ tzamuncode project --workspace /path/to/project
268
+ tzc project
269
+ """
270
+ project_command(workspace=workspace)
271
+
272
+ @app.command()
273
+ def login(
274
+ username: Optional[str] = typer.Option(
275
+ None,
276
+ "--username",
277
+ "-u",
278
+ help="TzamunAI username"
279
+ ),
280
+ api_key: Optional[str] = typer.Option(
281
+ None,
282
+ "--api-key",
283
+ "-k",
284
+ help="TzamunAI API key (alternative to username/password)"
285
+ )
286
+ ):
287
+ """
288
+ Login to TzamunAI (app.tzamun.ai)
289
+
290
+ Examples:
291
+ tzamuncode login
292
+ tzamuncode login --username myuser
293
+ tzamuncode login --api-key YOUR_API_KEY
294
+ """
295
+ from ..auth.auth_manager import AuthManager
296
+ from rich.prompt import Prompt
297
+ import getpass
298
+
299
+ auth = AuthManager()
300
+
301
+ # Check if already logged in
302
+ if auth.is_authenticated():
303
+ user_info = auth.get_user_info()
304
+ console.print(f"\n[bold yellow]⚠[/bold yellow] Already logged in as [cyan]{user_info.get('username')}[/cyan]")
305
+ if not Confirm.ask("Logout and login again?"):
306
+ return
307
+ auth.logout()
308
+
309
+ console.print("\n[bold cyan]πŸ” Login to TzamunAI[/bold cyan]\n")
310
+
311
+ # API Key login
312
+ if api_key:
313
+ console.print("[dim]Validating API key...[/dim]")
314
+ if auth.login_with_api_key(api_key):
315
+ console.print("\n[bold green]βœ“[/bold green] Successfully logged in with API key!\n")
316
+ else:
317
+ console.print("\n[bold red]βœ—[/bold red] Invalid API key\n")
318
+ return
319
+
320
+ # Username/Password login
321
+ if not username:
322
+ username = Prompt.ask("[cyan]Username[/cyan]")
323
+
324
+ password = getpass.getpass("Password: ")
325
+
326
+ console.print("\n[dim]Authenticating...[/dim]")
327
+
328
+ if auth.login_with_credentials(username, password):
329
+ console.print(f"\n[bold green]βœ“[/bold green] Successfully logged in as [cyan]{username}[/cyan]!\n")
330
+ console.print("[dim]Your session will expire in 30 days[/dim]\n")
331
+ else:
332
+ console.print("\n[bold red]βœ—[/bold red] Login failed. Check your credentials.\n")
333
+
334
+ @app.command()
335
+ def logout():
336
+ """
337
+ Logout from TzamunAI
338
+
339
+ Examples:
340
+ tzamuncode logout
341
+ """
342
+ from ..auth.auth_manager import AuthManager
343
+
344
+ auth = AuthManager()
345
+
346
+ if not auth.is_authenticated():
347
+ console.print("\n[dim]Not logged in[/dim]\n")
348
+ return
349
+
350
+ user_info = auth.get_user_info()
351
+ auth.logout()
352
+
353
+ console.print(f"\n[bold green]βœ“[/bold green] Logged out [cyan]{user_info.get('username')}[/cyan]\n")
354
+
355
+ @app.command()
356
+ def whoami():
357
+ """
358
+ Show current authentication status
359
+
360
+ Examples:
361
+ tzamuncode whoami
362
+ """
363
+ from ..auth.auth_manager import AuthManager
364
+
365
+ auth = AuthManager()
366
+
367
+ console.print()
368
+
369
+ if not auth.is_authenticated():
370
+ console.print("[bold yellow]Not authenticated[/bold yellow]")
371
+ console.print("\n[dim]Login with:[/dim] [cyan]tzamuncode login[/cyan]\n")
372
+ return
373
+
374
+ user_info = auth.get_user_info()
375
+
376
+ table = Table(
377
+ title="[bold cyan]Authentication Status[/bold cyan]",
378
+ border_style="blue",
379
+ show_header=True,
380
+ header_style="bold white on blue"
381
+ )
382
+ table.add_column("Property", style="bold cyan", width=20)
383
+ table.add_column("Value", style="yellow")
384
+
385
+ table.add_row("Status", "βœ“ Authenticated")
386
+ table.add_row("Username", user_info.get('username', 'N/A'))
387
+ table.add_row("Auth Type", user_info.get('type', 'N/A').replace('_', ' ').title())
388
+
389
+ console.print(table)
390
+ console.print()
391
+
392
+ @app.command()
393
+ def info():
394
+ """
395
+ Show information about TzamunCode and available models.
396
+ """
397
+ from .. import __version__
398
+ from ..auth.auth_manager import AuthManager
399
+
400
+ auth = AuthManager()
401
+
402
+ console.print(Panel.fit(
403
+ f"""[bold blue]TzamunCode CLI[/bold blue] v{__version__}
404
+
405
+ [bold]AI Coding Assistant powered by local models[/bold]
406
+
407
+ Built by [bold cyan]Tzamun Arabia IT Co.[/bold cyan] πŸ‡ΈπŸ‡¦
408
+
409
+ [dim]Privacy-first β€’ No cloud dependencies β€’ Complete control[/dim]
410
+ """,
411
+ border_style="blue"
412
+ ))
413
+
414
+ # Show auth status
415
+ if auth.is_authenticated():
416
+ user_info = auth.get_user_info()
417
+ console.print(f"\n[bold green]βœ“[/bold green] Logged in as [cyan]{user_info.get('username')}[/cyan]")
418
+ else:
419
+ console.print("\n[dim]Not logged in β€’ Use[/dim] [cyan]tzamuncode login[/cyan]")
420
+
421
+ # Check Ollama connection
422
+ try:
423
+ client = OllamaClient()
424
+ models = client.list_models()
425
+
426
+ console.print("\n[bold green]βœ“[/bold green] Connected to Ollama")
427
+ console.print(f"[bold]Available models:[/bold] {len(models)}")
428
+
429
+ for model in models[:5]: # Show first 5
430
+ console.print(f" β€’ {model}")
431
+
432
+ if len(models) > 5:
433
+ console.print(f" ... and {len(models) - 5} more")
434
+
435
+ except Exception as e:
436
+ console.print(f"\n[bold red]βœ—[/bold red] Could not connect to Ollama: {e}")
437
+ console.print("[dim]Make sure Ollama is running: ollama serve[/dim]")
438
+
439
+ def run():
440
+ """Entry point for the CLI"""
441
+ app()
442
+
443
+ if __name__ == "__main__":
444
+ run()