@deaquinodev/querky 0.4.4 → 0.4.6

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 +100 -70
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -39,10 +39,11 @@ var PgDbClient = class {
39
39
  }
40
40
  pg;
41
41
  async query(sql) {
42
- const result = await this.pg.query(sql);
42
+ const raw = await this.pg.query(sql);
43
+ const result = Array.isArray(raw) ? raw[raw.length - 1] : raw;
43
44
  return {
44
- fields: result.fields.map((f) => f.name),
45
- rows: result.rows,
45
+ fields: (result.fields ?? []).map((f) => f.name),
46
+ rows: result.rows ?? [],
46
47
  rowCount: result.rowCount ?? 0
47
48
  };
48
49
  }
@@ -625,8 +626,12 @@ var COMMANDS = {
625
626
  description: "Save last query as a named alias",
626
627
  category: "Aliases",
627
628
  usage: "/save <name>",
628
- detail: "Saves the last executed SQL query as a named alias scoped to the current database. Run it later with /<name>. Supports positional ($1, $2) and named (:param) substitution.",
629
- example: "/save active-orders",
629
+ detail: "Saves the last executed SQL query as a named alias scoped to the current database. Run it later with /<name>. If the query contains $1, $2 placeholders or :param placeholders, values are substituted at run time.",
630
+ examples: [
631
+ "/save active-orders (no params \u2014 run with /active-orders)",
632
+ "/save user-by-id (query had WHERE id = $1 \u2014 run with /user-by-id 42)",
633
+ "/save by-status (query had WHERE status = :status \u2014 run with /by-status :status=active)"
634
+ ],
630
635
  run: (ctx) => {
631
636
  const name = ctx.args.trim();
632
637
  if (!name) return { ok: false, message: "Usage: /save <name>" };
@@ -640,8 +645,14 @@ var COMMANDS = {
640
645
  description: "Define an alias inline",
641
646
  category: "Aliases",
642
647
  usage: "/alias <name> <SQL>",
643
- detail: "Defines a named alias without running a query first. Equivalent to /save but lets you specify the SQL directly.",
644
- example: "/alias recent SELECT * FROM events ORDER BY created_at DESC LIMIT 20",
648
+ detail: "Defines a named alias without running a query first. Use $1, $2 for positional args or :param for named args \u2014 values are substituted when the alias is invoked.",
649
+ examples: [
650
+ "/alias recent SELECT * FROM events ORDER BY created_at DESC LIMIT 20",
651
+ "/alias user SELECT * FROM users WHERE id = $1",
652
+ "/alias by-email SELECT * FROM users WHERE email = :email",
653
+ "/user 42 (positional)",
654
+ "/by-email :email=alice@example.com (named)"
655
+ ],
645
656
  run: (ctx) => {
646
657
  const [name, ...rest] = ctx.args.trim().split(/\s+/);
647
658
  if (!name || rest.length === 0) return { ok: false, message: "Usage: /alias <name> <SQL>" };
@@ -706,7 +717,8 @@ var COMMANDS = {
706
717
  description: cmd.description,
707
718
  psqlAlias: PSQL_REVERSE[name],
708
719
  detail: cmd.detail,
709
- example: cmd.example
720
+ example: cmd.example,
721
+ examples: cmd.examples
710
722
  };
711
723
  return { ok: true, message: "", helpData: { mode: "detail", entry } };
712
724
  }
@@ -1177,7 +1189,7 @@ function useVimInput(onSubmit, isActive, vimEnabled = true, onTab, history = [],
1177
1189
  }
1178
1190
  if (key.leftArrow) return { ...s, cursor: Math.max(0, s.cursor - 1) };
1179
1191
  if (key.rightArrow) return { ...s, cursor: Math.min(s.value.length, s.cursor + 1) };
1180
- if (key.tab) {
1192
+ if (key.tab && !key.shift) {
1181
1193
  const sugs = getSuggestions?.(s.value, s.cursor) ?? [];
1182
1194
  if (sugs.length > 0) {
1183
1195
  const next = s.suggestionIndex < sugs.length - 1 ? s.suggestionIndex + 1 : 0;
@@ -1187,6 +1199,14 @@ function useVimInput(onSubmit, isActive, vimEnabled = true, onTab, history = [],
1187
1199
  if (completed != null) return { ...s, value: completed, cursor: completed.length };
1188
1200
  return s;
1189
1201
  }
1202
+ if (key.tab && key.shift) {
1203
+ const sugs = getSuggestions?.(s.value, s.cursor) ?? [];
1204
+ if (sugs.length > 0) {
1205
+ const next = s.suggestionIndex <= 0 ? sugs.length - 1 : s.suggestionIndex - 1;
1206
+ return { ...s, suggestionIndex: next };
1207
+ }
1208
+ return s;
1209
+ }
1190
1210
  if (key.ctrl && input === "e") {
1191
1211
  return { ...s, pendingEditor: s.value };
1192
1212
  }
@@ -1484,9 +1504,10 @@ function FuzzyHighlight({ text, token, selected }) {
1484
1504
  (seg, i) => seg.hit ? /* @__PURE__ */ jsx(Text, { color: ACCENT, bold: true, children: seg.chars }, i) : /* @__PURE__ */ jsx(Text, { dimColor: !selected, children: seg.chars }, i)
1485
1505
  ) });
1486
1506
  }
1487
- var BG = "#1e1b4b";
1507
+ var BG = "#1e1e1e";
1488
1508
  var ACCENT = "#818cf8";
1489
- var PLACEHOLDER = "#6366f1";
1509
+ var PROMPT_MUTED = "#6b7280";
1510
+ var PLACEHOLDER = "#4b5563";
1490
1511
  var KW_COLOR = "#a5b4fc";
1491
1512
  var STR_COLOR = "#fb923c";
1492
1513
  var NUM_COLOR = "#86efac";
@@ -1498,9 +1519,9 @@ function sqlTokenColor(type) {
1498
1519
  if (type === "comment") return CMT_COLOR;
1499
1520
  return void 0;
1500
1521
  }
1501
- function SqlLine({ text }) {
1522
+ function SqlLine({ text, bg }) {
1502
1523
  const tokens = tokenizeSql(text);
1503
- return /* @__PURE__ */ jsx(Fragment, { children: tokens.map((tok, i) => /* @__PURE__ */ jsx(Text, { color: sqlTokenColor(tok.type), children: tok.text }, i)) });
1524
+ return /* @__PURE__ */ jsx(Fragment, { children: tokens.map((tok, i) => /* @__PURE__ */ jsx(Text, { backgroundColor: bg, color: sqlTokenColor(tok.type), children: tok.text }, i)) });
1504
1525
  }
1505
1526
  function SqlHighlightedInput({ text, cursorAt, mode, pad: pad2 }) {
1506
1527
  const tokens = tokenizeSql(text);
@@ -1518,7 +1539,7 @@ function SqlHighlightedInput({ text, cursorAt, mode, pad: pad2 }) {
1518
1539
  const after = tok.text.slice(rel + 1);
1519
1540
  if (before) parts.push(/* @__PURE__ */ jsx(Text, { backgroundColor: BG, color, children: before }, `${i}b`));
1520
1541
  if (mode === "INSERT") {
1521
- parts.push(/* @__PURE__ */ jsx(Text, { backgroundColor: BG, color: ACCENT, bold: true, children: "\u258C" }, `${i}c`));
1542
+ parts.push(/* @__PURE__ */ jsx(Text, { backgroundColor: BG, color: PROMPT_MUTED, bold: true, children: "\u258C" }, `${i}c`));
1522
1543
  } else {
1523
1544
  parts.push(/* @__PURE__ */ jsx(Text, { backgroundColor: ACCENT, color: BG, bold: true, children: ch || " " }, `${i}c`));
1524
1545
  }
@@ -1531,7 +1552,7 @@ function SqlHighlightedInput({ text, cursorAt, mode, pad: pad2 }) {
1531
1552
  }
1532
1553
  if (!cursorDone) {
1533
1554
  if (mode === "INSERT") {
1534
- parts.push(/* @__PURE__ */ jsx(Text, { backgroundColor: BG, color: ACCENT, bold: true, children: "\u258C" }, "c"));
1555
+ parts.push(/* @__PURE__ */ jsx(Text, { backgroundColor: BG, color: PROMPT_MUTED, bold: true, children: "\u258C" }, "c"));
1535
1556
  } else {
1536
1557
  parts.push(/* @__PURE__ */ jsx(Text, { backgroundColor: ACCENT, color: BG, bold: true, children: " " }, "c"));
1537
1558
  }
@@ -1623,16 +1644,19 @@ function QueryInput({ onSubmit, isLoading, onModeChange, onShellModeChange, vimE
1623
1644
  const isMultiLine = !isEmpty && !isShellMode && !isCommand && value.includes("\n");
1624
1645
  const dOff = isShellMode ? 2 : 0;
1625
1646
  const placeholder = "Type a SQL query\u2026";
1647
+ const previewResult = !isMultiLine && suggestionIndex >= 0 && suggestions.length > 0 ? handleSuggestionAccept(value, cursorPos, suggestions[suggestionIndex]) : null;
1648
+ const renderValue = previewResult?.value ?? value;
1649
+ const renderCursor = previewResult?.cursor ?? cursorPos;
1626
1650
  const lineWidth = innerWidth - 4;
1627
- const displayValue = value.slice(dOff);
1628
- const displayCursor = Math.max(0, cursorPos - dOff);
1651
+ const displayValue = renderValue.slice(dOff);
1652
+ const displayCursor = Math.max(0, renderCursor - dOff);
1629
1653
  const scrollStart = displayCursor > lineWidth - 1 ? displayCursor - lineWidth + 1 : 0;
1630
1654
  const visibleBefore = displayValue.slice(scrollStart, displayCursor);
1631
- const cursorChar = cursorPos < dOff ? " " : displayValue[displayCursor] ?? " ";
1655
+ const cursorChar = renderCursor < dOff ? " " : displayValue[displayCursor] ?? " ";
1632
1656
  const visibleAfter = displayValue.slice(displayCursor + 1, scrollStart + lineWidth);
1633
1657
  const textPad = " ".repeat(Math.max(0, lineWidth - visibleBefore.length - 1 - visibleAfter.length));
1634
- const visibleSql = value.slice(scrollStart, scrollStart + lineWidth);
1635
- const relativeSqlCursor = cursorPos - scrollStart;
1658
+ const visibleSql = renderValue.slice(scrollStart, scrollStart + lineWidth);
1659
+ const relativeSqlCursor = renderCursor - scrollStart;
1636
1660
  const sqlCursorAtEnd = relativeSqlCursor >= visibleSql.length;
1637
1661
  const sqlPad = " ".repeat(Math.max(0, lineWidth - visibleSql.length - (sqlCursorAtEnd ? 1 : 0)));
1638
1662
  const emptyPad = " ".repeat(Math.max(0, lineWidth - placeholder.length - 1));
@@ -1644,31 +1668,37 @@ function QueryInput({ onSubmit, isLoading, onModeChange, onShellModeChange, vimE
1644
1668
  );
1645
1669
  const hintsInline = totalHintsWidth <= termWidth;
1646
1670
  return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", children: [
1647
- isMultiLine ? /* @__PURE__ */ jsxs(Box, { flexDirection: "column", children: [
1648
- /* @__PURE__ */ jsx(Box, { flexDirection: "column", borderStyle: "round", borderColor: ACCENT, paddingX: 1, children: value.split("\n").map((line, i, arr) => {
1671
+ isMultiLine ? /* @__PURE__ */ jsxs(Fragment, { children: [
1672
+ /* @__PURE__ */ jsx(Text, { backgroundColor: BG, children: emptyLine }),
1673
+ value.split("\n").map((line, i, arr) => {
1649
1674
  const numW = String(arr.length).length;
1675
+ const prefixWidth = 2 + numW + 3;
1676
+ const contentWidth = innerWidth - prefixWidth;
1650
1677
  const isLast = i === arr.length - 1;
1678
+ const linePad = " ".repeat(Math.max(0, contentWidth - line.length - (isLast ? 1 : 0)));
1651
1679
  return /* @__PURE__ */ jsxs(Box, { children: [
1652
- /* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
1680
+ /* @__PURE__ */ jsxs(Text, { backgroundColor: BG, dimColor: true, children: [
1681
+ " ",
1653
1682
  String(i + 1).padStart(numW),
1654
1683
  " \u2502 "
1655
1684
  ] }),
1656
- /* @__PURE__ */ jsx(SqlLine, { text: line }),
1657
- isLast && (mode === "INSERT" ? /* @__PURE__ */ jsx(Text, { color: ACCENT, bold: true, children: "\u258C" }) : /* @__PURE__ */ jsx(Text, { backgroundColor: ACCENT, color: BG, bold: true, children: " " }))
1685
+ /* @__PURE__ */ jsx(SqlLine, { text: line, bg: BG }),
1686
+ isLast && (mode === "INSERT" ? /* @__PURE__ */ jsx(Text, { backgroundColor: BG, color: PROMPT_MUTED, bold: true, children: "\u258C" }) : /* @__PURE__ */ jsx(Text, { backgroundColor: ACCENT, color: BG, bold: true, children: " " })),
1687
+ /* @__PURE__ */ jsx(Text, { backgroundColor: BG, children: linePad })
1658
1688
  ] }, i);
1659
- }) }),
1660
- /* @__PURE__ */ jsx(Box, { marginTop: 1, children: /* @__PURE__ */ jsx(Text, { dimColor: true, children: "Enter: run \xB7 Ctrl+E / e: re-edit" }) })
1689
+ }),
1690
+ /* @__PURE__ */ jsx(Text, { backgroundColor: BG, children: emptyLine })
1661
1691
  ] }) : /* @__PURE__ */ jsxs(Fragment, { children: [
1662
1692
  /* @__PURE__ */ jsx(Text, { backgroundColor: BG, children: emptyLine }),
1663
1693
  /* @__PURE__ */ jsxs(Box, { children: [
1664
- /* @__PURE__ */ jsx(Text, { backgroundColor: BG, color: isShellMode ? theme.shellMode : ACCENT, bold: true, children: isShellMode ? " $ " : " > " }),
1694
+ /* @__PURE__ */ jsx(Text, { backgroundColor: BG, color: isShellMode ? theme.shellMode : PROMPT_MUTED, bold: true, children: isShellMode ? " $ " : " > " }),
1665
1695
  isEmpty ? /* @__PURE__ */ jsxs(Fragment, { children: [
1666
1696
  /* @__PURE__ */ jsx(Text, { backgroundColor: BG, color: PLACEHOLDER, children: placeholder }),
1667
- /* @__PURE__ */ jsx(Text, { backgroundColor: BG, color: ACCENT, bold: true, children: "\u258C" }),
1697
+ /* @__PURE__ */ jsx(Text, { backgroundColor: BG, color: PROMPT_MUTED, bold: true, children: "\u258C" }),
1668
1698
  /* @__PURE__ */ jsx(Text, { backgroundColor: BG, children: emptyPad })
1669
1699
  ] }) : isShellMode || isCommand ? /* @__PURE__ */ jsxs(Fragment, { children: [
1670
1700
  /* @__PURE__ */ jsx(Text, { backgroundColor: BG, children: visibleBefore }),
1671
- mode === "INSERT" ? /* @__PURE__ */ jsx(Text, { backgroundColor: BG, color: ACCENT, bold: true, children: "\u258C" }) : /* @__PURE__ */ jsx(Text, { backgroundColor: ACCENT, color: BG, bold: true, children: cursorChar }),
1701
+ mode === "INSERT" ? /* @__PURE__ */ jsx(Text, { backgroundColor: BG, color: PROMPT_MUTED, bold: true, children: "\u258C" }) : /* @__PURE__ */ jsx(Text, { backgroundColor: ACCENT, color: BG, bold: true, children: cursorChar }),
1672
1702
  /* @__PURE__ */ jsxs(Text, { backgroundColor: BG, children: [
1673
1703
  visibleAfter,
1674
1704
  textPad
@@ -1713,7 +1743,7 @@ import { Box as Box2, Text as Text2 } from "ink";
1713
1743
  import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
1714
1744
  var COL_PAD = 1;
1715
1745
  var INDIGO = "#818cf8";
1716
- var BORDER = "white";
1746
+ var BORDER2 = "white";
1717
1747
  var NULL_COLOR = "#6366f1";
1718
1748
  var NULL_MARKER = "\u2205";
1719
1749
  function isNull(val) {
@@ -1744,10 +1774,10 @@ function hline(widths, left, mid, right) {
1744
1774
  function ExpandedTable({ columns, rows }) {
1745
1775
  const keyWidth = columns.reduce((max, col) => Math.max(max, col.length), 0);
1746
1776
  return /* @__PURE__ */ jsx2(Box2, { flexDirection: "column", children: rows.map((row, i) => /* @__PURE__ */ jsxs2(Box2, { flexDirection: "column", marginBottom: i < rows.length - 1 ? 1 : 0, children: [
1747
- /* @__PURE__ */ jsx2(Text2, { color: BORDER, children: `\u2500[ Record ${i + 1} ]${"\u2500".repeat(Math.max(0, keyWidth + 14 - String(i + 1).length))}` }),
1777
+ /* @__PURE__ */ jsx2(Text2, { color: BORDER2, children: `\u2500[ Record ${i + 1} ]${"\u2500".repeat(Math.max(0, keyWidth + 14 - String(i + 1).length))}` }),
1748
1778
  columns.map((col) => /* @__PURE__ */ jsxs2(Box2, { children: [
1749
1779
  /* @__PURE__ */ jsx2(Text2, { color: INDIGO, bold: true, children: col.padEnd(keyWidth) }),
1750
- /* @__PURE__ */ jsx2(Text2, { color: BORDER, children: " \u2502 " }),
1780
+ /* @__PURE__ */ jsx2(Text2, { color: BORDER2, children: " \u2502 " }),
1751
1781
  isNull(row[col]) ? /* @__PURE__ */ jsx2(Text2, { color: NULL_COLOR, dimColor: true, children: NULL_MARKER }) : /* @__PURE__ */ jsx2(Text2, { children: cellValue(row[col]) })
1752
1782
  ] }, col))
1753
1783
  ] }, i)) });
@@ -1760,51 +1790,43 @@ function Table({ columns, rows, expanded = false }) {
1760
1790
  const botLine = hline(widths, "\u2570", "\u2534", "\u256F");
1761
1791
  function renderHeaderRow(cols) {
1762
1792
  return /* @__PURE__ */ jsxs2(Box2, { children: [
1763
- /* @__PURE__ */ jsx2(Text2, { color: BORDER, children: "\u2502" }),
1793
+ /* @__PURE__ */ jsx2(Text2, { color: BORDER2, children: "\u2502" }),
1764
1794
  cols.map((v, i) => /* @__PURE__ */ jsxs2(Box2, { children: [
1765
1795
  /* @__PURE__ */ jsx2(Text2, { color: INDIGO, bold: true, children: " ".repeat(COL_PAD) + pad(v, widths[i]) + " ".repeat(COL_PAD) }),
1766
- /* @__PURE__ */ jsx2(Text2, { color: BORDER, children: "\u2502" })
1796
+ /* @__PURE__ */ jsx2(Text2, { color: BORDER2, children: "\u2502" })
1767
1797
  ] }, i))
1768
1798
  ] });
1769
1799
  }
1770
1800
  function renderDataRow(row) {
1771
1801
  return /* @__PURE__ */ jsxs2(Box2, { children: [
1772
- /* @__PURE__ */ jsx2(Text2, { color: BORDER, children: "\u2502" }),
1802
+ /* @__PURE__ */ jsx2(Text2, { color: BORDER2, children: "\u2502" }),
1773
1803
  columns.map((col, i) => /* @__PURE__ */ jsxs2(Box2, { children: [
1774
1804
  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) }),
1775
- /* @__PURE__ */ jsx2(Text2, { color: BORDER, children: "\u2502" })
1805
+ /* @__PURE__ */ jsx2(Text2, { color: BORDER2, children: "\u2502" })
1776
1806
  ] }, i))
1777
1807
  ] });
1778
1808
  }
1779
1809
  return /* @__PURE__ */ jsxs2(Box2, { flexDirection: "column", children: [
1780
- /* @__PURE__ */ jsx2(Text2, { color: BORDER, children: topLine }),
1810
+ /* @__PURE__ */ jsx2(Text2, { color: BORDER2, children: topLine }),
1781
1811
  renderHeaderRow(columns),
1782
- /* @__PURE__ */ jsx2(Text2, { color: BORDER, children: midLine }),
1812
+ /* @__PURE__ */ jsx2(Text2, { color: BORDER2, children: midLine }),
1783
1813
  rows.map((row, i) => /* @__PURE__ */ jsxs2(Box2, { flexDirection: "column", children: [
1784
1814
  renderDataRow(row),
1785
- i < rows.length - 1 && /* @__PURE__ */ jsx2(Text2, { color: BORDER, children: midLine })
1815
+ i < rows.length - 1 && /* @__PURE__ */ jsx2(Text2, { color: BORDER2, children: midLine })
1786
1816
  ] }, i)),
1787
- /* @__PURE__ */ jsx2(Text2, { color: BORDER, children: botLine })
1817
+ /* @__PURE__ */ jsx2(Text2, { color: BORDER2, children: botLine })
1788
1818
  ] });
1789
1819
  }
1790
1820
 
1791
1821
  // src/ui/components/QueryResult.tsx
1792
1822
  import { jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
1793
- var ERROR_BG = "#3b0f0f";
1794
1823
  var ERROR_FG = "#ff4444";
1795
1824
  function ErrorBox({ message }) {
1796
- const cols = Math.max(0, (process.stdout.columns ?? 80) - 2);
1797
- const blank = " ".repeat(cols);
1798
1825
  const lines = message.split("\n");
1799
- return /* @__PURE__ */ jsxs3(Box3, { flexDirection: "column", marginTop: 1, children: [
1800
- /* @__PURE__ */ jsx3(Text3, { backgroundColor: ERROR_BG, children: blank }),
1801
- lines.map((line, i) => {
1802
- const content = (i === 0 ? " \u2717 " : " ") + line;
1803
- const padded = content.length < cols ? content + " ".repeat(cols - content.length) : content;
1804
- return /* @__PURE__ */ jsx3(Text3, { backgroundColor: ERROR_BG, color: ERROR_FG, bold: true, children: padded }, i);
1805
- }),
1806
- /* @__PURE__ */ jsx3(Text3, { backgroundColor: ERROR_BG, children: blank })
1807
- ] });
1826
+ return /* @__PURE__ */ jsx3(Box3, { flexDirection: "column", marginTop: 1, children: lines.map((line, i) => /* @__PURE__ */ jsxs3(Text3, { color: ERROR_FG, bold: true, children: [
1827
+ i === 0 ? "\u2717 " : " ",
1828
+ line
1829
+ ] }, i)) });
1808
1830
  }
1809
1831
  function formatDuration(ms) {
1810
1832
  if (ms < 1e3) return `${ms}ms`;
@@ -1944,7 +1966,7 @@ import { jsx as jsx5, jsxs as jsxs5 } from "react/jsx-runtime";
1944
1966
  var USAGE_WIDTH = 28;
1945
1967
  function HelpView({ data }) {
1946
1968
  if (data.mode === "detail" && data.entry) {
1947
- const { usage, description, psqlAlias, detail, example } = data.entry;
1969
+ const { usage, description, psqlAlias, detail, example, examples } = data.entry;
1948
1970
  return /* @__PURE__ */ jsxs5(Box5, { flexDirection: "column", marginTop: 1, children: [
1949
1971
  /* @__PURE__ */ jsxs5(Text5, { bold: true, color: "white", children: [
1950
1972
  usage,
@@ -1952,10 +1974,13 @@ function HelpView({ data }) {
1952
1974
  ] }),
1953
1975
  /* @__PURE__ */ jsx5(Box5, { marginTop: 1, children: /* @__PURE__ */ jsx5(Text5, { children: description }) }),
1954
1976
  detail && /* @__PURE__ */ jsx5(Box5, { marginTop: 1, children: /* @__PURE__ */ jsx5(Text5, { dimColor: true, children: detail }) }),
1955
- example && /* @__PURE__ */ jsxs5(Box5, { marginTop: 1, children: [
1977
+ examples && examples.length > 0 ? /* @__PURE__ */ jsxs5(Box5, { flexDirection: "column", marginTop: 1, children: [
1978
+ /* @__PURE__ */ jsx5(Text5, { dimColor: true, children: "Examples:" }),
1979
+ examples.map((ex, i) => /* @__PURE__ */ jsx5(Box5, { marginLeft: 2, children: /* @__PURE__ */ jsx5(Text5, { color: theme.accent, children: ex }) }, i))
1980
+ ] }) : example ? /* @__PURE__ */ jsxs5(Box5, { marginTop: 1, children: [
1956
1981
  /* @__PURE__ */ jsx5(Text5, { dimColor: true, children: "Example: " }),
1957
1982
  /* @__PURE__ */ jsx5(Text5, { color: theme.accent, children: example })
1958
- ] })
1983
+ ] }) : null
1959
1984
  ] });
1960
1985
  }
1961
1986
  if (data.mode === "list" && data.groups) {
@@ -1994,7 +2019,6 @@ var TABLE_COLORS = [
1994
2019
  "#fbbf24",
1995
2020
  "#2dd4bf"
1996
2021
  ];
1997
- var BORDER2 = "white";
1998
2022
  var PAD = 1;
1999
2023
  var GAP = 2;
2000
2024
  var FK_PREFIX = "FK \u2192 ";
@@ -2042,31 +2066,31 @@ function TableBox({ table, m, color, colorMap }) {
2042
2066
  const bot = "\u2570" + "\u2500".repeat(nameW + PAD * 2) + "\u2534" + "\u2500".repeat(typeW + PAD * 2) + "\u2534" + "\u2500".repeat(keyW + PAD * 2) + "\u256F";
2043
2067
  const headerW = totalW - 4;
2044
2068
  return /* @__PURE__ */ jsxs6(Box6, { flexDirection: "column", children: [
2045
- /* @__PURE__ */ jsx6(Text6, { color: BORDER2, children: top }),
2069
+ /* @__PURE__ */ jsx6(Text6, { color, children: top }),
2046
2070
  /* @__PURE__ */ jsxs6(Box6, { children: [
2047
- /* @__PURE__ */ jsx6(Text6, { color: BORDER2, children: "\u2502" }),
2071
+ /* @__PURE__ */ jsx6(Text6, { color, children: "\u2502" }),
2048
2072
  /* @__PURE__ */ jsxs6(Text6, { color, bold: true, children: [
2049
2073
  sp,
2050
2074
  p(table.name, headerW),
2051
2075
  sp
2052
2076
  ] }),
2053
- /* @__PURE__ */ jsx6(Text6, { color: BORDER2, children: "\u2502" })
2077
+ /* @__PURE__ */ jsx6(Text6, { color, children: "\u2502" })
2054
2078
  ] }),
2055
- /* @__PURE__ */ jsx6(Text6, { color: BORDER2, children: sep }),
2079
+ /* @__PURE__ */ jsx6(Text6, { color, children: sep }),
2056
2080
  table.columns.map((col, i) => /* @__PURE__ */ jsxs6(Box6, { children: [
2057
- /* @__PURE__ */ jsx6(Text6, { color: BORDER2, children: "\u2502" }),
2081
+ /* @__PURE__ */ jsx6(Text6, { color, children: "\u2502" }),
2058
2082
  /* @__PURE__ */ jsxs6(Text6, { children: [
2059
2083
  sp,
2060
2084
  p(col.name, nameW),
2061
2085
  sp
2062
2086
  ] }),
2063
- /* @__PURE__ */ jsx6(Text6, { color: BORDER2, children: "\u2502" }),
2087
+ /* @__PURE__ */ jsx6(Text6, { color, children: "\u2502" }),
2064
2088
  /* @__PURE__ */ jsxs6(Text6, { dimColor: true, children: [
2065
2089
  sp,
2066
2090
  p(col.type, typeW),
2067
2091
  sp
2068
2092
  ] }),
2069
- /* @__PURE__ */ jsx6(Text6, { color: BORDER2, children: "\u2502" }),
2093
+ /* @__PURE__ */ jsx6(Text6, { color, children: "\u2502" }),
2070
2094
  col.isPk ? /* @__PURE__ */ jsxs6(Text6, { bold: true, children: [
2071
2095
  sp,
2072
2096
  p("PK", keyW),
@@ -2076,7 +2100,7 @@ function TableBox({ table, m, color, colorMap }) {
2076
2100
  sp,
2077
2101
  FK_PREFIX
2078
2102
  ] }),
2079
- /* @__PURE__ */ jsxs6(Text6, { color: colorMap.get(col.fkTable) ?? BORDER2, children: [
2103
+ /* @__PURE__ */ jsxs6(Text6, { color: colorMap.get(col.fkTable) ?? color, children: [
2080
2104
  p(col.fkTable, keyW - FK_PREFIX.length),
2081
2105
  sp
2082
2106
  ] })
@@ -2085,9 +2109,9 @@ function TableBox({ table, m, color, colorMap }) {
2085
2109
  " ".repeat(keyW),
2086
2110
  sp
2087
2111
  ] }),
2088
- /* @__PURE__ */ jsx6(Text6, { color: BORDER2, children: "\u2502" })
2112
+ /* @__PURE__ */ jsx6(Text6, { color, children: "\u2502" })
2089
2113
  ] }, i)),
2090
- /* @__PURE__ */ jsx6(Text6, { color: BORDER2, children: bot })
2114
+ /* @__PURE__ */ jsx6(Text6, { color, children: bot })
2091
2115
  ] });
2092
2116
  }
2093
2117
  function ErdView({ data }) {
@@ -2105,7 +2129,7 @@ function ErdView({ data }) {
2105
2129
  {
2106
2130
  table: data.tables[ti],
2107
2131
  m: metrics[ti],
2108
- color: colorMap.get(data.tables[ti].name) ?? BORDER2,
2132
+ color: colorMap.get(data.tables[ti].name) ?? BORDER,
2109
2133
  colorMap
2110
2134
  }
2111
2135
  ) }, ti)) }, ri)) });
@@ -2124,6 +2148,12 @@ function limitLines(s, n) {
2124
2148
  return lines.slice(0, n).join("\n") + `
2125
2149
  \u2026 +${lines.length - n} more lines (scroll up after next submit)`;
2126
2150
  }
2151
+ function displayQuery(query) {
2152
+ const cols = process.stdout.columns ?? 80;
2153
+ const max = Math.max(20, cols - 16);
2154
+ const flat = query.replace(/\n/g, " ").replace(/\s+/g, " ").trim();
2155
+ return flat.length > max ? flat.slice(0, max) + "\u2026" : flat;
2156
+ }
2127
2157
  function EntryView({ entry }) {
2128
2158
  const showAi = entry.aiResponse !== "" || entry.aiError !== null;
2129
2159
  const showErd = entry.erdData !== null;
@@ -2136,7 +2166,7 @@ function EntryView({ entry }) {
2136
2166
  label,
2137
2167
  " "
2138
2168
  ] }),
2139
- /* @__PURE__ */ jsx7(Text7, { dimColor: true, children: entry.query })
2169
+ /* @__PURE__ */ jsx7(Text7, { dimColor: true, children: displayQuery(entry.query) })
2140
2170
  ] }),
2141
2171
  /* @__PURE__ */ jsx7(Box7, { marginTop: 1, flexDirection: "column", children: isShell ? entry.shellOutput !== null && /* @__PURE__ */ jsx7(Text7, { children: entry.shellOutput || "(no output)" }) : /* @__PURE__ */ jsxs7(Fragment4, { children: [
2142
2172
  entry.commandMessage && (entry.commandMessage.helpData ? /* @__PURE__ */ jsx7(HelpView, { data: entry.commandMessage.helpData }) : entry.commandMessage.ok ? /* @__PURE__ */ jsxs7(Text7, { color: theme.accent, children: [
@@ -2419,7 +2449,7 @@ function App({ connectionState, aiUrl: aiUrl2, aiModel: aiModel2, aiKey: aiKey2,
2419
2449
  activeLabel,
2420
2450
  " "
2421
2451
  ] }),
2422
- /* @__PURE__ */ jsx7(Text7, { dimColor: true, children: lastQuery })
2452
+ /* @__PURE__ */ jsx7(Text7, { dimColor: true, children: displayQuery(lastQuery) })
2423
2453
  ] }),
2424
2454
  /* @__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: [
2425
2455
  commandMessage && (commandMessage.helpData ? /* @__PURE__ */ jsx7(HelpView, { data: commandMessage.helpData }) : commandMessage.ok ? /* @__PURE__ */ jsxs7(Text7, { color: theme.accent, children: [
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@deaquinodev/querky",
3
- "version": "0.4.4",
3
+ "version": "0.4.6",
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": [