dbagent-cli 0.3.8__tar.gz → 0.4.0__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 (74) hide show
  1. {dbagent_cli-0.3.8 → dbagent_cli-0.4.0}/PKG-INFO +2 -2
  2. {dbagent_cli-0.3.8 → dbagent_cli-0.4.0}/dbagent/__init__.py +1 -1
  3. {dbagent_cli-0.3.8 → dbagent_cli-0.4.0}/dbagent/cli.py +17 -0
  4. {dbagent_cli-0.3.8 → dbagent_cli-0.4.0}/dbagent/llm/gemini_provider.py +14 -12
  5. {dbagent_cli-0.3.8 → dbagent_cli-0.4.0}/dbagent/ui/console.py +1 -1
  6. dbagent_cli-0.4.0/dbagent/ui/grid_window.py +245 -0
  7. {dbagent_cli-0.3.8 → dbagent_cli-0.4.0}/dbagent_cli.egg-info/PKG-INFO +2 -2
  8. {dbagent_cli-0.3.8 → dbagent_cli-0.4.0}/dbagent_cli.egg-info/SOURCES.txt +1 -0
  9. {dbagent_cli-0.3.8 → dbagent_cli-0.4.0}/pyproject.toml +2 -2
  10. {dbagent_cli-0.3.8 → dbagent_cli-0.4.0}/README.md +0 -0
  11. {dbagent_cli-0.3.8 → dbagent_cli-0.4.0}/dbagent/agent/confidence.py +0 -0
  12. {dbagent_cli-0.3.8 → dbagent_cli-0.4.0}/dbagent/agent/conversation.py +0 -0
  13. {dbagent_cli-0.3.8 → dbagent_cli-0.4.0}/dbagent/agent/doctor.py +0 -0
  14. {dbagent_cli-0.3.8 → dbagent_cli-0.4.0}/dbagent/agent/error_classifier.py +0 -0
  15. {dbagent_cli-0.3.8 → dbagent_cli-0.4.0}/dbagent/agent/generator.py +0 -0
  16. {dbagent_cli-0.3.8 → dbagent_cli-0.4.0}/dbagent/agent/pipeline.py +0 -0
  17. {dbagent_cli-0.3.8 → dbagent_cli-0.4.0}/dbagent/agent/recommender.py +0 -0
  18. {dbagent_cli-0.3.8 → dbagent_cli-0.4.0}/dbagent/agent/validator.py +0 -0
  19. {dbagent_cli-0.3.8 → dbagent_cli-0.4.0}/dbagent/config.py +0 -0
  20. {dbagent_cli-0.3.8 → dbagent_cli-0.4.0}/dbagent/connectors/base.py +0 -0
  21. {dbagent_cli-0.3.8 → dbagent_cli-0.4.0}/dbagent/connectors/factory.py +0 -0
  22. {dbagent_cli-0.3.8 → dbagent_cli-0.4.0}/dbagent/connectors/mongo.py +0 -0
  23. {dbagent_cli-0.3.8 → dbagent_cli-0.4.0}/dbagent/connectors/relational.py +0 -0
  24. {dbagent_cli-0.3.8 → dbagent_cli-0.4.0}/dbagent/execution/__init__.py +0 -0
  25. {dbagent_cli-0.3.8 → dbagent_cli-0.4.0}/dbagent/execution/cache.py +0 -0
  26. {dbagent_cli-0.3.8 → dbagent_cli-0.4.0}/dbagent/execution/changeset.py +0 -0
  27. {dbagent_cli-0.3.8 → dbagent_cli-0.4.0}/dbagent/execution/cost.py +0 -0
  28. {dbagent_cli-0.3.8 → dbagent_cli-0.4.0}/dbagent/execution/recovery.py +0 -0
  29. {dbagent_cli-0.3.8 → dbagent_cli-0.4.0}/dbagent/execution/sandbox.py +0 -0
  30. {dbagent_cli-0.3.8 → dbagent_cli-0.4.0}/dbagent/execution/streaming.py +0 -0
  31. {dbagent_cli-0.3.8 → dbagent_cli-0.4.0}/dbagent/llm/auto_setup.py +0 -0
  32. {dbagent_cli-0.3.8 → dbagent_cli-0.4.0}/dbagent/llm/base.py +0 -0
  33. {dbagent_cli-0.3.8 → dbagent_cli-0.4.0}/dbagent/llm/factory.py +0 -0
  34. {dbagent_cli-0.3.8 → dbagent_cli-0.4.0}/dbagent/llm/groq_provider.py +0 -0
  35. {dbagent_cli-0.3.8 → dbagent_cli-0.4.0}/dbagent/llm/mock_provider.py +0 -0
  36. {dbagent_cli-0.3.8 → dbagent_cli-0.4.0}/dbagent/llm/ollama_provider.py +0 -0
  37. {dbagent_cli-0.3.8 → dbagent_cli-0.4.0}/dbagent/llm/openrouter_provider.py +0 -0
  38. {dbagent_cli-0.3.8 → dbagent_cli-0.4.0}/dbagent/schema/cache.py +0 -0
  39. {dbagent_cli-0.3.8 → dbagent_cli-0.4.0}/dbagent/schema/formatter.py +0 -0
  40. {dbagent_cli-0.3.8 → dbagent_cli-0.4.0}/dbagent/schema/graph.py +0 -0
  41. {dbagent_cli-0.3.8 → dbagent_cli-0.4.0}/dbagent/schema/models.py +0 -0
  42. {dbagent_cli-0.3.8 → dbagent_cli-0.4.0}/dbagent/schema/retriever.py +0 -0
  43. {dbagent_cli-0.3.8 → dbagent_cli-0.4.0}/dbagent/schema/selector.py +0 -0
  44. {dbagent_cli-0.3.8 → dbagent_cli-0.4.0}/dbagent/security/__init__.py +0 -0
  45. {dbagent_cli-0.3.8 → dbagent_cli-0.4.0}/dbagent/security/audit.py +0 -0
  46. {dbagent_cli-0.3.8 → dbagent_cli-0.4.0}/dbagent/security/environment.py +0 -0
  47. {dbagent_cli-0.3.8 → dbagent_cli-0.4.0}/dbagent/security/masking.py +0 -0
  48. {dbagent_cli-0.3.8 → dbagent_cli-0.4.0}/dbagent/security/modes.py +0 -0
  49. {dbagent_cli-0.3.8 → dbagent_cli-0.4.0}/dbagent/security/rbac.py +0 -0
  50. {dbagent_cli-0.3.8 → dbagent_cli-0.4.0}/dbagent/semantic/__init__.py +0 -0
  51. {dbagent_cli-0.3.8 → dbagent_cli-0.4.0}/dbagent/semantic/dictionary.py +0 -0
  52. {dbagent_cli-0.3.8 → dbagent_cli-0.4.0}/dbagent/semantic/templates.py +0 -0
  53. {dbagent_cli-0.3.8 → dbagent_cli-0.4.0}/dbagent/sql/__init__.py +0 -0
  54. {dbagent_cli-0.3.8 → dbagent_cli-0.4.0}/dbagent/sql/optimizer.py +0 -0
  55. {dbagent_cli-0.3.8 → dbagent_cli-0.4.0}/dbagent/sql/validator.py +0 -0
  56. {dbagent_cli-0.3.8 → dbagent_cli-0.4.0}/dbagent/ui/viewer.py +0 -0
  57. {dbagent_cli-0.3.8 → dbagent_cli-0.4.0}/dbagent/ui/visualizer.py +0 -0
  58. {dbagent_cli-0.3.8 → dbagent_cli-0.4.0}/dbagent_cli.egg-info/dependency_links.txt +0 -0
  59. {dbagent_cli-0.3.8 → dbagent_cli-0.4.0}/dbagent_cli.egg-info/entry_points.txt +0 -0
  60. {dbagent_cli-0.3.8 → dbagent_cli-0.4.0}/dbagent_cli.egg-info/requires.txt +0 -0
  61. {dbagent_cli-0.3.8 → dbagent_cli-0.4.0}/dbagent_cli.egg-info/top_level.txt +0 -0
  62. {dbagent_cli-0.3.8 → dbagent_cli-0.4.0}/setup.cfg +0 -0
  63. {dbagent_cli-0.3.8 → dbagent_cli-0.4.0}/tests/test_cache.py +0 -0
  64. {dbagent_cli-0.3.8 → dbagent_cli-0.4.0}/tests/test_cli.py +0 -0
  65. {dbagent_cli-0.3.8 → dbagent_cli-0.4.0}/tests/test_connectors.py +0 -0
  66. {dbagent_cli-0.3.8 → dbagent_cli-0.4.0}/tests/test_doctor_and_viz.py +0 -0
  67. {dbagent_cli-0.3.8 → dbagent_cli-0.4.0}/tests/test_generator.py +0 -0
  68. {dbagent_cli-0.3.8 → dbagent_cli-0.4.0}/tests/test_graph.py +0 -0
  69. {dbagent_cli-0.3.8 → dbagent_cli-0.4.0}/tests/test_recovery.py +0 -0
  70. {dbagent_cli-0.3.8 → dbagent_cli-0.4.0}/tests/test_safety.py +0 -0
  71. {dbagent_cli-0.3.8 → dbagent_cli-0.4.0}/tests/test_sandbox.py +0 -0
  72. {dbagent_cli-0.3.8 → dbagent_cli-0.4.0}/tests/test_schema.py +0 -0
  73. {dbagent_cli-0.3.8 → dbagent_cli-0.4.0}/tests/test_security.py +0 -0
  74. {dbagent_cli-0.3.8 → dbagent_cli-0.4.0}/tests/test_semantic.py +0 -0
