sqlsaber 0.29.0__py3-none-any.whl → 0.29.1__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.
Potentially problematic release.
This version of sqlsaber might be problematic. Click here for more details.
- sqlsaber/application/auth_setup.py +3 -3
- sqlsaber/application/db_setup.py +2 -2
- sqlsaber/application/model_selection.py +2 -2
- sqlsaber/cli/auth.py +10 -8
- sqlsaber/cli/commands.py +3 -3
- sqlsaber/cli/database.py +22 -20
- sqlsaber/cli/interactive.py +11 -5
- sqlsaber/cli/memory.py +10 -10
- sqlsaber/cli/models.py +12 -12
- sqlsaber/cli/onboarding.py +41 -44
- sqlsaber/cli/threads.py +3 -3
- sqlsaber/config/api_keys.py +5 -5
- sqlsaber/config/oauth_flow.py +11 -10
- sqlsaber/config/oauth_tokens.py +7 -5
- sqlsaber/database/schema.py +1 -1
- sqlsaber/theme/manager.py +0 -8
- {sqlsaber-0.29.0.dist-info → sqlsaber-0.29.1.dist-info}/METADATA +1 -1
- {sqlsaber-0.29.0.dist-info → sqlsaber-0.29.1.dist-info}/RECORD +21 -21
- {sqlsaber-0.29.0.dist-info → sqlsaber-0.29.1.dist-info}/WHEEL +0 -0
- {sqlsaber-0.29.0.dist-info → sqlsaber-0.29.1.dist-info}/entry_points.txt +0 -0
- {sqlsaber-0.29.0.dist-info → sqlsaber-0.29.1.dist-info}/licenses/LICENSE +0 -0
|
@@ -104,7 +104,7 @@ async def setup_auth(
|
|
|
104
104
|
"""
|
|
105
105
|
# Check if auth is already configured
|
|
106
106
|
if auth_manager.has_auth_configured():
|
|
107
|
-
console.print("[
|
|
107
|
+
console.print("[success]✓ Authentication already configured![/success]")
|
|
108
108
|
return True, None
|
|
109
109
|
|
|
110
110
|
# Select provider
|
|
@@ -137,7 +137,7 @@ async def setup_auth(
|
|
|
137
137
|
)
|
|
138
138
|
return True, provider
|
|
139
139
|
else:
|
|
140
|
-
console.print("[
|
|
140
|
+
console.print("[error]✗ Anthropic OAuth setup failed.[/error]")
|
|
141
141
|
return False, None
|
|
142
142
|
|
|
143
143
|
# API key flow
|
|
@@ -160,5 +160,5 @@ async def setup_auth(
|
|
|
160
160
|
)
|
|
161
161
|
return True, provider
|
|
162
162
|
else:
|
|
163
|
-
console.print("[
|
|
163
|
+
console.print("[warning]No API key provided.[/warning]")
|
|
164
164
|
return False, None
|
sqlsaber/application/db_setup.py
CHANGED
|
@@ -88,7 +88,7 @@ async def collect_db_input(
|
|
|
88
88
|
try:
|
|
89
89
|
port = int(port_str)
|
|
90
90
|
except ValueError:
|
|
91
|
-
console.print("[
|
|
91
|
+
console.print("[error]Invalid port number. Using default.[/error]")
|
|
92
92
|
port = default_port
|
|
93
93
|
|
|
94
94
|
database = await prompter.text("Database name:")
|
|
@@ -205,7 +205,7 @@ async def test_connection(config: DatabaseConfig, password: str | None) -> bool:
|
|
|
205
205
|
await db_conn.close()
|
|
206
206
|
return True
|
|
207
207
|
except Exception as e:
|
|
208
|
-
console.print(f"[bold
|
|
208
|
+
console.print(f"[bold error]Connection failed:[/bold error] {e}", style="error")
|
|
209
209
|
return False
|
|
210
210
|
|
|
211
211
|
|
|
@@ -34,7 +34,7 @@ async def choose_model(
|
|
|
34
34
|
Selected model ID (provider:model_id) or None if cancelled
|
|
35
35
|
"""
|
|
36
36
|
if not models:
|
|
37
|
-
console.print("[
|
|
37
|
+
console.print("[warning]No models available[/warning]")
|
|
38
38
|
return None
|
|
39
39
|
|
|
40
40
|
# Filter by provider if restricted
|
|
@@ -42,7 +42,7 @@ async def choose_model(
|
|
|
42
42
|
models = [m for m in models if m.get("provider") == restrict_provider]
|
|
43
43
|
if not models:
|
|
44
44
|
console.print(
|
|
45
|
-
f"[
|
|
45
|
+
f"[warning]No models available for {restrict_provider}[/warning]"
|
|
46
46
|
)
|
|
47
47
|
return None
|
|
48
48
|
|
sqlsaber/cli/auth.py
CHANGED
|
@@ -49,7 +49,7 @@ def setup():
|
|
|
49
49
|
success, _ = asyncio.run(run_setup())
|
|
50
50
|
|
|
51
51
|
if not success:
|
|
52
|
-
console.print("\n[
|
|
52
|
+
console.print("\n[warning]No authentication configured.[/warning]")
|
|
53
53
|
|
|
54
54
|
console.print(
|
|
55
55
|
"\nYou can change this anytime by running [cyan]saber auth setup[/cyan] again."
|
|
@@ -64,8 +64,10 @@ def status():
|
|
|
64
64
|
console.print("\n[bold blue]Authentication Status[/bold blue]")
|
|
65
65
|
|
|
66
66
|
if auth_method is None:
|
|
67
|
-
console.print("[
|
|
68
|
-
console.print(
|
|
67
|
+
console.print("[warning]No authentication method configured[/warning]")
|
|
68
|
+
console.print(
|
|
69
|
+
"Run [primary]saber auth setup[/primary] to configure authentication."
|
|
70
|
+
)
|
|
69
71
|
return
|
|
70
72
|
|
|
71
73
|
# Show configured method summary
|
|
@@ -90,7 +92,7 @@ def status():
|
|
|
90
92
|
elif from_keyring:
|
|
91
93
|
console.print(f"> {provider}: [green]configured[/green]")
|
|
92
94
|
else:
|
|
93
|
-
console.print(f"> {provider}: [
|
|
95
|
+
console.print(f"> {provider}: [warning]not configured[/warning]")
|
|
94
96
|
|
|
95
97
|
|
|
96
98
|
@auth_app.command
|
|
@@ -105,7 +107,7 @@ def reset():
|
|
|
105
107
|
).ask()
|
|
106
108
|
|
|
107
109
|
if provider is None:
|
|
108
|
-
console.print("[
|
|
110
|
+
console.print("[warning]Reset cancelled.[/warning]")
|
|
109
111
|
return
|
|
110
112
|
|
|
111
113
|
api_key_manager = APIKeyManager()
|
|
@@ -121,7 +123,7 @@ def reset():
|
|
|
121
123
|
|
|
122
124
|
if not api_key_present and not oauth_present:
|
|
123
125
|
console.print(
|
|
124
|
-
f"[
|
|
126
|
+
f"[warning]No stored credentials found for {provider}. Nothing to reset.[/warning]"
|
|
125
127
|
)
|
|
126
128
|
return
|
|
127
129
|
|
|
@@ -153,7 +155,7 @@ def reset():
|
|
|
153
155
|
# Already absent; treat as success
|
|
154
156
|
pass
|
|
155
157
|
except Exception as e:
|
|
156
|
-
console.print(f"Warning: Could not remove API key: {e}", style="
|
|
158
|
+
console.print(f"Warning: Could not remove API key: {e}", style="warning")
|
|
157
159
|
|
|
158
160
|
# Optionally clear global auth method if removing Anthropic OAuth configuration
|
|
159
161
|
if provider == "anthropic" and oauth_present:
|
|
@@ -169,7 +171,7 @@ def reset():
|
|
|
169
171
|
config_manager._save_config(config)
|
|
170
172
|
console.print("Global auth method unset.", style="green")
|
|
171
173
|
|
|
172
|
-
console.print("\n[
|
|
174
|
+
console.print("\n[success]✓ Reset complete.[/success]")
|
|
173
175
|
console.print(
|
|
174
176
|
"Environment variables are not modified by this command.", style="dim"
|
|
175
177
|
)
|
sqlsaber/cli/commands.py
CHANGED
|
@@ -164,7 +164,7 @@ def query(
|
|
|
164
164
|
streaming_handler = StreamingQueryHandler(console)
|
|
165
165
|
db_type = sqlsaber_agent.db_type
|
|
166
166
|
console.print(
|
|
167
|
-
f"[
|
|
167
|
+
f"[primary]Connected to:[/primary] {db_name} ({db_type})\n"
|
|
168
168
|
)
|
|
169
169
|
run = await streaming_handler.execute_streaming_query(
|
|
170
170
|
actual_query, sqlsaber_agent
|
|
@@ -200,13 +200,13 @@ def query(
|
|
|
200
200
|
finally:
|
|
201
201
|
# Clean up
|
|
202
202
|
await db_conn.close()
|
|
203
|
-
console.print("\n[
|
|
203
|
+
console.print("\n[success]Goodbye![/success]")
|
|
204
204
|
|
|
205
205
|
# Run the async function with proper error handling
|
|
206
206
|
try:
|
|
207
207
|
asyncio.run(run_session())
|
|
208
208
|
except CLIError as e:
|
|
209
|
-
console.print(f"[
|
|
209
|
+
console.print(f"[error]Error:[/error] {e}")
|
|
210
210
|
sys.exit(e.exit_code)
|
|
211
211
|
|
|
212
212
|
|
sqlsaber/cli/database.py
CHANGED
|
@@ -95,7 +95,7 @@ def add(
|
|
|
95
95
|
db_input = asyncio.run(collect_input())
|
|
96
96
|
|
|
97
97
|
if db_input is None:
|
|
98
|
-
console.print("[
|
|
98
|
+
console.print("[warning]Operation cancelled[/warning]")
|
|
99
99
|
return
|
|
100
100
|
|
|
101
101
|
# Extract values from db_input
|
|
@@ -114,7 +114,7 @@ def add(
|
|
|
114
114
|
if type == "sqlite":
|
|
115
115
|
if not database:
|
|
116
116
|
console.print(
|
|
117
|
-
"[bold
|
|
117
|
+
"[bold error]Error:[/bold error] Database file path is required for SQLite"
|
|
118
118
|
)
|
|
119
119
|
sys.exit(1)
|
|
120
120
|
host = "localhost"
|
|
@@ -124,7 +124,7 @@ def add(
|
|
|
124
124
|
elif type == "duckdb":
|
|
125
125
|
if not database:
|
|
126
126
|
console.print(
|
|
127
|
-
"[bold
|
|
127
|
+
"[bold error]Error:[/bold error] Database file path is required for DuckDB"
|
|
128
128
|
)
|
|
129
129
|
sys.exit(1)
|
|
130
130
|
database = str(Path(database).expanduser().resolve())
|
|
@@ -135,7 +135,7 @@ def add(
|
|
|
135
135
|
else:
|
|
136
136
|
if not all([host, database, username]):
|
|
137
137
|
console.print(
|
|
138
|
-
"[bold
|
|
138
|
+
"[bold error]Error:[/bold error] Host, database, and username are required"
|
|
139
139
|
)
|
|
140
140
|
sys.exit(1)
|
|
141
141
|
|
|
@@ -179,7 +179,7 @@ def add(
|
|
|
179
179
|
console.print(f"[blue]Set '{name}' as default database[/blue]")
|
|
180
180
|
|
|
181
181
|
except Exception as e:
|
|
182
|
-
console.print(f"[bold
|
|
182
|
+
console.print(f"[bold error]Error adding database:[/bold error] {e}")
|
|
183
183
|
sys.exit(1)
|
|
184
184
|
|
|
185
185
|
|
|
@@ -190,19 +190,19 @@ def list():
|
|
|
190
190
|
default_name = config_manager.get_default_name()
|
|
191
191
|
|
|
192
192
|
if not databases:
|
|
193
|
-
console.print("[
|
|
193
|
+
console.print("[warning]No database connections configured[/warning]")
|
|
194
194
|
console.print("Use 'sqlsaber db add <name>' to add a database connection")
|
|
195
195
|
return
|
|
196
196
|
|
|
197
197
|
table = Table(title="Database Connections")
|
|
198
198
|
table.add_column("Name", style="cyan")
|
|
199
|
-
table.add_column("Type", style="
|
|
200
|
-
table.add_column("Host", style="
|
|
201
|
-
table.add_column("Port", style="
|
|
202
|
-
table.add_column("Database", style="
|
|
203
|
-
table.add_column("Username", style="
|
|
204
|
-
table.add_column("SSL", style="
|
|
205
|
-
table.add_column("Default", style="
|
|
199
|
+
table.add_column("Type", style="accent")
|
|
200
|
+
table.add_column("Host", style="success")
|
|
201
|
+
table.add_column("Port", style="warning")
|
|
202
|
+
table.add_column("Database", style="info")
|
|
203
|
+
table.add_column("Username", style="info")
|
|
204
|
+
table.add_column("SSL", style="success")
|
|
205
|
+
table.add_column("Default", style="error")
|
|
206
206
|
|
|
207
207
|
for db in databases:
|
|
208
208
|
is_default = "✓" if db.name == default_name else ""
|
|
@@ -239,7 +239,7 @@ def remove(
|
|
|
239
239
|
"""Remove a database connection."""
|
|
240
240
|
if not config_manager.get_database(name):
|
|
241
241
|
console.print(
|
|
242
|
-
f"[bold
|
|
242
|
+
f"[bold error]Error:[/bold error] Database connection '{name}' not found"
|
|
243
243
|
)
|
|
244
244
|
sys.exit(1)
|
|
245
245
|
|
|
@@ -252,7 +252,7 @@ def remove(
|
|
|
252
252
|
)
|
|
253
253
|
else:
|
|
254
254
|
console.print(
|
|
255
|
-
f"[bold
|
|
255
|
+
f"[bold error]Error:[/bold error] Failed to remove database connection '{name}'"
|
|
256
256
|
)
|
|
257
257
|
sys.exit(1)
|
|
258
258
|
else:
|
|
@@ -269,14 +269,16 @@ def set_default(
|
|
|
269
269
|
"""Set the default database connection."""
|
|
270
270
|
if not config_manager.get_database(name):
|
|
271
271
|
console.print(
|
|
272
|
-
f"[bold
|
|
272
|
+
f"[bold error]Error:[/bold error] Database connection '{name}' not found"
|
|
273
273
|
)
|
|
274
274
|
sys.exit(1)
|
|
275
275
|
|
|
276
276
|
if config_manager.set_default_database(name):
|
|
277
277
|
console.print(f"[green]Successfully set '{name}' as default database[/green]")
|
|
278
278
|
else:
|
|
279
|
-
console.print(
|
|
279
|
+
console.print(
|
|
280
|
+
f"[bold error]Error:[/bold error] Failed to set '{name}' as default"
|
|
281
|
+
)
|
|
280
282
|
sys.exit(1)
|
|
281
283
|
|
|
282
284
|
|
|
@@ -299,14 +301,14 @@ def test(
|
|
|
299
301
|
db_config = config_manager.get_database(name)
|
|
300
302
|
if not db_config:
|
|
301
303
|
console.print(
|
|
302
|
-
f"[bold
|
|
304
|
+
f"[bold error]Error:[/bold error] Database connection '{name}' not found"
|
|
303
305
|
)
|
|
304
306
|
sys.exit(1)
|
|
305
307
|
else:
|
|
306
308
|
db_config = config_manager.get_default_database()
|
|
307
309
|
if not db_config:
|
|
308
310
|
console.print(
|
|
309
|
-
"[bold
|
|
311
|
+
"[bold error]Error:[/bold error] No default database configured"
|
|
310
312
|
)
|
|
311
313
|
console.print(
|
|
312
314
|
"Use 'sqlsaber db add <name>' to add a database connection"
|
|
@@ -328,7 +330,7 @@ def test(
|
|
|
328
330
|
)
|
|
329
331
|
|
|
330
332
|
except Exception as e:
|
|
331
|
-
console.print(f"[bold
|
|
333
|
+
console.print(f"[bold error]✗ Connection failed:[/bold error] {e}")
|
|
332
334
|
sys.exit(1)
|
|
333
335
|
|
|
334
336
|
asyncio.run(test_connection())
|
sqlsaber/cli/interactive.py
CHANGED
|
@@ -84,14 +84,14 @@ class InteractiveSession:
|
|
|
84
84
|
|
|
85
85
|
def _banner(self) -> str:
|
|
86
86
|
"""Get the ASCII banner."""
|
|
87
|
-
return """
|
|
87
|
+
return """[primary]
|
|
88
88
|
███████ ██████ ██ ███████ █████ ██████ ███████ ██████
|
|
89
89
|
██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██
|
|
90
90
|
███████ ██ ██ ██ ███████ ███████ ██████ █████ ██████
|
|
91
91
|
██ ██ ▄▄ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██
|
|
92
92
|
███████ ██████ ███████ ███████ ██ ██ ██████ ███████ ██ ██
|
|
93
93
|
▀▀
|
|
94
|
-
"""
|
|
94
|
+
[/primary]"""
|
|
95
95
|
|
|
96
96
|
def _instructions(self) -> str:
|
|
97
97
|
"""Get the instruction text."""
|
|
@@ -123,12 +123,18 @@ class InteractiveSession:
|
|
|
123
123
|
def show_welcome_message(self):
|
|
124
124
|
"""Display welcome message for interactive mode."""
|
|
125
125
|
if self.first_message:
|
|
126
|
-
self.console.print(Panel.fit(self._banner()))
|
|
127
|
-
self.console.print(
|
|
126
|
+
self.console.print(Panel.fit(self._banner(), border_style="primary"))
|
|
127
|
+
self.console.print(
|
|
128
|
+
Markdown(
|
|
129
|
+
self._instructions(),
|
|
130
|
+
code_theme=self.tm.pygments_style_name,
|
|
131
|
+
inline_code_theme=self.tm.pygments_style_name,
|
|
132
|
+
)
|
|
133
|
+
)
|
|
128
134
|
|
|
129
135
|
db_name = self.database_name or "Unknown"
|
|
130
136
|
self.console.print(
|
|
131
|
-
f"[heading]\
|
|
137
|
+
f"[heading]\nConnected to {db_name} ({self._db_type_name()})[/heading]\n"
|
|
132
138
|
)
|
|
133
139
|
|
|
134
140
|
if self._thread_id:
|
sqlsaber/cli/memory.py
CHANGED
|
@@ -29,7 +29,7 @@ def _get_database_name(database: str | None = None) -> str:
|
|
|
29
29
|
db_config = config_manager.get_database(database)
|
|
30
30
|
if not db_config:
|
|
31
31
|
console.print(
|
|
32
|
-
f"[bold
|
|
32
|
+
f"[bold error]Error:[/bold error] Database connection '{database}' not found."
|
|
33
33
|
)
|
|
34
34
|
sys.exit(1)
|
|
35
35
|
return database
|
|
@@ -37,7 +37,7 @@ def _get_database_name(database: str | None = None) -> str:
|
|
|
37
37
|
db_config = config_manager.get_default_database()
|
|
38
38
|
if not db_config:
|
|
39
39
|
console.print(
|
|
40
|
-
"[bold
|
|
40
|
+
"[bold error]Error:[/bold error] No database connections configured."
|
|
41
41
|
)
|
|
42
42
|
console.print("Use 'sqlsaber db add <name>' to add a database connection.")
|
|
43
43
|
sys.exit(1)
|
|
@@ -64,7 +64,7 @@ def add(
|
|
|
64
64
|
console.print(f"[dim]Memory ID:[/dim] {memory.id}")
|
|
65
65
|
console.print(f"[dim]Content:[/dim] {memory.content}")
|
|
66
66
|
except Exception as e:
|
|
67
|
-
console.print(f"[bold
|
|
67
|
+
console.print(f"[bold error]Error adding memory:[/bold error] {e}")
|
|
68
68
|
sys.exit(1)
|
|
69
69
|
|
|
70
70
|
|
|
@@ -85,7 +85,7 @@ def list(
|
|
|
85
85
|
|
|
86
86
|
if not memories:
|
|
87
87
|
console.print(
|
|
88
|
-
f"[
|
|
88
|
+
f"[warning]No memories found for database '{database_name}'[/warning]"
|
|
89
89
|
)
|
|
90
90
|
console.print("Use 'sqlsaber memory add \"<content>\"' to add memories")
|
|
91
91
|
return
|
|
@@ -125,7 +125,7 @@ def show(
|
|
|
125
125
|
|
|
126
126
|
if not memory:
|
|
127
127
|
console.print(
|
|
128
|
-
f"[bold
|
|
128
|
+
f"[bold error]Error:[/bold error] Memory with ID '{memory_id}' not found for database '{database_name}'"
|
|
129
129
|
)
|
|
130
130
|
sys.exit(1)
|
|
131
131
|
|
|
@@ -154,12 +154,12 @@ def remove(
|
|
|
154
154
|
memory = memory_manager.get_memory_by_id(database_name, memory_id)
|
|
155
155
|
if not memory:
|
|
156
156
|
console.print(
|
|
157
|
-
f"[bold
|
|
157
|
+
f"[bold error]Error:[/bold error] Memory with ID '{memory_id}' not found for database '{database_name}'"
|
|
158
158
|
)
|
|
159
159
|
sys.exit(1)
|
|
160
160
|
|
|
161
161
|
# Show memory content before removal
|
|
162
|
-
console.print("[
|
|
162
|
+
console.print("[warning]Removing memory:[/warning]")
|
|
163
163
|
console.print(f"[dim]Content:[/dim] {memory.content}")
|
|
164
164
|
|
|
165
165
|
if memory_manager.remove_memory(database_name, memory_id):
|
|
@@ -168,7 +168,7 @@ def remove(
|
|
|
168
168
|
)
|
|
169
169
|
else:
|
|
170
170
|
console.print(
|
|
171
|
-
f"[bold
|
|
171
|
+
f"[bold error]Error:[/bold error] Failed to remove memory '{memory_id}'"
|
|
172
172
|
)
|
|
173
173
|
sys.exit(1)
|
|
174
174
|
|
|
@@ -198,14 +198,14 @@ def clear(
|
|
|
198
198
|
|
|
199
199
|
if memories_count == 0:
|
|
200
200
|
console.print(
|
|
201
|
-
f"[
|
|
201
|
+
f"[warning]No memories to clear for database '{database_name}'[/warning]"
|
|
202
202
|
)
|
|
203
203
|
return
|
|
204
204
|
|
|
205
205
|
if not force:
|
|
206
206
|
# Show confirmation
|
|
207
207
|
console.print(
|
|
208
|
-
f"[
|
|
208
|
+
f"[warning]About to clear {memories_count} memories for database '{database_name}'[/warning]"
|
|
209
209
|
)
|
|
210
210
|
|
|
211
211
|
if not questionary.confirm("Are you sure you want to proceed?").ask():
|
sqlsaber/cli/models.py
CHANGED
|
@@ -106,7 +106,7 @@ class ModelManager:
|
|
|
106
106
|
results.sort(key=lambda x: (x["provider"], x["name"]))
|
|
107
107
|
return results
|
|
108
108
|
except Exception as e:
|
|
109
|
-
console.print(f"[
|
|
109
|
+
console.print(f"[error]Error fetching models: {e}[/error]")
|
|
110
110
|
return []
|
|
111
111
|
|
|
112
112
|
def get_current_model(self) -> str:
|
|
@@ -121,7 +121,7 @@ class ModelManager:
|
|
|
121
121
|
config.set_model(model_id)
|
|
122
122
|
return True
|
|
123
123
|
except Exception as e:
|
|
124
|
-
console.print(f"[
|
|
124
|
+
console.print(f"[error]Error setting model: {e}[/error]")
|
|
125
125
|
return False
|
|
126
126
|
|
|
127
127
|
def reset_model(self) -> bool:
|
|
@@ -142,17 +142,17 @@ def list():
|
|
|
142
142
|
|
|
143
143
|
if not models:
|
|
144
144
|
console.print(
|
|
145
|
-
"[
|
|
145
|
+
"[warning]No models available or failed to fetch models[/warning]"
|
|
146
146
|
)
|
|
147
147
|
return
|
|
148
148
|
|
|
149
149
|
table = Table(title="Available Models")
|
|
150
150
|
table.add_column("Provider", style="magenta")
|
|
151
151
|
table.add_column("ID", style="cyan")
|
|
152
|
-
table.add_column("Name", style="
|
|
153
|
-
table.add_column("Description", style="
|
|
154
|
-
table.add_column("Context", style="
|
|
155
|
-
table.add_column("Current", style="bold
|
|
152
|
+
table.add_column("Name", style="success")
|
|
153
|
+
table.add_column("Description", style="info")
|
|
154
|
+
table.add_column("Context", style="warning", justify="right")
|
|
155
|
+
table.add_column("Current", style="bold accent", justify="center")
|
|
156
156
|
|
|
157
157
|
current_model = model_manager.get_current_model()
|
|
158
158
|
|
|
@@ -196,7 +196,7 @@ def set():
|
|
|
196
196
|
models = await fetch_models(model_manager)
|
|
197
197
|
|
|
198
198
|
if not models:
|
|
199
|
-
console.print("[
|
|
199
|
+
console.print("[error]Failed to fetch models. Cannot set model.[/error]")
|
|
200
200
|
sys.exit(1)
|
|
201
201
|
|
|
202
202
|
prompter = AsyncPrompter()
|
|
@@ -208,10 +208,10 @@ def set():
|
|
|
208
208
|
if model_manager.set_model(selected_model):
|
|
209
209
|
console.print(f"[green]✓ Model set to: {selected_model}[/green]")
|
|
210
210
|
else:
|
|
211
|
-
console.print("[
|
|
211
|
+
console.print("[error]✗ Failed to set model[/error]")
|
|
212
212
|
sys.exit(1)
|
|
213
213
|
else:
|
|
214
|
-
console.print("[
|
|
214
|
+
console.print("[warning]Operation cancelled[/warning]")
|
|
215
215
|
|
|
216
216
|
asyncio.run(interactive_set())
|
|
217
217
|
|
|
@@ -236,10 +236,10 @@ def reset():
|
|
|
236
236
|
f"[green]✓ Model reset to default: {ModelManager.DEFAULT_MODEL}[/green]"
|
|
237
237
|
)
|
|
238
238
|
else:
|
|
239
|
-
console.print("[
|
|
239
|
+
console.print("[error]✗ Failed to reset model[/error]")
|
|
240
240
|
sys.exit(1)
|
|
241
241
|
else:
|
|
242
|
-
console.print("[
|
|
242
|
+
console.print("[warning]Operation cancelled[/warning]")
|
|
243
243
|
|
|
244
244
|
asyncio.run(interactive_reset())
|
|
245
245
|
|
sqlsaber/cli/onboarding.py
CHANGED
|
@@ -32,16 +32,16 @@ def needs_onboarding(database_arg: str | None = None) -> bool:
|
|
|
32
32
|
|
|
33
33
|
def welcome_screen() -> None:
|
|
34
34
|
"""Display welcome screen to new users."""
|
|
35
|
-
banner = """
|
|
35
|
+
banner = """[primary]
|
|
36
36
|
███████ ██████ ██ ███████ █████ ██████ ███████ ██████
|
|
37
37
|
██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██
|
|
38
38
|
███████ ██ ██ ██ ███████ ███████ ██████ █████ ██████
|
|
39
39
|
██ ██ ▄▄ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██
|
|
40
40
|
███████ ██████ ███████ ███████ ██ ██ ██████ ███████ ██ ██
|
|
41
41
|
▀▀
|
|
42
|
-
"""
|
|
42
|
+
[/primary]"""
|
|
43
43
|
|
|
44
|
-
console.print(Panel.fit(banner, style="
|
|
44
|
+
console.print(Panel.fit(banner, style="primary"))
|
|
45
45
|
console.print()
|
|
46
46
|
|
|
47
47
|
welcome_message = """
|
|
@@ -52,7 +52,9 @@ SQLsaber is an agentic SQL assistant that lets you query your database using nat
|
|
|
52
52
|
Let's get you set up in just a few steps.
|
|
53
53
|
"""
|
|
54
54
|
|
|
55
|
-
console.print(
|
|
55
|
+
console.print(
|
|
56
|
+
Panel.fit(welcome_message.strip(), border_style="primary", padding=(1, 2))
|
|
57
|
+
)
|
|
56
58
|
console.print()
|
|
57
59
|
|
|
58
60
|
|
|
@@ -69,9 +71,7 @@ async def setup_database_guided() -> str | None:
|
|
|
69
71
|
)
|
|
70
72
|
from sqlsaber.application.prompts import AsyncPrompter
|
|
71
73
|
|
|
72
|
-
console.print("
|
|
73
|
-
console.print("[bold cyan]Step 1 of 2: Database Connection[/bold cyan]")
|
|
74
|
-
console.print("━" * 80, style="dim")
|
|
74
|
+
console.print("[heading]Step 1 of 2: Database Connection[/heading]")
|
|
75
75
|
console.print()
|
|
76
76
|
|
|
77
77
|
try:
|
|
@@ -92,7 +92,7 @@ async def setup_database_guided() -> str | None:
|
|
|
92
92
|
db_manager = DatabaseConfigManager()
|
|
93
93
|
if db_manager.get_database(name):
|
|
94
94
|
console.print(
|
|
95
|
-
f"[
|
|
95
|
+
f"[warning]Database connection '{name}' already exists.[/warning]"
|
|
96
96
|
)
|
|
97
97
|
return name
|
|
98
98
|
|
|
@@ -108,7 +108,7 @@ async def setup_database_guided() -> str | None:
|
|
|
108
108
|
db_config = build_config(db_input)
|
|
109
109
|
|
|
110
110
|
# Test the connection
|
|
111
|
-
console.print(f"[
|
|
111
|
+
console.print(f"[muted]Testing connection to '{name}'...[/muted]")
|
|
112
112
|
connection_success = await test_connection(db_config, db_input.password)
|
|
113
113
|
|
|
114
114
|
if not connection_success:
|
|
@@ -119,25 +119,25 @@ async def setup_database_guided() -> str | None:
|
|
|
119
119
|
return await setup_database_guided()
|
|
120
120
|
else:
|
|
121
121
|
console.print(
|
|
122
|
-
"[
|
|
122
|
+
"[warning]You can add a database later using 'saber db add'[/warning]"
|
|
123
123
|
)
|
|
124
124
|
return None
|
|
125
125
|
|
|
126
126
|
# Save the configuration
|
|
127
127
|
try:
|
|
128
128
|
save_database(db_manager, db_config, db_input.password)
|
|
129
|
-
console.print(f"[
|
|
129
|
+
console.print(f"[success]✓ Connection to '{name}' successful![/success]")
|
|
130
130
|
console.print()
|
|
131
131
|
return name
|
|
132
132
|
except Exception as e:
|
|
133
|
-
console.print(f"[
|
|
133
|
+
console.print(f"[error]Error saving database:[/error] {e}")
|
|
134
134
|
return None
|
|
135
135
|
|
|
136
136
|
except KeyboardInterrupt:
|
|
137
|
-
console.print("\n[
|
|
137
|
+
console.print("\n[warning]Setup cancelled.[/warning]")
|
|
138
138
|
return None
|
|
139
139
|
except Exception as e:
|
|
140
|
-
console.print(f"[
|
|
140
|
+
console.print(f"[error]Unexpected error:[/error] {e}")
|
|
141
141
|
return None
|
|
142
142
|
|
|
143
143
|
|
|
@@ -151,14 +151,14 @@ async def select_model_for_provider(provider: str) -> str | None:
|
|
|
151
151
|
|
|
152
152
|
try:
|
|
153
153
|
console.print()
|
|
154
|
-
console.print(f"[
|
|
154
|
+
console.print(f"[muted]Fetching available {provider.title()} models...[/muted]")
|
|
155
155
|
|
|
156
156
|
model_manager = ModelManager()
|
|
157
157
|
models = await fetch_models(model_manager, providers=[provider])
|
|
158
158
|
|
|
159
159
|
if not models:
|
|
160
160
|
console.print(
|
|
161
|
-
f"[
|
|
161
|
+
f"[warning]Could not fetch models for {provider}. Using default.[/warning]"
|
|
162
162
|
)
|
|
163
163
|
# Use provider-specific default or fallback to Anthropic
|
|
164
164
|
default_model_id = ModelManager.RECOMMENDED_MODELS.get(
|
|
@@ -178,10 +178,10 @@ async def select_model_for_provider(provider: str) -> str | None:
|
|
|
178
178
|
return selected_model
|
|
179
179
|
|
|
180
180
|
except KeyboardInterrupt:
|
|
181
|
-
console.print("\n[
|
|
181
|
+
console.print("\n[warning]Model selection cancelled.[/warning]")
|
|
182
182
|
return None
|
|
183
183
|
except Exception as e:
|
|
184
|
-
console.print(f"[
|
|
184
|
+
console.print(f"[warning]Error selecting model: {e}. Using default.[/warning]")
|
|
185
185
|
# Fallback to provider default
|
|
186
186
|
if provider in ModelManager.RECOMMENDED_MODELS:
|
|
187
187
|
return f"{provider}:{ModelManager.RECOMMENDED_MODELS[provider]}"
|
|
@@ -196,9 +196,7 @@ async def setup_auth_guided() -> tuple[bool, str | None]:
|
|
|
196
196
|
from sqlsaber.application.auth_setup import setup_auth
|
|
197
197
|
from sqlsaber.application.prompts import AsyncPrompter
|
|
198
198
|
|
|
199
|
-
console.print("
|
|
200
|
-
console.print("[bold cyan]Step 2 of 2: Authentication[/bold cyan]")
|
|
201
|
-
console.print("━" * 80, style="dim")
|
|
199
|
+
console.print("[primary]Step 2 of 2: Authentication[/primary]")
|
|
202
200
|
console.print()
|
|
203
201
|
|
|
204
202
|
try:
|
|
@@ -218,7 +216,7 @@ async def setup_auth_guided() -> tuple[bool, str | None]:
|
|
|
218
216
|
|
|
219
217
|
if not success:
|
|
220
218
|
console.print(
|
|
221
|
-
"[
|
|
219
|
+
"[warning]You can set it up later using 'saber auth setup'[/warning]"
|
|
222
220
|
)
|
|
223
221
|
console.print()
|
|
224
222
|
return False, None
|
|
@@ -233,16 +231,16 @@ async def setup_auth_guided() -> tuple[bool, str | None]:
|
|
|
233
231
|
if selected_model:
|
|
234
232
|
model_manager = ModelManager()
|
|
235
233
|
model_manager.set_model(selected_model)
|
|
236
|
-
console.print(f"[
|
|
234
|
+
console.print(f"[success]✓ Model set to: {selected_model}[/success]")
|
|
237
235
|
console.print()
|
|
238
236
|
return True, selected_model
|
|
239
237
|
|
|
240
238
|
except KeyboardInterrupt:
|
|
241
|
-
console.print("\n[
|
|
239
|
+
console.print("\n[warning]Setup cancelled.[/warning]")
|
|
242
240
|
console.print()
|
|
243
241
|
return False, None
|
|
244
242
|
except Exception as e:
|
|
245
|
-
console.print(f"[
|
|
243
|
+
console.print(f"[error]Unexpected error:[/error] {e}")
|
|
246
244
|
console.print()
|
|
247
245
|
return False, None
|
|
248
246
|
|
|
@@ -251,35 +249,34 @@ def success_screen(
|
|
|
251
249
|
database_name: str | None, auth_configured: bool, model_name: str | None = None
|
|
252
250
|
) -> None:
|
|
253
251
|
"""Display success screen after onboarding."""
|
|
254
|
-
|
|
255
|
-
console.print("[
|
|
256
|
-
console.print("━" * 80, style="dim")
|
|
252
|
+
|
|
253
|
+
console.print("[success]You're all set! 🚀[/success]")
|
|
257
254
|
console.print()
|
|
258
255
|
|
|
259
256
|
if database_name and auth_configured:
|
|
260
257
|
console.print(
|
|
261
|
-
f"[
|
|
258
|
+
f"[success]✓ Database '{database_name}' connected and ready to use[/success]"
|
|
262
259
|
)
|
|
263
|
-
console.print("[
|
|
260
|
+
console.print("[success]✓ Authentication configured[/success]")
|
|
264
261
|
if model_name:
|
|
265
|
-
console.print(f"[
|
|
262
|
+
console.print(f"[success]✓ Model: {model_name}[/success]")
|
|
266
263
|
elif database_name:
|
|
267
264
|
console.print(
|
|
268
|
-
f"[
|
|
265
|
+
f"[success]✓ Database '{database_name}' connected and ready to use[/success]"
|
|
269
266
|
)
|
|
270
267
|
console.print(
|
|
271
|
-
"[
|
|
268
|
+
"[warning]⚠ AI authentication not configured - you'll be prompted when needed[/warning]"
|
|
272
269
|
)
|
|
273
270
|
elif auth_configured:
|
|
274
|
-
console.print("[
|
|
271
|
+
console.print("[success]✓ AI authentication configured[/success]")
|
|
275
272
|
if model_name:
|
|
276
|
-
console.print(f"[
|
|
273
|
+
console.print(f"[success]✓ Model: {model_name}[/success]")
|
|
277
274
|
console.print(
|
|
278
|
-
"[
|
|
275
|
+
"[warning]⚠ No database configured - you'll need to provide one via -d flag[/warning]"
|
|
279
276
|
)
|
|
280
277
|
|
|
281
278
|
console.print()
|
|
282
|
-
console.print("[
|
|
279
|
+
console.print("[muted]Starting interactive session...[/muted]")
|
|
283
280
|
console.print()
|
|
284
281
|
|
|
285
282
|
|
|
@@ -298,9 +295,9 @@ async def run_onboarding() -> bool:
|
|
|
298
295
|
|
|
299
296
|
# If user cancelled database setup, exit
|
|
300
297
|
if database_name is None:
|
|
301
|
-
console.print("[
|
|
298
|
+
console.print("[warning]Database setup is required to continue.[/warning]")
|
|
302
299
|
console.print(
|
|
303
|
-
"[
|
|
300
|
+
"[muted]You can also provide a connection string using: saber -d <connection-string>[/muted]"
|
|
304
301
|
)
|
|
305
302
|
return False
|
|
306
303
|
|
|
@@ -313,13 +310,13 @@ async def run_onboarding() -> bool:
|
|
|
313
310
|
return True
|
|
314
311
|
|
|
315
312
|
except KeyboardInterrupt:
|
|
316
|
-
console.print("\n[
|
|
313
|
+
console.print("\n[warning]Onboarding cancelled.[/warning]")
|
|
317
314
|
console.print(
|
|
318
|
-
"[
|
|
319
|
-
"[
|
|
320
|
-
"[
|
|
315
|
+
"[muted]You can run setup commands manually:[/muted]\n"
|
|
316
|
+
"[muted] - saber db add <name> # Add database connection[/muted]\n"
|
|
317
|
+
"[muted] - saber auth setup # Configure authentication[/muted]"
|
|
321
318
|
)
|
|
322
319
|
sys.exit(0)
|
|
323
320
|
except Exception as e:
|
|
324
|
-
console.print(f"[
|
|
321
|
+
console.print(f"[error]Onboarding failed:[/error] {e}")
|
|
325
322
|
return False
|
sqlsaber/cli/threads.py
CHANGED
|
@@ -170,7 +170,7 @@ def _render_transcript(
|
|
|
170
170
|
Panel.fit(
|
|
171
171
|
content_str,
|
|
172
172
|
title=f"Tool result: {name}",
|
|
173
|
-
border_style="
|
|
173
|
+
border_style="warning",
|
|
174
174
|
)
|
|
175
175
|
)
|
|
176
176
|
except Exception:
|
|
@@ -183,7 +183,7 @@ def _render_transcript(
|
|
|
183
183
|
Panel.fit(
|
|
184
184
|
content_str,
|
|
185
185
|
title=f"Tool result: {name}",
|
|
186
|
-
border_style="
|
|
186
|
+
border_style="warning",
|
|
187
187
|
)
|
|
188
188
|
)
|
|
189
189
|
else:
|
|
@@ -194,7 +194,7 @@ def _render_transcript(
|
|
|
194
194
|
Panel.fit(
|
|
195
195
|
content_str,
|
|
196
196
|
title=f"Tool result: {name}",
|
|
197
|
-
border_style="
|
|
197
|
+
border_style="warning",
|
|
198
198
|
)
|
|
199
199
|
)
|
|
200
200
|
# Thinking parts omitted
|
sqlsaber/config/api_keys.py
CHANGED
|
@@ -36,7 +36,7 @@ class APIKeyManager:
|
|
|
36
36
|
return api_key
|
|
37
37
|
except Exception as e:
|
|
38
38
|
# Keyring access failed, continue to prompt
|
|
39
|
-
console.print(f"Keyring access failed: {e}", style="
|
|
39
|
+
console.print(f"Keyring access failed: {e}", style="muted warning")
|
|
40
40
|
|
|
41
41
|
# 3. Prompt user for API key
|
|
42
42
|
return self._prompt_and_store_key(provider, env_var_name, service_name)
|
|
@@ -72,7 +72,7 @@ class APIKeyManager:
|
|
|
72
72
|
if not api_key.strip():
|
|
73
73
|
console.print(
|
|
74
74
|
"No API key provided. Some functionality may not work.",
|
|
75
|
-
style="
|
|
75
|
+
style="warning",
|
|
76
76
|
)
|
|
77
77
|
return None
|
|
78
78
|
|
|
@@ -83,16 +83,16 @@ class APIKeyManager:
|
|
|
83
83
|
except Exception as e:
|
|
84
84
|
console.print(
|
|
85
85
|
f"Warning: Could not store API key in your operating system's credentials store: {e}",
|
|
86
|
-
style="
|
|
86
|
+
style="warning",
|
|
87
87
|
)
|
|
88
88
|
console.print(
|
|
89
|
-
"You may need to enter it again next time", style="
|
|
89
|
+
"You may need to enter it again next time", style="warning"
|
|
90
90
|
)
|
|
91
91
|
|
|
92
92
|
return api_key.strip()
|
|
93
93
|
|
|
94
94
|
except KeyboardInterrupt:
|
|
95
|
-
console.print("\nOperation cancelled", style="
|
|
95
|
+
console.print("\nOperation cancelled", style="warning")
|
|
96
96
|
return None
|
|
97
97
|
except Exception as e:
|
|
98
98
|
console.print(f"Error prompting for API key: {e}", style="red")
|
sqlsaber/config/oauth_flow.py
CHANGED
|
@@ -131,7 +131,7 @@ class AnthropicOAuthFlow:
|
|
|
131
131
|
if not questionary.confirm(
|
|
132
132
|
"Continue with browser-based authentication?", default=True
|
|
133
133
|
).ask():
|
|
134
|
-
console.print("[
|
|
134
|
+
console.print("[warning]Authentication cancelled.[/warning]")
|
|
135
135
|
return False
|
|
136
136
|
|
|
137
137
|
try:
|
|
@@ -168,7 +168,7 @@ class AnthropicOAuthFlow:
|
|
|
168
168
|
).ask()
|
|
169
169
|
|
|
170
170
|
if not auth_code:
|
|
171
|
-
console.print("[
|
|
171
|
+
console.print("[warning]Authentication cancelled.[/warning]")
|
|
172
172
|
return False
|
|
173
173
|
|
|
174
174
|
# Step 2: Exchange code for tokens
|
|
@@ -198,23 +198,23 @@ class AnthropicOAuthFlow:
|
|
|
198
198
|
)
|
|
199
199
|
|
|
200
200
|
if self.token_manager.store_oauth_token("anthropic", oauth_token):
|
|
201
|
-
console.print(
|
|
202
|
-
"\n[bold green]✓ Authentication successful![/bold green]"
|
|
203
|
-
)
|
|
201
|
+
console.print("\n[success]✓ Authentication successful![/success]")
|
|
204
202
|
console.print(
|
|
205
203
|
"Your Claude Pro/Max subscription is now configured for SQLSaber."
|
|
206
204
|
)
|
|
207
205
|
return True
|
|
208
206
|
else:
|
|
209
|
-
console.print(
|
|
207
|
+
console.print(
|
|
208
|
+
"[error]✗ Failed to store authentication tokens.[/error]"
|
|
209
|
+
)
|
|
210
210
|
return False
|
|
211
211
|
|
|
212
212
|
except KeyboardInterrupt:
|
|
213
|
-
console.print("\n[
|
|
213
|
+
console.print("\n[warning]Authentication cancelled by user.[/warning]")
|
|
214
214
|
return False
|
|
215
215
|
except Exception as e:
|
|
216
216
|
logger.error(f"OAuth authentication failed: {e}")
|
|
217
|
-
console.print(f"[
|
|
217
|
+
console.print(f"[error]✗ Authentication failed: {str(e)}[/error]")
|
|
218
218
|
return False
|
|
219
219
|
|
|
220
220
|
def refresh_token_if_needed(self) -> OAuthToken | None:
|
|
@@ -255,13 +255,14 @@ class AnthropicOAuthFlow:
|
|
|
255
255
|
console.print("OAuth token refreshed successfully", style="green")
|
|
256
256
|
return refreshed_token
|
|
257
257
|
else:
|
|
258
|
-
console.print("Failed to store refreshed token", style="
|
|
258
|
+
console.print("Failed to store refreshed token", style="warning")
|
|
259
259
|
return current_token
|
|
260
260
|
|
|
261
261
|
except Exception as e:
|
|
262
262
|
logger.warning(f"Token refresh failed: {e}")
|
|
263
263
|
console.print(
|
|
264
|
-
"Token refresh failed. You may need to re-authenticate.",
|
|
264
|
+
"Token refresh failed. You may need to re-authenticate.",
|
|
265
|
+
style="warning",
|
|
265
266
|
)
|
|
266
267
|
return current_token
|
|
267
268
|
|
sqlsaber/config/oauth_tokens.py
CHANGED
|
@@ -97,14 +97,14 @@ class OAuthTokenManager:
|
|
|
97
97
|
if token.is_expired():
|
|
98
98
|
console.print(
|
|
99
99
|
f"OAuth token for {provider} has expired and needs refresh",
|
|
100
|
-
style="
|
|
100
|
+
style="muted warning",
|
|
101
101
|
)
|
|
102
102
|
return token # Return anyway for refresh attempt
|
|
103
103
|
|
|
104
104
|
if token.expires_soon():
|
|
105
105
|
console.print(
|
|
106
106
|
f"OAuth token for {provider} expires soon, consider refreshing",
|
|
107
|
-
style="
|
|
107
|
+
style="muted warning",
|
|
108
108
|
)
|
|
109
109
|
|
|
110
110
|
return token
|
|
@@ -126,7 +126,7 @@ class OAuthTokenManager:
|
|
|
126
126
|
logger.error(f"Failed to store OAuth token for {provider}: {e}")
|
|
127
127
|
console.print(
|
|
128
128
|
f"Warning: Could not store OAuth token in keyring: {e}",
|
|
129
|
-
style="
|
|
129
|
+
style="warning",
|
|
130
130
|
)
|
|
131
131
|
return False
|
|
132
132
|
|
|
@@ -137,7 +137,7 @@ class OAuthTokenManager:
|
|
|
137
137
|
existing_token = self.get_oauth_token(provider)
|
|
138
138
|
if not existing_token:
|
|
139
139
|
console.print(
|
|
140
|
-
f"No existing OAuth token found for {provider}", style="
|
|
140
|
+
f"No existing OAuth token found for {provider}", style="warning"
|
|
141
141
|
)
|
|
142
142
|
return False
|
|
143
143
|
|
|
@@ -161,7 +161,9 @@ class OAuthTokenManager:
|
|
|
161
161
|
return True
|
|
162
162
|
except Exception as e:
|
|
163
163
|
logger.error(f"Failed to remove OAuth token for {provider}: {e}")
|
|
164
|
-
console.print(
|
|
164
|
+
console.print(
|
|
165
|
+
f"Warning: Could not remove OAuth token: {e}", style="warning"
|
|
166
|
+
)
|
|
165
167
|
return False
|
|
166
168
|
|
|
167
169
|
def has_oauth_token(self, provider: str) -> bool:
|
sqlsaber/database/schema.py
CHANGED
|
@@ -158,7 +158,7 @@ class SchemaManager:
|
|
|
158
158
|
table["schema"] = table["table_schema"]
|
|
159
159
|
table["type"] = table["table_type"] # Map table_type to type for display
|
|
160
160
|
|
|
161
|
-
return {"tables": tables_list}
|
|
161
|
+
return {"tables": tables_list, "total_tables": len(tables_list)}
|
|
162
162
|
|
|
163
163
|
async def close(self):
|
|
164
164
|
"""Close database connection."""
|
sqlsaber/theme/manager.py
CHANGED
|
@@ -18,14 +18,6 @@ from rich.theme import Theme
|
|
|
18
18
|
DEFAULT_THEME_NAME = "nord"
|
|
19
19
|
|
|
20
20
|
DEFAULT_ROLE_PALETTE = {
|
|
21
|
-
# base roles
|
|
22
|
-
"primary": "cyan",
|
|
23
|
-
"accent": "magenta",
|
|
24
|
-
"success": "green",
|
|
25
|
-
"warning": "yellow",
|
|
26
|
-
"error": "red",
|
|
27
|
-
"info": "cyan",
|
|
28
|
-
"muted": "dim",
|
|
29
21
|
# components
|
|
30
22
|
"table.header": "bold $primary",
|
|
31
23
|
"panel.border.user": "$info",
|
|
@@ -5,29 +5,29 @@ sqlsaber/agents/base.py,sha256=40-MKEoz5rGrqVIylV1U2DaAUSPFcC75ohRin4E3-kk,2668
|
|
|
5
5
|
sqlsaber/agents/mcp.py,sha256=Pn8tdDRUEVLYQyEi5nHRp9MKNePwHVVoeNI-uqWcr0Y,757
|
|
6
6
|
sqlsaber/agents/pydantic_ai_agent.py,sha256=wBxKz0pjOkL-HI-TXV6B67bczZNgu7k26Rr3w5usR3o,10064
|
|
7
7
|
sqlsaber/application/__init__.py,sha256=KY_-d5nEdQyAwNOsK5r-f7Tb69c63XbuEkHPeLpJal8,84
|
|
8
|
-
sqlsaber/application/auth_setup.py,sha256=
|
|
9
|
-
sqlsaber/application/db_setup.py,sha256=
|
|
10
|
-
sqlsaber/application/model_selection.py,sha256=
|
|
8
|
+
sqlsaber/application/auth_setup.py,sha256=D94dyU9bOVfnNHLnnFJb5PaeWsKPTL21CiS_DLcY93A,5114
|
|
9
|
+
sqlsaber/application/db_setup.py,sha256=ZSgR9rJJVHttIjsbYQS9GEIyzkM09k5RLrVGdegrfYc,6859
|
|
10
|
+
sqlsaber/application/model_selection.py,sha256=fSC06MZNKinHDR-csMFVYYJFyK8MydKf6pStof74Jp0,3191
|
|
11
11
|
sqlsaber/application/prompts.py,sha256=4rMGcWpYJbNWPMzqVWseUMx0nwvXOkWS6GaTAJ5mhfc,3473
|
|
12
12
|
sqlsaber/cli/__init__.py,sha256=qVSLVJLLJYzoC6aj6y9MFrzZvAwc4_OgxU9DlkQnZ4M,86
|
|
13
|
-
sqlsaber/cli/auth.py,sha256=
|
|
14
|
-
sqlsaber/cli/commands.py,sha256=
|
|
13
|
+
sqlsaber/cli/auth.py,sha256=elUpw8gypHGlxbHx4a4_z4wFznx2vr6V1h8lqpeC6OQ,6121
|
|
14
|
+
sqlsaber/cli/commands.py,sha256=Pii_SlVKpNEtt57_QPQzwC1u-x6tA8kuG8yd43undWE,8628
|
|
15
15
|
sqlsaber/cli/completers.py,sha256=g-hLDq5fiBx7gg8Bte1Lq8GU-ZxCYVs4dcPsmHPIcK4,6574
|
|
16
|
-
sqlsaber/cli/database.py,sha256=
|
|
16
|
+
sqlsaber/cli/database.py,sha256=Tqy8H5MnjsrmOSPcbA5Qy-u-IOYJCIXRJVhk0veLNDk,10726
|
|
17
17
|
sqlsaber/cli/display.py,sha256=WB5JCumhXadziDEX1EZHG3vN1Chol5FNAaTXHieqFK0,17892
|
|
18
|
-
sqlsaber/cli/interactive.py,sha256=
|
|
19
|
-
sqlsaber/cli/memory.py,sha256=
|
|
20
|
-
sqlsaber/cli/models.py,sha256=
|
|
21
|
-
sqlsaber/cli/onboarding.py,sha256=
|
|
18
|
+
sqlsaber/cli/interactive.py,sha256=PcY6mszImo_3PsqjjWmx_cOfj44OmKvD9ENOvGA-wjU,13715
|
|
19
|
+
sqlsaber/cli/memory.py,sha256=IKq09DUbqpvvtATsyDlpm7rDlGqWEhdUX9wgnR-oiq4,7850
|
|
20
|
+
sqlsaber/cli/models.py,sha256=iMTw3DCKIQbWfSfikwy-nQ5tiHWjoN4cbKA-G6RFlj4,8535
|
|
21
|
+
sqlsaber/cli/onboarding.py,sha256=iBGT-W-OJFRvQoEpuHYyO1c9Mym5c97eIefRvxGHtTg,11265
|
|
22
22
|
sqlsaber/cli/streaming.py,sha256=1XoZGPPMoTmBQVgp_Bqk483MR93j9oXxSV6Tx_-TpOg,6923
|
|
23
23
|
sqlsaber/cli/theme.py,sha256=hP0kmsMLCtqaT7b5wB1dk1hW1hV94oP4BHdz8S6887A,4243
|
|
24
|
-
sqlsaber/cli/threads.py,sha256=
|
|
24
|
+
sqlsaber/cli/threads.py,sha256=o9q9Hst1Wt7cxSyrpAtwG6pkUct6csgiAmN_0P_WO3k,13637
|
|
25
25
|
sqlsaber/config/__init__.py,sha256=olwC45k8Nc61yK0WmPUk7XHdbsZH9HuUAbwnmKe3IgA,100
|
|
26
|
-
sqlsaber/config/api_keys.py,sha256=
|
|
26
|
+
sqlsaber/config/api_keys.py,sha256=9RyhD5Bntq8NMFRPiZZo8YEHACK9MPyFGp8dsmQZ1iI,3678
|
|
27
27
|
sqlsaber/config/auth.py,sha256=b5qB2h1doXyO9Bn8z0CcL8LAR2jF431gGXBGKLgTmtQ,2756
|
|
28
28
|
sqlsaber/config/database.py,sha256=Yec6_0wdzq-ADblMNnbgvouYCimYOY_DWHT9oweaISc,11449
|
|
29
|
-
sqlsaber/config/oauth_flow.py,sha256=
|
|
30
|
-
sqlsaber/config/oauth_tokens.py,sha256=
|
|
29
|
+
sqlsaber/config/oauth_flow.py,sha256=P81lHhtICdhiQu8lNwyqn2m45FGEqCEzLgUQTLG5UW0,10343
|
|
30
|
+
sqlsaber/config/oauth_tokens.py,sha256=V4U8GAQHjTfgUcTzwjRVaIE7DeN0tF9OsSjiasHw7Uc,5970
|
|
31
31
|
sqlsaber/config/providers.py,sha256=JFjeJv1K5Q93zWSlWq3hAvgch1TlgoF0qFa0KJROkKY,2957
|
|
32
32
|
sqlsaber/config/settings.py,sha256=iB4CnGQ4hw8gxkaa9CVLB_JEy6Y9h9FQTAams5OCVyI,6421
|
|
33
33
|
sqlsaber/database/__init__.py,sha256=Gi9N_NOkD459WRWXDg3hSuGoBs3xWbMDRBvsTVmnGAg,2025
|
|
@@ -37,7 +37,7 @@ sqlsaber/database/duckdb.py,sha256=8HNKdx208aFK_YtwGjLz6LTne0xEmNevD-f9dRWlrFg,1
|
|
|
37
37
|
sqlsaber/database/mysql.py,sha256=wMzDQqq4GFbfEdqXtv_sCb4Qbr9GSWqYAvOLeo5UryY,14472
|
|
38
38
|
sqlsaber/database/postgresql.py,sha256=fuf2Wl29NKXvD3mqsR08PDleNQ1PG-fNvWSxT6HDh2M,13223
|
|
39
39
|
sqlsaber/database/resolver.py,sha256=wSCcn__aCqwIfpt_LCjtW2Zgb8RpG5PlmwwZHli1q_U,3628
|
|
40
|
-
sqlsaber/database/schema.py,sha256=
|
|
40
|
+
sqlsaber/database/schema.py,sha256=CuV0ewoVaERe1gj_fJFJFWAP8aEPgepmn6X6B7bgkfQ,6962
|
|
41
41
|
sqlsaber/database/sqlite.py,sha256=iReEIiSpkhhS1VzITd79ZWqSL3fHMyfe3DRCDpM0DvE,9421
|
|
42
42
|
sqlsaber/mcp/__init__.py,sha256=COdWq7wauPBp5Ew8tfZItFzbcLDSEkHBJSMhxzy8C9c,112
|
|
43
43
|
sqlsaber/mcp/mcp.py,sha256=tpNPHpkaCre1Xjp7c4DHXbTKeuYpDQ8qhmJZvAyr7Vk,3939
|
|
@@ -45,7 +45,7 @@ sqlsaber/memory/__init__.py,sha256=GiWkU6f6YYVV0EvvXDmFWe_CxarmDCql05t70MkTEWs,6
|
|
|
45
45
|
sqlsaber/memory/manager.py,sha256=p3fybMVfH-E4ApT1ZRZUnQIWSk9dkfUPCyfkmA0HALs,2739
|
|
46
46
|
sqlsaber/memory/storage.py,sha256=ne8szLlGj5NELheqLnI7zu21V8YS4rtpYGGC7tOmi-s,5745
|
|
47
47
|
sqlsaber/theme/__init__.py,sha256=qCICX1Cg4B6yCbZ1UrerxglWxcqldRFVSRrSs73na_8,188
|
|
48
|
-
sqlsaber/theme/manager.py,sha256=
|
|
48
|
+
sqlsaber/theme/manager.py,sha256=xOi1ZLNr31ZtE8-WzxdtvywCB1rbJ7z2DTzcqHsCavY,6377
|
|
49
49
|
sqlsaber/threads/__init__.py,sha256=Hh3dIG1tuC8fXprREUpslCIgPYz8_6o7aRLx4yNeO48,139
|
|
50
50
|
sqlsaber/threads/storage.py,sha256=rsUdxT4CR52D7xtGir9UlsFnBMk11jZeflzDrk2q4ME,11183
|
|
51
51
|
sqlsaber/tools/__init__.py,sha256=x3YdmX_7P0Qq_HtZHAgfIVKTLxYqKk6oc4tGsujQWsc,586
|
|
@@ -55,8 +55,8 @@ sqlsaber/tools/instructions.py,sha256=X-x8maVkkyi16b6Tl0hcAFgjiYceZaSwyWTfmrvx8U
|
|
|
55
55
|
sqlsaber/tools/registry.py,sha256=HWOQMsNIdL4XZS6TeNUyrL-5KoSDH6PHsWd3X66o-18,3211
|
|
56
56
|
sqlsaber/tools/sql_guard.py,sha256=dTDwcZP-N4xPGzcr7MQtKUxKrlDzlc1irr9aH5a4wvk,6182
|
|
57
57
|
sqlsaber/tools/sql_tools.py,sha256=ujmAcfLkNaBrb5LWEgWcINQEQSX0LRPX3VK5Dag1Sj4,9178
|
|
58
|
-
sqlsaber-0.29.
|
|
59
|
-
sqlsaber-0.29.
|
|
60
|
-
sqlsaber-0.29.
|
|
61
|
-
sqlsaber-0.29.
|
|
62
|
-
sqlsaber-0.29.
|
|
58
|
+
sqlsaber-0.29.1.dist-info/METADATA,sha256=kx_nQDGhcDUJp4DadT7Pi89QsUuf8S5W6IVqwaJfuXM,7174
|
|
59
|
+
sqlsaber-0.29.1.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
|
60
|
+
sqlsaber-0.29.1.dist-info/entry_points.txt,sha256=qEbOB7OffXPFgyJc7qEIJlMEX5RN9xdzLmWZa91zCQQ,162
|
|
61
|
+
sqlsaber-0.29.1.dist-info/licenses/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
|
|
62
|
+
sqlsaber-0.29.1.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|