@deaquinodev/querky 0.4.8 → 0.4.10

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 +412 -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.10" : 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,208 @@ 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);
2042
1889
  }
2043
- function groupIntoRows(metrics, termW) {
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");
1973
+ }
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);
2031
+ function renderTable(t, m, color) {
2032
+ const { nameW, typeW, keyW, totalW } = m;
2033
+ const sp = " ".repeat(PAD);
2034
+ const p = (s, w) => s.slice(0, w).padEnd(w);
2035
+ const bdr = (s) => c(ERD_BORDER, s);
2036
+ const tc = (s) => cbold(color, s);
2037
+ const top = bdr("\u256D" + "\u2500".repeat(totalW - 2) + "\u256E");
2038
+ const headerW = totalW - 4;
2039
+ const headerLine = bdr("\u2502") + tc(sp + p(t.name, headerW) + sp) + bdr("\u2502");
2040
+ const sep = bdr("\u251C" + "\u2500".repeat(nameW + PAD * 2) + "\u252C" + "\u2500".repeat(typeW + PAD * 2) + "\u252C" + "\u2500".repeat(keyW + PAD * 2) + "\u2524");
2041
+ const bot = bdr("\u2570" + "\u2500".repeat(nameW + PAD * 2) + "\u2534" + "\u2500".repeat(typeW + PAD * 2) + "\u2534" + "\u2500".repeat(keyW + PAD * 2) + "\u256F");
2042
+ const out = [top, headerLine, sep];
2043
+ for (const col of t.columns) {
2044
+ let keyPart;
2045
+ if (col.isPk) {
2046
+ keyPart = sp + bold(p("PK", keyW)) + sp;
2047
+ } else if (col.fkTable) {
2048
+ const fkColor = colorMap.get(col.fkTable) ?? color;
2049
+ keyPart = sp + dim(FK_PREFIX) + c(fkColor, p(col.fkTable, keyW - FK_PREFIX.length)) + sp;
2050
+ } else {
2051
+ keyPart = sp + " ".repeat(keyW) + sp;
2052
+ }
2053
+ out.push(
2054
+ bdr("\u2502") + sp + p(col.name, nameW) + sp + bdr("\u2502") + dim(sp + p(col.type, typeW) + sp) + bdr("\u2502") + keyPart + bdr("\u2502")
2055
+ );
2056
+ }
2057
+ out.push(bot);
2058
+ return out;
2059
+ }
2044
2060
  const rows = [];