@@ -1,7 +1,7 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: dbagent-cli
3
- Version: 0.3.8
4
- Summary: Production-Grade AI Database Copilot with Responsive Zoom-Out & Wide Table Viewing (CLI)
3
+ Version: 0.4.0
4
+ Summary: Enterprise AI Database Copilot with Interactive Data Grid Window & High-Performance LLM (CLI)
5
5
  Author: Santhosh Gupta
6
6
  Requires-Python: >=3.9
7
7
  Description-Content-Type: text/markdown
@@ -2,5 +2,5 @@
2
2
  DB-Agent: Universal Database Introspection and Script Generation AI Agent (CLI).
3
3
  """
4
4
 
5
- __version__ = "0.3.8"
5
+ __version__ = "0.4.0"
6
6
  __author__ = "Santhosh Gupta"
@@ -60,6 +60,7 @@ from dbagent.ui.console import (
60
60
  open_interactive_scroller,
61
61
  )
62
62
  from dbagent.ui.viewer import SchemaViewer
63
+ from dbagent.ui.grid_window import open_desktop_grid_window, open_browser_grid_window
63
64
 
64
65
  app = typer.Typer(
65
66
  name="db-agent",
@@ -636,6 +637,22 @@ def chat_command(
636
637
  print_results_table(last_result.columns, last_result.rows, title="All Columns (Wide View)", show_all=True)
637
638
  continue
638
639
 
640
+ if cmd_name in [":window", ":gui", ":grid", ":w"]:
641
+ if not last_result or not last_result.rows:
642
+ print_warning("No previous query results to display.")
643
+ continue
644
+ print_info("Opening desktop interactive window with horizontal & vertical scrollbars...")
645
+ open_desktop_grid_window(last_result.columns, last_result.rows, title=f"DB-Agent Data Grid")
646
+ continue
647
+
648
+ if cmd_name in [":web", ":browser", ":html"]:
649
+ if not last_result or not last_result.rows:
650
+ print_warning("No previous query results to display.")
651
+ continue
652
+ print_info("Opening browser interactive data table...")
653
+ open_browser_grid_window(last_result.columns, last_result.rows, title=f"DB-Agent Data View")
654
+ continue
655
+
639
656
  if cmd_name in [":scroll", ":scroller", ":pager"]:
640
657
  if not last_result or not last_result.rows:
641
658
  print_warning("No previous query results to scroll.")
@@ -1,6 +1,6 @@
1
1
  """
