ai-coding-assistant 0.5.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.
- ai_coding_assistant-0.5.0.dist-info/METADATA +226 -0
- ai_coding_assistant-0.5.0.dist-info/RECORD +89 -0
- ai_coding_assistant-0.5.0.dist-info/WHEEL +4 -0
- ai_coding_assistant-0.5.0.dist-info/entry_points.txt +3 -0
- ai_coding_assistant-0.5.0.dist-info/licenses/LICENSE +21 -0
- coding_assistant/__init__.py +3 -0
- coding_assistant/__main__.py +19 -0
- coding_assistant/cli/__init__.py +1 -0
- coding_assistant/cli/app.py +158 -0
- coding_assistant/cli/commands/__init__.py +19 -0
- coding_assistant/cli/commands/ask.py +178 -0
- coding_assistant/cli/commands/config.py +438 -0
- coding_assistant/cli/commands/diagram.py +267 -0
- coding_assistant/cli/commands/document.py +410 -0
- coding_assistant/cli/commands/explain.py +192 -0
- coding_assistant/cli/commands/fix.py +249 -0
- coding_assistant/cli/commands/index.py +162 -0
- coding_assistant/cli/commands/refactor.py +245 -0
- coding_assistant/cli/commands/search.py +182 -0
- coding_assistant/cli/commands/serve_docs.py +128 -0
- coding_assistant/cli/repl.py +381 -0
- coding_assistant/cli/theme.py +90 -0
- coding_assistant/codebase/__init__.py +1 -0
- coding_assistant/codebase/crawler.py +93 -0
- coding_assistant/codebase/parser.py +266 -0
- coding_assistant/config/__init__.py +25 -0
- coding_assistant/config/config_manager.py +615 -0
- coding_assistant/config/settings.py +82 -0
- coding_assistant/context/__init__.py +19 -0
- coding_assistant/context/chunker.py +443 -0
- coding_assistant/context/enhanced_retriever.py +322 -0
- coding_assistant/context/hybrid_search.py +311 -0
- coding_assistant/context/ranker.py +355 -0
- coding_assistant/context/retriever.py +119 -0
- coding_assistant/context/window.py +362 -0
- coding_assistant/documentation/__init__.py +23 -0
- coding_assistant/documentation/agents/__init__.py +27 -0
- coding_assistant/documentation/agents/coordinator.py +510 -0
- coding_assistant/documentation/agents/module_documenter.py +111 -0
- coding_assistant/documentation/agents/synthesizer.py +139 -0
- coding_assistant/documentation/agents/task_delegator.py +100 -0
- coding_assistant/documentation/decomposition/__init__.py +21 -0
- coding_assistant/documentation/decomposition/context_preserver.py +477 -0
- coding_assistant/documentation/decomposition/module_detector.py +302 -0
- coding_assistant/documentation/decomposition/partitioner.py +621 -0
- coding_assistant/documentation/generators/__init__.py +14 -0
- coding_assistant/documentation/generators/dataflow_generator.py +440 -0
- coding_assistant/documentation/generators/diagram_generator.py +511 -0
- coding_assistant/documentation/graph/__init__.py +13 -0
- coding_assistant/documentation/graph/dependency_builder.py +468 -0
- coding_assistant/documentation/graph/module_analyzer.py +475 -0
- coding_assistant/documentation/writers/__init__.py +11 -0
- coding_assistant/documentation/writers/markdown_writer.py +322 -0
- coding_assistant/embeddings/__init__.py +0 -0
- coding_assistant/embeddings/generator.py +89 -0
- coding_assistant/embeddings/store.py +187 -0
- coding_assistant/exceptions/__init__.py +50 -0
- coding_assistant/exceptions/base.py +110 -0
- coding_assistant/exceptions/llm.py +249 -0
- coding_assistant/exceptions/recovery.py +263 -0
- coding_assistant/exceptions/storage.py +213 -0
- coding_assistant/exceptions/validation.py +230 -0
- coding_assistant/llm/__init__.py +1 -0
- coding_assistant/llm/client.py +277 -0
- coding_assistant/llm/gemini_client.py +181 -0
- coding_assistant/llm/groq_client.py +160 -0
- coding_assistant/llm/prompts.py +98 -0
- coding_assistant/llm/together_client.py +160 -0
- coding_assistant/operations/__init__.py +13 -0
- coding_assistant/operations/differ.py +369 -0
- coding_assistant/operations/generator.py +347 -0
- coding_assistant/operations/linter.py +430 -0
- coding_assistant/operations/validator.py +406 -0
- coding_assistant/storage/__init__.py +9 -0
- coding_assistant/storage/database.py +363 -0
- coding_assistant/storage/session.py +231 -0
- coding_assistant/utils/__init__.py +31 -0
- coding_assistant/utils/cache.py +477 -0
- coding_assistant/utils/hardware.py +132 -0
- coding_assistant/utils/keystore.py +206 -0
- coding_assistant/utils/logger.py +32 -0
- coding_assistant/utils/progress.py +311 -0
- coding_assistant/validation/__init__.py +13 -0
- coding_assistant/validation/files.py +305 -0
- coding_assistant/validation/inputs.py +335 -0
- coding_assistant/validation/params.py +280 -0
- coding_assistant/validation/sanitizers.py +243 -0
- coding_assistant/vcs/__init__.py +5 -0
- coding_assistant/vcs/git.py +269 -0
|
@@ -0,0 +1,267 @@
|
|
|
1
|
+
"""Diagram generation command.
|
|
2
|
+
|
|
3
|
+
This module provides CLI commands for generating visual diagrams
|
|
4
|
+
of code structure, dependencies, and data flow.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from pathlib import Path
|
|
8
|
+
from typing import Optional
|
|
9
|
+
import typer
|
|
10
|
+
from rich.console import Console
|
|
11
|
+
from rich.progress import Progress, SpinnerColumn, TextColumn
|
|
12
|
+
from rich.panel import Panel
|
|
13
|
+
from rich.table import Table
|
|
14
|
+
|
|
15
|
+
from coding_assistant.documentation.graph.dependency_builder import DependencyGraphBuilder
|
|
16
|
+
from coding_assistant.documentation.graph.module_analyzer import ModuleAnalyzer
|
|
17
|
+
from coding_assistant.documentation.decomposition.partitioner import HierarchicalPartitioner
|
|
18
|
+
from coding_assistant.documentation.generators.diagram_generator import MermaidDiagramGenerator
|
|
19
|
+
from coding_assistant.documentation.generators.dataflow_generator import DataFlowGenerator
|
|
20
|
+
from coding_assistant.codebase.parser import CodeParser
|
|
21
|
+
from coding_assistant.utils.logger import get_logger
|
|
22
|
+
|
|
23
|
+
logger = get_logger(__name__)
|
|
24
|
+
console = Console()
|
|
25
|
+
|
|
26
|
+
# Create Typer app for diagram subcommands
|
|
27
|
+
diagram_app = typer.Typer(
|
|
28
|
+
name="diagram",
|
|
29
|
+
help="Generate visual diagrams of code structure",
|
|
30
|
+
no_args_is_help=True
|
|
31
|
+
)
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
@diagram_app.command("generate")
|
|
35
|
+
def generate_diagram_command(
|
|
36
|
+
diagram_type: str = typer.Argument(
|
|
37
|
+
...,
|
|
38
|
+
help="Diagram type: architecture, dependency, class, dataflow"
|
|
39
|
+
),
|
|
40
|
+
output: Optional[Path] = typer.Option(
|
|
41
|
+
None,
|
|
42
|
+
"--output",
|
|
43
|
+
"-o",
|
|
44
|
+
help="Output file (default: <type>.mmd)"
|
|
45
|
+
),
|
|
46
|
+
codebase_path: Optional[Path] = typer.Option(
|
|
47
|
+
None,
|
|
48
|
+
"--path",
|
|
49
|
+
"-p",
|
|
50
|
+
help="Path to codebase (default: current directory)"
|
|
51
|
+
),
|
|
52
|
+
max_nodes: int = typer.Option(
|
|
53
|
+
40,
|
|
54
|
+
"--max-nodes",
|
|
55
|
+
help="Maximum nodes in graph diagrams"
|
|
56
|
+
),
|
|
57
|
+
direction: str = typer.Option(
|
|
58
|
+
"TB",
|
|
59
|
+
"--direction",
|
|
60
|
+
"-d",
|
|
61
|
+
help="Graph direction (TB, LR, RL, BT)"
|
|
62
|
+
),
|
|
63
|
+
):
|
|
64
|
+
"""
|
|
65
|
+
Generate a single diagram of the codebase.
|
|
66
|
+
|
|
67
|
+
Supported diagram types:
|
|
68
|
+
- architecture: High-level module structure
|
|
69
|
+
- dependency: File/module dependencies
|
|
70
|
+
- class: OOP structure with inheritance
|
|
71
|
+
- dataflow: Data movement through system
|
|
72
|
+
|
|
73
|
+
Examples:
|
|
74
|
+
assistant diagram generate architecture
|
|
75
|
+
assistant diagram generate dependency --max-nodes 30
|
|
76
|
+
assistant diagram generate class --output classes.mmd
|
|
77
|
+
"""
|
|
78
|
+
codebase = codebase_path or Path.cwd()
|
|
79
|
+
|
|
80
|
+
console.print(Panel.fit(
|
|
81
|
+
f"[bold cyan]Generating {diagram_type} Diagram[/bold cyan]\\n"
|
|
82
|
+
f"Analyzing: {codebase}",
|
|
83
|
+
border_style="cyan"
|
|
84
|
+
))
|
|
85
|
+
|
|
86
|
+
try:
|
|
87
|
+
# Build dependency graph
|
|
88
|
+
with Progress(
|
|
89
|
+
SpinnerColumn(),
|
|
90
|
+
TextColumn("[progress.description]{task.description}"),
|
|
91
|
+
console=console
|
|
92
|
+
) as progress:
|
|
93
|
+
|
|
94
|
+
task1 = progress.add_task("[cyan]Building dependency graph...", total=None)
|
|
95
|
+
builder = DependencyGraphBuilder(codebase)
|
|
96
|
+
file_graph = builder.build_file_graph()
|
|
97
|
+
progress.update(task1, completed=True)
|
|
98
|
+
|
|
99
|
+
diagram_gen = MermaidDiagramGenerator()
|
|
100
|
+
dataflow_gen = DataFlowGenerator()
|
|
101
|
+
|
|
102
|
+
# Generate requested diagram type
|
|
103
|
+
diagram_code = None
|
|
104
|
+
|
|
105
|
+
if diagram_type == "architecture":
|
|
106
|
+
task2 = progress.add_task("[cyan]Detecting modules...", total=None)
|
|
107
|
+
analyzer = ModuleAnalyzer(file_graph)
|
|
108
|
+
modules = analyzer.detect_modules()
|
|
109
|
+
progress.update(task2, completed=True)
|
|
110
|
+
|
|
111
|
+
task3 = progress.add_task("[cyan]Creating partitions...", total=None)
|
|
112
|
+
file_sizes = {
|
|
113
|
+
node: file_graph.nodes[node].get('line_count', 0)
|
|
114
|
+
for node in file_graph.nodes()
|
|
115
|
+
}
|
|
116
|
+
partitioner = HierarchicalPartitioner()
|
|
117
|
+
partitions = partitioner.partition(file_graph, file_sizes, modules)
|
|
118
|
+
progress.update(task3, completed=True)
|
|
119
|
+
|
|
120
|
+
task4 = progress.add_task("[cyan]Generating architecture diagram...", total=None)
|
|
121
|
+
diagram_code = diagram_gen.generate_architecture_diagram(
|
|
122
|
+
partitions,
|
|
123
|
+
file_graph,
|
|
124
|
+
direction=direction
|
|
125
|
+
)
|
|
126
|
+
progress.update(task4, completed=True)
|
|
127
|
+
|
|
128
|
+
elif diagram_type == "dependency":
|
|
129
|
+
task2 = progress.add_task("[cyan]Generating dependency graph...", total=None)
|
|
130
|
+
diagram_code = diagram_gen.generate_dependency_graph(
|
|
131
|
+
file_graph,
|
|
132
|
+
max_nodes=max_nodes,
|
|
133
|
+
show_files=True
|
|
134
|
+
)
|
|
135
|
+
progress.update(task2, completed=True)
|
|
136
|
+
|
|
137
|
+
elif diagram_type == "class":
|
|
138
|
+
task2 = progress.add_task("[cyan]Parsing files...", total=None)
|
|
139
|
+
parser = CodeParser()
|
|
140
|
+
parsed_files = {}
|
|
141
|
+
|
|
142
|
+
sample_files = list(file_graph.nodes())[:30]
|
|
143
|
+
for file_path in sample_files:
|
|
144
|
+
try:
|
|
145
|
+
parsed = parser.parse_file(file_path)
|
|
146
|
+
parsed_files[file_path] = parsed
|
|
147
|
+
except Exception:
|
|
148
|
+
pass
|
|
149
|
+
|
|
150
|
+
progress.update(task2, completed=True)
|
|
151
|
+
|
|
152
|
+
task3 = progress.add_task("[cyan]Generating class diagram...", total=None)
|
|
153
|
+
diagram_code = diagram_gen.generate_class_diagram(
|
|
154
|
+
parsed_files,
|
|
155
|
+
max_classes=25
|
|
156
|
+
)
|
|
157
|
+
progress.update(task3, completed=True)
|
|
158
|
+
|
|
159
|
+
elif diagram_type == "dataflow":
|
|
160
|
+
task2 = progress.add_task("[cyan]Parsing files...", total=None)
|
|
161
|
+
parser = CodeParser()
|
|
162
|
+
parsed_files = {}
|
|
163
|
+
|
|
164
|
+
sample_files = list(file_graph.nodes())[:30]
|
|
165
|
+
for file_path in sample_files:
|
|
166
|
+
try:
|
|
167
|
+
parsed = parser.parse_file(file_path)
|
|
168
|
+
parsed_files[file_path] = parsed
|
|
169
|
+
except Exception:
|
|
170
|
+
pass
|
|
171
|
+
|
|
172
|
+
progress.update(task2, completed=True)
|
|
173
|
+
|
|
174
|
+
task3 = progress.add_task("[cyan]Extracting data flow...", total=None)
|
|
175
|
+
dataflow_info = dataflow_gen.extract_dataflow_from_parsed_files(
|
|
176
|
+
parsed_files,
|
|
177
|
+
max_entities=35
|
|
178
|
+
)
|
|
179
|
+
progress.update(task3, completed=True)
|
|
180
|
+
|
|
181
|
+
task4 = progress.add_task("[cyan]Generating dataflow diagram...", total=None)
|
|
182
|
+
diagram_code = dataflow_gen.generate_dataflow_diagram(
|
|
183
|
+
dataflow_info['entities'],
|
|
184
|
+
dataflow_info['transformations'],
|
|
185
|
+
dataflow_info['external_systems']
|
|
186
|
+
)
|
|
187
|
+
progress.update(task4, completed=True)
|
|
188
|
+
|
|
189
|
+
else:
|
|
190
|
+
console.print(f"[red]Error:[/red] Unknown diagram type: {diagram_type}")
|
|
191
|
+
console.print("[yellow]Supported types:[/yellow] architecture, dependency, class, dataflow")
|
|
192
|
+
raise typer.Exit(1)
|
|
193
|
+
|
|
194
|
+
# Determine output path
|
|
195
|
+
if output is None:
|
|
196
|
+
output = Path(f"{diagram_type}.mmd")
|
|
197
|
+
|
|
198
|
+
# Write diagram
|
|
199
|
+
output.write_text(diagram_code)
|
|
200
|
+
|
|
201
|
+
# Success message
|
|
202
|
+
console.print(f"\\n[green]✓[/green] Diagram generated: {output}")
|
|
203
|
+
console.print(f"[dim]Lines:[/dim] {len(diagram_code.splitlines())}")
|
|
204
|
+
console.print(f"[dim]Size:[/dim] {len(diagram_code)} chars")
|
|
205
|
+
|
|
206
|
+
# Viewing instructions
|
|
207
|
+
console.print("\\n[cyan]How to view:[/cyan]")
|
|
208
|
+
console.print(" 1. Visit https://mermaid.live")
|
|
209
|
+
console.print(f" 2. Copy contents of {output}")
|
|
210
|
+
console.print(" 3. Paste and view rendered diagram")
|
|
211
|
+
console.print("")
|
|
212
|
+
|
|
213
|
+
except Exception as e:
|
|
214
|
+
console.print(f"\\n[bold red]Error:[/bold red] {e}")
|
|
215
|
+
logger.exception("Diagram generation failed")
|
|
216
|
+
raise typer.Exit(1)
|
|
217
|
+
|
|
218
|
+
|
|
219
|
+
@diagram_app.command("list")
|
|
220
|
+
def list_diagrams_command():
|
|
221
|
+
"""
|
|
222
|
+
List available diagram types and their descriptions.
|
|
223
|
+
|
|
224
|
+
Examples:
|
|
225
|
+
assistant diagram list
|
|
226
|
+
"""
|
|
227
|
+
console.print("[bold cyan]Available Diagram Types[/bold cyan]\\n")
|
|
228
|
+
|
|
229
|
+
table = Table(show_header=True, header_style="bold magenta")
|
|
230
|
+
table.add_column("Type")
|
|
231
|
+
table.add_column("Description")
|
|
232
|
+
table.add_column("Best For")
|
|
233
|
+
|
|
234
|
+
table.add_row(
|
|
235
|
+
"architecture",
|
|
236
|
+
"High-level module structure",
|
|
237
|
+
"Understanding overall system design"
|
|
238
|
+
)
|
|
239
|
+
|
|
240
|
+
table.add_row(
|
|
241
|
+
"dependency",
|
|
242
|
+
"File/module dependencies",
|
|
243
|
+
"Finding tightly coupled components"
|
|
244
|
+
)
|
|
245
|
+
|
|
246
|
+
table.add_row(
|
|
247
|
+
"class",
|
|
248
|
+
"OOP structure with inheritance",
|
|
249
|
+
"Understanding class relationships"
|
|
250
|
+
)
|
|
251
|
+
|
|
252
|
+
table.add_row(
|
|
253
|
+
"dataflow",
|
|
254
|
+
"Data movement through system",
|
|
255
|
+
"Tracing data transformations"
|
|
256
|
+
)
|
|
257
|
+
|
|
258
|
+
console.print(table)
|
|
259
|
+
|
|
260
|
+
console.print("\\n[cyan]Example usage:[/cyan]")
|
|
261
|
+
console.print(" assistant diagram generate architecture")
|
|
262
|
+
console.print(" assistant diagram generate dependency --max-nodes 50")
|
|
263
|
+
console.print("")
|
|
264
|
+
|
|
265
|
+
|
|
266
|
+
# Export the Typer app
|
|
267
|
+
__all__ = ['diagram_app']
|
|
@@ -0,0 +1,410 @@
|
|
|
1
|
+
"""Documentation generation command.
|
|
2
|
+
|
|
3
|
+
This module provides the main CLI command for generating comprehensive
|
|
4
|
+
repository documentation using the CodeWiki integration.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
import asyncio
|
|
8
|
+
from pathlib import Path
|
|
9
|
+
from typing import Optional, Dict
|
|
10
|
+
import typer
|
|
11
|
+
from rich.console import Console
|
|
12
|
+
from rich.progress import Progress, SpinnerColumn, TextColumn, BarColumn
|
|
13
|
+
from rich.panel import Panel
|
|
14
|
+
from rich.table import Table
|
|
15
|
+
|
|
16
|
+
from coding_assistant.documentation.graph.dependency_builder import DependencyGraphBuilder
|
|
17
|
+
from coding_assistant.documentation.graph.module_analyzer import ModuleAnalyzer
|
|
18
|
+
from coding_assistant.documentation.decomposition.partitioner import HierarchicalPartitioner
|
|
19
|
+
from coding_assistant.documentation.decomposition.context_preserver import ContextPreserver
|
|
20
|
+
from coding_assistant.documentation.agents.coordinator import MultiAgentCoordinator
|
|
21
|
+
from coding_assistant.documentation.agents.synthesizer import DocumentationSynthesizer
|
|
22
|
+
from coding_assistant.documentation.generators.diagram_generator import MermaidDiagramGenerator
|
|
23
|
+
from coding_assistant.documentation.generators.dataflow_generator import DataFlowGenerator
|
|
24
|
+
from coding_assistant.codebase.parser import CodeParser
|
|
25
|
+
from coding_assistant.utils.logger import get_logger
|
|
26
|
+
|
|
27
|
+
logger = get_logger(__name__)
|
|
28
|
+
console = Console()
|
|
29
|
+
|
|
30
|
+
# Create Typer app for document subcommands
|
|
31
|
+
document_app = typer.Typer(
|
|
32
|
+
name="document",
|
|
33
|
+
help="Generate comprehensive documentation for the codebase",
|
|
34
|
+
no_args_is_help=True
|
|
35
|
+
)
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
@document_app.command("generate")
|
|
39
|
+
def generate_command(
|
|
40
|
+
output_dir: Path = typer.Option(
|
|
41
|
+
"./docs/generated",
|
|
42
|
+
"--output",
|
|
43
|
+
"-o",
|
|
44
|
+
help="Output directory for documentation"
|
|
45
|
+
),
|
|
46
|
+
codebase_path: Optional[Path] = typer.Option(
|
|
47
|
+
None,
|
|
48
|
+
"--path",
|
|
49
|
+
"-p",
|
|
50
|
+
help="Path to codebase (default: current directory)"
|
|
51
|
+
),
|
|
52
|
+
include_diagrams: bool = typer.Option(
|
|
53
|
+
True,
|
|
54
|
+
"--diagrams/--no-diagrams",
|
|
55
|
+
help="Include visual diagrams"
|
|
56
|
+
),
|
|
57
|
+
max_agents: int = typer.Option(
|
|
58
|
+
3,
|
|
59
|
+
"--agents",
|
|
60
|
+
"-a",
|
|
61
|
+
help="Maximum concurrent documentation agents"
|
|
62
|
+
),
|
|
63
|
+
format_type: str = typer.Option(
|
|
64
|
+
"markdown",
|
|
65
|
+
"--format",
|
|
66
|
+
"-f",
|
|
67
|
+
help="Output format (markdown, html)"
|
|
68
|
+
),
|
|
69
|
+
):
|
|
70
|
+
"""
|
|
71
|
+
Generate comprehensive documentation for the codebase.
|
|
72
|
+
|
|
73
|
+
This command uses the CodeWiki integration to:
|
|
74
|
+
- Analyze code structure and dependencies
|
|
75
|
+
- Partition repository into logical modules
|
|
76
|
+
- Generate documentation using parallel LLM agents
|
|
77
|
+
- Create visual diagrams (architecture, dependencies, etc.)
|
|
78
|
+
- Synthesize repository overview
|
|
79
|
+
|
|
80
|
+
Examples:
|
|
81
|
+
assistant document generate
|
|
82
|
+
assistant document generate --output ./docs
|
|
83
|
+
assistant document generate --agents 5 --no-diagrams
|
|
84
|
+
"""
|
|
85
|
+
asyncio.run(_generate_documentation_async(
|
|
86
|
+
output_dir=output_dir,
|
|
87
|
+
codebase_path=codebase_path or Path.cwd(),
|
|
88
|
+
include_diagrams=include_diagrams,
|
|
89
|
+
max_agents=max_agents,
|
|
90
|
+
format_type=format_type
|
|
91
|
+
))
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
async def _generate_documentation_async(
|
|
95
|
+
output_dir: Path,
|
|
96
|
+
codebase_path: Path,
|
|
97
|
+
include_diagrams: bool,
|
|
98
|
+
max_agents: int,
|
|
99
|
+
format_type: str
|
|
100
|
+
):
|
|
101
|
+
"""Generate documentation asynchronously."""
|
|
102
|
+
|
|
103
|
+
console.print(Panel.fit(
|
|
104
|
+
"[bold cyan]CodeWiki Documentation Generation[/bold cyan]\\n"
|
|
105
|
+
f"Analyzing: {codebase_path}",
|
|
106
|
+
border_style="cyan"
|
|
107
|
+
))
|
|
108
|
+
|
|
109
|
+
try:
|
|
110
|
+
# Phase 1: Build dependency graph
|
|
111
|
+
console.print("\\n[bold]Phase 1: Code Analysis[/bold]")
|
|
112
|
+
|
|
113
|
+
with Progress(
|
|
114
|
+
SpinnerColumn(),
|
|
115
|
+
TextColumn("[progress.description]{task.description}"),
|
|
116
|
+
console=console
|
|
117
|
+
) as progress:
|
|
118
|
+
|
|
119
|
+
task1 = progress.add_task("[cyan]Building dependency graph...", total=None)
|
|
120
|
+
builder = DependencyGraphBuilder(codebase_path)
|
|
121
|
+
file_graph = builder.build_file_graph()
|
|
122
|
+
module_graph = builder.build_module_graph(file_graph)
|
|
123
|
+
progress.update(task1, completed=True)
|
|
124
|
+
|
|
125
|
+
task2 = progress.add_task("[cyan]Detecting modules...", total=None)
|
|
126
|
+
analyzer = ModuleAnalyzer(file_graph)
|
|
127
|
+
modules = analyzer.detect_modules()
|
|
128
|
+
progress.update(task2, completed=True)
|
|
129
|
+
|
|
130
|
+
task3 = progress.add_task("[cyan]Computing metrics...", total=None)
|
|
131
|
+
metrics = builder.compute_metrics(file_graph)
|
|
132
|
+
progress.update(task3, completed=True)
|
|
133
|
+
|
|
134
|
+
console.print(f"[green]✓[/green] Analyzed {file_graph.number_of_nodes()} files, "
|
|
135
|
+
f"detected {len(modules)} modules\\n")
|
|
136
|
+
|
|
137
|
+
# Phase 2: Partition repository
|
|
138
|
+
console.print("[bold]Phase 2: Repository Partitioning[/bold]")
|
|
139
|
+
|
|
140
|
+
with Progress(
|
|
141
|
+
SpinnerColumn(),
|
|
142
|
+
TextColumn("[progress.description]{task.description}"),
|
|
143
|
+
console=console
|
|
144
|
+
) as progress:
|
|
145
|
+
|
|
146
|
+
task1 = progress.add_task("[cyan]Partitioning repository...", total=None)
|
|
147
|
+
|
|
148
|
+
file_sizes = {
|
|
149
|
+
node: file_graph.nodes[node].get('line_count', 0)
|
|
150
|
+
for node in file_graph.nodes()
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
partitioner = HierarchicalPartitioner(
|
|
154
|
+
max_partition_size=2000,
|
|
155
|
+
min_partition_size=100,
|
|
156
|
+
min_cohesion=0.3
|
|
157
|
+
)
|
|
158
|
+
|
|
159
|
+
partitions = partitioner.partition(file_graph, file_sizes, modules)
|
|
160
|
+
progress.update(task1, completed=True)
|
|
161
|
+
|
|
162
|
+
task2 = progress.add_task("[cyan]Extracting context...", total=None)
|
|
163
|
+
|
|
164
|
+
preserver = ContextPreserver()
|
|
165
|
+
contexts = {}
|
|
166
|
+
|
|
167
|
+
for partition in partitions:
|
|
168
|
+
context = preserver.extract_context(partition, partitions, file_graph)
|
|
169
|
+
contexts[partition.name] = context
|
|
170
|
+
|
|
171
|
+
progress.update(task2, completed=True)
|
|
172
|
+
|
|
173
|
+
console.print(f"[green]✓[/green] Created {len(partitions)} partitions with architectural context\\n")
|
|
174
|
+
|
|
175
|
+
# Phase 3: Generate documentation
|
|
176
|
+
console.print("[bold]Phase 3: Documentation Generation[/bold]")
|
|
177
|
+
|
|
178
|
+
coordinator = MultiAgentCoordinator(
|
|
179
|
+
max_concurrent_agents=max_agents,
|
|
180
|
+
use_async=True
|
|
181
|
+
)
|
|
182
|
+
|
|
183
|
+
with Progress(
|
|
184
|
+
SpinnerColumn(),
|
|
185
|
+
TextColumn("[progress.description]{task.description}"),
|
|
186
|
+
BarColumn(),
|
|
187
|
+
TextColumn("[progress.percentage]{task.percentage:>3.0f}%"),
|
|
188
|
+
console=console
|
|
189
|
+
) as progress:
|
|
190
|
+
|
|
191
|
+
task = progress.add_task(
|
|
192
|
+
"[cyan]Generating module documentation...",
|
|
193
|
+
total=len(partitions)
|
|
194
|
+
)
|
|
195
|
+
|
|
196
|
+
# Parse files for detailed documentation
|
|
197
|
+
parser = CodeParser()
|
|
198
|
+
parsed_files = {}
|
|
199
|
+
|
|
200
|
+
for partition in partitions:
|
|
201
|
+
for file_path in partition.files[:10]: # Limit files per partition
|
|
202
|
+
try:
|
|
203
|
+
parsed = parser.parse_file(file_path)
|
|
204
|
+
parsed_files[file_path] = parsed
|
|
205
|
+
except Exception as e:
|
|
206
|
+
logger.debug(f"Failed to parse {file_path}: {e}")
|
|
207
|
+
|
|
208
|
+
# Generate module documentation
|
|
209
|
+
module_docs = await coordinator.generate_documentation(
|
|
210
|
+
partitions,
|
|
211
|
+
contexts,
|
|
212
|
+
parsed_files
|
|
213
|
+
)
|
|
214
|
+
|
|
215
|
+
progress.update(task, completed=len(partitions))
|
|
216
|
+
|
|
217
|
+
stats = coordinator.get_completion_stats()
|
|
218
|
+
console.print(f"[green]✓[/green] Generated documentation for {stats['completed']}/{stats['total']} modules "
|
|
219
|
+
f"({stats['completion_rate']:.0%} success rate)\\n")
|
|
220
|
+
|
|
221
|
+
# Phase 4: Generate diagrams
|
|
222
|
+
diagrams = {}
|
|
223
|
+
|
|
224
|
+
if include_diagrams:
|
|
225
|
+
console.print("[bold]Phase 4: Diagram Generation[/bold]")
|
|
226
|
+
|
|
227
|
+
diagram_gen = MermaidDiagramGenerator()
|
|
228
|
+
dataflow_gen = DataFlowGenerator()
|
|
229
|
+
|
|
230
|
+
with Progress(
|
|
231
|
+
SpinnerColumn(),
|
|
232
|
+
TextColumn("[progress.description]{task.description}"),
|
|
233
|
+
console=console
|
|
234
|
+
) as progress:
|
|
235
|
+
|
|
236
|
+
task1 = progress.add_task("[cyan]Generating architecture diagram...", total=None)
|
|
237
|
+
diagrams['architecture'] = diagram_gen.generate_architecture_diagram(
|
|
238
|
+
partitions,
|
|
239
|
+
file_graph,
|
|
240
|
+
direction="TB"
|
|
241
|
+
)
|
|
242
|
+
progress.update(task1, completed=True)
|
|
243
|
+
|
|
244
|
+
task2 = progress.add_task("[cyan]Generating dependency graph...", total=None)
|
|
245
|
+
diagrams['dependencies'] = diagram_gen.generate_dependency_graph(
|
|
246
|
+
file_graph,
|
|
247
|
+
max_nodes=40,
|
|
248
|
+
show_files=True
|
|
249
|
+
)
|
|
250
|
+
progress.update(task2, completed=True)
|
|
251
|
+
|
|
252
|
+
if parsed_files:
|
|
253
|
+
task3 = progress.add_task("[cyan]Generating class diagram...", total=None)
|
|
254
|
+
diagrams['classes'] = diagram_gen.generate_class_diagram(
|
|
255
|
+
parsed_files,
|
|
256
|
+
max_classes=20
|
|
257
|
+
)
|
|
258
|
+
progress.update(task3, completed=True)
|
|
259
|
+
|
|
260
|
+
task4 = progress.add_task("[cyan]Generating data flow diagram...", total=None)
|
|
261
|
+
dataflow_info = dataflow_gen.extract_dataflow_from_parsed_files(
|
|
262
|
+
parsed_files,
|
|
263
|
+
max_entities=30
|
|
264
|
+
)
|
|
265
|
+
|
|
266
|
+
if dataflow_info['entities'] or dataflow_info['transformations']:
|
|
267
|
+
diagrams['dataflow'] = dataflow_gen.generate_dataflow_diagram(
|
|
268
|
+
dataflow_info['entities'],
|
|
269
|
+
dataflow_info['transformations'],
|
|
270
|
+
dataflow_info['external_systems']
|
|
271
|
+
)
|
|
272
|
+
progress.update(task4, completed=True)
|
|
273
|
+
|
|
274
|
+
console.print(f"[green]✓[/green] Generated {len(diagrams)} diagrams\\n")
|
|
275
|
+
|
|
276
|
+
# Phase 5: Synthesize overview
|
|
277
|
+
console.print("[bold]Phase 5: Repository Overview[/bold]")
|
|
278
|
+
|
|
279
|
+
with Progress(
|
|
280
|
+
SpinnerColumn(),
|
|
281
|
+
TextColumn("[progress.description]{task.description}"),
|
|
282
|
+
console=console
|
|
283
|
+
) as progress:
|
|
284
|
+
|
|
285
|
+
task = progress.add_task("[cyan]Synthesizing repository overview...", total=None)
|
|
286
|
+
|
|
287
|
+
synthesizer = DocumentationSynthesizer()
|
|
288
|
+
|
|
289
|
+
repo_metadata = {
|
|
290
|
+
'name': codebase_path.name,
|
|
291
|
+
'path': str(codebase_path),
|
|
292
|
+
'total_files': file_graph.number_of_nodes(),
|
|
293
|
+
'total_modules': len(modules),
|
|
294
|
+
'total_partitions': len(partitions)
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
overview = await synthesizer.synthesize_overview(
|
|
298
|
+
module_docs,
|
|
299
|
+
partitions,
|
|
300
|
+
repo_metadata
|
|
301
|
+
)
|
|
302
|
+
|
|
303
|
+
progress.update(task, completed=True)
|
|
304
|
+
|
|
305
|
+
console.print(f"[green]✓[/green] Repository overview synthesized\\n")
|
|
306
|
+
|
|
307
|
+
# Phase 6: Write output
|
|
308
|
+
console.print("[bold]Phase 6: Writing Documentation[/bold]")
|
|
309
|
+
|
|
310
|
+
with Progress(
|
|
311
|
+
SpinnerColumn(),
|
|
312
|
+
TextColumn("[progress.description]{task.description}"),
|
|
313
|
+
console=console
|
|
314
|
+
) as progress:
|
|
315
|
+
|
|
316
|
+
task = progress.add_task("[cyan]Writing documentation files...", total=None)
|
|
317
|
+
|
|
318
|
+
from coding_assistant.documentation.writers.markdown_writer import MarkdownWriter
|
|
319
|
+
|
|
320
|
+
writer = MarkdownWriter(output_dir)
|
|
321
|
+
|
|
322
|
+
written_files = writer.write_documentation(
|
|
323
|
+
overview=overview,
|
|
324
|
+
module_docs=module_docs,
|
|
325
|
+
diagrams=diagrams,
|
|
326
|
+
partitions=partitions,
|
|
327
|
+
repo_metadata=repo_metadata
|
|
328
|
+
)
|
|
329
|
+
|
|
330
|
+
progress.update(task, completed=True)
|
|
331
|
+
|
|
332
|
+
console.print(f"[green]✓[/green] Wrote {len(written_files)} documentation files\\n")
|
|
333
|
+
|
|
334
|
+
# Success summary
|
|
335
|
+
console.print("\\n" + "=" * 70)
|
|
336
|
+
console.print("[bold green]Documentation Generation Complete![/bold green]")
|
|
337
|
+
console.print("=" * 70)
|
|
338
|
+
|
|
339
|
+
summary_table = Table(show_header=False, box=None, padding=(0, 2))
|
|
340
|
+
summary_table.add_column("Metric", style="cyan")
|
|
341
|
+
summary_table.add_column("Value", style="green")
|
|
342
|
+
|
|
343
|
+
summary_table.add_row("Output Directory", str(output_dir))
|
|
344
|
+
summary_table.add_row("Files Analyzed", str(file_graph.number_of_nodes()))
|
|
345
|
+
summary_table.add_row("Modules Detected", str(len(modules)))
|
|
346
|
+
summary_table.add_row("Partitions Created", str(len(partitions)))
|
|
347
|
+
summary_table.add_row("Module Docs Generated", f"{stats['completed']}/{stats['total']}")
|
|
348
|
+
summary_table.add_row("Diagrams Generated", str(len(diagrams)))
|
|
349
|
+
summary_table.add_row("Documentation Files", str(len(written_files)))
|
|
350
|
+
|
|
351
|
+
console.print("\\n")
|
|
352
|
+
console.print(summary_table)
|
|
353
|
+
|
|
354
|
+
console.print(f"\\n[cyan]View documentation:[/cyan] {output_dir}/README.md")
|
|
355
|
+
console.print(f"[dim]Or run:[/dim] [yellow]assistant serve-docs --dir {output_dir}[/yellow]\\n")
|
|
356
|
+
|
|
357
|
+
except Exception as e:
|
|
358
|
+
console.print(f"\\n[bold red]Error:[/bold red] {e}")
|
|
359
|
+
logger.exception("Documentation generation failed")
|
|
360
|
+
raise typer.Exit(1)
|
|
361
|
+
|
|
362
|
+
|
|
363
|
+
@document_app.command("status")
|
|
364
|
+
def status_command(
|
|
365
|
+
output_dir: Path = typer.Option(
|
|
366
|
+
"./docs/generated",
|
|
367
|
+
"--output",
|
|
368
|
+
"-o",
|
|
369
|
+
help="Documentation output directory"
|
|
370
|
+
),
|
|
371
|
+
):
|
|
372
|
+
"""
|
|
373
|
+
Show status of generated documentation.
|
|
374
|
+
|
|
375
|
+
Examples:
|
|
376
|
+
assistant document status
|
|
377
|
+
assistant document status --output ./docs
|
|
378
|
+
"""
|
|
379
|
+
console.print(f"[bold cyan]Documentation Status[/bold cyan]\\n")
|
|
380
|
+
|
|
381
|
+
if not output_dir.exists():
|
|
382
|
+
console.print(f"[yellow]⚠[/yellow] Documentation directory does not exist: {output_dir}")
|
|
383
|
+
console.print(f"[dim]Run:[/dim] [cyan]assistant document generate[/cyan] to create documentation\\n")
|
|
384
|
+
return
|
|
385
|
+
|
|
386
|
+
# Count documentation files
|
|
387
|
+
md_files = list(output_dir.glob("**/*.md"))
|
|
388
|
+
diagram_files = list(output_dir.glob("**/*.mmd"))
|
|
389
|
+
|
|
390
|
+
status_table = Table(show_header=True, header_style="bold magenta")
|
|
391
|
+
status_table.add_column("Item")
|
|
392
|
+
status_table.add_column("Count", justify="right")
|
|
393
|
+
|
|
394
|
+
status_table.add_row("Markdown Files", str(len(md_files)))
|
|
395
|
+
status_table.add_row("Diagram Files", str(len(diagram_files)))
|
|
396
|
+
status_table.add_row("Total Files", str(len(md_files) + len(diagram_files)))
|
|
397
|
+
|
|
398
|
+
console.print(status_table)
|
|
399
|
+
|
|
400
|
+
console.print(f"\\n[cyan]Location:[/cyan] {output_dir}")
|
|
401
|
+
|
|
402
|
+
if (output_dir / "README.md").exists():
|
|
403
|
+
console.print(f"[green]✓[/green] Repository overview available")
|
|
404
|
+
console.print(f"[dim]View:[/dim] {output_dir}/README.md\\n")
|
|
405
|
+
else:
|
|
406
|
+
console.print(f"[yellow]⚠[/yellow] README.md not found\\n")
|
|
407
|
+
|
|
408
|
+
|
|
409
|
+
# Export the Typer app
|
|
410
|
+
__all__ = ['document_app']
|