2045
- let row = [];
2046
- let usedW = 0;
2047
- for (let i = 0; i < metrics.length; i++) {
2048
- const w = metrics[i].totalW;
2061
+ let row = [], usedW = 0;
2062
+ for (let i = 0; i < allMetrics.length; i++) {
2063
+ const w = allMetrics[i].totalW;
2049
2064
  if (row.length === 0) {
2050
2065
  row.push(i);
2051
2066
  usedW = w;
@@ -2059,120 +2074,83 @@ function groupIntoRows(metrics, termW) {
2059
2074
  }
2060
2075
  }
2061
2076
  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
- ] });
2077
+ const output = [];
2078
+ for (const tableRow of rows) {
2079
+ const blocks = tableRow.map(
2080
+ (ti) => renderTable(data.tables[ti], allMetrics[ti], colorMap.get(data.tables[ti].name) ?? ERD_PALETTE[0])
2081
+ );
2082
+ const height = Math.max(...blocks.map((b) => b.length));
2083
+ for (let line = 0; line < height; line++) {
2084
+ const parts = blocks.map((b, j) => {
2085
+ const l = b[line] ?? " ".repeat(allMetrics[tableRow[j]].totalW);
2086
+ return j < blocks.length - 1 ? l + " ".repeat(GAP) : l;
2087
+ });
2088
+ output.push(parts.join(""));
2089
+ }
2090
+ output.push("");
2091
+ }
2092
+ return output.join("\n").trimEnd();
2120
2093
  }
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." });
2094
+ function fmtAi(text, error) {
2095
+ const lines = [cbold(ACCENT2, "Explanation:"), ""];
2096
+ if (error) {
2097
+ lines.push(fmtError(error));
2098
+ } else {
2099
+ lines.push(c(AI_COL, text));
2124
2100
  }
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
2101
+ return lines.join("\n");
2102
+ }
2103
+ function fmtEntry(entry) {
2104
+ const isShell = entry.query.startsWith("!");
2105
+ const isCommand = !isShell && (entry.query.startsWith("/") || entry.query.startsWith("\\"));
2106
+ const label = isShell ? "Shell" : isCommand ? "Command" : "Query";
2107
+ const lines = [" " + fmtHeader(label, entry.query), ""];
2108
+ if (isShell) {
2109
+ if (entry.shellOutput !== null) lines.push(" " + entry.shellOutput.replace(/\n/g, "\n "));
2110
+ } else if (entry.commandMessage) {
2111
+ if (entry.commandMessage.helpData) {
2112
+ lines.push(fmtHelp(entry.commandMessage.helpData).replace(/\n/g, "\n "));
2113
+ } else if (entry.commandMessage.ok) {
2114
+ lines.push(" " + fmtOk(entry.commandMessage.text));
2115
+ } else {
2116
+ lines.push(" " + fmtError(entry.commandMessage.text));
2138
2117
  }
2139
- ) }, ti)) }, ri)) });
2118
+ } else if (entry.erdData) {
2119
+ lines.push(" " + fmtErd(entry.erdData).replace(/\n/g, "\n "));
2120
+ } else if (entry.aiResponse || entry.aiError) {
2121
+ lines.push(" " + fmtAi(entry.aiResponse, entry.aiError).replace(/\n/g, "\n "));
2122
+ } else {
2123
+ const result = fmtQueryResult(entry.queryState, entry.elapsed, entry.page, 50);
2124
+ if (result) lines.push(" " + result.replace(/\n/g, "\n "));
2125
+ }
2126
+ lines.push("");
2127
+ return lines.join("\n");
2140
2128
  }
2141
2129
 
2142
2130
  // 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;
2131
+ import { jsx as jsx5, jsxs as jsxs5 } from "react/jsx-runtime";
2145
2132
  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
2133
  var QUERY_HEADER_COLOR = "#9ca3af";