2
2
  Google Gemini Free Tier LLM Provider.
3
- Uses Gemini 2.5 Flash / Gemini 2.0 Flash / Gemini 1.5 Flash via direct HTTP API.
3
+ Uses gemini-3.6-flash (current primary), gemini-3.7-flash, gemini-3.5-flash, gemini-flash-latest.
4
4
  """
5
5
 
6
6
  import json
@@ -14,13 +14,15 @@ class GeminiProvider(BaseLLMProvider):
14
14
  """Google Gemini LLM provider (Free Tier available)."""
15
15
 
16
16
  FALLBACK_MODELS = [
17
+ "gemini-3.6-flash",
18
+ "gemini-3.7-flash",
19
+ "gemini-3.5-flash",
20
+ "gemini-flash-latest",
21
+ "gemini-pro-latest",
17
22
  "gemini-2.5-flash",
18
- "gemini-2.0-flash",
19
- "gemini-1.5-flash",
20
- "gemini-1.5-pro",
21
23
  ]
22
24
 
23
- def __init__(self, api_key: Optional[str] = None, default_model: str = "gemini-2.5-flash"):
25
+ def __init__(self, api_key: Optional[str] = None, default_model: str = "gemini-3.6-flash"):
24
26
  self.api_key = api_key or os.getenv("GEMINI_API_KEY")
25
27
  self.default_model = default_model
26
28
 
@@ -82,7 +84,7 @@ class GeminiProvider(BaseLLMProvider):
82
84
 
83
85
  try:
84
86
  if stream_callback:
85
- response = requests.post(endpoint, json=payload, stream=True, timeout=15)
87
+ response = requests.post(endpoint, json=payload, stream=True, timeout=10)
86
88
  if response.status_code == 200:
87
89
  full_text = []
88
90
  for line in response.iter_lines():
@@ -102,13 +104,13 @@ class GeminiProvider(BaseLLMProvider):
102
104
  except Exception:
103
105
  pass
104
106
  return "".join(full_text)
105
- elif response.status_code in (404, 400):
106
- last_error = f"Model {target_model} not available ({response.status_code})"
107
+ elif response.status_code in (404, 400, 503, 429):
108
+ last_error = f"Model {target_model} status {response.status_code}"
107
109
  continue
108
110
  else:
109
111
  raise RuntimeError(f"Gemini API error ({response.status_code}): {response.text}")
110
112
  else:
111
- response = requests.post(endpoint, json=payload, timeout=15)
113
+ response = requests.post(endpoint, json=payload, timeout=10)
112
114
  if response.status_code == 200:
113
115
  data = response.json()
114
116
  candidates = data.get("candidates", [])
@@ -116,13 +118,13 @@ class GeminiProvider(BaseLLMProvider):
116
118
  parts = candidates[0].get("content", {}).get("parts", [])
117
119
  return "".join(p.get("text", "") for p in parts)
118
120
  return ""
119
- elif response.status_code in (404, 400):
120
- last_error = f"Model {target_model} not available ({response.status_code})"
121
+ elif response.status_code in (404, 400, 503, 429):
122
+ last_error = f"Model {target_model} status {response.status_code}"
121
123
  continue
122
124
  else:
123
125
  raise RuntimeError(f"Gemini API error ({response.status_code}): {response.text}")
124
126
  except requests.exceptions.Timeout:
125
- last_error = f"Model {target_model} request timed out"
127
+ last_error = f"Model {target_model} timed out"
126
128
  continue
127
129
  except Exception as e:
128
130
  last_error = str(e)
@@ -113,7 +113,7 @@ def print_results_table(
113
113
 
114
114
  if total_pages > 1 and not show_all:
115
115
  console.print(
116
- f"[dim]⚡ [bold]:page <1-{total_pages}>[/bold] to switch page | [bold]:wide[/bold] / zoom-out for all columns | [bold]:card[/bold] for vertical view | [bold]:scroll[/bold] for scroller[/dim]"
116
+ f"[dim]⚡ [bold]:window[/bold] (GUI scroll window) | [bold]:page <1-{total_pages}>[/bold] | [bold]:card[/bold] (vertical) | [bold]:wide[/bold] (zoom-out)[/dim]"
117
117
  )
118
118
  console.print(f"[bold green]Total rows:[/bold green] {len(rows)}\n")
119
119
 
@@ -0,0 +1,245 @@
1
+ """
2
+ Interactive Desktop and Browser Data Grid Viewers with Horizontal & Vertical Scrollbars.
3
+ """
4
+
5
+ import os
6
+ import tempfile
7
+ import webbrowser
8
+ import threading
9
+ from typing import List, Dict, Any, Optional
10
+
11
+
12
+ def open_desktop_grid_window(
13
+ columns: List[str],
14
+ rows: List[Dict[str, Any]],
15
+ title: str = "DB-Agent Interactive Data Viewer",
16
+ ) -> None:
17
+ """
18
+ Opens a native desktop GUI window with smooth horizontal and vertical scrollbars,
19
+ search/filter bar, and resizable columns. Runs in a separate thread.
20
+ """
21
+ if not columns or not rows:
22
+ return
23
+
24
+ def _launch_gui():
25
+ try:
26
+ import tkinter as tk
27
+ from tkinter import ttk, messagebox, filedialog
28
+ import csv
29
+
30
+ root = tk.Tk()
31
+ root.title(f"{title} - ({len(rows)} rows, {len(columns)} columns)")
32
+ root.geometry("1100x650")
33
+ root.minsize(700, 400)
34
+
35
+ # Modern Styling
36
+ style = ttk.Style()
37
+ try:
38
+ style.theme_use("clam")
39
+ except Exception:
40
+ pass
41
+
42
+ style.configure("Treeview.Heading", font=("Segoe UI", 10, "bold"), background="#2c3e50", foreground="white")
43
+ style.configure("Treeview", font=("Segoe UI", 9), rowheight=24)
44
+ style.map("Treeview", background=[("selected", "#3498db")])
45
+
46
+ # Top toolbar (Search & Export)
47
+ top_frame = ttk.Frame(root, padding=8)
48
+ top_frame.pack(fill=tk.X, side=tk.TOP)
49
+
50
+ ttk.Label(top_frame, text="🔍 Search / Filter:", font=("Segoe UI", 9, "bold")).pack(side=tk.LEFT, padx=(0, 5))
51
+ search_var = tk.StringVar()
52
+ search_entry = ttk.Entry(top_frame, textvariable=search_var, width=30)
53
+ search_entry.pack(side=tk.LEFT, padx=5)
54
+
55
+ status_lbl = ttk.Label(top_frame, text=f"Total: {len(rows)} records, {len(columns)} columns", font=("Segoe UI", 9))
56
+ status_lbl.pack(side=tk.LEFT, padx=15)
57
+
58
+ def _export_csv():
59
+ fpath = filedialog.asksaveasfilename(
60
+ defaultextension=".csv",
61
+ filetypes=[("CSV Files", "*.csv"), ("All Files", "*.*")],
62
+ initialfile="query_results.csv",
63
+ )
64
+ if fpath:
65
+ try:
66
+ with open(fpath, "w", newline="", encoding="utf-8") as f:
67
+ writer = csv.writer(f)
68
+ writer.writerow(columns)
69
+ for r in rows:
70
+ writer.writerow([r.get(c, "") for c in columns])
71
+ messagebox.showinfo("Export Success", f"Exported {len(rows)} rows to:\n{fpath}")
72
+ except Exception as e:
73
+ messagebox.showerror("Export Failed", str(e))
74
+
75
+ export_btn = ttk.Button(top_frame, text="💾 Export to CSV", command=_export_csv)
76
+ export_btn.pack(side=tk.RIGHT, padx=5)
77
+
78
+ # Center Data Grid Frame with Both Scrollbars
79
+ grid_frame = ttk.Frame(root)
80
+ grid_frame.pack(fill=tk.BOTH, expand=True, padx=8, pady=(0, 8))
81
+
82
+ # Vertical Scrollbar
83
+ v_scroll = ttk.Scrollbar(grid_frame, orient=tk.VERTICAL)
84
+ v_scroll.pack(side=tk.RIGHT, fill=tk.Y)
85
+
86
+ # Horizontal Scrollbar
87
+ h_scroll = ttk.Scrollbar(grid_frame, orient=tk.HORIZONTAL)
88
+ h_scroll.pack(side=tk.BOTTOM, fill=tk.X)
89
+
90
+ # Treeview Table
91
+ tree = ttk.Treeview(
92
+ grid_frame,
93
+ columns=columns,
94
+ show="headings",
95
+ yscrollcommand=v_scroll.set,
96
+ xscrollcommand=h_scroll.set,
97
+ )
98
+ v_scroll.config(command=tree.yview)
99
+ h_scroll.config(command=tree.xview)
100
+ tree.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)
101
+
102
+ # Configure Columns
103
+ for col in columns:
104
+ tree.heading(col, text=col)
105
+ # Dynamic column width based on column name length
106
+ col_w = max(120, min(280, len(str(col)) * 12))
107
+ tree.column(col, width=col_w, minwidth=80, stretch=False)
108
+
109
+ def populate_table(filter_text=""):
110
+ tree.delete(*tree.get_children())
111
+ f_lower = filter_text.strip().lower()
112
+ count = 0
113
+ for r in rows:
114
+ row_vals = [str(r.get(c, "")) if r.get(c) is not None else "NULL" for c in columns]
115
+ if f_lower:
116
+ if not any(f_lower in v.lower() for v in row_vals):
117
+ continue
118
+ tree.insert("", tk.END, values=row_vals)
119
+ count += 1
120
+ status_lbl.config(text=f"Showing: {count} of {len(rows)} rows ({len(columns)} columns)")
121
+
122
+ populate_table()
123
+
124
+ def on_search_change(*args):
125
+ populate_table(search_var.get())
126
+
127
+ search_var.trace_add("write", on_search_change)
128
+
129
+ root.mainloop()
130
+ except Exception as e:
131
+ print(f"[DB-Agent GUI Error] Could not launch desktop window: {e}")
132
+
133
+ # Launch GUI in background thread so CLI prompt stays responsive
134
+ thread = threading.Thread(target=_launch_gui, daemon=True)
135
+ thread.start()
136
+
137
+
138
+ def open_browser_grid_window(
139
+ columns: List[str],
140
+ rows: List[Dict[str, Any]],
141
+ title: str = "DB-Agent Interactive Data Grid",
142
+ ) -> None:
143
+ """
144
+ Generates a standalone, ultra-fast HTML data grid with frozen headers,
145
+ instant horizontal & vertical scrolling, search, and CSV export, then opens it in browser.
146
+ """
147
+ if not columns or not rows:
148
+ return
149
+
150
+ import json
151
+
152
+ cols_json = json.dumps([{"title": c, "field": c, "headerFilter": "input", "resizable": True} for c in columns])
153
+ data_json = json.dumps(rows, default=str)
154
+
155
+ html_content = f"""<!DOCTYPE html>
156
+ <html lang="en">
157
+ <head>
158
+ <meta charset="UTF-8">
159
+ <title>{title}</title>
160
+ <link href="https://unpkg.com/tabulator-tables@5.5.0/dist/css/tabulator_midnight.min.css" rel="stylesheet">
161
+ <script type="text/javascript" src="https://unpkg.com/tabulator-tables@5.5.0/dist/js/tabulator.min.js"></script>
162
+ <style>
163
+ body {{
164
+ margin: 0;
165
+ padding: 16px;
166
+ font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
167
+ background: #0f172a;
168
+ color: #f8fafc;
169
+ }}
170
+ .header {{
171
+ display: flex;
172
+ justify-content: space-between;
173
+ align-items: center;
174
+ margin-bottom: 12px;
175
+ }}
176
+ h1 {{
177
+ margin: 0;
178
+ font-size: 1.3rem;
179
+ color: #38bdf8;
180
+ }}
181
+ .badge {{
182
+ background: #1e293b;
183
+ padding: 4px 10px;
184
+ border-radius: 6px;
185
+ font-size: 0.85rem;
186
+ color: #94a3b8;
187
+ border: 1px solid #334155;
188
+ }}
189
+ .btn {{
190
+ background: #0284c7;
191
+ color: white;
192
+ border: none;
193
+ padding: 6px 14px;
194
+ border-radius: 6px;
195
+ font-weight: 600;
196
+ cursor: pointer;
197
+ }}
198
+ .btn:hover {{
199
+ background: #0369a1;
200
+ }}
201
+ #data-table {{
202
+ height: calc(100vh - 85px);
203
+ background: #1e293b;
204
+ border-radius: 8px;
205
+ border: 1px solid #334155;
206
+ }}
207
+ </style>
208
+ </head>
209
+ <body>
210
+ <div class="header">
211
+ <div>
212
+ <h1>📊 {title}</h1>
213
+ <span class="badge">{len(rows)} Records &bull; {len(columns)} Columns</span>
214
+ </div>
215
+ <div>
216
+ <button class="btn" onclick="table.download('csv', 'data_export.csv')">💾 Download CSV</button>
217
+ </div>
218
+ </div>
219
+ <div id="data-table"></div>
220
+
221
+ <script>
222
+ const tableData = {data_json};
223
+ const tableCols = {cols_json};
224
+
225
+ const table = new Tabulator("#data-table", {{
226
+ data: tableData,
227
+ columns: tableCols,
228
+ layout: "fitData",
229
+ pagination: false,
230
+ renderVertical: "virtual",
231
+ renderHorizontal: "virtual",
232
+ movableColumns: true,
233
+ responsiveLayout: false,
234
+ }});
235
+ </script>
236
+ </body>
237
+ </html>
238
+ """
239
+
240
+ temp_dir = tempfile.gettempdir()
241
+ temp_path = os.path.join(temp_dir, "dbagent_data_grid.html")
242
+ with open(temp_path, "w", encoding="utf-8") as f:
243
+ f.write(html_content)
244
+
245
+ webbrowser.open(f"file://{temp_path}")
@@ -1,7 +1,7 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: dbagent-cli
3
- Version: 0.3.8
4
- Summary: Production-Grade AI Database Copilot with Responsive Zoom-Out & Wide Table Viewing (CLI)
3
+ Version: 0.4.0
4
+ Summary: Enterprise AI Database Copilot with Interactive Data Grid Window & High-Performance LLM (CLI)
5
5
  Author: Santhosh Gupta
6
6
  Requires-Python: >=3.9
7
7
  Description-Content-Type: text/markdown
@@ -49,6 +49,7 @@ dbagent/sql/__init__.py
49
49
  dbagent/sql/optimizer.py
50
50
  dbagent/sql/validator.py
51
51
  dbagent/ui/console.py
52
+ dbagent/ui/grid_window.py
52
53
  dbagent/ui/viewer.py
53
54
  dbagent/ui/visualizer.py
54
55
  dbagent_cli.egg-info/PKG-INFO
@@ -4,8 +4,8 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "dbagent-cli"
7
- version = "0.3.8"
8
- description = "Production-Grade AI Database Copilot with Responsive Zoom-Out & Wide Table Viewing (CLI)"
7
+ version = "0.4.0"
8
+ description = "Enterprise AI Database Copilot with Interactive Data Grid Window & High-Performance LLM (CLI)"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.9"
11
11
  authors = [
File without changes
File without changes