dbagent-cli 0.9.4__tar.gz → 0.9.6__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.
- {dbagent_cli-0.9.4 → dbagent_cli-0.9.6}/PKG-INFO +1 -1
- {dbagent_cli-0.9.4 → dbagent_cli-0.9.6}/dbagent/__init__.py +1 -1
- {dbagent_cli-0.9.4 → dbagent_cli-0.9.6}/dbagent/agent/generator.py +16 -0
- {dbagent_cli-0.9.4 → dbagent_cli-0.9.6}/dbagent/agent/pipeline.py +8 -2
- {dbagent_cli-0.9.4 → dbagent_cli-0.9.6}/dbagent/cli.py +65 -21
- {dbagent_cli-0.9.4 → dbagent_cli-0.9.6}/dbagent/connectors/base.py +30 -3
- {dbagent_cli-0.9.4 → dbagent_cli-0.9.6}/dbagent_cli.egg-info/PKG-INFO +1 -1
- {dbagent_cli-0.9.4 → dbagent_cli-0.9.6}/pyproject.toml +1 -1
- {dbagent_cli-0.9.4 → dbagent_cli-0.9.6}/README.md +0 -0
- {dbagent_cli-0.9.4 → dbagent_cli-0.9.6}/dbagent/agent/confidence.py +0 -0
- {dbagent_cli-0.9.4 → dbagent_cli-0.9.6}/dbagent/agent/conversation.py +0 -0
- {dbagent_cli-0.9.4 → dbagent_cli-0.9.6}/dbagent/agent/doctor.py +0 -0
- {dbagent_cli-0.9.4 → dbagent_cli-0.9.6}/dbagent/agent/error_classifier.py +0 -0
- {dbagent_cli-0.9.4 → dbagent_cli-0.9.6}/dbagent/agent/recommender.py +0 -0
- {dbagent_cli-0.9.4 → dbagent_cli-0.9.6}/dbagent/agent/validator.py +0 -0
- {dbagent_cli-0.9.4 → dbagent_cli-0.9.6}/dbagent/config.py +0 -0
- {dbagent_cli-0.9.4 → dbagent_cli-0.9.6}/dbagent/connectors/factory.py +0 -0
- {dbagent_cli-0.9.4 → dbagent_cli-0.9.6}/dbagent/connectors/mongo.py +0 -0
- {dbagent_cli-0.9.4 → dbagent_cli-0.9.6}/dbagent/connectors/relational.py +0 -0
- {dbagent_cli-0.9.4 → dbagent_cli-0.9.6}/dbagent/execution/__init__.py +0 -0
- {dbagent_cli-0.9.4 → dbagent_cli-0.9.6}/dbagent/execution/cache.py +0 -0
- {dbagent_cli-0.9.4 → dbagent_cli-0.9.6}/dbagent/execution/changeset.py +0 -0
- {dbagent_cli-0.9.4 → dbagent_cli-0.9.6}/dbagent/execution/cost.py +0 -0
- {dbagent_cli-0.9.4 → dbagent_cli-0.9.6}/dbagent/execution/recovery.py +0 -0
- {dbagent_cli-0.9.4 → dbagent_cli-0.9.6}/dbagent/execution/sandbox.py +0 -0
- {dbagent_cli-0.9.4 → dbagent_cli-0.9.6}/dbagent/execution/streaming.py +0 -0
- {dbagent_cli-0.9.4 → dbagent_cli-0.9.6}/dbagent/llm/anthropic_provider.py +0 -0
- {dbagent_cli-0.9.4 → dbagent_cli-0.9.6}/dbagent/llm/auto_setup.py +0 -0
- {dbagent_cli-0.9.4 → dbagent_cli-0.9.6}/dbagent/llm/base.py +0 -0
- {dbagent_cli-0.9.4 → dbagent_cli-0.9.6}/dbagent/llm/deepseek_provider.py +0 -0
- {dbagent_cli-0.9.4 → dbagent_cli-0.9.6}/dbagent/llm/factory.py +0 -0
- {dbagent_cli-0.9.4 → dbagent_cli-0.9.6}/dbagent/llm/gemini_provider.py +0 -0
- {dbagent_cli-0.9.4 → dbagent_cli-0.9.6}/dbagent/llm/groq_provider.py +0 -0
- {dbagent_cli-0.9.4 → dbagent_cli-0.9.6}/dbagent/llm/mistral_provider.py +0 -0
- {dbagent_cli-0.9.4 → dbagent_cli-0.9.6}/dbagent/llm/mock_provider.py +0 -0
- {dbagent_cli-0.9.4 → dbagent_cli-0.9.6}/dbagent/llm/ollama_provider.py +0 -0
- {dbagent_cli-0.9.4 → dbagent_cli-0.9.6}/dbagent/llm/openai_provider.py +0 -0
- {dbagent_cli-0.9.4 → dbagent_cli-0.9.6}/dbagent/llm/openrouter_provider.py +0 -0
- {dbagent_cli-0.9.4 → dbagent_cli-0.9.6}/dbagent/schema/cache.py +0 -0
- {dbagent_cli-0.9.4 → dbagent_cli-0.9.6}/dbagent/schema/formatter.py +0 -0
- {dbagent_cli-0.9.4 → dbagent_cli-0.9.6}/dbagent/schema/graph.py +0 -0
- {dbagent_cli-0.9.4 → dbagent_cli-0.9.6}/dbagent/schema/ground_truth.py +0 -0
- {dbagent_cli-0.9.4 → dbagent_cli-0.9.6}/dbagent/schema/models.py +0 -0
- {dbagent_cli-0.9.4 → dbagent_cli-0.9.6}/dbagent/schema/retriever.py +0 -0
- {dbagent_cli-0.9.4 → dbagent_cli-0.9.6}/dbagent/schema/selector.py +0 -0
- {dbagent_cli-0.9.4 → dbagent_cli-0.9.6}/dbagent/security/__init__.py +0 -0
- {dbagent_cli-0.9.4 → dbagent_cli-0.9.6}/dbagent/security/audit.py +0 -0
- {dbagent_cli-0.9.4 → dbagent_cli-0.9.6}/dbagent/security/environment.py +0 -0
- {dbagent_cli-0.9.4 → dbagent_cli-0.9.6}/dbagent/security/masking.py +0 -0
- {dbagent_cli-0.9.4 → dbagent_cli-0.9.6}/dbagent/security/modes.py +0 -0
- {dbagent_cli-0.9.4 → dbagent_cli-0.9.6}/dbagent/security/rbac.py +0 -0
- {dbagent_cli-0.9.4 → dbagent_cli-0.9.6}/dbagent/semantic/__init__.py +0 -0
- {dbagent_cli-0.9.4 → dbagent_cli-0.9.6}/dbagent/semantic/dictionary.py +0 -0
- {dbagent_cli-0.9.4 → dbagent_cli-0.9.6}/dbagent/semantic/knowledge.py +0 -0
- {dbagent_cli-0.9.4 → dbagent_cli-0.9.6}/dbagent/semantic/templates.py +0 -0
- {dbagent_cli-0.9.4 → dbagent_cli-0.9.6}/dbagent/sql/__init__.py +0 -0
- {dbagent_cli-0.9.4 → dbagent_cli-0.9.6}/dbagent/sql/optimizer.py +0 -0
- {dbagent_cli-0.9.4 → dbagent_cli-0.9.6}/dbagent/sql/validator.py +0 -0
- {dbagent_cli-0.9.4 → dbagent_cli-0.9.6}/dbagent/ui/chat_screen.py +0 -0
- {dbagent_cli-0.9.4 → dbagent_cli-0.9.6}/dbagent/ui/console.py +0 -0
- {dbagent_cli-0.9.4 → dbagent_cli-0.9.6}/dbagent/ui/grid_window.py +0 -0
- {dbagent_cli-0.9.4 → dbagent_cli-0.9.6}/dbagent/ui/viewer.py +0 -0
- {dbagent_cli-0.9.4 → dbagent_cli-0.9.6}/dbagent/ui/visualizer.py +0 -0
- {dbagent_cli-0.9.4 → dbagent_cli-0.9.6}/dbagent_cli.egg-info/SOURCES.txt +0 -0
- {dbagent_cli-0.9.4 → dbagent_cli-0.9.6}/dbagent_cli.egg-info/dependency_links.txt +0 -0
- {dbagent_cli-0.9.4 → dbagent_cli-0.9.6}/dbagent_cli.egg-info/entry_points.txt +0 -0
- {dbagent_cli-0.9.4 → dbagent_cli-0.9.6}/dbagent_cli.egg-info/requires.txt +0 -0
- {dbagent_cli-0.9.4 → dbagent_cli-0.9.6}/dbagent_cli.egg-info/top_level.txt +0 -0
- {dbagent_cli-0.9.4 → dbagent_cli-0.9.6}/setup.cfg +0 -0
- {dbagent_cli-0.9.4 → dbagent_cli-0.9.6}/tests/test_cache.py +0 -0
- {dbagent_cli-0.9.4 → dbagent_cli-0.9.6}/tests/test_cli.py +0 -0
- {dbagent_cli-0.9.4 → dbagent_cli-0.9.6}/tests/test_connectors.py +0 -0
- {dbagent_cli-0.9.4 → dbagent_cli-0.9.6}/tests/test_direct_sql.py +0 -0
- {dbagent_cli-0.9.4 → dbagent_cli-0.9.6}/tests/test_doctor_and_viz.py +0 -0
- {dbagent_cli-0.9.4 → dbagent_cli-0.9.6}/tests/test_generator.py +0 -0
- {dbagent_cli-0.9.4 → dbagent_cli-0.9.6}/tests/test_graph.py +0 -0
- {dbagent_cli-0.9.4 → dbagent_cli-0.9.6}/tests/test_knowledge.py +0 -0
- {dbagent_cli-0.9.4 → dbagent_cli-0.9.6}/tests/test_providers.py +0 -0
- {dbagent_cli-0.9.4 → dbagent_cli-0.9.6}/tests/test_recovery.py +0 -0
- {dbagent_cli-0.9.4 → dbagent_cli-0.9.6}/tests/test_safety.py +0 -0
- {dbagent_cli-0.9.4 → dbagent_cli-0.9.6}/tests/test_sandbox.py +0 -0
- {dbagent_cli-0.9.4 → dbagent_cli-0.9.6}/tests/test_schema.py +0 -0
- {dbagent_cli-0.9.4 → dbagent_cli-0.9.6}/tests/test_security.py +0 -0
- {dbagent_cli-0.9.4 → dbagent_cli-0.9.6}/tests/test_semantic.py +0 -0
|
@@ -166,11 +166,27 @@ class ScriptGenerator:
|
|
|
166
166
|
"related tables", "related tebales", "table mappings", "related tables mappings",
|
|
167
167
|
"related tebales mappings", "not correct", "not right", "check all the tables",
|
|
168
168
|
"mappings also", "find all mappings", "check links", "check mappings",
|
|
169
|
+
"is fk_", "are fk_", "is pk_", "are pk_", "difference between", "compare",
|
|
170
|
+
"tell me", "check it and tell me", "check and tell me", "same or different",
|
|
171
|
+
"flow diagram", "flow chart", "give the flow diagram", "give the diagram",
|
|
172
|
+
"show flow diagram", "give diagram", "show diagram", "architecture diagram",
|
|
169
173
|
]
|
|
170
174
|
for kw in analysis_keywords:
|
|
171
175
|
if kw in prompt_lower:
|
|
172
176
|
return "analysis"
|
|
173
177
|
|
|
178
|
+
# Regex for "how <X> and <Y> were/are linked/connected/related"
|
|
179
|
+
if re.search(r'\bhow\b.*\b(?:linked|connected|related|mapped|joined)\b', prompt_lower):
|
|
180
|
+
return "analysis"
|
|
181
|
+
|
|
182
|
+
# Regex for diagram / blueprint requests
|
|
183
|
+
if re.search(r'\b(?:flow\s+diagram|diagram|flow\s+chart|blueprint|er\s+diagram)\b', prompt_lower):
|
|
184
|
+
return "analysis"
|
|
185
|
+
|
|
186
|
+
# Comparative analysis questions (e.g. "is fk_site_group_id and fk_group_id same", "are table_a and table_b related")
|
|
187
|
+
if re.search(r'\b(?:is|are)\b.*\b(?:same|different|difference|related|equal|linked)\b', prompt_lower):
|
|
188
|
+
return "analysis"
|
|
189
|
+
|
|
174
190
|
# Contextual clarification for analysis (e.g. "i mean ivis_scope", "i mean table_x")
|
|
175
191
|
if re.search(r'\bi mean\b', prompt_lower) and not re.search(r'\b(insert|update|delete|drop)\b', prompt_lower):
|
|
176
192
|
return "analysis"
|
|
@@ -241,7 +241,7 @@ class QueryPipeline:
|
|
|
241
241
|
if not exact and not fuzzy:
|
|
242
242
|
inherited = self.conversation.get_active_tables()
|
|
243
243
|
if inherited:
|
|
244
|
-
exact = inherited[:
|
|
244
|
+
exact = inherited[:8]
|
|
245
245
|
|
|
246
246
|
sub_schema, join_steps = self._get_fast_schema_context(user_prompt, exact, fuzzy)
|
|
247
247
|
result.schema = sub_schema
|
|
@@ -594,10 +594,16 @@ class QueryPipeline:
|
|
|
594
594
|
)
|
|
595
595
|
|
|
596
596
|
if result.success:
|
|
597
|
+
sql_tables = set()
|
|
598
|
+
if result.sql:
|
|
599
|
+
import re as _re
|
|
600
|
+
for m in _re.findall(r'\b(?:FROM|JOIN)\s+([a-zA-Z0-9_]+)', result.sql, _re.IGNORECASE):
|
|
601
|
+
sql_tables.add(m.lower())
|
|
602
|
+
turn_tables = list(set((exact or []) + (fuzzy or []) + list(sql_tables)))
|
|
597
603
|
self.conversation.add_turn(
|
|
598
604
|
user_prompt=user_prompt,
|
|
599
605
|
sql=result.sql,
|
|
600
|
-
tables=
|
|
606
|
+
tables=turn_tables,
|
|
601
607
|
is_chat=False,
|
|
602
608
|
)
|
|
603
609
|
|
|
@@ -98,10 +98,13 @@ audit_logger = AuditLogger()
|
|
|
98
98
|
# Dynamic Animated Spinner with Rotating Messages
|
|
99
99
|
# ---------------------------------------------------------------------------
|
|
100
100
|
|
|
101
|
+
_active_spinner: Optional["DynamicSpinner"] = None
|
|
102
|
+
|
|
103
|
+
|
|
101
104
|
class DynamicSpinner:
|
|
102
105
|
"""
|
|
103
106
|
Context manager that shows an animated spinner with rotating contextual messages.
|
|
104
|
-
Messages cycle every ~1.
|
|
107
|
+
Messages cycle every ~1.2s so the user always sees progress.
|
|
105
108
|
Displays elapsed time suffix like (2.3s).
|
|
106
109
|
"""
|
|
107
110
|
|
|
@@ -193,7 +196,7 @@ class DynamicSpinner:
|
|
|
193
196
|
]
|
|
194
197
|
return cls(messages=messages, interval=1.2)
|
|
195
198
|
|
|
196
|
-
def __init__(self, messages: Optional[List[str]] = None, interval: float = 1.
|
|
199
|
+
def __init__(self, messages: Optional[List[str]] = None, interval: float = 1.2):
|
|
197
200
|
self._messages = messages or self.DEFAULT_MESSAGES
|
|
198
201
|
self._interval = interval
|
|
199
202
|
self._stop_event = threading.Event()
|
|
@@ -202,6 +205,8 @@ class DynamicSpinner:
|
|
|
202
205
|
self._status = None
|
|
203
206
|
|
|
204
207
|
def __enter__(self):
|
|
208
|
+
global _active_spinner
|
|
209
|
+
_active_spinner = self
|
|
205
210
|
self._start_time = time.time()
|
|
206
211
|
self._stop_event.clear()
|
|
207
212
|
self._status = console.status(f"[bold cyan]{self._messages[0]}[/bold cyan]")
|
|
@@ -211,11 +216,36 @@ class DynamicSpinner:
|
|
|
211
216
|
return self
|
|
212
217
|
|
|
213
218
|
def __exit__(self, *args):
|
|
219
|
+
global _active_spinner
|
|
220
|
+
_active_spinner = None
|
|
214
221
|
self._stop_event.set()
|
|
215
222
|
if self._thread:
|
|
216
|
-
self._thread.join(timeout=
|
|
223
|
+
self._thread.join(timeout=1)
|
|
224
|
+
if self._status:
|
|
225
|
+
try:
|
|
226
|
+
self._status.__exit__(*args)
|
|
227
|
+
except Exception:
|
|
228
|
+
pass
|
|
229
|
+
|
|
230
|
+
def pause(self):
|
|
231
|
+
"""Temporarily pause the spinner so interactive prompts don't clash."""
|
|
232
|
+
self._stop_event.set()
|
|
217
233
|
if self._status:
|
|
218
|
-
|
|
234
|
+
try:
|
|
235
|
+
self._status.stop()
|
|
236
|
+
except Exception:
|
|
237
|
+
pass
|
|
238
|
+
|
|
239
|
+
def resume(self):
|
|
240
|
+
"""Resume the spinner after interactive prompt finishes."""
|
|
241
|
+
self._stop_event.clear()
|
|
242
|
+
if self._status:
|
|
243
|
+
try:
|
|
244
|
+
self._status.start()
|
|
245
|
+
except Exception:
|
|
246
|
+
pass
|
|
247
|
+
self._thread = threading.Thread(target=self._rotate, daemon=True)
|
|
248
|
+
self._thread.start()
|
|
219
249
|
|
|
220
250
|
@property
|
|
221
251
|
def elapsed_ms(self) -> float:
|
|
@@ -265,28 +295,42 @@ def resolve_db_url(db_arg: Optional[str] = None) -> str:
|
|
|
265
295
|
|
|
266
296
|
def _confirm_callback(sql: str, warnings: List[str]) -> bool:
|
|
267
297
|
"""Prompt user to confirm a write or DDL operation."""
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
298
|
+
global _active_spinner
|
|
299
|
+
if _active_spinner:
|
|
300
|
+
_active_spinner.pause()
|
|
301
|
+
try:
|
|
302
|
+
console.print("")
|
|
303
|
+
print_code(sql, "sql", "Action Requires Confirmation")
|
|
304
|
+
for w in warnings:
|
|
305
|
+
print_warning(w)
|
|
306
|
+
return Confirm.ask("Execute this statement on the database?", default=False)
|
|
307
|
+
finally:
|
|
308
|
+
if _active_spinner:
|
|
309
|
+
_active_spinner.resume()
|
|
273
310
|
|
|
274
311
|
|
|
275
312
|
def _choice_callback(prompt_text: str, choices: List[str]) -> Optional[str]:
|
|
276
313
|
"""Prompt user to disambiguate table choices."""
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
choice = Prompt.ask("Select number or table name", default="1")
|
|
314
|
+
global _active_spinner
|
|
315
|
+
if _active_spinner:
|
|
316
|
+
_active_spinner.pause()
|
|
281
317
|
try:
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
318
|
+
console.print(f"\n[bold yellow]?[/bold yellow] {prompt_text}")
|
|
319
|
+
for i, c in enumerate(choices, 1):
|
|
320
|
+
console.print(f" [{i}] {c}")
|
|
321
|
+
choice = Prompt.ask("Select number or table name", default="1")
|
|
322
|
+
try:
|
|
323
|
+
idx = int(choice) - 1
|
|
324
|
+
if 0 <= idx < len(choices):
|
|
325
|
+
return choices[idx]
|
|
326
|
+
except ValueError:
|
|
327
|
+
pass
|
|
328
|
+
if choice in choices:
|
|
329
|
+
return choice
|
|
330
|
+
return choices[0]
|
|
331
|
+
finally:
|
|
332
|
+
if _active_spinner:
|
|
333
|
+
_active_spinner.resume()
|
|
290
334
|
|
|
291
335
|
|
|
292
336
|
def _display_pipeline_result(result: PipelineResult, show_sql: bool = True) -> None:
|
|
@@ -53,7 +53,32 @@ class BaseConnector(ABC):
|
|
|
53
53
|
exact = []
|
|
54
54
|
fuzzy = []
|
|
55
55
|
|
|
56
|
-
|
|
56
|
+
stop_words = {
|
|
57
|
+
"check", "tell", "same", "show", "list", "find", "get", "is", "are", "does", "will", "can", "what",
|
|
58
|
+
"which", "how", "why", "where", "with", "and", "from", "that", "this", "these", "those", "have",
|
|
59
|
+
"has", "had", "not", "all", "any", "few", "some", "many", "each", "every", "table", "tables",
|
|
60
|
+
"column", "columns", "field", "fields", "row", "rows", "record", "records", "data", "info",
|
|
61
|
+
"information", "name", "names", "type", "types", "key", "keys", "id", "ids", "status", "true",
|
|
62
|
+
"false", "null", "seriously", "please", "mean", "like", "about", "between", "among", "into",
|
|
63
|
+
"onto", "over", "under", "before", "after", "during", "since", "until", "across", "along",
|
|
64
|
+
"throughout", "outside", "inside", "above", "below", "behind", "beyond", "plus", "except",
|
|
65
|
+
"but", "against", "towards", "upon", "within", "without", "give", "also", "explain", "look",
|
|
66
|
+
"know", "make", "take", "help", "view", "count", "done", "good", "nice", "okay", "fine",
|
|
67
|
+
"flow", "diagram", "chart", "graph", "link", "links", "structure", "design", "model", "blueprint",
|
|
68
|
+
"mapping", "mappings", "overview", "query", "code", "script", "report", "summary", "relation",
|
|
69
|
+
"relations", "relationship", "relationships", "architecture"
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
raw_tokens = set(re.findall(r'\b[a-zA-Z0-9_]+\b', prompt_lower))
|
|
73
|
+
tokens = set(raw_tokens)
|
|
74
|
+
|
|
75
|
+
# Extract entity stems from foreign key column tokens (e.g. fk_site_group_id -> site_group, fk_group_id -> group)
|
|
76
|
+
for tok in raw_tokens:
|
|
77
|
+
if tok.startswith("fk_") or tok.startswith("pk_"):
|
|
78
|
+
entity = re.sub(r'^(?:fk_|pk_)', '', tok)
|
|
79
|
+
entity = re.sub(r'_(?:id|code|key|no|num)$', '', entity)
|
|
80
|
+
if entity and len(entity) >= 3 and entity not in stop_words:
|
|
81
|
+
tokens.add(entity)
|
|
57
82
|
|
|
58
83
|
for t in all_tables:
|
|
59
84
|
t_lower = t.lower()
|
|
@@ -64,7 +89,7 @@ class BaseConnector(ABC):
|
|
|
64
89
|
|
|
65
90
|
# 2. Match without common prefixes (e.g. "ivis_scope" -> "scope", "scopes")
|
|
66
91
|
unprefixed = re.sub(r'^(?:ivis_|tbl_|table_|app_)', '', t_lower)
|
|
67
|
-
if unprefixed and len(unprefixed) >= 3:
|
|
92
|
+
if unprefixed and len(unprefixed) >= 3 and unprefixed not in stop_words:
|
|
68
93
|
if (unprefixed in tokens or
|
|
69
94
|
f"{unprefixed}s" in tokens or
|
|
70
95
|
f"{unprefixed}es" in tokens or
|
|
@@ -73,8 +98,10 @@ class BaseConnector(ABC):
|
|
|
73
98
|
exact.append(t)
|
|
74
99
|
continue
|
|
75
100
|
|
|
76
|
-
# 3. Fuzzy partial match
|
|
101
|
+
# 3. Fuzzy partial match (strictly exclude English stop words)
|
|
77
102
|
for tok in tokens:
|
|
103
|
+
if tok in stop_words:
|
|
104
|
+
continue
|
|
78
105
|
if len(tok) >= 4 and (tok in t_lower or t_lower in tok):
|
|
79
106
|
if t not in exact and t not in fuzzy:
|
|
80
107
|
fuzzy.append(t)
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "dbagent-cli"
|
|
7
|
-
version = "0.9.
|
|
7
|
+
version = "0.9.6"
|
|
8
8
|
description = "Enterprise AI Database Copilot, Schema Graph Introspector & Autonomous Recovery Agent (CLI)"
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
requires-python = ">=3.9"
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|