k-cli-for-devs 1.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 (75) hide show
  1. k_cli/__init__.py +77 -0
  2. k_cli/agents/__init__.py +0 -0
  3. k_cli/agents/adversarial_swarm.py +338 -0
  4. k_cli/agents/agent_core.py +255 -0
  5. k_cli/agents/background_daemon.py +141 -0
  6. k_cli/agents/orchestrator.py +376 -0
  7. k_cli/agents/persona.py +649 -0
  8. k_cli/agents/scaffold_engine.py +121 -0
  9. k_cli/agents/strands_agent.py +832 -0
  10. k_cli/agents/subagents.py +1496 -0
  11. k_cli/cli.py +3297 -0
  12. k_cli/core/__init__.py +0 -0
  13. k_cli/core/airgap.py +95 -0
  14. k_cli/core/credentials.py +548 -0
  15. k_cli/core/intent_sensor.py +177 -0
  16. k_cli/core/llm_driver.py +1028 -0
  17. k_cli/core/model_manager.py +1109 -0
  18. k_cli/core/models_hub.py +913 -0
  19. k_cli/core/prompting.py +41 -0
  20. k_cli/core/sdk.py +322 -0
  21. k_cli/core/session.py +826 -0
  22. k_cli/core/smart_router.py +230 -0
  23. k_cli/core/storage_manager.py +176 -0
  24. k_cli/core/viewport_engine.py +117 -0
  25. k_cli/demo/demo_runner.py +579 -0
  26. k_cli/git/__init__.py +0 -0
  27. k_cli/git/ai_bisect.py +208 -0
  28. k_cli/git/conflict_resolver.py +1039 -0
  29. k_cli/git/git_guard.py +417 -0
  30. k_cli/git/patcher.py +1175 -0
  31. k_cli/git/repo_map.py +1780 -0
  32. k_cli/git/smart_git.py +928 -0
  33. k_cli/git/verifier.py +969 -0
  34. k_cli/github/__init__.py +0 -0
  35. k_cli/github/dedup_engine.py +787 -0
  36. k_cli/github/github_client.py +1702 -0
  37. k_cli/github/github_engine.py +641 -0
  38. k_cli/github/local_hub.py +209 -0
  39. k_cli/github/pr_watcher.py +129 -0
  40. k_cli/github/trending.py +205 -0
  41. k_cli/tools/__init__.py +0 -0
  42. k_cli/tools/audit.py +79 -0
  43. k_cli/tools/chaos_immunity.py +377 -0
  44. k_cli/tools/codebase_qa.py +106 -0
  45. k_cli/tools/command_runner.py +256 -0
  46. k_cli/tools/diagram_generator.py +547 -0
  47. k_cli/tools/doc_retriever.py +1332 -0
  48. k_cli/tools/feature.py +105 -0
  49. k_cli/tools/ghost_daemon.py +122 -0
  50. k_cli/tools/incident_triage.py +1365 -0
  51. k_cli/tools/mcp_client.py +1846 -0
  52. k_cli/tools/repo_gardener.py +142 -0
  53. k_cli/tools/rules.py +109 -0
  54. k_cli/tools/security.py +52 -0
  55. k_cli/tools/security_healer.py +999 -0
  56. k_cli/tools/synapse_graph.py +155 -0
  57. k_cli/tui/__init__.py +0 -0
  58. k_cli/tui/diff_viewer.py +223 -0
  59. k_cli/tui/tui.py +1145 -0
  60. k_cli/tui/tui_animations.py +648 -0
  61. k_cli/tui/tui_app.py +2788 -0
  62. k_cli/ui/__init__.py +10 -0
  63. k_cli/ui/simple_repl.py +315 -0
  64. k_cli/web/__init__.py +7 -0
  65. k_cli/web/server.py +624 -0
  66. k_cli/web/static/app.js +830 -0
  67. k_cli/web/static/index.html +495 -0
  68. k_cli/web/static/monitor.html +189 -0
  69. k_cli/web/static/style.css +838 -0
  70. k_cli_for_devs-1.0.0.dist-info/METADATA +461 -0
  71. k_cli_for_devs-1.0.0.dist-info/RECORD +75 -0
  72. k_cli_for_devs-1.0.0.dist-info/WHEEL +5 -0
  73. k_cli_for_devs-1.0.0.dist-info/entry_points.txt +2 -0
  74. k_cli_for_devs-1.0.0.dist-info/licenses/LICENSE +21 -0
  75. k_cli_for_devs-1.0.0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,547 @@
