groknroll 2.0.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.
Files changed (62) hide show
  1. groknroll/__init__.py +36 -0
  2. groknroll/__main__.py +9 -0
  3. groknroll/agents/__init__.py +18 -0
  4. groknroll/agents/agent_manager.py +187 -0
  5. groknroll/agents/base_agent.py +118 -0
  6. groknroll/agents/build_agent.py +231 -0
  7. groknroll/agents/plan_agent.py +215 -0
  8. groknroll/cli/__init__.py +7 -0
  9. groknroll/cli/enhanced_cli.py +372 -0
  10. groknroll/cli/large_codebase_cli.py +413 -0
  11. groknroll/cli/main.py +331 -0
  12. groknroll/cli/rlm_commands.py +258 -0
  13. groknroll/clients/__init__.py +63 -0
  14. groknroll/clients/anthropic.py +112 -0
  15. groknroll/clients/azure_openai.py +142 -0
  16. groknroll/clients/base_lm.py +33 -0
  17. groknroll/clients/gemini.py +162 -0
  18. groknroll/clients/litellm.py +105 -0
  19. groknroll/clients/openai.py +129 -0
  20. groknroll/clients/portkey.py +94 -0
  21. groknroll/core/__init__.py +9 -0
  22. groknroll/core/agent.py +339 -0
  23. groknroll/core/comms_utils.py +264 -0
  24. groknroll/core/context.py +251 -0
  25. groknroll/core/exceptions.py +181 -0
  26. groknroll/core/large_codebase.py +564 -0
  27. groknroll/core/lm_handler.py +206 -0
  28. groknroll/core/rlm.py +446 -0
  29. groknroll/core/rlm_codebase.py +448 -0
  30. groknroll/core/rlm_integration.py +256 -0
  31. groknroll/core/types.py +276 -0
  32. groknroll/environments/__init__.py +34 -0
  33. groknroll/environments/base_env.py +182 -0
  34. groknroll/environments/constants.py +32 -0
  35. groknroll/environments/docker_repl.py +336 -0
  36. groknroll/environments/local_repl.py +388 -0
  37. groknroll/environments/modal_repl.py +502 -0
  38. groknroll/environments/prime_repl.py +588 -0
  39. groknroll/logger/__init__.py +4 -0
  40. groknroll/logger/rlm_logger.py +63 -0
  41. groknroll/logger/verbose.py +393 -0
  42. groknroll/operations/__init__.py +15 -0
  43. groknroll/operations/bash_ops.py +447 -0
  44. groknroll/operations/file_ops.py +473 -0
  45. groknroll/operations/git_ops.py +620 -0
  46. groknroll/oracle/__init__.py +11 -0
  47. groknroll/oracle/codebase_indexer.py +238 -0
  48. groknroll/oracle/oracle_agent.py +278 -0
  49. groknroll/setup.py +34 -0
  50. groknroll/storage/__init__.py +14 -0
  51. groknroll/storage/database.py +272 -0
  52. groknroll/storage/models.py +128 -0
  53. groknroll/utils/__init__.py +0 -0
  54. groknroll/utils/parsing.py +168 -0
  55. groknroll/utils/prompts.py +146 -0
  56. groknroll/utils/rlm_utils.py +19 -0
  57. groknroll-2.0.0.dist-info/METADATA +246 -0
  58. groknroll-2.0.0.dist-info/RECORD +62 -0
  59. groknroll-2.0.0.dist-info/WHEEL +5 -0
  60. groknroll-2.0.0.dist-info/entry_points.txt +3 -0
  61. groknroll-2.0.0.dist-info/licenses/LICENSE +21 -0
  62. groknroll-2.0.0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,413 @@
