feat: terminal CLI with interactive SQL shell#313
Draft
debba wants to merge 4 commits into
Draft
Conversation
- New clap subcommands: connections, databases, schemas, tables, describe, query, install-cli - `query <conn>` without SQL opens an interactive shell (rustyline): multi-line statements, persistent history, psql-style meta commands (\dt, \d, \l, \dn, \use, \f, \limit, \schema) - Multi-database connections: -d/--database on each command and \use in the shell, mirroring the GUI's per-call database override - Extract shared headless connection resolution (keychain, SSH/K8s tunnels, driver registry) from the MCP server into headless.rs - Route keychain logging through the log crate instead of raw stdout - Install sqlx Any drivers in headless mode (test_connection panicked without them) - install-cli symlinks the binary into /usr/local/bin or ~/.local/bin
Add a "Command Line" section to Settings > General to install, remove and reinstall the 'tabularis' command without leaving the GUI, mirroring VSCode's "Install 'code' command in PATH". - Backend: get_cli_install_status / install_cli_shortcut / remove_cli_shortcut Tauri commands on top of cli::install, which now exposes structured state (installed, link path, in PATH, removable). - Status detection recognizes both symlinks created by install-cli and the binary itself already reachable via PATH; removal only ever deletes a symlink that resolves to the running binary, never foreign entries or package-manager installs. - The UI shows the installed path, a copyable PATH export hint when the bin dir is not in PATH, and offers force-replace only after a foreign-entry conflict. - GUI management is gated to macOS, where the binary lives at a stable path inside the .app bundle: on Linux the binary is either already in PATH or at an ephemeral AppImage/Flatpak path, so the section is hidden there. The install-cli subcommand stays available on all Unix. - settings.cli.* strings added to all 8 locales; unit tests for the new Rust helpers and the TS utils.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Tabularis now works from the terminal. The binary gains a set of clap subcommands that reuse the same connection resolution as the MCP server (keychain passwords, SSH/K8s tunnels, plugin drivers), so every saved connection is reachable from a script or a shell session, addressed by connection id or name. No Tauri runtime is started in this mode.
Command map
tabularis connections(ls)--json)tabularis databases <conn>tabularis schemas <conn>tabularis tables <conn>-d,--schema,--json)tabularis describe <conn> <table>tabularis query <conn> [SQL](q)tabularis install-cliquerypicks its mode from the invocation: SQL argument → one-shot; piped stdin → executes the piped statement; interactive TTY with no SQL → opens the shell.Output formats: aligned ASCII table (default),
--format json(array of row objects),--format csv. Result data goes to stdout and logs to stderr, so piping stays clean. Non-zero exit code on failure.Interactive shell
tabularis query <conn>opens a REPL backed by rustyline: line editing, persistent history (cli_history.txtin the app config dir), multi-line statements executed on a terminating;, Ctrl-C drops the current buffer, Ctrl-D exits. Meta commands:Multi-database connections
Multi-db connections resolve to their first database, which made the remaining ones unreachable outside the GUI. All db-scoped commands now accept
-d/--database, and the shell adds\use <db>: the switch is validated with a connection test before being applied, and the prompt shows the active database (Demo · MySQL:blog_demo>). This reuses the GUI's per-calldatabaseoverride semantics (DatabaseSelection::Single).Internals
mcp/mod.rs(keychain lookup, SSH/K8s expansion, driver registration) moved to a sharedheadless.rs; the MCP server now wraps them with its JSON-RPC error type. No behavior change on the MCP side.keychain_utilslogged viaprintln!, which polluted stdout (a problem once stdout carries parseable CSV/JSON) and bypassed the in-app log buffer. It now goes through thelogcrate.sqlx::any::install_default_drivers(), so the defaulttest_connectionpath panicked. It is now installed inheadless::register_drivers(), which also covers--mcp.-psn_*) still boot the GUI, while misspelled subcommands and bad flag values surface clap's error instead of silently opening a window.Tests
37 new unit tests: clap parsing (GUI fallback error kinds, value enums, aliases), table/CSV/JSON rendering (alignment, control-character escaping, quoting), limit and database-override semantics, and the install-cli symlink logic (idempotency, refusal to clobber foreign files,
--force). Full suite: 692 passing.Manually exercised against the demo MySQL connection: one-shot queries, stdin pipes, the shell with
\useacross the three demo databases, andinstall-cliinto a scratch directory.Known limitations
windows_subsystem = "windows"), so CLI output is invisible there. Same constraint as the existing--mcpmode.SET, transactions, temp tables) does not persist between statements. Stated in\?.Notes
This PR doubled as an experiment in agent-driven development: implementation, tests, and this description were produced end to end with Fable 5 (Anthropic), with human direction and review throughout.