1
+ """
2
+ diagram_generator.py - Visual Architecture & Mermaid Diagram Generator for K-CLI
3
+
4
+ Features:
5
+ 1. Multi-Language AST & Symbol Inspection:
6
+ - Integrates with `repo_map.py` to inspect classes, functions, imports, and module dependencies.
7
+ - Detects hierarchical layers (UI, Core Engine, Verification & Safety, Knowledge & Context).
8
+ 2. Clean, Beautiful Mermaid Diagram Synthesis:
9
+ - High-Level Architecture Flowchart (`flowchart TD` / `graph TD`) with styled subgraphs and nodes.
10
+ - Core Sequence Diagrams (`sequenceDiagram`) tracing execution loops (Incident Triage & Auto-Heal, Verification Loop, Subagent Swarm DAG).
11
+ - Component & Module Dependency Matrix Diagrams.
12
+ - Class Hierarchy Diagrams (`classDiagram`) with methods and properties.
13
+ 3. Terminal Output & Markdown File Injection:
14
+ - Outputs directly to CLI/TUI terminal.
15
+ - Injects or updates diagrams cleanly in `ARCHITECTURE.md`, `README.md`, or custom markdown documents using bounded comment markers.
16
+ """
17
+
18
+ from __future__ import annotations
19
+
20
+ import logging
21
+ import os
22
+ import re
23
+ from dataclasses import dataclass, field
24
+ from enum import Enum
25
+ from pathlib import Path
26
+ from typing import Any, Dict, List, Optional, Set, Tuple, Union
27
+
28
+ logger = logging.getLogger(__name__)
29
+
30
+ # Safe import for RepoMap
31
+ try:
32
+ from k_cli.git.repo_map import RepoMap
33
+ except (ModuleNotFoundError, ImportError):
34
+ try:
35
+ from repo_map import RepoMap
36
+ except (ModuleNotFoundError, ImportError):
37
+ RepoMap = None # type: ignore
38
+
39
+
40
+ class DiagramType(str, Enum):
41
+ """Supported diagram types."""
42
+ FLOWCHART = "flowchart"
43
+ SEQUENCE = "sequence"
44
+ CLASS_DIAGRAM = "class_diagram"
45
+ COMPONENT = "component"
46
+ ALL = "all"
47
+
48
+
49
+ class DiagramGenerator:
50
+ """
51
+ AST-driven Mermaid architecture diagram generator and markdown injector.
52
+ """
53
+
54
+ MARKER_START = "<!-- K_CLI_ARCHITECTURE_START -->"
55
+ MARKER_END = "<!-- K_CLI_ARCHITECTURE_END -->"
56
+
57
+ def __init__(self, repo_path: str = ".") -> None:
58
+ self.repo_path = Path(repo_path).resolve()
59
+ self._repo_map = RepoMap(str(self.repo_path)) if RepoMap else None
60
+
61
+ # =========================================================================
62
+ # 1. Flowchart & Architecture Diagram Synthesis
63
+ # =========================================================================
64
+
65
+ def _sanitize_id(self, name: str) -> str:
66
+ """Sanitizes module/file name to a valid Mermaid node identifier."""
67
+ clean = re.sub(r'[^a-zA-Z0-9_]', '_', name)
68
+ if clean and clean[0].isdigit():
69
+ clean = f"node_{clean}"
70
+ return clean or "node_root"
71
+
72
+ def _classify_layer(self, rel_path: str) -> str:
73
+ """Classifies a file or module into architectural layers."""
74
+ fname = Path(rel_path).name.lower()
75
+ if "test" in fname or "tests" in rel_path:
76
+ return "Test Suite & Verification"
77
+ elif any(token in fname for token in ("cli", "tui", "repl", "view", "viewer", "ui", "console")):
78
+ return "UI & Workstation"
79
+ elif any(token in fname for token in ("orchestrator", "llm", "driver", "model", "subagent", "persona", "mcp")):
80
+ return "Core Engine & Agent Swarm"
81
+ elif any(token in fname for token in ("verifier", "patcher", "guard", "security", "audit", "rollback")):
82
+ return "Verification & Safety Net"
83
+ elif any(token in fname for token in ("repo_map", "doc", "retriever", "rule", "workflow", "triage", "diagram", "dedup")):
84
+ return "Knowledge & Visual Architecture"
85
+ else:
86
+ parent = Path(rel_path).parent.name
87
+ return parent.capitalize() if parent and parent != "." else "General Modules"
88
+
89
+ def generate_flowchart(
90
+ self,
91
+ repo_path: Optional[str] = None,
92
+ focus_modules: Optional[List[str]] = None,
93
+ max_nodes: int = 35,
94
+ direction: str = "TD",
95
+ ) -> str:
96
+ """
97
+ Generates a clean Mermaid flowchart diagram of repository architecture,
98
+ grouping modules into styled subgraphs with symbol summaries and dependency edges.
99
+
100
+ Args:
101
+ repo_path: Optional workspace path.
102
+ focus_modules: Optional list of modules to focus on.
103
+ max_nodes: Maximum nodes to render in the diagram.
104
+ direction: Graph direction ('TD', 'LR', 'TB').
105
+
106
+ Returns:
107
+ Mermaid flowchart markdown string.
108
+ """
109
+ r_path = Path(repo_path).resolve() if repo_path else self.repo_path
110
+ rm = RepoMap(str(r_path)) if RepoMap else self._repo_map
111
+
112
+ if not rm:
113
+ return "```mermaid\ngraph TD\n Root[\"Workspace\"]\n```"
114
+
115
+ files = rm.scan_workspace_files()
116
+ if not files:
117
+ return "```mermaid\ngraph TD\n Empty[\"Empty Workspace\"]\n```"
118
+
119
+ dep_graph = rm.get_dependency_graph()
120
+
121
+ # Filter and prioritize files
122
+ rel_files: List[Tuple[str, str]] = [] # (abs_path, rel_path)
123
+ for f in files:
124
+ try:
125
+ rel = str(Path(f).relative_to(r_path)).replace("\\", "/")
126
+ except ValueError:
127
+ rel = Path(f).name
128
+
129
+ if focus_modules:
130
+ if any(m in rel for m in focus_modules):
131
+ rel_files.append((f, rel))
132
+ else:
133
+ # Skip deeply nested tests or cache if exceeding max_nodes
134
+ if not rel.startswith("tests/") and not rel.startswith("k_cli_env/"):
135
+ rel_files.append((f, rel))
136
+
137
+ if len(rel_files) > max_nodes:
138
+ rel_files = rel_files[:max_nodes]
139
+
140
+ # Group by layer
141
+ layer_groups: Dict[str, List[Tuple[str, str, List[Dict[str, Any]]]]] = {}
142
+ for abs_p, rel_p in rel_files:
143
+ layer = self._classify_layer(rel_p)
144
+ symbols = rm.extract_symbols(abs_p) if rm else []
145
+ layer_groups.setdefault(layer, []).append((abs_p, rel_p, symbols))
146
+
147
+ lines: List[str] = [
148
+ f"```mermaid",
149
+ f"flowchart {direction}",
150
+ ]
151
+
152
+ # Render subgraphs
153
+ node_id_map: Dict[str, str] = {}
154
+
155
+ for layer_name, members in layer_groups.items():
156
+ subgraph_id = self._sanitize_id(layer_name)
157
+ lines.append(f" subgraph {subgraph_id}[\"{layer_name}\"]")
158
+ for abs_p, rel_p, symbols in members:
159
+ node_id = self._sanitize_id(rel_p)
160
+ node_id_map[rel_p] = node_id
161
+ node_id_map[Path(rel_p).stem] = node_id
162
+ node_id_map[Path(rel_p).name] = node_id
163
+
164
+ # Format key symbols (classes & functions)
165
+ classes = [s["name"] for s in symbols if s.get("type") in ("class", "struct")][:2]
166
+ funcs = [s["name"] for s in symbols if s.get("type") in ("function", "async_function")][:2]
167
+
168
+ symbol_text = ""
169
+ if classes:
170
+ symbol_text += "<br/><b>Classes:</b> " + ", ".join(classes)
171
+ if funcs and not classes:
172
+ symbol_text += "<br/><b>Funcs:</b> " + ", ".join(funcs)
173
+
174
+ label = f"<b>{Path(rel_p).name}</b>{symbol_text}"
175
+ lines.append(f" {node_id}[\"{label}\"]")
176
+ lines.append(" end")
177
+
178
+ # Render dependency edges
179
+ added_edges: Set[Tuple[str, str]] = set()
180
+ for src_rel, targets in dep_graph.items():
181
+ src_id = node_id_map.get(src_rel) or node_id_map.get(Path(src_rel).stem) or node_id_map.get(Path(src_rel).name)
182
+ if not src_id:
183
+ continue
184
+ for tgt_rel in targets:
185
+ tgt_id = node_id_map.get(tgt_rel) or node_id_map.get(Path(tgt_rel).stem) or node_id_map.get(Path(tgt_rel).name)
186
+ if tgt_id and tgt_id != src_id and (src_id, tgt_id) not in added_edges:
187
+ added_edges.add((src_id, tgt_id))
188
+ lines.append(f" {src_id} --> {tgt_id}")
189
+
190
+ # Add CSS classes & styling
191
+ lines.append("")
192
+ lines.append(" %% Styling & Theme")
193
+ lines.append(" classDef ui fill:#f3e5f5,stroke:#8e24aa,stroke-width:2px,color:#4a148c;")
194
+ lines.append(" classDef core fill:#e1f5fe,stroke:#0288d1,stroke-width:2px,color:#01579b;")
195
+ lines.append(" classDef safety fill:#e8f5e9,stroke:#43a047,stroke-width:2px,color:#1b5e20;")
196
+ lines.append(" classDef knowledge fill:#fff3e0,stroke:#fb8c00,stroke-width:2px,color:#e65100;")
197
+ lines.append(" classDef general fill:#eceff1,stroke:#607d8b,stroke-width:2px,color:#263238;")
198
+
199
+ # Apply classes to nodes
200
+ for rel_p, node_id in node_id_map.items():
201
+ layer = self._classify_layer(rel_p)
202
+ if "UI" in layer:
203
+ lines.append(f" class {node_id} ui;")
204
+ elif "Core" in layer:
205
+ lines.append(f" class {node_id} core;")
206
+ elif "Verification" in layer or "Safety" in layer:
207
+ lines.append(f" class {node_id} safety;")
208
+ elif "Knowledge" in layer or "Visual" in layer:
209
+ lines.append(f" class {node_id} knowledge;")
210
+ else:
211
+ lines.append(f" class {node_id} general;")
212
+
213
+ lines.append("```")
214
+ return "\n".join(lines)
215
+
216
+ # =========================================================================
217
+ # 2. Sequence Diagrams Synthesis
218
+ # =========================================================================
219
+
220
+ def generate_sequence_diagram(
221
+ self,
222
+ flow_name: str = "incident_triage",
223
+ repo_path: Optional[str] = None,
224
+ ) -> str:
225
+ """
226
+ Generates Mermaid sequence diagrams for key architectural workflows.
227
+
228
+ Supported flows:
229
+ - "incident_triage" / "triage_and_heal": Incident log ingestion, culprit AST resolution, and auto-heal loop.
230
+ - "verification_loop" / "agent_execution": Developer task, LLM generation, AST verification, and git checkpoint.
231
+ - "subagent_swarm" / "dag_execution": Parallel task decomposition, role worker dispatch, and synthesis.
232
+ """
233
+ flow = flow_name.lower().strip()
234
+
235
+ if flow in ("incident_triage", "triage", "auto_heal", "triage_and_heal"):
236
+ return (
237
+ "```mermaid\n"
238
+ "sequenceDiagram\n"
239
+ " autonumber\n"
240
+ " actor Dev as Developer / CI\n"
241
+ " participant CLI as k-cli CLI/TUI\n"
242
+ " participant Triage as IncidentTriageEngine\n"
243
+ " participant Repo as RepoMap (AST)\n"
244
+ " participant LLM as Universal LLM Driver\n"
245
+ " participant Patcher as Surgical Patcher\n"
246
+ " participant Verifier as Ground-Truth Verifier\n"
247
+ " participant Git as Git Guard\n"
248
+ "\n"
249
+ " Dev->>CLI: k incident triage --log crash.log\n"
250
+ " CLI->>Triage: triage_log_or_trace(raw_log)\n"
251
+ " Triage->>Triage: Parse stack trace (Python/Node/Rust/Go/C++/Docker/CI)\n"
252
+ " Triage->>Repo: Cross-reference culprit frames & extract AST symbol\n"
253
+ " Repo-->>Triage: Enclosing symbol, lines, and source snippet\n"
254
+ " Triage->>LLM: Analyze root cause & synthesize reproduction\n"
255
+ " LLM-->>Triage: IncidentReport (Root Cause & Fix Guidance)\n"
256
+ " Triage-->>CLI: IncidentReport Card\n"
257
+ "\n"
258
+ " opt Auto-Heal Enabled\n"
259
+ " CLI->>Triage: auto_heal_incident(incident, verifier, patcher)\n"
260
+ " Triage->>Git: Create workspace safety snapshot\n"
261
+ " Triage->>LLM: Generate SEARCH/REPLACE patch & regression test\n"
262
+ " LLM-->>Triage: Surgical Patch Blocks + Test Code\n"
263
+ " Triage->>Patcher: Apply candidate SEARCH/REPLACE block\n"
264
+ " Patcher-->>Triage: Syntactically patched file\n"
265
+ " Triage->>Verifier: Validate AST syntax & execute regression test\n"
266
+ " alt Verification Passes\n"
267
+ " Verifier-->>Triage: Test Passed (0 errors)\n"
268
+ " Triage->>Git: Commit atomic verified change\n"
269
+ " Triage-->>CLI: IncidentHealResult (Success & Diff)\n"
270
+ " CLI-->>Dev: Verified Fix Applied & Diff Rendered\n"
271
+ " else Verification Fails\n"
272
+ " Verifier-->>Triage: Test Failure Trace\n"
273
+ " Triage->>Git: Rollback workspace (git restore)\n"
274
+ " Triage-->>CLI: IncidentHealResult (Failure & Safe Rollback)\n"
275
+ " CLI-->>Dev: Rollback Notification & Diagnostics\n"
276
+ " end\n"
277
+ " end\n"
278
+ "```"
279
+ )
280
+
281
+ elif flow in ("verification_loop", "agent_execution", "core_loop"):
282
+ return (
283
+ "```mermaid\n"
284
+ "sequenceDiagram\n"
285
+ " autonumber\n"
286
+ " actor Dev as Developer\n"
287
+ " participant CLI as CLI / TUI Workstation\n"
288
+ " participant Session as Session & Rules\n"
289
+ " participant LLM as Universal LLM Driver\n"
290
+ " participant Verifier as Ground-Truth Verifier\n"
291
+ " participant Patcher as Surgical Patcher\n"
292
+ " participant Git as Git Guard\n"
293
+ "\n"
294
+ " Dev->>CLI: k-cli run \"task\" or /plan\n"
295
+ " CLI->>Session: Load context files & bounded rules\n"
296
+ " Session->>LLM: Enhanced prompt with repo map & signatures\n"
297
+ " LLM-->>Session: Candidate code / SEARCH-REPLACE blocks\n"
298
+ " Session->>Verifier: AST Syntax & Type Check\n"
299
+ " alt Verification Fails\n"
300
+ " Verifier-->>Session: Syntax error trace & line numbers\n"
301
+ " Session->>LLM: Auto-debug prompt with error trace\n"
302
+ " LLM-->>Session: Repaired candidate code\n"
303
+ " Session->>Verifier: Re-verify repaired code\n"
304
+ " end\n"
305
+ " Session->>Git: Create workspace safety checkpoint\n"
306
+ " Session->>Patcher: Apply surgical patch\n"
307
+ " Session->>Verifier: Run project test suite (pytest / cargo / npm)\n"
308
+ " alt Tests Pass\n"
309
+ " Verifier-->>Session: All tests passed\n"
310
+ " Session->>Git: Commit atomic verified change\n"
311
+ " Session-->>CLI: Verified Diff & Success Card\n"
312
+ " else Tests Fail\n"
313
+ " Verifier-->>Session: Test failure output\n"
314
+ " Session->>Git: Auto-rollback workspace (git restore)\n"
315
+ " Session-->>CLI: Rollback notification & error details\n"
316
+ " end\n"
317
+ "```"
318
+ )
319
+
320
+ elif flow in ("subagent_swarm", "dag_execution", "swarm"):
321
+ return (
322
+ "```mermaid\n"
323
+ "sequenceDiagram\n"
324
+ " autonumber\n"
325
+ " actor User as Developer\n"
326
+ " participant Orch as Orchestrator\n"
327
+ " participant Disp as SubagentDispatcher\n"
328
+ " participant Exp as [EXPLORER Worker]\n"
329
+ " participant Res as [RESEARCHER Worker]\n"
330
+ " participant Cod as [CODER Worker]\n"
331
+ " participant Test as [TESTER Worker]\n"
332
+ " participant Ver as Verifier Guard\n"
333
+ "\n"
334
+ " User->>Orch: Execute multi-stage goal\n"
335
+ " Orch->>Disp: Decompose into DAG Task Graph\n"
336
+ " Disp->>Exp: 1. Survey workspace & dependencies\n"
337
+ " Exp-->>Disp: Workspace context & file list\n"
338
+ " Disp->>Res: 2. Extract signatures & DevDocs\n"
339
+ " Res-->>Disp: API contracts & interfaces\n"
340
+ " Disp->>Cod: 3. Generate surgical implementation\n"
341
+ " Cod-->>Disp: Candidate patch blocks\n"
342
+ " Disp->>Test: 4. Generate regression test suite\n"
343
+ " Test-->>Disp: Unit test code\n"
344
+ " Disp->>Ver: Verify AST syntax & execute test\n"
345
+ " Ver-->>Disp: Verification passed\n"
346
+ " Disp-->>Orch: Aggregated DAG Execution Result\n"
347
+ " Orch-->>User: Verified Goal Completed\n"
348
+ "```"
349
+ )
350
+
351
+ else:
352
+ # Generic workflow sequence diagram
353
+ return (
354
+ "```mermaid\n"
355
+ "sequenceDiagram\n"
356
+ " autonumber\n"
357
+ " actor User\n"
358
+ " participant CLI as k-cli\n"
359
+ " participant Core as Core Engine\n"
360
+ " participant Output as Result\n"
361
+ " User->>CLI: Invoke command\n"
362
+ " CLI->>Core: Process request\n"
363
+ " Core-->>Output: Render results\n"
364
+ " Output-->>User: Display in terminal / file\n"
365
+ "```"
366
+ )
367
+
368
+ # =========================================================================
369
+ # 3. Class Diagram Synthesis
370
+ # =========================================================================
371
+
372
+ def generate_class_diagram(
373
+ self,
374
+ repo_path: Optional[str] = None,
375
+ focus_files: Optional[List[str]] = None,
376
+ max_classes: int = 20,
377
+ ) -> str:
378
+ """
379
+ Generates a Mermaid classDiagram showing classes, methods, and relationships.
380
+
381
+ Args:
382
+ repo_path: Optional workspace path.
383
+ focus_files: Optional file list to filter.
384
+ max_classes: Max classes to include.
385
+
386
+ Returns:
387
+ Mermaid classDiagram markdown string.
388
+ """
389
+ r_path = Path(repo_path).resolve() if repo_path else self.repo_path
390
+ rm = RepoMap(str(r_path)) if RepoMap else self._repo_map
391
+
392
+ if not rm:
393
+ return "```mermaid\nclassDiagram\n class Workspace\n```"
394
+
395
+ files = rm.scan_workspace_files()
396
+ lines: List[str] = [
397
+ "```mermaid",
398
+ "classDiagram",
399
+ ]
400
+
401
+ class_count = 0
402
+ for f in files:
403
+ try:
404
+ rel = str(Path(f).relative_to(r_path)).replace("\\", "/")
405
+ except ValueError:
406
+ rel = Path(f).name
407
+
408
+ if focus_files and not any(ff in rel for ff in focus_files):
409
+ continue
410
+ if "test" in rel or "k_cli_env" in rel:
411
+ continue
412
+
413
+ symbols = rm.extract_symbols(f)
414
+ for sym in symbols:
415
+ if sym.get("type") in ("class", "struct") and class_count < max_classes:
416
+ cname = sym.get("name", "")
417
+ if not cname:
418
+ continue
419
+ class_count += 1
420
+ safe_cname = self._sanitize_id(cname)
421
+ lines.append(f" class {safe_cname} {{")
422
+ # Add methods
423
+ methods = sym.get("methods", [])
424
+ for m in methods[:5]:
425
+ m_name = m.get("name", "")
426
+ if m_name and not m_name.startswith("__"):
427
+ lines.append(f" +{m_name}()")
428
+ lines.append(" }")
429
+
430
+ if class_count == 0:
431
+ lines.append(" class KCLIApplication")
432
+
433
+ lines.append("```")
434
+ return "\n".join(lines)
435
+
436
+ # =========================================================================
437
+ # 4. Comprehensive Architecture Synthesis & Markdown Injection
438
+ # =========================================================================
439
+
440
+ def generate_mermaid_architecture(
441
+ self,
442
+ repo_path: str = ".",
443
+ output_file: Optional[str] = None,
444
+ diagram_type: str = "all",
445
+ title: Optional[str] = None,
446
+ ) -> str:
447
+ """
448
+ Main entrypoint: Inspects codebase AST imports, symbol dependencies, and module hierarchy,
449
+ produces clean, beautiful Mermaid flowchart and sequence diagrams, and optionally
450
+ injects/updates into ARCHITECTURE.md or README.md.
451
+
452
+ Args:
453
+ repo_path: Root directory of the repository.
454
+ output_file: Optional path to markdown file for injection (e.g. ARCHITECTURE.md).
455
+ diagram_type: Diagram type ('flowchart', 'sequence', 'class_diagram', 'all').
456
+ title: Optional custom section title.
457
+
458
+ Returns:
459
+ Generated Markdown document containing the complete architecture diagrams.
460
+ """
461
+ self.repo_path = Path(repo_path).resolve()
462
+
463
+ sections: List[str] = []
464
+ sec_title = title or "K-CLI Visual Repository Architecture"
465
+ sections.append(f"## {sec_title}\n")
466
+
467
+ dtype = diagram_type.lower().strip()
468
+
469
+ if dtype in ("flowchart", "all"):
470
+ sections.append("### 1. High-Level Modular Component Architecture")
471
+ sections.append(self.generate_flowchart(repo_path=str(self.repo_path)))
472
+ sections.append("")
473
+
474
+ if dtype in ("sequence", "all"):
475
+ sections.append("### 2. Incident Triage & Auto-Heal Execution Loop")
476
+ sections.append(self.generate_sequence_diagram(flow_name="incident_triage", repo_path=str(self.repo_path)))
477
+ sections.append("")
478
+
479
+ sections.append("### 3. Ground-Truth Verification & Rollback Loop")
480
+ sections.append(self.generate_sequence_diagram(flow_name="verification_loop", repo_path=str(self.repo_path)))
481
+ sections.append("")
482
+
483
+ if dtype in ("class_diagram", "all"):
484
+ sections.append("### 4. Core Domain Symbol & Class Hierarchy")
485
+ sections.append(self.generate_class_diagram(repo_path=str(self.repo_path)))
486
+ sections.append("")
487
+
488
+ full_content = "\n".join(sections)
489
+
490
+ if output_file:
491
+ self.inject_into_file(full_content, output_file)
492
+
493
+ return full_content
494
+
495
+ def inject_into_file(
496
+ self,
497
+ content: str,
498
+ output_file: str,
499
+ marker_start: str = MARKER_START,
500
+ marker_end: str = MARKER_END,
501
+ ) -> bool:
502
+ """
503
+ Injects or updates generated Mermaid architecture diagrams into a Markdown file
504
+ (e.g., ARCHITECTURE.md or README.md) enclosed cleanly within comment markers.
505
+
506
+ Args:
507
+ content: Diagram content to inject.
508
+ output_file: Target file path.
509
+ marker_start: Opening comment marker.
510
+ marker_end: Closing comment marker.
511
+
512
+ Returns:
513
+ True if injection was successful.
514
+ """
515
+ out_path = Path(output_file)
516
+ if not out_path.is_absolute():
517
+ out_path = (self.repo_path / out_path).resolve()
518
+
519
+ out_path.parent.mkdir(parents=True, exist_ok=True)
520
+
521
+ wrapped_content = f"{marker_start}\n\n{content.strip()}\n\n{marker_end}"
522
+
523
+ if out_path.exists() and out_path.is_file():
524
+ existing_text = out_path.read_text(encoding="utf-8", errors="replace")
525
+ if marker_start in existing_text and marker_end in existing_text:
526
+ # Replace between markers
527
+ pattern = re.compile(
528
+ re.escape(marker_start) + r"[\s\S]*?" + re.escape(marker_end),
529
+ re.MULTILINE,
530
+ )
531
+ updated_text = pattern.sub(wrapped_content, existing_text)
532
+ else:
533
+ # Append to bottom of file
534
+ updated_text = existing_text.rstrip() + "\n\n---\n\n" + wrapped_content + "\n"
535
+ else:
536
+ # Create fresh document
537
+ updated_text = f"# Repository Architecture\n\n{wrapped_content}\n"
538
+
539
+ out_path.write_text(updated_text, encoding="utf-8")
540
+ logger.info(f"Successfully injected Mermaid architecture diagram into {out_path}")
541
+ return True
542
+
543
+
544
+ __all__ = [
545
+ "DiagramType",
546
+ "DiagramGenerator",
547
+ ]