@deaquinodev/querky 0.4.8 → 0.4.9

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 (2) hide show
  1. package/dist/index.js +413 -508
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -3,7 +3,7 @@
3
3
  // src/index.tsx
4
4
  import { useState as useState6, useEffect as useEffect5 } from "react";
5
5
  import { parseArgs } from "util";
6
- import { render, Box as Box9, Text as Text9 } from "ink";
6
+ import { render, Box as Box7, Text as Text7 } from "ink";
7
7
 
8
8
  // src/db/client.ts
9
9
  import { Client } from "pg";
@@ -81,7 +81,7 @@ var SqliteDbClient = class {
81
81
  const stmt = this.db.prepare(sql);
82
82
  if (stmt.reader) {
83
83
  const rows = stmt.all();
84
- const fields = stmt.columns().map((c) => c.name);
84
+ const fields = stmt.columns().map((c2) => c2.name);
85
85
  return { fields, rows, rowCount: rows.length };
86
86
  }
87
87
  const info = stmt.run();
@@ -197,7 +197,7 @@ import { useState as useState4, useEffect as useEffect4, useRef as useRef2 } fro
197
197
  import { writeFileSync as writeFileSync5 } from "fs";
198
198
  import { homedir as homedir4 } from "os";
199
199
  import { join as join5 } from "path";
200
- import { Box as Box7, Text as Text7, useApp, useInput as useInput2, useStdin as useStdin2, Static } from "ink";
200
+ import { Box as Box5, Static, Text as Text5, useApp, useInput as useInput2, useStdin as useStdin2 } from "ink";
201
201
 
202
202
  // src/db/query.ts
203
203
  async function runQuery(client, sql) {
@@ -741,10 +741,10 @@ var BUILTIN_COMMAND_LIST = Object.entries(COMMANDS).map(([name, cmd]) => ({
741
741
  description: cmd.description
742
742
  }));
743
743
  function getCompletions(partial, aliases = {}) {
744
- if (partial.length === 0) return BUILTIN_COMMAND_LIST.map((c) => c.name);
744
+ if (partial.length === 0) return BUILTIN_COMMAND_LIST.map((c2) => c2.name);
745
745
  const tokenLower = partial.toLowerCase();
746
746
  const candidates = [
747
- ...BUILTIN_COMMAND_LIST.map((c) => c.name),
747
+ ...BUILTIN_COMMAND_LIST.map((c2) => c2.name),
748
748
  ...Object.keys(aliases).filter((n) => !COMMANDS[n])
749
749
  ];
750
750
  return candidates.map((n) => ({ n, score: fuzzyScore(tokenLower, n.toLowerCase()) })).filter(({ score }) => score >= 0).sort((a, b) => b.score - a.score).map(({ n }) => n);
@@ -831,7 +831,7 @@ async function fetchErd(client, driver) {
831
831
  if (!tableMap.has(tableName)) tableMap.set(tableName, []);
832
832
  const cols = tableMap.get(tableName);
833
833
  const colName = String(row["column_name"] ?? "");
834
- if (cols.some((c) => c.name === colName)) continue;
834
+ if (cols.some((c2) => c2.name === colName)) continue;
835
835
  cols.push({
836
836
  name: colName,
837
837
  type: String(row["data_type"] ?? ""),
@@ -1523,7 +1523,7 @@ function SqlLine({ text, bg }) {
1523
1523
  const tokens = tokenizeSql(text);
1524
1524
  return /* @__PURE__ */ jsx(Fragment, { children: tokens.map((tok, i) => /* @__PURE__ */ jsx(Text, { backgroundColor: bg, color: sqlTokenColor(tok.type), children: tok.text }, i)) });
1525
1525
  }
1526
- function SqlHighlightedInput({ text, cursorAt, mode, pad: pad2 }) {
1526
+ function SqlHighlightedInput({ text, cursorAt, mode, pad }) {
1527
1527
  const tokens = tokenizeSql(text);
1528
1528
  const parts = [];
1529
1529
  let pos = 0;
@@ -1557,7 +1557,7 @@ function SqlHighlightedInput({ text, cursorAt, mode, pad: pad2 }) {
1557
1557
  parts.push(/* @__PURE__ */ jsx(Text, { backgroundColor: ACCENT, color: BG, bold: true, children: " " }, "c"));
1558
1558
  }
1559
1559
  }
1560
- parts.push(/* @__PURE__ */ jsx(Text, { backgroundColor: BG, children: pad2 }, "pad"));
1560
+ parts.push(/* @__PURE__ */ jsx(Text, { backgroundColor: BG, children: pad }, "pad"));
1561
1561
  return /* @__PURE__ */ jsx(Fragment, { children: parts });
1562
1562
  }
1563
1563
  var HINTS = {
@@ -1586,7 +1586,7 @@ var HINTS = {
1586
1586
  ["/toggle-vim-mode", "ENABLE VIM"]
1587
1587
  ]
1588
1588
  };
1589
- var BUILTIN_DESC_MAP = Object.fromEntries(BUILTIN_COMMAND_LIST.map((c) => [c.name, c.description]));
1589
+ var BUILTIN_DESC_MAP = Object.fromEntries(BUILTIN_COMMAND_LIST.map((c2) => [c2.name, c2.description]));
1590
1590
  function QueryInput({ onSubmit, isLoading, onModeChange, onShellModeChange, vimEnabled = true, history = [], aliases = {}, schema }) {
1591
1591
  function handleTab(current) {
1592
1592
  if (!current.startsWith("/")) return null;
@@ -1752,82 +1752,6 @@ import { Box as Box3, Text as Text3 } from "ink";
1752
1752
  // src/ui/components/Table.tsx
1753
1753
  import { Box as Box2, Text as Text2 } from "ink";
1754
1754
  import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
1755
- var COL_PAD = 1;
1756
- var INDIGO = "#818cf8";
1757
- var BORDER = "white";
1758
- var NULL_COLOR = "#6366f1";
1759
- var NULL_MARKER = "\u2205";
1760
- function isNull(val) {
1761
- return val === null || val === void 0;
1762
- }
1763
- function cellValue(val) {
1764
- if (isNull(val)) return NULL_MARKER;
1765
- if (val instanceof Date) return val.toISOString();
1766
- if (typeof val === "object") return JSON.stringify(val);
1767
- return String(val);
1768
- }
1769
- function colWidths(columns, rows) {
1770
- return columns.map((col) => {
1771
- const dataMax = rows.reduce(
1772
- (max, row) => Math.max(max, cellValue(row[col]).length),
1773
- 0
1774
- );
1775
- return Math.max(col.length, dataMax);
1776
- });
1777
- }
1778
- function pad(str, width) {
1779
- return str.slice(0, width).padEnd(width);
1780
- }
1781
- function hline(widths, left, mid, right) {
1782
- const segments = widths.map((w) => "\u2500".repeat(w + COL_PAD * 2));
1783
- return left + segments.join(mid) + right;
1784
- }
1785
- function ExpandedTable({ columns, rows }) {
1786
- const keyWidth = columns.reduce((max, col) => Math.max(max, col.length), 0);
1787
- return /* @__PURE__ */ jsx2(Box2, { flexDirection: "column", children: rows.map((row, i) => /* @__PURE__ */ jsxs2(Box2, { flexDirection: "column", marginBottom: i < rows.length - 1 ? 1 : 0, children: [
1788
- /* @__PURE__ */ jsx2(Text2, { color: BORDER, children: `\u2500[ Record ${i + 1} ]${"\u2500".repeat(Math.max(0, keyWidth + 14 - String(i + 1).length))}` }),
1789
- columns.map((col) => /* @__PURE__ */ jsxs2(Box2, { children: [
1790
- /* @__PURE__ */ jsx2(Text2, { color: INDIGO, bold: true, children: col.padEnd(keyWidth) }),
1791
- /* @__PURE__ */ jsx2(Text2, { color: BORDER, children: " \u2502 " }),
1792
- isNull(row[col]) ? /* @__PURE__ */ jsx2(Text2, { color: NULL_COLOR, dimColor: true, children: NULL_MARKER }) : /* @__PURE__ */ jsx2(Text2, { children: cellValue(row[col]) })
1793
- ] }, col))
1794
- ] }, i)) });
1795
- }
1796
- function Table({ columns, rows, expanded = false }) {
1797
- if (expanded) return /* @__PURE__ */ jsx2(ExpandedTable, { columns, rows });
1798
- const widths = colWidths(columns, rows);
1799
- const topLine = hline(widths, "\u256D", "\u252C", "\u256E");
1800
- const midLine = hline(widths, "\u251C", "\u253C", "\u2524");
1801
- const botLine = hline(widths, "\u2570", "\u2534", "\u256F");
1802
- function renderHeaderRow(cols) {
1803
- return /* @__PURE__ */ jsxs2(Box2, { children: [
1804
- /* @__PURE__ */ jsx2(Text2, { color: BORDER, children: "\u2502" }),
1805
- cols.map((v, i) => /* @__PURE__ */ jsxs2(Box2, { children: [
1806
- /* @__PURE__ */ jsx2(Text2, { color: INDIGO, bold: true, children: " ".repeat(COL_PAD) + pad(v, widths[i]) + " ".repeat(COL_PAD) }),
1807
- /* @__PURE__ */ jsx2(Text2, { color: BORDER, children: "\u2502" })
1808
- ] }, i))
1809
- ] });
1810
- }
1811
- function renderDataRow(row) {
1812
- return /* @__PURE__ */ jsxs2(Box2, { children: [
1813
- /* @__PURE__ */ jsx2(Text2, { color: BORDER, children: "\u2502" }),
1814
- columns.map((col, i) => /* @__PURE__ */ jsxs2(Box2, { children: [
1815
- isNull(row[col]) ? /* @__PURE__ */ jsx2(Text2, { color: NULL_COLOR, dimColor: true, children: " ".repeat(COL_PAD) + pad(NULL_MARKER, widths[i]) + " ".repeat(COL_PAD) }) : /* @__PURE__ */ jsx2(Text2, { children: " ".repeat(COL_PAD) + pad(cellValue(row[col]), widths[i]) + " ".repeat(COL_PAD) }),
1816
- /* @__PURE__ */ jsx2(Text2, { color: BORDER, children: "\u2502" })
1817
- ] }, i))
1818
- ] });
1819
- }
1820
- return /* @__PURE__ */ jsxs2(Box2, { flexDirection: "column", children: [
1821
- /* @__PURE__ */ jsx2(Text2, { color: BORDER, children: topLine }),
1822
- renderHeaderRow(columns),
1823
- /* @__PURE__ */ jsx2(Text2, { color: BORDER, children: midLine }),
1824
- rows.map((row, i) => /* @__PURE__ */ jsxs2(Box2, { flexDirection: "column", children: [
1825
- renderDataRow(row),
1826
- i < rows.length - 1 && /* @__PURE__ */ jsx2(Text2, { color: BORDER, children: midLine })
1827
- ] }, i)),
1828
- /* @__PURE__ */ jsx2(Text2, { color: BORDER, children: botLine })
1829
- ] });
1830
- }
1831
1755
 
1832
1756
  // src/ui/components/QueryResult.tsx
1833
1757
  import { jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
@@ -1839,82 +1763,11 @@ function ErrorBox({ message }) {
1839
1763
  line
1840
1764
  ] }, i)) });
1841
1765
  }
1842
- function formatDuration(ms) {
1843
- if (ms < 1e3) return `${ms}ms`;
1844
- return `${(ms / 1e3).toFixed(2)}s`;
1845
- }
1846
- function useTerminalWidth() {
1847
- const [width, setWidth] = useState3(process.stdout.columns ?? 80);
1848
- useEffect3(() => {
1849
- const handler = () => setWidth(process.stdout.columns ?? 80);
1850
- process.stdout.on("resize", handler);
1851
- return () => {
1852
- process.stdout.off("resize", handler);
1853
- };
1854
- }, []);
1855
- return width;
1856
- }
1857
- function QueryResult({ state, elapsed, page, pageSize }) {
1858
- const termWidth = useTerminalWidth();
1859
- if (state.status === "idle" || state.status === "running") return null;
1860
- const timing = elapsed !== null ? ` \xB7 ${formatDuration(elapsed)}` : "";
1861
- if (state.status === "error") {
1862
- return /* @__PURE__ */ jsxs3(Box3, { flexDirection: "column", children: [
1863
- /* @__PURE__ */ jsx3(ErrorBox, { message: state.message }),
1864
- elapsed !== null && /* @__PURE__ */ jsx3(Text3, { color: theme.accent, dimColor: true, children: formatDuration(elapsed) })
1865
- ] });
1866
- }
1867
- const { result } = state;
1868
- const columns = result.fields;
1869
- if (result.rows.length === 0) {
1870
- return /* @__PURE__ */ jsx3(Box3, { children: /* @__PURE__ */ jsxs3(Text3, { color: theme.accent, children: [
1871
- "No rows returned (",
1872
- result.rowCount ?? 0,
1873
- " affected)",
1874
- timing
1875
- ] }) });
1876
- }
1877
- const totalRows = result.rows.length;
1878
- const totalPages = Math.ceil(totalRows / pageSize);
1879
- const currentPage = Math.min(page, totalPages - 1);
1880
- const start = currentPage * pageSize;
1881
- const displayRows = result.rows.slice(start, start + pageSize);
1882
- const isPaged = totalRows > pageSize;
1883
- const widths = colWidths(columns, displayRows);
1884
- const tableWidth = 1 + widths.reduce((sum, w) => sum + w + 3, 0);
1885
- const expanded = tableWidth > termWidth;
1886
- return /* @__PURE__ */ jsxs3(Box3, { flexDirection: "column", children: [
1887
- /* @__PURE__ */ jsx3(Table, { columns, rows: displayRows, expanded }),
1888
- /* @__PURE__ */ jsxs3(Box3, { marginTop: 1, flexDirection: "column", children: [
1889
- isPaged && /* @__PURE__ */ jsxs3(Text3, { color: theme.warning, children: [
1890
- "Page ",
1891
- currentPage + 1,
1892
- " of ",
1893
- totalPages,
1894
- " \xB7 showing rows ",
1895
- start + 1,
1896
- "\u2013",
1897
- start + displayRows.length,
1898
- " of ",
1899
- totalRows,
1900
- currentPage > 0 ? " /prev" : "",
1901
- currentPage < totalPages - 1 ? " /next" : ""
1902
- ] }),
1903
- /* @__PURE__ */ jsxs3(Text3, { color: theme.accent, children: [
1904
- displayRows.length,
1905
- " row",
1906
- displayRows.length !== 1 ? "s" : "",
1907
- timing,
1908
- expanded ? " [expanded]" : ""
1909
- ] })
1910
- ] })
1911
- ] });
1912
- }
1913
1766
 
1914
1767
  // src/ui/components/Banner.tsx
1915
1768
  import { Box as Box4, Text as Text4 } from "ink";
1916
1769
  import { Fragment as Fragment2, jsx as jsx4, jsxs as jsxs4 } from "react/jsx-runtime";
1917
- var version = true ? "0.4.8" : process.env.npm_package_version ?? "unknown";
1770
+ var version = true ? "0.4.9" : process.env.npm_package_version ?? "unknown";
1918
1771
  var LOGO = [
1919
1772
  " \u2597\u2584\u2584\u2584\u2584\u2584\u2596",
1920
1773
  "\u2590\u2591 \u25CF \u25CF \u2591\u258C",
@@ -1963,56 +1816,40 @@ function Banner({ connectionState }) {
1963
1816
  ] });
1964
1817
  }
1965
1818
 
1966
- // src/ui/components/HelpView.tsx
1967
- import { Box as Box5, Text as Text5 } from "ink";
1968
- import { jsx as jsx5, jsxs as jsxs5 } from "react/jsx-runtime";
1969
- var USAGE_WIDTH = 28;
1970
- function HelpView({ data }) {
1971
- if (data.mode === "detail" && data.entry) {
1972
- const { usage, description, psqlAlias, detail, example, examples } = data.entry;
1973
- return /* @__PURE__ */ jsxs5(Box5, { flexDirection: "column", marginTop: 1, children: [
1974
- /* @__PURE__ */ jsxs5(Text5, { bold: true, color: "white", children: [
1975
- usage,
1976
- psqlAlias ? ` ${psqlAlias}` : ""
1977
- ] }),
1978
- /* @__PURE__ */ jsx5(Box5, { marginTop: 1, children: /* @__PURE__ */ jsx5(Text5, { children: description }) }),
1979
- detail && /* @__PURE__ */ jsx5(Box5, { marginTop: 1, children: /* @__PURE__ */ jsx5(Text5, { dimColor: true, children: detail }) }),
1980
- examples && examples.length > 0 ? /* @__PURE__ */ jsxs5(Box5, { flexDirection: "column", marginTop: 1, children: [
1981
- /* @__PURE__ */ jsx5(Text5, { dimColor: true, children: "Examples:" }),
1982
- examples.map((ex, i) => /* @__PURE__ */ jsx5(Box5, { marginLeft: 2, children: /* @__PURE__ */ jsx5(Text5, { color: theme.accent, children: ex }) }, i))
1983
- ] }) : example ? /* @__PURE__ */ jsxs5(Box5, { marginTop: 1, children: [
1984
- /* @__PURE__ */ jsx5(Text5, { dimColor: true, children: "Example: " }),
1985
- /* @__PURE__ */ jsx5(Text5, { color: theme.accent, children: example })
1986
- ] }) : null
1987
- ] });
1988
- }
1989
- if (data.mode === "list" && data.groups) {
1990
- return /* @__PURE__ */ jsxs5(Box5, { flexDirection: "column", marginTop: 1, children: [
1991
- data.groups.map((group, gi) => /* @__PURE__ */ jsxs5(Box5, { flexDirection: "column", marginBottom: gi < data.groups.length - 1 ? 1 : 0, children: [
1992
- /* @__PURE__ */ jsx5(Text5, { bold: true, color: theme.accent, children: group.category }),
1993
- group.entries.map((entry) => /* @__PURE__ */ jsxs5(Box5, { marginLeft: 2, children: [
1994
- /* @__PURE__ */ jsx5(Text5, { color: "white", children: entry.usage.padEnd(USAGE_WIDTH) }),
1995
- /* @__PURE__ */ jsx5(Text5, { dimColor: true, children: entry.description }),
1996
- entry.psqlAlias && /* @__PURE__ */ jsxs5(Text5, { dimColor: true, children: [
1997
- " ",
1998
- entry.psqlAlias
1999
- ] })
2000
- ] }, entry.name))
2001
- ] }, group.category)),
2002
- /* @__PURE__ */ jsx5(Box5, { marginTop: 1, children: /* @__PURE__ */ jsxs5(Text5, { dimColor: true, children: [
2003
- "/help ",
2004
- "<command>",
2005
- " for more details."
2006
- ] }) })
2007
- ] });
2008
- }
2009
- return null;
2010
- }
2011
-
2012
- // src/ui/components/ErdView.tsx
2013
- import { Box as Box6, Text as Text6 } from "ink";
2014
- import { Fragment as Fragment3, jsx as jsx6, jsxs as jsxs6 } from "react/jsx-runtime";
2015
- var TABLE_COLORS = [
1819
+ // src/ui/format.ts
1820
+ var R = "\x1B[0m";
1821
+ var BOLD = "\x1B[1m";
1822
+ var DIM = "\x1B[2m";
1823
+ function fg(hex) {
1824
+ const r = parseInt(hex.slice(1, 3), 16);
1825
+ const g = parseInt(hex.slice(3, 5), 16);
1826
+ const b = parseInt(hex.slice(5, 7), 16);
1827
+ return `\x1B[38;2;${r};${g};${b}m`;
1828
+ }
1829
+ function c(hex, s) {
1830
+ return fg(hex) + s + R;
1831
+ }
1832
+ function bold(s) {
1833
+ return BOLD + s + R;
1834
+ }
1835
+ function dim(s) {
1836
+ return DIM + s + R;
1837
+ }
1838
+ function cbold(hex, s) {
1839
+ return fg(hex) + BOLD + s + R;
1840
+ }
1841
+ function cdim(hex, s) {
1842
+ return fg(hex) + DIM + s + R;
1843
+ }
1844
+ var ACCENT2 = "#818cf8";
1845
+ var HEADER_COL = "#9ca3af";
1846
+ var NULL_COL = "#6366f1";
1847
+ var INDIGO = "#818cf8";
1848
+ var AI_COL = "#a5b4fc";
1849
+ var ERROR_COL = "#ff4444";
1850
+ var WARN_COL = "#f59e0b";
1851
+ var ERD_BORDER = "#4b5563";
1852
+ var ERD_PALETTE = [
2016
1853
  "#f472b6",
2017
1854
  "#34d399",
2018
1855
  "#fb923c",
@@ -2022,30 +1859,179 @@ var TABLE_COLORS = [
2022
1859
  "#fbbf24",
2023
1860
  "#2dd4bf"
2024
1861
  ];
2025
- var BORDER2 = "#4b5563";
2026
- var PAD = 1;
2027
- var GAP = 2;
2028
- var FK_PREFIX = "FK \u2192 ";
2029
- function computeMetrics(table) {
2030
- const nameW = Math.max(2, ...table.columns.map((c) => c.name.length));
2031
- const typeW = Math.max(4, ...table.columns.map((c) => c.type.length));
2032
- const keyW = Math.max(
2033
- 2,
2034
- ...table.columns.map((c) => {
2035
- if (c.isPk) return 2;
2036
- if (c.fkTable) return FK_PREFIX.length + c.fkTable.length;
2037
- return 0;
2038
- })
2039
- );
2040
- const totalW = 4 + 3 * PAD * 2 + nameW + typeW + keyW;
2041
- return { nameW, typeW, keyW, totalW };
1862
+ var NULL_MARKER = "\u2205";
1863
+ var COL_PAD = 1;
1864
+ var SP = " ".repeat(COL_PAD);
1865
+ function fmtHeader(label, query) {
1866
+ const dot = cbold(ACCENT2, "\u25CF ");
1867
+ if (query.includes("\n")) {
1868
+ const lines = query.split("\n").map((l) => cbold(HEADER_COL, " " + l));
1869
+ return dot + cbold(HEADER_COL, label + ":") + "\n" + lines.join("\n");
1870
+ }
1871
+ return dot + cbold(HEADER_COL, `${label}(${query})`);
1872
+ }
1873
+ function fmtError(message) {
1874
+ return message.split("\n").map(
1875
+ (line, i) => cbold(ERROR_COL, (i === 0 ? "\u2717 " : " ") + line)
1876
+ ).join("\n");
1877
+ }
1878
+ function fmtOk(text) {
1879
+ return c(ACCENT2, "\u2713 ") + text;
1880
+ }
1881
+ function isNull(v) {
1882
+ return v === null || v === void 0;
1883
+ }
1884
+ function cellStr(v) {
1885
+ if (isNull(v)) return NULL_MARKER;
1886
+ if (v instanceof Date) return v.toISOString();
1887
+ if (typeof v === "object") return JSON.stringify(v);
1888
+ return String(v);
1889
+ }
1890
+ function colWidths2(columns, rows) {
1891
+ return columns.map((col) => {
1892
+ const dataMax = rows.reduce((mx, row) => Math.max(mx, cellStr(row[col]).length), 0);
1893
+ return Math.max(col.length, dataMax);
1894
+ });
1895
+ }
1896
+ function hline(widths, l, m, r) {
1897
+ return l + widths.map((w) => "\u2500".repeat(w + COL_PAD * 2)).join(m) + r;
1898
+ }
1899
+ function fmtTable(columns, rows) {
1900
+ const widths = colWidths2(columns, rows);
1901
+ const top = hline(widths, "\u256D", "\u252C", "\u256E");
1902
+ const mid = hline(widths, "\u251C", "\u253C", "\u2524");
1903
+ const bot = hline(widths, "\u2570", "\u2534", "\u256F");
1904
+ function headerRow() {
1905
+ const cells = columns.map(
1906
+ (col, i) => cbold(INDIGO, SP + col.slice(0, widths[i]).padEnd(widths[i]) + SP)
1907
+ );
1908
+ return "\u2502" + cells.join("\u2502") + "\u2502";
1909
+ }
1910
+ function dataRow(row) {
1911
+ const cells = columns.map((col, i) => {
1912
+ const v = cellStr(row[col]);
1913
+ const cell = SP + v.slice(0, widths[i]).padEnd(widths[i]) + SP;
1914
+ return isNull(row[col]) ? cdim(NULL_COL, cell) : cell;
1915
+ });
1916
+ return "\u2502" + cells.join("\u2502") + "\u2502";
1917
+ }
1918
+ const out = [top, headerRow(), mid];
1919
+ rows.forEach((row, i) => {
1920
+ out.push(dataRow(row));
1921
+ if (i < rows.length - 1) out.push(mid);
1922
+ });
1923
+ out.push(bot);
1924
+ return out.join("\n");
1925
+ }
1926
+ function fmtExpanded(columns, rows) {
1927
+ const kw = columns.reduce((mx, c2) => Math.max(mx, c2.length), 0);
1928
+ const separator = (i) => "\u2500[ Record " + (i + 1) + " ]" + "\u2500".repeat(Math.max(0, kw + 14 - String(i + 1).length));
1929
+ const out = [];
1930
+ rows.forEach((row, i) => {
1931
+ if (i > 0) out.push("");
1932
+ out.push(dim(separator(i)));
1933
+ for (const col of columns) {
1934
+ const val = isNull(row[col]) ? cdim(NULL_COL, NULL_MARKER) : cellStr(row[col]);
1935
+ out.push(cbold(INDIGO, col.padEnd(kw)) + dim(" \u2502 ") + val);
1936
+ }
1937
+ });
1938
+ return out.join("\n");
1939
+ }
1940
+ function fmtDuration(ms) {
1941
+ return ms < 1e3 ? `${ms}ms` : `${(ms / 1e3).toFixed(2)}s`;
1942
+ }
1943
+ function fmtQueryResult(state, elapsed, page, pageSize) {
1944
+ if (state.status === "idle" || state.status === "running") return "";
1945
+ const timing = elapsed !== null ? ` \xB7 ${fmtDuration(elapsed)}` : "";
1946
+ if (state.status === "error") {
1947
+ const t = elapsed !== null ? "\n" + cdim(ACCENT2, fmtDuration(elapsed)) : "";
1948
+ return fmtError(state.message) + t;
1949
+ }
1950
+ const { result } = state;
1951
+ const { fields, rows } = result;
1952
+ if (rows.length === 0) {
1953
+ return c(ACCENT2, `No rows returned (${result.rowCount ?? 0} affected)${timing}`);
1954
+ }
1955
+ const totalRows = rows.length;
1956
+ const totalPages = Math.ceil(totalRows / pageSize);
1957
+ const currentPage = Math.min(page, totalPages - 1);
1958
+ const start = currentPage * pageSize;
1959
+ const displayRows = rows.slice(start, start + pageSize);
1960
+ const isPaged = totalRows > pageSize;
1961
+ const termWidth = process.stdout.columns ?? 80;
1962
+ const widths = colWidths2(fields, displayRows);
1963
+ const tableWidth = 1 + widths.reduce((sum, w) => sum + w + 3, 0);
1964
+ const expanded = tableWidth > termWidth;
1965
+ const table = expanded ? fmtExpanded(fields, displayRows) : fmtTable(fields, displayRows);
1966
+ const lines = [table];
1967
+ if (isPaged) {
1968
+ const nav = (currentPage > 0 ? " /prev" : "") + (currentPage < totalPages - 1 ? " /next" : "");
1969
+ lines.push(c(WARN_COL, `Page ${currentPage + 1} of ${totalPages} \xB7 rows ${start + 1}\u2013${start + displayRows.length} of ${totalRows}${nav}`));
1970
+ }
1971
+ lines.push(c(ACCENT2, `${displayRows.length} row${displayRows.length !== 1 ? "s" : ""}${timing}${expanded ? " [expanded]" : ""}`));
1972
+ return lines.join("\n");
2042
1973
  }
2043
- function groupIntoRows(metrics, termW) {
1974
+ var USAGE_WIDTH = 28;
1975
+ function fmtHelp(data) {
1976
+ if (data.mode === "detail" && data.entry) {
1977
+ const { usage, description, psqlAlias, detail, example, examples } = data.entry;
1978
+ const lines = [];
1979
+ lines.push(bold(usage) + (psqlAlias ? " " + dim(psqlAlias) : ""));
1980
+ lines.push("");
1981
+ lines.push(description);
1982
+ if (detail) {
1983
+ lines.push("");
1984
+ lines.push(dim(detail));
1985
+ }
1986
+ if (examples && examples.length > 0) {
1987
+ lines.push("");
1988
+ lines.push(dim("Examples:"));
1989
+ for (const ex of examples) lines.push(" " + c(ACCENT2, ex));
1990
+ } else if (example) {
1991
+ lines.push("");
1992
+ lines.push(dim("Example: ") + c(ACCENT2, example));
1993
+ }
1994
+ return lines.join("\n");
1995
+ }
1996
+ if (data.mode === "list" && data.groups) {
1997
+ const lines = [];
1998
+ data.groups.forEach((group, gi) => {
1999
+ if (gi > 0) lines.push("");
2000
+ lines.push(cbold(ACCENT2, group.category));
2001
+ for (const entry of group.entries) {
2002
+ const alias = entry.psqlAlias ? dim(" " + entry.psqlAlias) : "";
2003
+ lines.push(" " + entry.usage.padEnd(USAGE_WIDTH) + dim(entry.description) + alias);
2004
+ }
2005
+ });
2006
+ lines.push("");
2007
+ lines.push(dim("/help <command> for more details."));
2008
+ return lines.join("\n");
2009
+ }
2010
+ return "";
2011
+ }
2012
+ function fmtErd(data) {
2013
+ if (data.tables.length === 0) return dim("No tables found in the current schema.");
2014
+ const termW = process.stdout.columns ?? 80;
2015
+ const FK_PREFIX = "FK \u2192 ";
2016
+ const PAD = 1;
2017
+ const GAP = 2;
2018
+ const colorMap = new Map(
2019
+ data.tables.map((t, i) => [t.name, ERD_PALETTE[i % ERD_PALETTE.length]])
2020
+ );
2021
+ function metrics(t) {
2022
+ const nameW = Math.max(2, ...t.columns.map((c2) => c2.name.length));
2023
+ const typeW = Math.max(4, ...t.columns.map((c2) => c2.type.length));
2024
+ const keyW = Math.max(2, ...t.columns.map(
2025
+ (c2) => c2.isPk ? 2 : c2.fkTable ? FK_PREFIX.length + c2.fkTable.length : 0
2026
+ ));
2027
+ const totalW = 4 + 3 * PAD * 2 + nameW + typeW + keyW;
2028
+ return { nameW, typeW, keyW, totalW };
2029
+ }
2030
+ const allMetrics = data.tables.map(metrics);
2044
2031
  const rows = [];
2045
- let row = [];
2046
- let usedW = 0;
2047
- for (let i = 0; i < metrics.length; i++) {
2048
- const w = metrics[i].totalW;
2032
+ let row = [], usedW = 0;
2033
+ for (let i = 0; i < allMetrics.length; i++) {
2034
+ const w = allMetrics[i].totalW;
2049
2035
  if (row.length === 0) {
2050
2036
  row.push(i);
2051
2037
  usedW = w;
@@ -2059,120 +2045,113 @@ function groupIntoRows(metrics, termW) {
2059
2045
  }
2060
2046
  }
2061
2047
  if (row.length > 0) rows.push(row);
2062
- return rows;
2063
- }
2064
- function TableBox({ table, m, color, colorMap }) {
2065
- const { nameW, typeW, keyW, totalW } = m;
2066
- const sp = " ".repeat(PAD);
2067
- const p = (s, w) => s.slice(0, w).padEnd(w);
2068
- const top = "\u256D" + "\u2500".repeat(totalW - 2) + "\u256E";
2069
- const sep = "\u251C" + "\u2500".repeat(nameW + PAD * 2) + "\u252C" + "\u2500".repeat(typeW + PAD * 2) + "\u252C" + "\u2500".repeat(keyW + PAD * 2) + "\u2524";
2070
- const bot = "\u2570" + "\u2500".repeat(nameW + PAD * 2) + "\u2534" + "\u2500".repeat(typeW + PAD * 2) + "\u2534" + "\u2500".repeat(keyW + PAD * 2) + "\u256F";
2071
- const headerW = totalW - 4;
2072
- return /* @__PURE__ */ jsxs6(Box6, { flexDirection: "column", children: [
2073
- /* @__PURE__ */ jsx6(Text6, { color: BORDER2, children: top }),
2074
- /* @__PURE__ */ jsxs6(Box6, { children: [
2075
- /* @__PURE__ */ jsx6(Text6, { color: BORDER2, children: "\u2502" }),
2076
- /* @__PURE__ */ jsxs6(Text6, { color, bold: true, children: [
2077
- sp,
2078
- p(table.name, headerW),
2079
- sp
2080
- ] }),
2081
- /* @__PURE__ */ jsx6(Text6, { color: BORDER2, children: "\u2502" })
2082
- ] }),
2083
- /* @__PURE__ */ jsx6(Text6, { color: BORDER2, children: sep }),
2084
- table.columns.map((col, i) => /* @__PURE__ */ jsxs6(Box6, { children: [
2085
- /* @__PURE__ */ jsx6(Text6, { color: BORDER2, children: "\u2502" }),
2086
- /* @__PURE__ */ jsxs6(Text6, { children: [
2087
- sp,
2088
- p(col.name, nameW),
2089
- sp
2090
- ] }),
2091
- /* @__PURE__ */ jsx6(Text6, { color: BORDER2, children: "\u2502" }),
2092
- /* @__PURE__ */ jsxs6(Text6, { dimColor: true, children: [
2093
- sp,
2094
- p(col.type, typeW),
2095
- sp
2096
- ] }),
2097
- /* @__PURE__ */ jsx6(Text6, { color: BORDER2, children: "\u2502" }),
2098
- col.isPk ? /* @__PURE__ */ jsxs6(Text6, { bold: true, children: [
2099
- sp,
2100
- p("PK", keyW),
2101
- sp
2102
- ] }) : col.fkTable ? /* @__PURE__ */ jsxs6(Fragment3, { children: [
2103
- /* @__PURE__ */ jsxs6(Text6, { dimColor: true, children: [
2104
- sp,
2105
- FK_PREFIX
2106
- ] }),
2107
- /* @__PURE__ */ jsxs6(Text6, { color: colorMap.get(col.fkTable) ?? color, children: [
2108
- p(col.fkTable, keyW - FK_PREFIX.length),
2109
- sp
2110
- ] })
2111
- ] }) : /* @__PURE__ */ jsxs6(Text6, { children: [
2112
- sp,
2113
- " ".repeat(keyW),
2114
- sp
2115
- ] }),
2116
- /* @__PURE__ */ jsx6(Text6, { color: BORDER2, children: "\u2502" })
2117
- ] }, i)),
2118
- /* @__PURE__ */ jsx6(Text6, { color: BORDER2, children: bot })
2119
- ] });
2048
+ function renderTable(t, m, color) {
2049
+ const { nameW, typeW, keyW, totalW } = m;
2050
+ const sp = " ".repeat(PAD);
2051
+ const p = (s, w) => s.slice(0, w).padEnd(w);
2052
+ const bdr = (s) => c(ERD_BORDER, s);
2053
+ const tc = (s) => cbold(color, s);
2054
+ const top = bdr("\u256D" + "\u2500".repeat(totalW - 2) + "\u256E");
2055
+ const headerW = totalW - 4;
2056
+ const headerLine = bdr("\u2502") + tc(sp + p(t.name, headerW) + sp) + bdr("\u2502");
2057
+ const sep = bdr("\u251C" + "\u2500".repeat(nameW + PAD * 2) + "\u252C" + "\u2500".repeat(typeW + PAD * 2) + "\u252C" + "\u2500".repeat(keyW + PAD * 2) + "\u2524");
2058
+ const bot = bdr("\u2570" + "\u2500".repeat(nameW + PAD * 2) + "\u2534" + "\u2500".repeat(typeW + PAD * 2) + "\u2534" + "\u2500".repeat(keyW + PAD * 2) + "\u256F");
2059
+ const out = [top, headerLine, sep];
2060
+ for (const col of t.columns) {
2061
+ let keyPart;
2062
+ if (col.isPk) {
2063
+ keyPart = sp + bold(p("PK", keyW)) + sp;
2064
+ } else if (col.fkTable) {
2065
+ const fkColor = colorMap.get(col.fkTable) ?? color;
2066
+ keyPart = sp + dim(FK_PREFIX) + c(fkColor, p(col.fkTable, keyW - FK_PREFIX.length)) + sp;
2067
+ } else {
2068
+ keyPart = sp + " ".repeat(keyW) + sp;
2069
+ }
2070
+ out.push(
2071
+ bdr("\u2502") + sp + p(col.name, nameW) + sp + bdr("\u2502") + dim(sp + p(col.type, typeW) + sp) + bdr("\u2502") + keyPart + bdr("\u2502")
2072
+ );
2073
+ }
2074
+ out.push(bot);
2075
+ return out;
2076
+ }
2077
+ const output = [];
2078
+ for (const tableRow of rows) {
2079
+ const blocks = tableRow.map((ti) => {
2080
+ const t = data.tables[ti];
2081
+ return renderTable(t, allMetrics[ti], colorMap.get(t.name) ?? ERD_PALETTE[0]);
2082
+ });
2083
+ const height = Math.max(...blocks.map((b) => b.length));
2084
+ for (let line = 0; line < height; line++) {
2085
+ const parts = blocks.map((b, j) => {
2086
+ const l = b[line] ?? " ".repeat(allMetrics[tableRow[j]].totalW);
2087
+ return j < blocks.length - 1 ? l + " ".repeat(GAP) : l;
2088
+ });
2089
+ output.push(parts.join(""));
2090
+ }
2091
+ output.push("");
2092
+ }
2093
+ return output.join("\n").trimEnd();
2120
2094
  }
2121
- function ErdView({ data }) {
2122
- if (data.tables.length === 0) {
2123
- return /* @__PURE__ */ jsx6(Text6, { dimColor: true, children: "No tables found in the current schema." });
2095
+ function fmtAi(text, error) {
2096
+ const lines = [cbold(ACCENT2, "Explanation:"), ""];
2097
+ if (error) {
2098
+ lines.push(fmtError(error));
2099
+ } else {
2100
+ lines.push(c(AI_COL, text));
2124
2101
  }
2125
- const termW = process.stdout.columns ?? 80;
2126
- const metrics = data.tables.map(computeMetrics);
2127
- const colorMap = new Map(
2128
- data.tables.map((t, i) => [t.name, TABLE_COLORS[i % TABLE_COLORS.length]])
2129
- );
2130
- const rows = groupIntoRows(metrics, termW);
2131
- return /* @__PURE__ */ jsx6(Box6, { flexDirection: "column", marginTop: 1, children: rows.map((row, ri) => /* @__PURE__ */ jsx6(Box6, { flexDirection: "row", marginBottom: ri < rows.length - 1 ? 1 : 0, children: row.map((ti, j) => /* @__PURE__ */ jsx6(Box6, { marginRight: j < row.length - 1 ? GAP : 0, children: /* @__PURE__ */ jsx6(
2132
- TableBox,
2133
- {
2134
- table: data.tables[ti],
2135
- m: metrics[ti],
2136
- color: colorMap.get(data.tables[ti].name) ?? BORDER2,
2137
- colorMap
2102
+ return lines.join("\n");
2103
+ }
2104
+ function fmtEntry(entry) {
2105
+ const isShell = entry.query.startsWith("!");
2106
+ const isCommand = !isShell && (entry.query.startsWith("/") || entry.query.startsWith("\\"));
2107
+ const label = isShell ? "Shell" : isCommand ? "Command" : "Query";
2108
+ const lines = [" " + fmtHeader(label, entry.query), ""];
2109
+ if (isShell) {
2110
+ if (entry.shellOutput !== null) lines.push(" " + entry.shellOutput.replace(/\n/g, "\n "));
2111
+ } else if (entry.commandMessage) {
2112
+ if (entry.commandMessage.helpData) {
2113
+ lines.push(fmtHelp(entry.commandMessage.helpData).replace(/\n/g, "\n "));
2114
+ } else if (entry.commandMessage.ok) {
2115
+ lines.push(" " + fmtOk(entry.commandMessage.text));
2116
+ } else {
2117
+ lines.push(" " + fmtError(entry.commandMessage.text));
2138
2118
  }
2139
- ) }, ti)) }, ri)) });
2119
+ } else if (entry.erdData) {
2120
+ lines.push(" " + fmtErd(entry.erdData).replace(/\n/g, "\n "));
2121
+ } else if (entry.aiResponse || entry.aiError) {
2122
+ lines.push(" " + fmtAi(entry.aiResponse, entry.aiError).replace(/\n/g, "\n "));
2123
+ } else {
2124
+ const result = fmtQueryResult(entry.queryState, entry.elapsed, entry.page, 50);
2125
+ if (result) lines.push(" " + result.replace(/\n/g, "\n "));
2126
+ }
2127
+ lines.push("");
2128
+ return lines.join("\n");
2140
2129
  }
2141
2130
 
2142
2131
  // src/ui/components/App.tsx
2143
- import { Fragment as Fragment4, jsx as jsx7, jsxs as jsxs7 } from "react/jsx-runtime";
2144
- var PAGE_SIZE = 50;
2132
+ import { jsx as jsx5, jsxs as jsxs5 } from "react/jsx-runtime";
2145
2133
  var PLACEHOLDER2 = "#a5b4fc";
2146
- function activePageSize() {
2147
- return Math.max(3, (process.stdout.rows ?? 24) - 21);
2148
- }
2149
- function limitLines(s, n) {
2150
- const lines = s.split("\n");
2151
- if (lines.length <= n) return s;
2152
- return lines.slice(0, n).join("\n") + `
2153
- \u2026 +${lines.length - n} more lines (scroll up after next submit)`;
2154
- }
2155
2134
  var QUERY_HEADER_COLOR = "#9ca3af";
2156
2135
  function QueryHeader({ label, query }) {
2157
2136
  const isMultiLine = query.includes("\n");
2158
2137
  if (isMultiLine) {
2159
- return /* @__PURE__ */ jsxs7(Box7, { flexDirection: "column", children: [
2160
- /* @__PURE__ */ jsxs7(Text7, { children: [
2161
- /* @__PURE__ */ jsx7(Text7, { color: theme.accent, bold: true, children: "\u25CF " }),
2162
- /* @__PURE__ */ jsxs7(Text7, { color: QUERY_HEADER_COLOR, bold: true, children: [
2138
+ return /* @__PURE__ */ jsxs5(Box5, { flexDirection: "column", children: [
2139
+ /* @__PURE__ */ jsxs5(Text5, { children: [
2140
+ /* @__PURE__ */ jsx5(Text5, { color: theme.accent, bold: true, children: "\u25CF " }),
2141
+ /* @__PURE__ */ jsxs5(Text5, { color: QUERY_HEADER_COLOR, bold: true, children: [
2163
2142
  label,
2164
2143
  ":"
2165
2144
  ] })
2166
2145
  ] }),
2167
- query.split("\n").map((line, i) => /* @__PURE__ */ jsxs7(Text7, { color: QUERY_HEADER_COLOR, bold: true, children: [
2146
+ query.split("\n").map((line, i) => /* @__PURE__ */ jsxs5(Text5, { color: QUERY_HEADER_COLOR, bold: true, children: [
2168
2147
  " ",
2169
2148
  line
2170
2149
  ] }, i))
2171
2150
  ] });
2172
2151
  }
2173
- return /* @__PURE__ */ jsxs7(Text7, { children: [
2174
- /* @__PURE__ */ jsx7(Text7, { color: theme.accent, bold: true, children: "\u25CF " }),
2175
- /* @__PURE__ */ jsxs7(Text7, { color: QUERY_HEADER_COLOR, bold: true, children: [
2152
+ return /* @__PURE__ */ jsxs5(Text5, { children: [
2153
+ /* @__PURE__ */ jsx5(Text5, { color: theme.accent, bold: true, children: "\u25CF " }),
2154
+ /* @__PURE__ */ jsxs5(Text5, { color: QUERY_HEADER_COLOR, bold: true, children: [
2176
2155
  label,
2177
2156
  "(",
2178
2157
  query,
@@ -2180,54 +2159,31 @@ function QueryHeader({ label, query }) {
2180
2159
  ] })
2181
2160
  ] });
2182
2161
  }
2183
- function EntryView({ entry }) {
2184
- const showAi = entry.aiResponse !== "" || entry.aiError !== null;
2185
- const showErd = entry.erdData !== null;
2186
- const isShell = entry.query.startsWith("!");
2187
- const isCommand = !isShell && (entry.query.startsWith("/") || entry.query.startsWith("\\"));
2188
- const label = isShell ? "Shell" : isCommand ? "Command" : "Query";
2189
- return /* @__PURE__ */ jsxs7(Box7, { flexDirection: "column", marginBottom: 1, paddingX: 1, children: [
2190
- /* @__PURE__ */ jsx7(QueryHeader, { label, query: entry.query }),
2191
- /* @__PURE__ */ jsx7(Box7, { marginTop: 1, flexDirection: "column", children: isShell ? entry.shellOutput !== null && /* @__PURE__ */ jsx7(Text7, { children: entry.shellOutput || "(no output)" }) : /* @__PURE__ */ jsxs7(Fragment4, { children: [
2192
- entry.commandMessage && (entry.commandMessage.helpData ? /* @__PURE__ */ jsx7(HelpView, { data: entry.commandMessage.helpData }) : entry.commandMessage.ok ? /* @__PURE__ */ jsxs7(Text7, { color: theme.accent, children: [
2193
- "\u2713 ",
2194
- entry.commandMessage.text
2195
- ] }) : /* @__PURE__ */ jsx7(ErrorBox, { message: entry.commandMessage.text })),
2196
- showErd ? /* @__PURE__ */ jsx7(ErdView, { data: entry.erdData }) : showAi ? /* @__PURE__ */ jsxs7(Box7, { flexDirection: "column", children: [
2197
- /* @__PURE__ */ jsx7(Text7, { color: theme.accent, bold: true, children: "Explanation:" }),
2198
- /* @__PURE__ */ jsx7(Box7, { flexDirection: "column", marginTop: 1, children: entry.aiError ? /* @__PURE__ */ jsx7(ErrorBox, { message: entry.aiError }) : /* @__PURE__ */ jsx7(Text7, { color: PLACEHOLDER2, children: entry.aiResponse }) })
2199
- ] }) : !entry.commandMessage && /* @__PURE__ */ jsx7(QueryResult, { state: entry.queryState, elapsed: entry.elapsed, page: entry.page, pageSize: PAGE_SIZE })
2200
- ] }) })
2201
- ] });
2202
- }
2203
2162
  function App({ connectionState, aiUrl: aiUrl2, aiModel: aiModel2, aiKey: aiKey2, onChangeDatabase }) {
2204
2163
  const { exit } = useApp();
2205
2164
  const { isRawModeSupported } = useStdin2();
2206
- const [queryState, setQueryState] = useState4({ status: "idle" });
2207
- const [lastQuery, setLastQuery] = useState4("");
2165
+ const [active, setActive] = useState4({ type: "idle" });
2166
+ const [hasHistory, setHasHistory] = useState4(false);
2167
+ const [completedEntries, setCompletedEntries] = useState4([]);
2168
+ const entryIdRef = useRef2(0);
2208
2169
  const [lastSqlQuery, setLastSqlQuery] = useState4("");
2209
2170
  const [lastResult, setLastResult] = useState4(null);
2210
- const [page, setPage] = useState4(0);
2171
+ const [lastResultPage, setLastResultPage] = useState4(0);
2211
2172
  const [vimMode, setVimMode] = useState4("INSERT");
2212
2173
  const [inputIsShell, setInputIsShell] = useState4(false);
2213
- const [elapsed, setElapsed] = useState4(null);
2214
2174
  const [vimEnabled, setVimEnabled] = useState4(true);
2215
- const [commandMessage, setCommandMessage] = useState4(null);
2216
2175
  const [history, setHistory] = useState4(() => loadHistory());
2217
2176
  const [schema, setSchema] = useState4(null);
2218
- const [aiResponse, setAiResponse] = useState4("");
2219
- const [isStreaming, setIsStreaming] = useState4(false);
2220
- const [aiError, setAiError] = useState4(null);
2221
- const [shellOutput, setShellOutput] = useState4(null);
2222
- const [isShellRunning, setIsShellRunning] = useState4(false);
2223
- const [erdData, setErdData] = useState4(null);
2224
- const [isErdLoading, setIsErdLoading] = useState4(false);
2225
- const [completedEntries, setCompletedEntries] = useState4([]);
2226
- const entryIdRef = useRef2(0);
2227
2177
  const aliasScope = connectionState.status === "connected" ? makeScope(connectionState.driver, connectionState.user, connectionState.host, connectionState.database) : "";
2228
2178
  const [aliases, setAliases] = useState4(
2229
2179
  () => aliasScope ? getAllAliases(aliasScope) : {}
2230
2180
  );
2181
+ function writeEntry(entry) {
2182
+ const formatted = fmtEntry(entry);
2183
+ const id = String(++entryIdRef.current);
2184
+ setCompletedEntries((prev) => [...prev, { id, formatted }]);
2185
+ setHasHistory(true);
2186
+ }
2231
2187
  function handleSaveAlias(name, query) {
2232
2188
  saveAlias(aliasScope, name, query);
2233
2189
  setAliases(getAllAliases(aliasScope));
@@ -2271,65 +2227,55 @@ function App({ connectionState, aiUrl: aiUrl2, aiModel: aiModel2, aiKey: aiKey2,
2271
2227
  },
2272
2228
  { isActive: isRawModeSupported }
2273
2229
  );
2274
- async function handleExplain(query) {
2275
- setAiResponse("");
2276
- setAiError(null);
2277
- setIsStreaming(true);
2278
- setCommandMessage(null);
2279
- setQueryState({ status: "idle" });
2280
- try {
2281
- for await (const chunk of streamExplain(query, aiUrl2, aiModel2, aiKey2 || void 0)) {
2282
- setAiResponse((prev) => prev + chunk);
2283
- }
2284
- } catch (err) {
2285
- setAiError(err instanceof Error ? err.message : String(err));
2286
- } finally {
2287
- setIsStreaming(false);
2230
+ async function handleQuery(sql) {
2231
+ if (connectionState.status !== "connected") return;
2232
+ setLastSqlQuery(sql);
2233
+ setActive({ type: "loading", label: "Query", query: sql });
2234
+ const updated = addToHistory(history, sql);
2235
+ setHistory(updated);
2236
+ saveHistory(updated);
2237
+ const start = Date.now();
2238
+ const result = await runQuery(connectionState.client, sql);
2239
+ const elapsed = Date.now() - start;
2240
+ if (result.status === "success") {
2241
+ setLastResult(result.result);
2242
+ setLastResultPage(0);
2288
2243
  }
2244
+ writeEntry({ query: sql, commandMessage: null, queryState: result, elapsed, page: 0, aiResponse: "", aiError: null, shellOutput: null, erdData: null });
2245
+ setActive({ type: "idle" });
2289
2246
  }
2290
2247
  async function handleErd() {
2291
2248
  if (connectionState.status !== "connected") {
2292
- setCommandMessage({ ok: false, text: "Not connected to a database." });
2249
+ writeEntry({ query: "/erd", commandMessage: { ok: false, text: "Not connected." }, queryState: { status: "idle" }, elapsed: null, page: 0, aiResponse: "", aiError: null, shellOutput: null, erdData: null });
2293
2250
  return;
2294
2251
  }
2295
- setErdData(null);
2296
- setIsErdLoading(true);
2297
- setCommandMessage(null);
2298
- setQueryState({ status: "idle" });
2299
- setAiResponse("");
2300
- setAiError(null);
2252
+ setActive({ type: "loading", label: "Command", query: "/erd" });
2301
2253
  try {
2302
2254
  const data = await fetchErd(connectionState.client, connectionState.driver);
2303
- setErdData(data);
2255
+ writeEntry({ query: "/erd", commandMessage: null, queryState: { status: "idle" }, elapsed: null, page: 0, aiResponse: "", aiError: null, shellOutput: null, erdData: data });
2304
2256
  } catch (err) {
2305
- setCommandMessage({ ok: false, text: err instanceof Error ? err.message : String(err) });
2306
- } finally {
2307
- setIsErdLoading(false);
2257
+ writeEntry({ query: "/erd", commandMessage: { ok: false, text: err instanceof Error ? err.message : String(err) }, queryState: { status: "idle" }, elapsed: null, page: 0, aiResponse: "", aiError: null, shellOutput: null, erdData: null });
2308
2258
  }
2259
+ setActive({ type: "idle" });
2309
2260
  }
2310
- async function handleQuery(sql) {
2311
- if (connectionState.status !== "connected") return;
2312
- setErdData(null);
2313
- setAiResponse("");
2314
- setAiError(null);
2315
- setCommandMessage(null);
2316
- setLastQuery(sql);
2317
- setLastSqlQuery(sql);
2318
- setElapsed(null);
2319
- setPage(0);
2320
- setQueryState({ status: "running" });
2321
- const updated = addToHistory(history, sql);
2322
- setHistory(updated);
2323
- saveHistory(updated);
2324
- const start = Date.now();
2325
- const result = await runQuery(connectionState.client, sql);
2326
- setElapsed(Date.now() - start);
2327
- setQueryState(result);
2328
- if (result.status === "success") setLastResult(result.result);
2261
+ async function handleExplain(query) {
2262
+ setActive({ type: "streaming", query, text: "", error: null });
2263
+ let fullText = "";
2264
+ let error = null;
2265
+ try {
2266
+ for await (const chunk of streamExplain(query, aiUrl2, aiModel2, aiKey2 || void 0)) {
2267
+ fullText += chunk;
2268
+ setActive({ type: "streaming", query, text: fullText, error: null });
2269
+ }
2270
+ } catch (err) {
2271
+ error = err instanceof Error ? err.message : String(err);
2272
+ }
2273
+ writeEntry({ query: "/explain", commandMessage: null, queryState: { status: "idle" }, elapsed: null, page: 0, aiResponse: fullText, aiError: error, shellOutput: null, erdData: null });
2274
+ setActive({ type: "idle" });
2329
2275
  }
2330
2276
  function handleExport(format) {
2331
2277
  if (!lastResult || lastResult.rows.length === 0) {
2332
- setCommandMessage({ ok: false, text: "No results to export \u2014 run a query first." });
2278
+ writeEntry({ query: `/export ${format}`, commandMessage: { ok: false, text: "No results to export \u2014 run a query first." }, queryState: { status: "idle" }, elapsed: null, page: 0, aiResponse: "", aiError: null, shellOutput: null, erdData: null });
2333
2279
  return;
2334
2280
  }
2335
2281
  const ts = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-").slice(0, 19);
@@ -2349,57 +2295,36 @@ function App({ connectionState, aiUrl: aiUrl2, aiModel: aiModel2, aiKey: aiKey2,
2349
2295
  );
2350
2296
  writeFileSync5(filename, [header, ...rows].join("\n"));
2351
2297
  }
2352
- setCommandMessage({ ok: true, text: `Exported to ${filename}` });
2298
+ writeEntry({ query: `/export ${format}`, commandMessage: { ok: true, text: `Exported to ${filename}` }, queryState: { status: "idle" }, elapsed: null, page: 0, aiResponse: "", aiError: null, shellOutput: null, erdData: null });
2353
2299
  } catch (err) {
2354
- setCommandMessage({ ok: false, text: err instanceof Error ? err.message : String(err) });
2355
- }
2356
- }
2357
- function snapshotActiveEntry() {
2358
- if (lastQuery === "") return;
2359
- setCompletedEntries((prev) => [
2360
- ...prev,
2361
- {
2362
- id: entryIdRef.current++,
2363
- query: lastQuery,
2364
- commandMessage,
2365
- queryState,
2366
- elapsed,
2367
- page,
2368
- aiResponse,
2369
- aiError,
2370
- shellOutput,
2371
- erdData
2372
- }
2373
- ]);
2300
+ writeEntry({ query: `/export ${format}`, commandMessage: { ok: false, text: err instanceof Error ? err.message : String(err) }, queryState: { status: "idle" }, elapsed: null, page: 0, aiResponse: "", aiError: null, shellOutput: null, erdData: null });
2301
+ }
2374
2302
  }
2375
2303
  async function handleShell(cmd) {
2376
- setErdData(null);
2377
- setShellOutput(null);
2378
- setIsShellRunning(true);
2379
- setCommandMessage(null);
2380
- setAiResponse("");
2381
- setAiError(null);
2382
- setQueryState({ status: "idle" });
2304
+ const q = `!${cmd}`;
2305
+ setActive({ type: "loading", label: "Shell", query: q });
2383
2306
  const result = await runShell(cmd);
2384
2307
  const combined = [result.stdout, result.stderr].filter(Boolean).join("\n");
2385
- setShellOutput(combined || "(no output)");
2386
- setIsShellRunning(false);
2308
+ writeEntry({ query: q, commandMessage: null, queryState: { status: "idle" }, elapsed: null, page: 0, aiResponse: "", aiError: null, shellOutput: combined || "(no output)", erdData: null });
2309
+ setActive({ type: "idle" });
2387
2310
  }
2388
2311
  async function handleSubmit(sql) {
2389
2312
  if (sql === "/next") {
2390
- setPage((p) => p + 1);
2313
+ if (!lastResult) return;
2314
+ const p = lastResultPage + 1;
2315
+ setLastResultPage(p);
2316
+ writeEntry({ query: "/next", commandMessage: null, queryState: { status: "success", result: lastResult }, elapsed: null, page: p, aiResponse: "", aiError: null, shellOutput: null, erdData: null });
2391
2317
  return;
2392
2318
  }
2393
2319
  if (sql === "/prev") {
2394
- setPage((p) => Math.max(0, p - 1));
2320
+ if (!lastResult || lastResultPage === 0) return;
2321
+ const p = lastResultPage - 1;
2322
+ setLastResultPage(p);
2323
+ writeEntry({ query: "/prev", commandMessage: null, queryState: { status: "success", result: lastResult }, elapsed: null, page: p, aiResponse: "", aiError: null, shellOutput: null, erdData: null });
2395
2324
  return;
2396
2325
  }
2397
- snapshotActiveEntry();
2398
2326
  if (sql.startsWith("!")) {
2399
- const cmd = sql.slice(1).trim();
2400
- setLastQuery(sql);
2401
- setShellOutput(null);
2402
- void handleShell(cmd);
2327
+ void handleShell(sql.slice(1).trim());
2403
2328
  return;
2404
2329
  }
2405
2330
  if (sql.startsWith("/") || sql.startsWith("\\")) {
@@ -2424,62 +2349,45 @@ function App({ connectionState, aiUrl: aiUrl2, aiModel: aiModel2, aiKey: aiKey2,
2424
2349
  },
2425
2350
  onClear: () => {
2426
2351
  setCompletedEntries([]);
2427
- setLastQuery("");
2428
- setCommandMessage(null);
2429
- setQueryState({ status: "idle" });
2430
- setShellOutput(null);
2431
- setAiResponse("");
2432
- setAiError(null);
2433
- setElapsed(null);
2434
- setPage(0);
2435
- process.stdout.write("\x1B[2J\x1B[H");
2352
+ setHasHistory(false);
2353
+ setActive({ type: "idle" });
2354
+ process.stdout.write("\x1B[H\x1B[2J\x1B[3J");
2436
2355
  },
2437
2356
  aliases,
2438
2357
  onSaveAlias: handleSaveAlias,
2439
2358
  onDeleteAlias: handleDeleteAlias
2440
2359
  });
2441
2360
  if (result.cleared) return;
2442
- setLastQuery(sql);
2443
- setErdData(null);
2444
- setAiResponse("");
2445
- setAiError(null);
2446
- setElapsed(null);
2447
- setPage(0);
2448
- setQueryState({ status: "idle" });
2449
- if (result.helpData) setCommandMessage({ ok: result.ok, text: "", helpData: result.helpData });
2450
- else if (result.message) setCommandMessage({ ok: result.ok, text: result.message });
2451
- else setCommandMessage(null);
2361
+ if (result.helpData) {
2362
+ writeEntry({ query: sql, commandMessage: { ok: result.ok, text: "", helpData: result.helpData }, queryState: { status: "idle" }, elapsed: null, page: 0, aiResponse: "", aiError: null, shellOutput: null, erdData: null });
2363
+ } else if (result.message) {
2364
+ writeEntry({ query: sql, commandMessage: { ok: result.ok, text: result.message }, queryState: { status: "idle" }, elapsed: null, page: 0, aiResponse: "", aiError: null, shellOutput: null, erdData: null });
2365
+ }
2452
2366
  return;
2453
2367
  }
2454
2368
  void handleQuery(sql);
2455
2369
  }
2456
- const isLoading = queryState.status === "running" || isStreaming || isShellRunning || isErdLoading;
2370
+ const isLoading = active.type !== "idle";
2457
2371
  const isConnected = connectionState.status === "connected";
2458
- const showAi = aiResponse !== "" || isStreaming || aiError !== null;
2459
- const isShellEntry = lastQuery.startsWith("!");
2460
- const isCommand = !isShellEntry && (lastQuery.startsWith("/") || lastQuery.startsWith("\\"));
2461
- const activeLabel = isShellEntry ? "Shell:" : isCommand ? "Command:" : "Query:";
2462
- return /* @__PURE__ */ jsxs7(Box7, { flexDirection: "column", children: [
2463
- /* @__PURE__ */ jsx7(Static, { items: completedEntries, children: (entry) => /* @__PURE__ */ jsx7(EntryView, { entry }, entry.id) }),
2464
- /* @__PURE__ */ jsxs7(Box7, { flexDirection: "column", paddingX: 1, children: [
2465
- lastQuery === "" && /* @__PURE__ */ jsx7(Banner, { connectionState }),
2466
- lastQuery !== "" && /* @__PURE__ */ jsxs7(Box7, { flexDirection: "column", marginBottom: 2, children: [
2467
- /* @__PURE__ */ jsx7(QueryHeader, { label: activeLabel.replace(":", ""), query: lastQuery }),
2468
- /* @__PURE__ */ jsx7(Box7, { marginTop: 1, flexDirection: "column", children: isShellEntry ? isShellRunning ? /* @__PURE__ */ jsx7(Text7, { dimColor: true, children: "running\u2026" }) : /* @__PURE__ */ jsx7(Text7, { children: limitLines(shellOutput ?? "", activePageSize()) }) : /* @__PURE__ */ jsxs7(Fragment4, { children: [
2469
- commandMessage && (commandMessage.helpData ? /* @__PURE__ */ jsx7(HelpView, { data: commandMessage.helpData }) : commandMessage.ok ? /* @__PURE__ */ jsxs7(Text7, { color: theme.accent, children: [
2470
- "\u2713 ",
2471
- commandMessage.text
2472
- ] }) : /* @__PURE__ */ jsx7(ErrorBox, { message: commandMessage.text })),
2473
- isErdLoading ? /* @__PURE__ */ jsx7(Text7, { dimColor: true, children: "Fetching schema\u2026" }) : erdData ? /* @__PURE__ */ jsx7(ErdView, { data: erdData }) : showAi ? /* @__PURE__ */ jsxs7(Box7, { flexDirection: "column", children: [
2474
- /* @__PURE__ */ jsx7(Text7, { color: theme.accent, bold: true, children: "Explanation:" }),
2475
- /* @__PURE__ */ jsx7(Box7, { flexDirection: "column", marginTop: 1, children: aiError ? /* @__PURE__ */ jsx7(ErrorBox, { message: aiError }) : /* @__PURE__ */ jsxs7(Text7, { color: PLACEHOLDER2, children: [
2476
- aiResponse,
2477
- isStreaming && /* @__PURE__ */ jsx7(Text7, { color: PLACEHOLDER2, children: "\u258B" })
2478
- ] }) })
2479
- ] }) : !commandMessage && /* @__PURE__ */ jsx7(QueryResult, { state: queryState, elapsed, page, pageSize: activePageSize() })
2480
- ] }) })
2372
+ return /* @__PURE__ */ jsxs5(Box5, { flexDirection: "column", children: [
2373
+ /* @__PURE__ */ jsx5(Static, { items: completedEntries, children: ({ id, formatted }) => /* @__PURE__ */ jsx5(Box5, { children: /* @__PURE__ */ jsx5(Text5, { children: formatted }) }, id) }),
2374
+ /* @__PURE__ */ jsxs5(Box5, { flexDirection: "column", paddingX: 1, children: [
2375
+ !hasHistory && active.type === "idle" && /* @__PURE__ */ jsx5(Banner, { connectionState }),
2376
+ active.type === "loading" && /* @__PURE__ */ jsxs5(Box5, { flexDirection: "column", marginBottom: 1, children: [
2377
+ /* @__PURE__ */ jsx5(QueryHeader, { label: active.label, query: active.query }),
2378
+ /* @__PURE__ */ jsx5(Text5, { dimColor: true, children: " running\u2026" })
2379
+ ] }),
2380
+ active.type === "streaming" && /* @__PURE__ */ jsxs5(Box5, { flexDirection: "column", marginBottom: 1, children: [
2381
+ /* @__PURE__ */ jsx5(QueryHeader, { label: "Query", query: active.query }),
2382
+ /* @__PURE__ */ jsxs5(Box5, { flexDirection: "column", marginTop: 1, children: [
2383
+ /* @__PURE__ */ jsx5(Text5, { color: theme.accent, bold: true, children: "Explanation:" }),
2384
+ /* @__PURE__ */ jsx5(Box5, { marginTop: 1, children: active.error ? /* @__PURE__ */ jsx5(ErrorBox, { message: active.error }) : /* @__PURE__ */ jsxs5(Text5, { color: PLACEHOLDER2, children: [
2385
+ active.text,
2386
+ /* @__PURE__ */ jsx5(Text5, { color: PLACEHOLDER2, children: "\u258B" })
2387
+ ] }) })
2388
+ ] })
2481
2389
  ] }),
2482
- isConnected ? /* @__PURE__ */ jsx7(
2390
+ isConnected ? /* @__PURE__ */ jsx5(
2483
2391
  QueryInput,
2484
2392
  {
2485
2393
  onSubmit: handleSubmit,
@@ -2491,16 +2399,16 @@ function App({ connectionState, aiUrl: aiUrl2, aiModel: aiModel2, aiKey: aiKey2,
2491
2399
  aliases,
2492
2400
  schema: schema ?? void 0
2493
2401
  }
2494
- ) : /* @__PURE__ */ jsx7(Text7, { dimColor: true, children: "Not connected. Press Ctrl+C to exit." }),
2495
- (vimEnabled || inputIsShell) && /* @__PURE__ */ jsx7(Box7, { marginTop: 1, children: /* @__PURE__ */ jsx7(Text7, { bold: true, color: inputIsShell ? theme.shellMode : vimMode === "NORMAL" ? theme.normalMode : theme.insertMode, children: isRawModeSupported ? inputIsShell ? "[SHELL]" : `[${vimMode}]` : "" }) })
2402
+ ) : /* @__PURE__ */ jsx5(Text5, { dimColor: true, children: "Not connected. Press Ctrl+C to exit." }),
2403
+ (vimEnabled || inputIsShell) && /* @__PURE__ */ jsx5(Box5, { marginTop: 1, children: /* @__PURE__ */ jsx5(Text5, { bold: true, color: inputIsShell ? theme.shellMode : vimMode === "NORMAL" ? theme.normalMode : theme.insertMode, children: isRawModeSupported ? inputIsShell ? "[SHELL]" : `[${vimMode}]` : "" }) })
2496
2404
  ] })
2497
2405
  ] });
2498
2406
  }
2499
2407
 
2500
2408
  // src/ui/components/ConnectionWizard.tsx
2501
2409
  import { useState as useState5 } from "react";
2502
- import { Box as Box8, Text as Text8, useInput as useInput3, useStdin as useStdin3 } from "ink";
2503
- import { jsx as jsx8, jsxs as jsxs8 } from "react/jsx-runtime";
2410
+ import { Box as Box6, Text as Text6, useInput as useInput3, useStdin as useStdin3 } from "ink";
2411
+ import { jsx as jsx6, jsxs as jsxs6 } from "react/jsx-runtime";
2504
2412
  var DRIVERS = ["postgresql", "mysql", "sqlite"];
2505
2413
  var LABEL_WIDTH = 10;
2506
2414
  function fieldLabels(driver) {
@@ -2655,36 +2563,36 @@ function ConnectionWizard({ onConnect, initialError }) {
2655
2563
  { isActive: isRawModeSupported }
2656
2564
  );
2657
2565
  const isPassword = (idx) => fields.driver !== "sqlite" && idx === 5;
2658
- return /* @__PURE__ */ jsxs8(Box8, { flexDirection: "column", paddingX: 2, paddingTop: 2, paddingBottom: 1, children: [
2659
- /* @__PURE__ */ jsx8(Box8, { marginBottom: 1, children: /* @__PURE__ */ jsx8(Text8, { bold: true, color: theme.accent, children: "Connect to a database" }) }),
2566
+ return /* @__PURE__ */ jsxs6(Box6, { flexDirection: "column", paddingX: 2, paddingTop: 2, paddingBottom: 1, children: [
2567
+ /* @__PURE__ */ jsx6(Box6, { marginBottom: 1, children: /* @__PURE__ */ jsx6(Text6, { bold: true, color: theme.accent, children: "Connect to a database" }) }),
2660
2568
  labels.map((label, idx) => {
2661
2569
  const isFocused = focus === idx;
2662
2570
  const isDriver = idx === 0;
2663
- return /* @__PURE__ */ jsxs8(Box8, { children: [
2664
- /* @__PURE__ */ jsx8(Text8, { color: isFocused ? theme.accent : void 0, bold: isFocused, children: label.padEnd(LABEL_WIDTH) }),
2665
- isDriver ? /* @__PURE__ */ jsx8(Box8, { children: DRIVERS.map((d, i) => /* @__PURE__ */ jsxs8(Box8, { children: [
2666
- i > 0 && /* @__PURE__ */ jsx8(Text8, { children: " " }),
2667
- /* @__PURE__ */ jsxs8(Text8, { color: fields.driver === d ? theme.accent : void 0, bold: fields.driver === d, children: [
2571
+ return /* @__PURE__ */ jsxs6(Box6, { children: [
2572
+ /* @__PURE__ */ jsx6(Text6, { color: isFocused ? theme.accent : void 0, bold: isFocused, children: label.padEnd(LABEL_WIDTH) }),
2573
+ isDriver ? /* @__PURE__ */ jsx6(Box6, { children: DRIVERS.map((d, i) => /* @__PURE__ */ jsxs6(Box6, { children: [
2574
+ i > 0 && /* @__PURE__ */ jsx6(Text6, { children: " " }),
2575
+ /* @__PURE__ */ jsxs6(Text6, { color: fields.driver === d ? theme.accent : void 0, bold: fields.driver === d, children: [
2668
2576
  fields.driver === d ? "\u25CF " : "\u25CB ",
2669
2577
  d.charAt(0).toUpperCase() + d.slice(1)
2670
2578
  ] })
2671
- ] }, d)) }) : /* @__PURE__ */ jsxs8(Box8, { children: [
2672
- /* @__PURE__ */ jsx8(Text8, { children: isPassword(idx) ? "\u2022".repeat(getTextValue(idx).length) : getTextValue(idx) }),
2673
- isFocused && /* @__PURE__ */ jsx8(Text8, { color: theme.accent, bold: true, children: "\u258C" }),
2674
- isFocused && isPassword(idx) && keychainHint && /* @__PURE__ */ jsx8(Text8, { dimColor: true, children: " (from keychain)" })
2579
+ ] }, d)) }) : /* @__PURE__ */ jsxs6(Box6, { children: [
2580
+ /* @__PURE__ */ jsx6(Text6, { children: isPassword(idx) ? "\u2022".repeat(getTextValue(idx).length) : getTextValue(idx) }),
2581
+ isFocused && /* @__PURE__ */ jsx6(Text6, { color: theme.accent, bold: true, children: "\u258C" }),
2582
+ isFocused && isPassword(idx) && keychainHint && /* @__PURE__ */ jsx6(Text6, { dimColor: true, children: " (from keychain)" })
2675
2583
  ] })
2676
2584
  ] }, label);
2677
2585
  }),
2678
- /* @__PURE__ */ jsx8(Box8, { marginTop: 1, children: connecting ? /* @__PURE__ */ jsx8(Text8, { dimColor: true, children: "Connecting\u2026" }) : error ? /* @__PURE__ */ jsxs8(Text8, { color: theme.error, children: [
2586
+ /* @__PURE__ */ jsx6(Box6, { marginTop: 1, children: connecting ? /* @__PURE__ */ jsx6(Text6, { dimColor: true, children: "Connecting\u2026" }) : error ? /* @__PURE__ */ jsxs6(Text6, { color: theme.error, children: [
2679
2587
  "\u2717 ",
2680
2588
  error
2681
2589
  ] }) : null }),
2682
- /* @__PURE__ */ jsx8(Box8, { marginTop: 1, children: /* @__PURE__ */ jsx8(Text8, { dimColor: true, children: "Tab \xB7 \u2191\u2193 navigate Enter connect \u2190\u2192 cycle driver" }) })
2590
+ /* @__PURE__ */ jsx6(Box6, { marginTop: 1, children: /* @__PURE__ */ jsx6(Text6, { dimColor: true, children: "Tab \xB7 \u2191\u2193 navigate Enter connect \u2190\u2192 cycle driver" }) })
2683
2591
  ] });
2684
2592
  }
2685
2593
 
2686
2594
  // src/index.tsx
2687
- import { jsx as jsx9 } from "react/jsx-runtime";
2595
+ import { jsx as jsx7 } from "react/jsx-runtime";
2688
2596
  var { values } = parseArgs({
2689
2597
  args: process.argv.slice(2).filter((a) => a !== "--"),
2690
2598
  options: {
@@ -2714,10 +2622,10 @@ function Root({ initialDsn: initialDsn2, aiUrl: aiUrl2, aiModel: aiModel2, aiKey
2714
2622
  }
2715
2623
  }, []);
2716
2624
  if (initialDsn2 && !connectionState && !dsnError) {
2717
- return /* @__PURE__ */ jsx9(Box9, { paddingX: 2, paddingTop: 1, children: /* @__PURE__ */ jsx9(Text9, { dimColor: true, children: "Connecting\u2026" }) });
2625
+ return /* @__PURE__ */ jsx7(Box7, { paddingX: 2, paddingTop: 1, children: /* @__PURE__ */ jsx7(Text7, { dimColor: true, children: "Connecting\u2026" }) });
2718
2626
  }
2719
2627
  if (!connectionState) {
2720
- return /* @__PURE__ */ jsx9(ConnectionWizard, { onConnect: setConnectionState, initialError: dsnError ?? void 0 });
2628
+ return /* @__PURE__ */ jsx7(ConnectionWizard, { onConnect: setConnectionState, initialError: dsnError ?? void 0 });
2721
2629
  }
2722
2630
  async function handleChangeDatabase(database) {
2723
2631
  if (connectionState.status !== "connected") return;
@@ -2727,7 +2635,7 @@ function Root({ initialDsn: initialDsn2, aiUrl: aiUrl2, aiModel: aiModel2, aiKey
2727
2635
  const next = await connectParams({ ...current.params, database });
2728
2636
  setConnectionState(next);
2729
2637
  }
2730
- return /* @__PURE__ */ jsx9(
2638
+ return /* @__PURE__ */ jsx7(
2731
2639
  App,
2732
2640
  {
2733
2641
  connectionState,
@@ -2740,10 +2648,7 @@ function Root({ initialDsn: initialDsn2, aiUrl: aiUrl2, aiModel: aiModel2, aiKey
2740
2648
  }
2741
2649
  );
2742
2650
  }
2743
- process.stdout.write("\x1B[?1049h\x1B[H");
2744
- process.on("exit", () => process.stdout.write("\x1B[?1049l"));
2745
- process.on("SIGTERM", () => process.exit(0));
2746
2651
  render(
2747
- /* @__PURE__ */ jsx9(Root, { initialDsn, aiUrl, aiModel, aiKey }),
2652
+ /* @__PURE__ */ jsx7(Root, { initialDsn, aiUrl, aiModel, aiKey }),
2748
2653
  { exitOnCtrlC: true }
2749
2654
  );
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@deaquinodev/querky",
3
- "version": "0.4.8",
3
+ "version": "0.4.9",
4
4
  "description": "A quirky terminal SQL client with vim mode, AI features, and schema-aware autocomplete",
5
5
  "main": "dist/index.js",
6
6
  "files": [