2156
2134
  function QueryHeader({ label, query }) {
2157
2135
  const isMultiLine = query.includes("\n");
2158
2136
  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: [
2137
+ return /* @__PURE__ */ jsxs5(Box5, { flexDirection: "column", children: [
2138
+ /* @__PURE__ */ jsxs5(Text5, { children: [
2139
+ /* @__PURE__ */ jsx5(Text5, { color: theme.accent, bold: true, children: "\u25CF " }),
2140
+ /* @__PURE__ */ jsxs5(Text5, { color: QUERY_HEADER_COLOR, bold: true, children: [
2163
2141
  label,
2164
2142
  ":"
2165
2143
  ] })
2166
2144
  ] }),
2167
- query.split("\n").map((line, i) => /* @__PURE__ */ jsxs7(Text7, { color: QUERY_HEADER_COLOR, bold: true, children: [
2145
+ query.split("\n").map((line, i) => /* @__PURE__ */ jsxs5(Text5, { color: QUERY_HEADER_COLOR, bold: true, children: [
2168
2146
  " ",
2169
2147
  line
2170
2148
  ] }, i))
2171
2149
  ] });
2172
2150
  }
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: [
2151
+ return /* @__PURE__ */ jsxs5(Text5, { children: [
2152
+ /* @__PURE__ */ jsx5(Text5, { color: theme.accent, bold: true, children: "\u25CF " }),
2153
+ /* @__PURE__ */ jsxs5(Text5, { color: QUERY_HEADER_COLOR, bold: true, children: [
2176
2154
  label,
2177
2155
  "(",
2178
2156
  query,
@@ -2180,54 +2158,31 @@ function QueryHeader({ label, query }) {
2180
2158
  ] })
2181
2159
  ] });
2182
2160
  }
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
2161
  function App({ connectionState, aiUrl: aiUrl2, aiModel: aiModel2, aiKey: aiKey2, onChangeDatabase }) {
2204
2162
  const { exit } = useApp();
2205
2163
  const { isRawModeSupported } = useStdin2();
2206
- const [queryState, setQueryState] = useState4({ status: "idle" });
2207
- const [lastQuery, setLastQuery] = useState4("");
2164
+ const [active, setActive] = useState4({ type: "idle" });
2165
+ const [hasHistory, setHasHistory] = useState4(false);
2166
+ const [completedEntries, setCompletedEntries] = useState4([]);
2167
+ const entryIdRef = useRef2(0);
2208
2168
  const [lastSqlQuery, setLastSqlQuery] = useState4("");
2209
2169
  const [lastResult, setLastResult] = useState4(null);
2210
- const [page, setPage] = useState4(0);
2170
+ const [lastResultPage, setLastResultPage] = useState4(0);
2211
2171
  const [vimMode, setVimMode] = useState4("INSERT");
2212
2172
  const [inputIsShell, setInputIsShell] = useState4(false);
2213
- const [elapsed, setElapsed] = useState4(null);
2214
2173
  const [vimEnabled, setVimEnabled] = useState4(true);
2215
- const [commandMessage, setCommandMessage] = useState4(null);
2216
2174
  const [history, setHistory] = useState4(() => loadHistory());
2217
2175
  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
2176
  const aliasScope = connectionState.status === "connected" ? makeScope(connectionState.driver, connectionState.user, connectionState.host, connectionState.database) : "";
2228
2177
  const [aliases, setAliases] = useState4(
2229
2178
  () => aliasScope ? getAllAliases(aliasScope) : {}
2230
2179
  );
2180
+ function writeEntry(entry) {
2181
+ const formatted = fmtEntry(entry);
2182
+ const id = String(++entryIdRef.current);
2183
+ setCompletedEntries((prev) => [...prev, { id, formatted }]);
2184
+ setHasHistory(true);
2185
+ }
2231
2186
  function handleSaveAlias(name, query) {
2232
2187
  saveAlias(aliasScope, name, query);
2233
2188
  setAliases(getAllAliases(aliasScope));
@@ -2271,65 +2226,55 @@ function App({ connectionState, aiUrl: aiUrl2, aiModel: aiModel2, aiKey: aiKey2,
2271
2226
  },
2272
2227
  { isActive: isRawModeSupported }
2273
2228
  );
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);
2229
+ async function handleQuery(sql) {
2230
+ if (connectionState.status !== "connected") return;
2231
+ setLastSqlQuery(sql);
2232
+ setActive({ type: "loading", label: "Query", query: sql });
2233
+ const updated = addToHistory(history, sql);
2234
+ setHistory(updated);
2235
+ saveHistory(updated);
2236
+ const start = Date.now();
2237
+ const result = await runQuery(connectionState.client, sql);
2238
+ const elapsed = Date.now() - start;
2239
+ if (result.status === "success") {
2240
+ setLastResult(result.result);
2241
+ setLastResultPage(0);
2288
2242
  }
2243
+ writeEntry({ query: sql, commandMessage: null, queryState: result, elapsed, page: 0, aiResponse: "", aiError: null, shellOutput: null, erdData: null });
2244
+ setActive({ type: "idle" });
2289
2245
  }
2290
2246
  async function handleErd() {
2291
2247
  if (connectionState.status !== "connected") {
2292
- setCommandMessage({ ok: false, text: "Not connected to a database." });
2248
+ writeEntry({ query: "/erd", commandMessage: { ok: false, text: "Not connected." }, queryState: { status: "idle" }, elapsed: null, page: 0, aiResponse: "", aiError: null, shellOutput: null, erdData: null });
2293
2249
  return;
2294
2250
  }
2295
- setErdData(null);
2296
- setIsErdLoading(true);
2297
- setCommandMessage(null);
2298
- setQueryState({ status: "idle" });
2299
- setAiResponse("");
2300
- setAiError(null);
2251
+ setActive({ type: "loading", label: "Command", query: "/erd" });
2301
2252
  try {
2302
2253
  const data = await fetchErd(connectionState.client, connectionState.driver);
2303
- setErdData(data);
2254
+ writeEntry({ query: "/erd", commandMessage: null, queryState: { status: "idle" }, elapsed: null, page: 0, aiResponse: "", aiError: null, shellOutput: null, erdData: data });
2304
2255
  } catch (err) {
2305
- setCommandMessage({ ok: false, text: err instanceof Error ? err.message : String(err) });
2306
- } finally {
2307
- setIsErdLoading(false);
2256
+ 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
2257
  }
2258
+ setActive({ type: "idle" });
2309
2259
  }
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);
2260
+ async function handleExplain(query) {
2261
+ setActive({ type: "streaming", query, text: "", error: null });
2262
+ let fullText = "";
2263
+ let error = null;
2264
+ try {
2265
+ for await (const chunk of streamExplain(query, aiUrl2, aiModel2, aiKey2 || void 0)) {
2266
+ fullText += chunk;
2267
+ setActive({ type: "streaming", query, text: fullText, error: null });
2268
+ }
2269
+ } catch (err) {
2270
+ error = err instanceof Error ? err.message : String(err);
2271
+ }
2272
+ writeEntry({ query: "/explain", commandMessage: null, queryState: { status: "idle" }, elapsed: null, page: 0, aiResponse: fullText, aiError: error, shellOutput: null, erdData: null });
2273
+ setActive({ type: "idle" });
2329
2274
  }
2330
2275
  function handleExport(format) {
2331
2276
  if (!lastResult || lastResult.rows.length === 0) {
2332
- setCommandMessage({ ok: false, text: "No results to export \u2014 run a query first." });
2277
+ 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
2278
  return;
2334
2279
  }
2335
2280
  const ts = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-").slice(0, 19);
@@ -2349,57 +2294,36 @@ function App({ connectionState, aiUrl: aiUrl2, aiModel: aiModel2, aiKey: aiKey2,
2349
2294
  );
2350
2295
  writeFileSync5(filename, [header, ...rows].join("\n"));
2351
2296
  }
2352
- setCommandMessage({ ok: true, text: `Exported to ${filename}` });
2297
+ 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
2298
  } 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
- ]);
2299
+ 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 });
2300
+ }
2374
2301
  }