1
+ """
2
+ CLI commands for working with large codebases
3
+
4
+ Specialized commands to handle massive projects without context rot.
5
+ """
6
+
7
+ import sys
8
+ from pathlib import Path
9
+ from typing import Optional
10
+
11
+ import click
12
+ from rich.console import Console
13
+ from rich.panel import Panel
14
+ from rich.table import Table
15
+ from rich.tree import Tree
16
+ from rich.progress import Progress, SpinnerColumn, TextColumn
17
+
18
+ from groknroll.core.large_codebase import LargeCodebaseHandler
19
+ from groknroll.storage.database import Database
20
+ from groknroll.agents.agent_manager import AgentManager
21
+
22
+ console = Console()
23
+
24
+
25
+ @click.group()
26
+ def large():
27
+ """Commands for working with large codebases"""
28
+ pass
29
+
30
+
31
+ @large.command()
32
+ @click.option('--path', type=click.Path(exists=True), help='Project path')
33
+ def map_codebase(path: Optional[str]):
34
+ """
35
+ Create hierarchical map of large codebase
36
+
37
+ This command chunks your codebase intelligently and creates
38
+ a dependency graph for efficient navigation.
39
+ """
40
+ project_path = Path(path) if path else Path.cwd()
41
+
42
+ try:
43
+ with Progress(
44
+ SpinnerColumn(),
45
+ TextColumn("[progress.description]{task.description}"),
46
+ console=console
47
+ ) as progress:
48
+ task = progress.add_task("Mapping codebase...", total=None)
49
+
50
+ db = Database()
51
+ handler = LargeCodebaseHandler(project_path, db)
52
+ codebase_map = handler.chunk_codebase()
53
+
54
+ progress.update(task, completed=True)
55
+
56
+ # Display results
57
+ console.print()
58
+ console.print(Panel.fit(
59
+ f"[bold green]✓ Codebase mapped successfully![/bold green]\n\n"
60
+ f"[cyan]Total Files:[/cyan] {codebase_map.total_files:,}\n"
61
+ f"[cyan]Total Lines:[/cyan] {codebase_map.total_lines:,}\n"
62
+ f"[cyan]Total Chunks:[/cyan] {len(codebase_map.chunks):,}\n"
63
+ f"[cyan]Modules:[/cyan] {len(codebase_map.modules):,}",
64
+ title="[bold]Codebase Map[/bold]",
65
+ border_style="green"
66
+ ))
67
+
68
+ # Language breakdown
69
+ overview = handler.get_codebase_overview()
70
+
71
+ if overview['languages']:
72
+ console.print()
73
+ lang_table = Table(title="Language Distribution", show_header=True)
74
+ lang_table.add_column("Language", style="cyan")
75
+ lang_table.add_column("Files", justify="right", style="green")
76
+ lang_table.add_column("Lines", justify="right", style="blue")
77
+ lang_table.add_column("% of Total", justify="right", style="magenta")
78
+
79
+ total_lines = overview['total_lines']
80
+ for lang, stats in sorted(
81
+ overview['languages'].items(),
82
+ key=lambda x: x[1]['lines'],
83
+ reverse=True
84
+ ):
85
+ percentage = (stats['lines'] / total_lines * 100) if total_lines > 0 else 0
86
+ lang_table.add_row(
87
+ lang,
88
+ f"{stats['files']:,}",
89
+ f"{stats['lines']:,}",
90
+ f"{percentage:.1f}%"
91
+ )
92
+
93
+ console.print(lang_table)
94
+
95
+ # Top modules
96
+ if overview['top_modules']:
97
+ console.print()
98
+ mod_table = Table(title="Largest Modules", show_header=True)
99
+ mod_table.add_column("Module", style="cyan")
100
+ mod_table.add_column("Lines", justify="right", style="blue")
101
+
102
+ for mod in overview['top_modules'][:10]:
103
+ mod_table.add_row(mod['module'], f"{mod['lines']:,}")
104
+
105
+ console.print(mod_table)
106
+
107
+ console.print(f"\n[dim]Map saved to: {project_path}/.groknroll/cache/codebase_map.json[/dim]")
108
+
109
+ except Exception as e:
110
+ console.print(f"[bold red]Error:[/bold red] {e}")
111
+ import traceback
112
+ traceback.print_exc()
113
+ sys.exit(1)
114
+
115
+
116
+ @large.command()
117
+ @click.option('--path', type=click.Path(exists=True), help='Project path')
118
+ def overview(path: Optional[str]):
119
+ """Show high-level overview of large codebase"""
120
+ project_path = Path(path) if path else Path.cwd()
121
+
122
+ try:
123
+ db = Database()
124
+ handler = LargeCodebaseHandler(project_path, db)
125
+ overview = handler.get_codebase_overview()
126
+
127
+ # Display overview
128
+ console.print()
129
+ console.print(Panel.fit(
130
+ f"[bold cyan]Project:[/bold cyan] {project_path.name}\n"
131
+ f"[cyan]Files:[/cyan] {overview['total_files']:,}\n"
132
+ f"[cyan]Lines of Code:[/cyan] {overview['total_lines']:,}\n"
133
+ f"[cyan]Modules:[/cyan] {overview['total_modules']:,}\n"
134
+ f"[cyan]Chunks:[/cyan] {overview['total_chunks']:,}",
135
+ title="[bold]Codebase Overview[/bold]",
136
+ border_style="cyan"
137
+ ))
138
+
139
+ # Languages
140
+ console.print()
141
+ lang_table = Table(title="Languages", show_header=True)
142
+ lang_table.add_column("Language", style="cyan")
143
+ lang_table.add_column("Files", justify="right", style="green")
144
+ lang_table.add_column("Lines", justify="right", style="blue")
145
+
146
+ for lang, stats in sorted(
147
+ overview['languages'].items(),
148
+ key=lambda x: x[1]['lines'],
149
+ reverse=True
150
+ ):
151
+ lang_table.add_row(
152
+ lang,
153
+ f"{stats['files']:,}",
154
+ f"{stats['lines']:,}"
155
+ )
156
+
157
+ console.print(lang_table)
158
+
159
+ except Exception as e:
160
+ console.print(f"[bold red]Error:[/bold red] {e}")
161
+ sys.exit(1)
162
+
163
+
164
+ @large.command()
165
+ @click.argument('module_path')
166
+ @click.option('--path', type=click.Path(exists=True), help='Project path')
167
+ def inspect_module(module_path: str, path: Optional[str]):
168
+ """Inspect a specific module (directory) in detail"""
169
+ project_path = Path(path) if path else Path.cwd()
170
+
171
+ try:
172
+ db = Database()
173
+ handler = LargeCodebaseHandler(project_path, db)
174
+ summary = handler.get_module_summary(module_path)
175
+
176
+ if 'error' in summary:
177
+ console.print(f"[bold red]Error:[/bold red] {summary['error']}")
178
+
179
+ if 'available_modules' in summary:
180
+ console.print("\n[yellow]Available modules:[/yellow]")
181
+ for mod in summary['available_modules']:
182
+ console.print(f" • {mod}")
183
+
184
+ sys.exit(1)
185
+
186
+ # Display module summary
187
+ console.print()
188
+ console.print(Panel.fit(
189
+ f"[bold cyan]Module:[/bold cyan] {summary['module']}\n"
190
+ f"[cyan]Files:[/cyan] {summary['files']}\n"
191
+ f"[cyan]Total Lines:[/cyan] {summary['total_lines']:,}",
192
+ title="[bold]Module Summary[/bold]",
193
+ border_style="cyan"
194
+ ))
195
+
196
+ # Languages in module
197
+ if summary['languages']:
198
+ console.print()
199
+ lang_table = Table(title="Languages in Module", show_header=True)
200
+ lang_table.add_column("Language", style="cyan")
201
+ lang_table.add_column("Files", justify="right", style="green")
202
+ lang_table.add_column("Lines", justify="right", style="blue")
203
+
204
+ for lang, stats in sorted(
205
+ summary['languages'].items(),
206
+ key=lambda x: x[1]['lines'],
207
+ reverse=True
208
+ ):
209
+ lang_table.add_row(
210
+ lang,
211
+ str(stats['files']),
212
+ f"{stats['lines']:,}"
213
+ )
214
+
215
+ console.print(lang_table)
216
+
217
+ # Files in module
218
+ if summary['chunks']:
219
+ console.print()
220
+ file_table = Table(title="Files", show_header=True)
221
+ file_table.add_column("File", style="cyan")
222
+ file_table.add_column("Language", style="green")
223
+ file_table.add_column("Lines", justify="right", style="blue")
224
+
225
+ for chunk in sorted(summary['chunks'], key=lambda x: x['lines'], reverse=True)[:20]:
226
+ file_table.add_row(
227
+ chunk['file'],
228
+ chunk['language'],
229
+ f"{chunk['lines']:,}"
230
+ )
231
+
232
+ console.print(file_table)
233
+
234
+ if len(summary['chunks']) > 20:
235
+ console.print(f"\n[dim]Showing 20 of {len(summary['chunks'])} files[/dim]")
236
+
237
+ except Exception as e:
238
+ console.print(f"[bold red]Error:[/bold red] {e}")
239
+ sys.exit(1)
240
+
241
+
242
+ @large.command()
243
+ @click.argument('symbol')
244
+ @click.option('--path', type=click.Path(exists=True), help='Project path')
245
+ def find_symbol(symbol: str, path: Optional[str]):
246
+ """Find definition of a symbol across entire codebase"""
247
+ project_path = Path(path) if path else Path.cwd()
248
+
249
+ try:
250
+ with console.status(f"[bold cyan]Searching for '{symbol}'..."):
251
+ db = Database()
252
+ handler = LargeCodebaseHandler(project_path, db)
253
+ results = handler.navigate_to_definition(symbol)
254
+
255
+ if not results:
256
+ console.print(f"[yellow]No definitions found for '{symbol}'[/yellow]")
257
+ return
258
+
259
+ # Display results
260
+ console.print()
261
+ table = Table(title=f"Definitions of '{symbol}'", show_header=True)
262
+ table.add_column("File", style="cyan")
263
+ table.add_column("Line", justify="right", style="green")
264
+ table.add_column("Code", style="white")
265
+
266
+ for result in results[:20]:
267
+ table.add_row(
268
+ result['file'],
269
+ str(result['line']),
270
+ result['snippet'][:80]
271
+ )
272
+
273
+ console.print(table)
274
+
275
+ if len(results) > 20:
276
+ console.print(f"\n[dim]Showing 20 of {len(results)} results[/dim]")
277
+
278
+ except Exception as e:
279
+ console.print(f"[bold red]Error:[/bold red] {e}")
280
+ sys.exit(1)
281
+
282
+
283
+ @large.command()
284
+ @click.option('--path', type=click.Path(exists=True), help='Project path')
285
+ def check_changes(path: Optional[str]):
286
+ """Check which files have changed since last analysis (incremental)"""
287
+ project_path = Path(path) if path else Path.cwd()
288
+
289
+ try:
290
+ with console.status("[bold cyan]Checking for changes..."):
291
+ db = Database()
292
+ handler = LargeCodebaseHandler(project_path, db)
293
+ changed = handler.get_changed_chunks()
294
+
295
+ if not changed:
296
+ console.print("[bold green]✓ No changes detected[/bold green]")
297
+ console.print("\n[dim]All files are up to date with last analysis[/dim]")
298
+ return
299
+
300
+ # Display changed files
301
+ console.print()
302
+ console.print(f"[bold yellow]⚠ {len(changed)} file(s) changed[/bold yellow]\n")
303
+
304
+ table = Table(title="Changed Files", show_header=True)
305
+ table.add_column("File", style="cyan")
306
+ table.add_column("Language", style="green")
307
+ table.add_column("Lines", justify="right", style="blue")
308
+
309
+ for chunk in changed[:50]:
310
+ relative_path = chunk.path.relative_to(project_path)
311
+ table.add_row(
312
+ str(relative_path),
313
+ chunk.language,
314
+ f"{chunk.size:,}"
315
+ )
316
+
317
+ console.print(table)
318
+
319
+ if len(changed) > 50:
320
+ console.print(f"\n[dim]Showing 50 of {len(changed)} changed files[/dim]")
321
+
322
+ console.print(f"\n[dim]Tip: Use 'groknroll large analyze-changes' to analyze these changes with RLM[/dim]")
323
+
324
+ except Exception as e:
325
+ console.print(f"[bold red]Error:[/bold red] {e}")
326
+ sys.exit(1)
327
+
328
+
329
+ @large.command()
330
+ @click.argument('task')
331
+ @click.option('--path', type=click.Path(exists=True), help='Project path')
332
+ @click.option('--max-context', type=int, default=50, help='Max chunks to include in context')
333
+ def smart_task(task: str, path: Optional[str], max_context: int):
334
+ """
335
+ Execute task with smart context selection (no context rot!)
336
+
337
+ Uses intelligent chunking to only load relevant parts of codebase.
338
+ Perfect for massive projects with 100K+ lines.
339
+ """
340
+ project_path = Path(path) if path else Path.cwd()
341
+
342
+ try:
343
+ # Get relevant context
344
+ with console.status("[bold cyan]Finding relevant code..."):
345
+ db = Database()
346
+ handler = LargeCodebaseHandler(project_path, db)
347
+ relevant_chunks = handler.get_relevant_context(task, max_chunks=max_context)
348
+
349
+ console.print()
350
+ console.print(Panel(
351
+ f"[cyan]Found {len(relevant_chunks)} relevant code chunks[/cyan]\n"
352
+ f"[dim]Total context: ~{sum(c.size for c in relevant_chunks):,} lines[/dim]",
353
+ title="[bold]Smart Context Selection[/bold]",
354
+ border_style="cyan"
355
+ ))
356
+
357
+ # Show what's being analyzed
358
+ console.print("\n[bold]Analyzing:[/bold]")
359
+ for chunk in relevant_chunks[:10]:
360
+ relative_path = chunk.path.relative_to(project_path)
361
+ console.print(f" • {relative_path} ({chunk.size} lines)")
362
+
363
+ if len(relevant_chunks) > 10:
364
+ console.print(f" • ... and {len(relevant_chunks) - 10} more files")
365
+
366
+ # Execute with build agent
367
+ console.print()
368
+ with console.status("[bold cyan]Build agent working..."):
369
+ manager = AgentManager(project_path)
370
+
371
+ # Add relevant files to context
372
+ context = {
373
+ "relevant_files": [
374
+ {
375
+ "path": str(c.path.relative_to(project_path)),
376
+ "lines": c.size,
377
+ "language": c.language
378
+ }
379
+ for c in relevant_chunks
380
+ ],
381
+ "total_context_lines": sum(c.size for c in relevant_chunks)
382
+ }
383
+
384
+ response = manager.execute(task, agent="build", context=context)
385
+
386
+ # Display response
387
+ console.print()
388
+ if response.success:
389
+ from rich.markdown import Markdown
390
+ console.print(Panel(
391
+ Markdown(response.message),
392
+ title="[bold green]✓ Build Agent[/bold green]",
393
+ border_style="green"
394
+ ))
395
+
396
+ console.print(f"\n[dim]Completed in {response.time:.1f}s "
397
+ f"(cost: ${response.cost:.4f})[/dim]")
398
+ else:
399
+ console.print(Panel(
400
+ response.message,
401
+ title="[bold red]✗ Build Agent Failed[/bold red]",
402
+ border_style="red"
403
+ ))
404
+
405
+ except Exception as e:
406
+ console.print(f"[bold red]Error:[/bold red] {e}")
407
+ import traceback
408
+ traceback.print_exc()
409
+ sys.exit(1)
410
+
411
+
412
+ if __name__ == "__main__":
413
+ large()