2375
2302
  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" });
2303
+ const q = `!${cmd}`;
2304
+ setActive({ type: "loading", label: "Shell", query: q });
2383
2305
  const result = await runShell(cmd);
2384
2306
  const combined = [result.stdout, result.stderr].filter(Boolean).join("\n");
2385
- setShellOutput(combined || "(no output)");
2386
- setIsShellRunning(false);
2307
+ writeEntry({ query: q, commandMessage: null, queryState: { status: "idle" }, elapsed: null, page: 0, aiResponse: "", aiError: null, shellOutput: combined || "(no output)", erdData: null });
2308
+ setActive({ type: "idle" });
2387
2309
  }
2388
2310
  async function handleSubmit(sql) {
2389
2311
  if (sql === "/next") {
2390
- setPage((p) => p + 1);
2312
+ if (!lastResult) return;
2313
+ const p = lastResultPage + 1;
2314
+ setLastResultPage(p);
2315
+ writeEntry({ query: "/next", commandMessage: null, queryState: { status: "success", result: lastResult }, elapsed: null, page: p, aiResponse: "", aiError: null, shellOutput: null, erdData: null });
2391
2316
  return;
2392
2317
  }
2393
2318
  if (sql === "/prev") {
2394
- setPage((p) => Math.max(0, p - 1));
2319
+ if (!lastResult || lastResultPage === 0) return;
2320
+ const p = lastResultPage - 1;
2321
+ setLastResultPage(p);
2322
+ writeEntry({ query: "/prev", commandMessage: null, queryState: { status: "success", result: lastResult }, elapsed: null, page: p, aiResponse: "", aiError: null, shellOutput: null, erdData: null });
2395
2323
  return;
2396
2324
  }
2397
- snapshotActiveEntry();
2398
2325
  if (sql.startsWith("!")) {
2399
- const cmd = sql.slice(1).trim();
2400
- setLastQuery(sql);
2401
- setShellOutput(null);
2402
- void handleShell(cmd);
2326
+ void handleShell(sql.slice(1).trim());
2403
2327
  return;
2404
2328
  }
2405
2329
  if (sql.startsWith("/") || sql.startsWith("\\")) {
@@ -2424,62 +2348,45 @@ function App({ connectionState, aiUrl: aiUrl2, aiModel: aiModel2, aiKey: aiKey2,
2424
2348
  },
2425
2349
  onClear: () => {
2426
2350
  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");
2351
+ setHasHistory(false);
2352
+ setActive({ type: "idle" });
2353
+ process.stdout.write("\x1B[H\x1B[2J\x1B[3J");
2436
2354
  },
2437
2355
  aliases,
2438
2356
  onSaveAlias: handleSaveAlias,
2439
2357
  onDeleteAlias: handleDeleteAlias
2440
2358
  });
2441
2359
  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);
2360
+ if (result.helpData) {
2361
+ 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 });
2362
+ } else if (result.message) {
2363
+ writeEntry({ query: sql, commandMessage: { ok: result.ok, text: result.message }, queryState: { status: "idle" }, elapsed: null, page: 0, aiResponse: "", aiError: null, shellOutput: null, erdData: null });
2364
+ }
2452
2365
  return;
2453
2366
  }
2454
2367
  void handleQuery(sql);
2455
2368
  }
2456
- const isLoading = queryState.status === "running" || isStreaming || isShellRunning || isErdLoading;
2369
+ const isLoading = active.type !== "idle";
2457
2370
  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
- ] }) })
2371
+ return /* @__PURE__ */ jsxs5(Box5, { flexDirection: "column", children: [
2372
+ /* @__PURE__ */ jsx5(Static, { items: completedEntries, children: ({ id, formatted }) => /* @__PURE__ */ jsx5(Box5, { children: /* @__PURE__ */ jsx5(Text5, { children: formatted }) }, id) }),
2373
+ /* @__PURE__ */ jsxs5(Box5, { flexDirection: "column", paddingX: 1, children: [
2374
+ !hasHistory && active.type === "idle" && /* @__PURE__ */ jsx5(Banner, { connectionState }),
2375
+ active.type === "loading" && /* @__PURE__ */ jsxs5(Box5, { flexDirection: "column", marginBottom: 1, children: [
2376
+ /* @__PURE__ */ jsx5(QueryHeader, { label: active.label, query: active.query }),
2377
+ /* @__PURE__ */ jsx5(Text5, { dimColor: true, children: " running\u2026" })
2378
+ ] }),
2379
+ active.type === "streaming" && /* @__PURE__ */ jsxs5(Box5, { flexDirection: "column", marginBottom: 1, children: [
2380
+ /* @__PURE__ */ jsx5(QueryHeader, { label: "Query", query: active.query }),
2381
+ /* @__PURE__ */ jsxs5(Box5, { flexDirection: "column", marginTop: 1, children: [
2382
+ /* @__PURE__ */ jsx5(Text5, { color: theme.accent, bold: true, children: "Explanation:" }),
2383
+ /* @__PURE__ */ jsx5(Box5, { marginTop: 1, children: active.error ? /* @__PURE__ */ jsx5(ErrorBox, { message: active.error }) : /* @__PURE__ */ jsxs5(Text5, { color: PLACEHOLDER2, children: [
2384
+ active.text,
2385
+ /* @__PURE__ */ jsx5(Text5, { color: PLACEHOLDER2, children: "\u258B" })
2386
+ ] }) })
2387
+ ] })
2481
2388
  ] }),
2482
- isConnected ? /* @__PURE__ */ jsx7(
2389
+ isConnected ? /* @__PURE__ */ jsx5(
2483
2390
  QueryInput,
2484
2391
  {
2485
2392
  onSubmit: handleSubmit,
@@ -2491,16 +2398,16 @@ function App({ connectionState, aiUrl: aiUrl2, aiModel: aiModel2, aiKey: aiKey2,
2491
2398
  aliases,
2492
2399
  schema: schema ?? void 0
2493
2400
  }
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}]` : "" }) })
2401
+ ) : /* @__PURE__ */ jsx5(Text5, { dimColor: true, children: "Not connected. Press Ctrl+C to exit." }),
2402
+ (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
2403
  ] })
2497
2404
  ] });
2498
2405
  }
2499
2406
 
2500
2407
  // src/ui/components/ConnectionWizard.tsx
2501
2408
  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";
2409
+ import { Box as Box6, Text as Text6, useInput as useInput3, useStdin as useStdin3 } from "ink";
2410
+ import { jsx as jsx6, jsxs as jsxs6 } from "react/jsx-runtime";
2504
2411
  var DRIVERS = ["postgresql", "mysql", "sqlite"];
2505
2412
  var LABEL_WIDTH = 10;
2506
2413
  function fieldLabels(driver) {
@@ -2655,36 +2562,36 @@ function ConnectionWizard({ onConnect, initialError }) {
2655
2562
  { isActive: isRawModeSupported }
2656
2563
  );
2657
2564
  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" }) }),
2565
+ return /* @__PURE__ */ jsxs6(Box6, { flexDirection: "column", paddingX: 2, paddingTop: 2, paddingBottom: 1, children: [
2566
+ /* @__PURE__ */ jsx6(Box6, { marginBottom: 1, children: /* @__PURE__ */ jsx6(Text6, { bold: true, color: theme.accent, children: "Connect to a database" }) }),
2660
2567
  labels.map((label, idx) => {
2661
2568
  const isFocused = focus === idx;
2662
2569
  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: [
2570
+ return /* @__PURE__ */ jsxs6(Box6, { children: [
2571
+ /* @__PURE__ */ jsx6(Text6, { color: isFocused ? theme.accent : void 0, bold: isFocused, children: label.padEnd(LABEL_WIDTH) }),
2572
+ isDriver ? /* @__PURE__ */ jsx6(Box6, { children: DRIVERS.map((d, i) => /* @__PURE__ */ jsxs6(Box6, { children: [
2573
+ i > 0 && /* @__PURE__ */ jsx6(Text6, { children: " " }),
2574
+ /* @__PURE__ */ jsxs6(Text6, { color: fields.driver === d ? theme.accent : void 0, bold: fields.driver === d, children: [
2668
2575
  fields.driver === d ? "\u25CF " : "\u25CB ",
2669
2576
  d.charAt(0).toUpperCase() + d.slice(1)
2670
2577
  ] })
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)" })
2578
+ ] }, d)) }) : /* @__PURE__ */ jsxs6(Box6, { children: [
2579
+ /* @__PURE__ */ jsx6(Text6, { children: isPassword(idx) ? "\u2022".repeat(getTextValue(idx).length) : getTextValue(idx) }),
2580
+ isFocused && /* @__PURE__ */ jsx6(Text6, { color: theme.accent, bold: true, children: "\u258C" }),
2581
+ isFocused && isPassword(idx) && keychainHint && /* @__PURE__ */ jsx6(Text6, { dimColor: true, children: " (from keychain)" })
2675
2582
  ] })
2676
2583
  ] }, label);
2677
2584
  }),
2678
- /* @__PURE__ */ jsx8(Box8, { marginTop: 1, children: connecting ? /* @__PURE__ */ jsx8(Text8, { dimColor: true, children: "Connecting\u2026" }) : error ? /* @__PURE__ */ jsxs8(Text8, { color: theme.error, children: [
2585
+ /* @__PURE__ */ jsx6(Box6, { marginTop: 1, children: connecting ? /* @__PURE__ */ jsx6(Text6, { dimColor: true, children: "Connecting\u2026" }) : error ? /* @__PURE__ */ jsxs6(Text6, { color: theme.error, children: [
2679
2586
  "\u2717 ",
2680
2587
  error
2681
2588
  ] }) : 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" }) })
2589
+ /* @__PURE__ */ jsx6(Box6, { marginTop: 1, children: /* @__PURE__ */ jsx6(Text6, { dimColor: true, children: "Tab \xB7 \u2191\u2193 navigate Enter connect \u2190\u2192 cycle driver" }) })
2683
2590
  ] });
2684
2591
  }
2685
2592
 
2686
2593
  // src/index.tsx
2687
- import { jsx as jsx9 } from "react/jsx-runtime";
2594
+ import { jsx as jsx7 } from "react/jsx-runtime";
2688
2595
  var { values } = parseArgs({
2689
2596
  args: process.argv.slice(2).filter((a) => a !== "--"),
2690
2597
  options: {
@@ -2714,10 +2621,10 @@ function Root({ initialDsn: initialDsn2, aiUrl: aiUrl2, aiModel: aiModel2, aiKey
2714
2621
  }
2715
2622
  }, []);
2716
2623
  if (initialDsn2 && !connectionState && !dsnError) {
2717
- return /* @__PURE__ */ jsx9(Box9, { paddingX: 2, paddingTop: 1, children: /* @__PURE__ */ jsx9(Text9, { dimColor: true, children: "Connecting\u2026" }) });
2624
+ return /* @__PURE__ */ jsx7(Box7, { paddingX: 2, paddingTop: 1, children: /* @__PURE__ */ jsx7(Text7, { dimColor: true, children: "Connecting\u2026" }) });
2718
2625
  }
2719
2626
  if (!connectionState) {
2720
- return /* @__PURE__ */ jsx9(ConnectionWizard, { onConnect: setConnectionState, initialError: dsnError ?? void 0 });
2627
+ return /* @__PURE__ */ jsx7(ConnectionWizard, { onConnect: setConnectionState, initialError: dsnError ?? void 0 });
2721
2628
  }
2722
2629
  async function handleChangeDatabase(database) {
2723
2630
  if (connectionState.status !== "connected") return;
@@ -2727,7 +2634,7 @@ function Root({ initialDsn: initialDsn2, aiUrl: aiUrl2, aiModel: aiModel2, aiKey
2727
2634
  const next = await connectParams({ ...current.params, database });
2728
2635
  setConnectionState(next);
2729
2636
  }
2730
- return /* @__PURE__ */ jsx9(
2637
+ return /* @__PURE__ */ jsx7(
2731
2638
  App,
2732
2639
  {
2733
2640
  connectionState,
@@ -2740,10 +2647,7 @@ function Root({ initialDsn: initialDsn2, aiUrl: aiUrl2, aiModel: aiModel2, aiKey
2740
2647
  }
2741
2648
  );
2742
2649
  }
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
2650
  render(
2747
- /* @__PURE__ */ jsx9(Root, { initialDsn, aiUrl, aiModel, aiKey }),
2651
+ /* @__PURE__ */ jsx7(Root, { initialDsn, aiUrl, aiModel, aiKey }),
2748
2652
  { exitOnCtrlC: true }
2749
2653
  );
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@deaquinodev/querky",
3
- "version": "0.4.8",
3
+ "version": "0.4.10",
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": [