@deaquinodev/querky 0.4.3 → 0.4.5
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.
- package/dist/index.js +338 -77
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
// src/index.tsx
|
|
4
4
|
import { useState as useState5, useEffect as useEffect5 } from "react";
|
|
5
5
|
import { parseArgs } from "util";
|
|
6
|
-
import { render, Box as
|
|
6
|
+
import { render, Box as Box9, Text as Text9 } from "ink";
|
|
7
7
|
|
|
8
8
|
// src/db/client.ts
|
|
9
9
|
import { Client } from "pg";
|
|
@@ -39,10 +39,11 @@ var PgDbClient = class {
|
|
|
39
39
|
}
|
|
40
40
|
pg;
|
|
41
41
|
async query(sql) {
|
|
42
|
-
const
|
|
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
|
}
|
|
@@ -196,7 +197,7 @@ import { useState as useState3, useEffect as useEffect4, useRef as useRef2 } fro
|
|
|
196
197
|
import { writeFileSync as writeFileSync5 } from "fs";
|
|
197
198
|
import { homedir as homedir4 } from "os";
|
|
198
199
|
import { join as join6 } from "path";
|
|
199
|
-
import { Box as
|
|
200
|
+
import { Box as Box7, Text as Text7, Static, useApp, useInput as useInput2, useStdin as useStdin2 } from "ink";
|
|
200
201
|
|
|
201
202
|
// src/db/query.ts
|
|
202
203
|
async function runQuery(client, sql) {
|
|
@@ -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>.
|
|
629
|
-
|
|
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.
|
|
644
|
-
|
|
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>" };
|
|
@@ -678,6 +689,16 @@ var COMMANDS = {
|
|
|
678
689
|
return removed ? { ok: true, message: `Removed /${name}` } : { ok: false, message: `No alias named /${name}` };
|
|
679
690
|
}
|
|
680
691
|
},
|
|
692
|
+
"erd": {
|
|
693
|
+
description: "Visualize tables and relationships as a schema diagram",
|
|
694
|
+
category: "Schema",
|
|
695
|
+
usage: "/erd",
|
|
696
|
+
detail: "Fetches all tables, columns, and foreign key relationships from the connected database and renders a color-coded schema diagram. Each table gets a unique color; FK references use the color of the table they point to.",
|
|
697
|
+
run: (ctx) => {
|
|
698
|
+
ctx.onErd();
|
|
699
|
+
return { ok: true, message: "" };
|
|
700
|
+
}
|
|
701
|
+
},
|
|
681
702
|
"help": {
|
|
682
703
|
description: "Show help for all commands or a specific command",
|
|
683
704
|
category: "Session",
|
|
@@ -696,7 +717,8 @@ var COMMANDS = {
|
|
|
696
717
|
description: cmd.description,
|
|
697
718
|
psqlAlias: PSQL_REVERSE[name],
|
|
698
719
|
detail: cmd.detail,
|
|
699
|
-
example: cmd.example
|
|
720
|
+
example: cmd.example,
|
|
721
|
+
examples: cmd.examples
|
|
700
722
|
};
|
|
701
723
|
return { ok: true, message: "", helpData: { mode: "detail", entry } };
|
|
702
724
|
}
|
|
@@ -745,6 +767,83 @@ function runCommand(input, ctx) {
|
|
|
745
767
|
return { ok: false, message: `Unknown command: ${prefix}${rawName}` };
|
|
746
768
|
}
|
|
747
769
|
|
|
770
|
+
// src/db/erd.ts
|
|
771
|
+
function erdSql(driver) {
|
|
772
|
+
if (driver === "postgresql") {
|
|
773
|
+
return `
|
|
774
|
+
SELECT c.table_name, c.column_name, c.data_type,
|
|
775
|
+
(pk.column_name IS NOT NULL) AS is_pk,
|
|
776
|
+
fk.foreign_table AS fk_table
|
|
777
|
+
FROM information_schema.columns c
|
|
778
|
+
LEFT JOIN (
|
|
779
|
+
SELECT kcu.table_name, kcu.column_name
|
|
780
|
+
FROM information_schema.table_constraints tc
|
|
781
|
+
JOIN information_schema.key_column_usage kcu
|
|
782
|
+
ON tc.constraint_name = kcu.constraint_name AND tc.table_schema = kcu.table_schema
|
|
783
|
+
WHERE tc.constraint_type = 'PRIMARY KEY' AND tc.table_schema = 'public'
|
|
784
|
+
) pk ON pk.table_name = c.table_name AND pk.column_name = c.column_name
|
|
785
|
+
LEFT JOIN (
|
|
786
|
+
SELECT kcu.table_name, kcu.column_name, ccu.table_name AS foreign_table
|
|
787
|
+
FROM information_schema.table_constraints tc
|
|
788
|
+
JOIN information_schema.key_column_usage kcu
|
|
789
|
+
ON tc.constraint_name = kcu.constraint_name AND tc.table_schema = kcu.table_schema
|
|
790
|
+
JOIN information_schema.constraint_column_usage ccu
|
|
791
|
+
ON tc.constraint_name = ccu.constraint_name AND tc.table_schema = ccu.table_schema
|
|
792
|
+
WHERE tc.constraint_type = 'FOREIGN KEY' AND tc.table_schema = 'public'
|
|
793
|
+
) fk ON fk.table_name = c.table_name AND fk.column_name = c.column_name
|
|
794
|
+
WHERE c.table_schema = 'public'
|
|
795
|
+
ORDER BY c.table_name, c.ordinal_position
|
|
796
|
+
`;
|
|
797
|
+
}
|
|
798
|
+
if (driver === "mysql") {
|
|
799
|
+
return `
|
|
800
|
+
SELECT c.TABLE_NAME AS table_name, c.COLUMN_NAME AS column_name,
|
|
801
|
+
c.DATA_TYPE AS data_type,
|
|
802
|
+
(c.COLUMN_KEY = 'PRI') AS is_pk,
|
|
803
|
+
kcu.REFERENCED_TABLE_NAME AS fk_table
|
|
804
|
+
FROM information_schema.COLUMNS c
|
|
805
|
+
LEFT JOIN information_schema.KEY_COLUMN_USAGE kcu
|
|
806
|
+
ON kcu.TABLE_SCHEMA = c.TABLE_SCHEMA
|
|
807
|
+
AND kcu.TABLE_NAME = c.TABLE_NAME
|
|
808
|
+
AND kcu.COLUMN_NAME = c.COLUMN_NAME
|
|
809
|
+
AND kcu.REFERENCED_TABLE_NAME IS NOT NULL
|
|
810
|
+
WHERE c.TABLE_SCHEMA = DATABASE()
|
|
811
|
+
ORDER BY c.TABLE_NAME, c.ORDINAL_POSITION
|
|
812
|
+
`;
|
|
813
|
+
}
|
|
814
|
+
return `
|
|
815
|
+
SELECT m.name AS table_name, p.name AS column_name,
|
|
816
|
+
p.type AS data_type,
|
|
817
|
+
(p.pk > 0) AS is_pk,
|
|
818
|
+
f."table" AS fk_table
|
|
819
|
+
FROM sqlite_master m
|
|
820
|
+
JOIN pragma_table_info(m.name) p
|
|
821
|
+
LEFT JOIN pragma_foreign_key_list(m.name) f ON f."from" = p.name
|
|
822
|
+
WHERE m.type = 'table' AND m.name NOT LIKE 'sqlite_%'
|
|
823
|
+
ORDER BY m.name, p.cid
|
|
824
|
+
`;
|
|
825
|
+
}
|
|
826
|
+
async function fetchErd(client, driver) {
|
|
827
|
+
const result = await client.query(erdSql(driver));
|
|
828
|
+
const tableMap = /* @__PURE__ */ new Map();
|
|
829
|
+
for (const row of result.rows) {
|
|
830
|
+
const tableName = String(row["table_name"] ?? "");
|
|
831
|
+
if (!tableMap.has(tableName)) tableMap.set(tableName, []);
|
|
832
|
+
const cols = tableMap.get(tableName);
|
|
833
|
+
const colName = String(row["column_name"] ?? "");
|
|
834
|
+
if (cols.some((c) => c.name === colName)) continue;
|
|
835
|
+
cols.push({
|
|
836
|
+
name: colName,
|
|
837
|
+
type: String(row["data_type"] ?? ""),
|
|
838
|
+
isPk: Boolean(row["is_pk"]),
|
|
839
|
+
fkTable: row["fk_table"] ? String(row["fk_table"]) : void 0
|
|
840
|
+
});
|
|
841
|
+
}
|
|
842
|
+
return {
|
|
843
|
+
tables: Array.from(tableMap.entries()).map(([name, columns]) => ({ name, columns }))
|
|
844
|
+
};
|
|
845
|
+
}
|
|
846
|
+
|
|
748
847
|
// src/commands/shell.ts
|
|
749
848
|
import { exec } from "child_process";
|
|
750
849
|
import { readFileSync as readFileSync2, writeFileSync as writeFileSync2, unlinkSync } from "fs";
|
|
@@ -1626,7 +1725,7 @@ import { Box as Box2, Text as Text2 } from "ink";
|
|
|
1626
1725
|
import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
1627
1726
|
var COL_PAD = 1;
|
|
1628
1727
|
var INDIGO = "#818cf8";
|
|
1629
|
-
var
|
|
1728
|
+
var BORDER2 = "white";
|
|
1630
1729
|
var NULL_COLOR = "#6366f1";
|
|
1631
1730
|
var NULL_MARKER = "\u2205";
|
|
1632
1731
|
function isNull(val) {
|
|
@@ -1657,10 +1756,10 @@ function hline(widths, left, mid, right) {
|
|
|
1657
1756
|
function ExpandedTable({ columns, rows }) {
|
|
1658
1757
|
const keyWidth = columns.reduce((max, col) => Math.max(max, col.length), 0);
|
|
1659
1758
|
return /* @__PURE__ */ jsx2(Box2, { flexDirection: "column", children: rows.map((row, i) => /* @__PURE__ */ jsxs2(Box2, { flexDirection: "column", marginBottom: i < rows.length - 1 ? 1 : 0, children: [
|
|
1660
|
-
/* @__PURE__ */ jsx2(Text2, { color:
|
|
1759
|
+
/* @__PURE__ */ jsx2(Text2, { color: BORDER2, children: `\u2500[ Record ${i + 1} ]${"\u2500".repeat(Math.max(0, keyWidth + 14 - String(i + 1).length))}` }),
|
|
1661
1760
|
columns.map((col) => /* @__PURE__ */ jsxs2(Box2, { children: [
|
|
1662
1761
|
/* @__PURE__ */ jsx2(Text2, { color: INDIGO, bold: true, children: col.padEnd(keyWidth) }),
|
|
1663
|
-
/* @__PURE__ */ jsx2(Text2, { color:
|
|
1762
|
+
/* @__PURE__ */ jsx2(Text2, { color: BORDER2, children: " \u2502 " }),
|
|
1664
1763
|
isNull(row[col]) ? /* @__PURE__ */ jsx2(Text2, { color: NULL_COLOR, dimColor: true, children: NULL_MARKER }) : /* @__PURE__ */ jsx2(Text2, { children: cellValue(row[col]) })
|
|
1665
1764
|
] }, col))
|
|
1666
1765
|
] }, i)) });
|
|
@@ -1673,31 +1772,31 @@ function Table({ columns, rows, expanded = false }) {
|
|
|
1673
1772
|
const botLine = hline(widths, "\u2570", "\u2534", "\u256F");
|
|
1674
1773
|
function renderHeaderRow(cols) {
|
|
1675
1774
|
return /* @__PURE__ */ jsxs2(Box2, { children: [
|
|
1676
|
-
/* @__PURE__ */ jsx2(Text2, { color:
|
|
1775
|
+
/* @__PURE__ */ jsx2(Text2, { color: BORDER2, children: "\u2502" }),
|
|
1677
1776
|
cols.map((v, i) => /* @__PURE__ */ jsxs2(Box2, { children: [
|
|
1678
1777
|
/* @__PURE__ */ jsx2(Text2, { color: INDIGO, bold: true, children: " ".repeat(COL_PAD) + pad(v, widths[i]) + " ".repeat(COL_PAD) }),
|
|
1679
|
-
/* @__PURE__ */ jsx2(Text2, { color:
|
|
1778
|
+
/* @__PURE__ */ jsx2(Text2, { color: BORDER2, children: "\u2502" })
|
|
1680
1779
|
] }, i))
|
|
1681
1780
|
] });
|
|
1682
1781
|
}
|
|
1683
1782
|
function renderDataRow(row) {
|
|
1684
1783
|
return /* @__PURE__ */ jsxs2(Box2, { children: [
|
|
1685
|
-
/* @__PURE__ */ jsx2(Text2, { color:
|
|
1784
|
+
/* @__PURE__ */ jsx2(Text2, { color: BORDER2, children: "\u2502" }),
|
|
1686
1785
|
columns.map((col, i) => /* @__PURE__ */ jsxs2(Box2, { children: [
|
|
1687
1786
|
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) }),
|
|
1688
|
-
/* @__PURE__ */ jsx2(Text2, { color:
|
|
1787
|
+
/* @__PURE__ */ jsx2(Text2, { color: BORDER2, children: "\u2502" })
|
|
1689
1788
|
] }, i))
|
|
1690
1789
|
] });
|
|
1691
1790
|
}
|
|
1692
1791
|
return /* @__PURE__ */ jsxs2(Box2, { flexDirection: "column", children: [
|
|
1693
|
-
/* @__PURE__ */ jsx2(Text2, { color:
|
|
1792
|
+
/* @__PURE__ */ jsx2(Text2, { color: BORDER2, children: topLine }),
|
|
1694
1793
|
renderHeaderRow(columns),
|
|
1695
|
-
/* @__PURE__ */ jsx2(Text2, { color:
|
|
1794
|
+
/* @__PURE__ */ jsx2(Text2, { color: BORDER2, children: midLine }),
|
|
1696
1795
|
rows.map((row, i) => /* @__PURE__ */ jsxs2(Box2, { flexDirection: "column", children: [
|
|
1697
1796
|
renderDataRow(row),
|
|
1698
|
-
i < rows.length - 1 && /* @__PURE__ */ jsx2(Text2, { color:
|
|
1797
|
+
i < rows.length - 1 && /* @__PURE__ */ jsx2(Text2, { color: BORDER2, children: midLine })
|
|
1699
1798
|
] }, i)),
|
|
1700
|
-
/* @__PURE__ */ jsx2(Text2, { color:
|
|
1799
|
+
/* @__PURE__ */ jsx2(Text2, { color: BORDER2, children: botLine })
|
|
1701
1800
|
] });
|
|
1702
1801
|
}
|
|
1703
1802
|
|
|
@@ -1857,7 +1956,7 @@ import { jsx as jsx5, jsxs as jsxs5 } from "react/jsx-runtime";
|
|
|
1857
1956
|
var USAGE_WIDTH = 28;
|
|
1858
1957
|
function HelpView({ data }) {
|
|
1859
1958
|
if (data.mode === "detail" && data.entry) {
|
|
1860
|
-
const { usage, description, psqlAlias, detail, example } = data.entry;
|
|
1959
|
+
const { usage, description, psqlAlias, detail, example, examples } = data.entry;
|
|
1861
1960
|
return /* @__PURE__ */ jsxs5(Box5, { flexDirection: "column", marginTop: 1, children: [
|
|
1862
1961
|
/* @__PURE__ */ jsxs5(Text5, { bold: true, color: "white", children: [
|
|
1863
1962
|
usage,
|
|
@@ -1865,10 +1964,13 @@ function HelpView({ data }) {
|
|
|
1865
1964
|
] }),
|
|
1866
1965
|
/* @__PURE__ */ jsx5(Box5, { marginTop: 1, children: /* @__PURE__ */ jsx5(Text5, { children: description }) }),
|
|
1867
1966
|
detail && /* @__PURE__ */ jsx5(Box5, { marginTop: 1, children: /* @__PURE__ */ jsx5(Text5, { dimColor: true, children: detail }) }),
|
|
1868
|
-
|
|
1967
|
+
examples && examples.length > 0 ? /* @__PURE__ */ jsxs5(Box5, { flexDirection: "column", marginTop: 1, children: [
|
|
1968
|
+
/* @__PURE__ */ jsx5(Text5, { dimColor: true, children: "Examples:" }),
|
|
1969
|
+
examples.map((ex, i) => /* @__PURE__ */ jsx5(Box5, { marginLeft: 2, children: /* @__PURE__ */ jsx5(Text5, { color: theme.accent, children: ex }) }, i))
|
|
1970
|
+
] }) : example ? /* @__PURE__ */ jsxs5(Box5, { marginTop: 1, children: [
|
|
1869
1971
|
/* @__PURE__ */ jsx5(Text5, { dimColor: true, children: "Example: " }),
|
|
1870
1972
|
/* @__PURE__ */ jsx5(Text5, { color: theme.accent, children: example })
|
|
1871
|
-
] })
|
|
1973
|
+
] }) : null
|
|
1872
1974
|
] });
|
|
1873
1975
|
}
|
|
1874
1976
|
if (data.mode === "list" && data.groups) {
|
|
@@ -1894,8 +1996,137 @@ function HelpView({ data }) {
|
|
|
1894
1996
|
return null;
|
|
1895
1997
|
}
|
|
1896
1998
|
|
|
1897
|
-
// src/ui/components/
|
|
1999
|
+
// src/ui/components/ErdView.tsx
|
|
2000
|
+
import { Box as Box6, Text as Text6 } from "ink";
|
|
1898
2001
|
import { Fragment as Fragment3, jsx as jsx6, jsxs as jsxs6 } from "react/jsx-runtime";
|
|
2002
|
+
var TABLE_COLORS = [
|
|
2003
|
+
"#f472b6",
|
|
2004
|
+
"#34d399",
|
|
2005
|
+
"#fb923c",
|
|
2006
|
+
"#60a5fa",
|
|
2007
|
+
"#a78bfa",
|
|
2008
|
+
"#f87171",
|
|
2009
|
+
"#fbbf24",
|
|
2010
|
+
"#2dd4bf"
|
|
2011
|
+
];
|
|
2012
|
+
var PAD = 1;
|
|
2013
|
+
var GAP = 2;
|
|
2014
|
+
var FK_PREFIX = "FK \u2192 ";
|
|
2015
|
+
function computeMetrics(table) {
|
|
2016
|
+
const nameW = Math.max(2, ...table.columns.map((c) => c.name.length));
|
|
2017
|
+
const typeW = Math.max(4, ...table.columns.map((c) => c.type.length));
|
|
2018
|
+
const keyW = Math.max(
|
|
2019
|
+
2,
|
|
2020
|
+
...table.columns.map((c) => {
|
|
2021
|
+
if (c.isPk) return 2;
|
|
2022
|
+
if (c.fkTable) return FK_PREFIX.length + c.fkTable.length;
|
|
2023
|
+
return 0;
|
|
2024
|
+
})
|
|
2025
|
+
);
|
|
2026
|
+
const totalW = 4 + 3 * PAD * 2 + nameW + typeW + keyW;
|
|
2027
|
+
return { nameW, typeW, keyW, totalW };
|
|
2028
|
+
}
|
|
2029
|
+
function groupIntoRows(metrics, termW) {
|
|
2030
|
+
const rows = [];
|
|
2031
|
+
let row = [];
|
|
2032
|
+
let usedW = 0;
|
|
2033
|
+
for (let i = 0; i < metrics.length; i++) {
|
|
2034
|
+
const w = metrics[i].totalW;
|
|
2035
|
+
if (row.length === 0) {
|
|
2036
|
+
row.push(i);
|
|
2037
|
+
usedW = w;
|
|
2038
|
+
} else if (usedW + GAP + w <= termW) {
|
|
2039
|
+
row.push(i);
|
|
2040
|
+
usedW += GAP + w;
|
|
2041
|
+
} else {
|
|
2042
|
+
rows.push(row);
|
|
2043
|
+
row = [i];
|
|
2044
|
+
usedW = w;
|
|
2045
|
+
}
|
|
2046
|
+
}
|
|
2047
|
+
if (row.length > 0) rows.push(row);
|
|
2048
|
+
return rows;
|
|
2049
|
+
}
|
|
2050
|
+
function TableBox({ table, m, color, colorMap }) {
|
|
2051
|
+
const { nameW, typeW, keyW, totalW } = m;
|
|
2052
|
+
const sp = " ".repeat(PAD);
|
|
2053
|
+
const p = (s, w) => s.slice(0, w).padEnd(w);
|
|
2054
|
+
const top = "\u256D" + "\u2500".repeat(totalW - 2) + "\u256E";
|
|
2055
|
+
const sep = "\u251C" + "\u2500".repeat(nameW + PAD * 2) + "\u252C" + "\u2500".repeat(typeW + PAD * 2) + "\u252C" + "\u2500".repeat(keyW + PAD * 2) + "\u2524";
|
|
2056
|
+
const bot = "\u2570" + "\u2500".repeat(nameW + PAD * 2) + "\u2534" + "\u2500".repeat(typeW + PAD * 2) + "\u2534" + "\u2500".repeat(keyW + PAD * 2) + "\u256F";
|
|
2057
|
+
const headerW = totalW - 4;
|
|
2058
|
+
return /* @__PURE__ */ jsxs6(Box6, { flexDirection: "column", children: [
|
|
2059
|
+
/* @__PURE__ */ jsx6(Text6, { color, children: top }),
|
|
2060
|
+
/* @__PURE__ */ jsxs6(Box6, { children: [
|
|
2061
|
+
/* @__PURE__ */ jsx6(Text6, { color, children: "\u2502" }),
|
|
2062
|
+
/* @__PURE__ */ jsxs6(Text6, { color, bold: true, children: [
|
|
2063
|
+
sp,
|
|
2064
|
+
p(table.name, headerW),
|
|
2065
|
+
sp
|
|
2066
|
+
] }),
|
|
2067
|
+
/* @__PURE__ */ jsx6(Text6, { color, children: "\u2502" })
|
|
2068
|
+
] }),
|
|
2069
|
+
/* @__PURE__ */ jsx6(Text6, { color, children: sep }),
|
|
2070
|
+
table.columns.map((col, i) => /* @__PURE__ */ jsxs6(Box6, { children: [
|
|
2071
|
+
/* @__PURE__ */ jsx6(Text6, { color, children: "\u2502" }),
|
|
2072
|
+
/* @__PURE__ */ jsxs6(Text6, { children: [
|
|
2073
|
+
sp,
|
|
2074
|
+
p(col.name, nameW),
|
|
2075
|
+
sp
|
|
2076
|
+
] }),
|
|
2077
|
+
/* @__PURE__ */ jsx6(Text6, { color, children: "\u2502" }),
|
|
2078
|
+
/* @__PURE__ */ jsxs6(Text6, { dimColor: true, children: [
|
|
2079
|
+
sp,
|
|
2080
|
+
p(col.type, typeW),
|
|
2081
|
+
sp
|
|
2082
|
+
] }),
|
|
2083
|
+
/* @__PURE__ */ jsx6(Text6, { color, children: "\u2502" }),
|
|
2084
|
+
col.isPk ? /* @__PURE__ */ jsxs6(Text6, { bold: true, children: [
|
|
2085
|
+
sp,
|
|
2086
|
+
p("PK", keyW),
|
|
2087
|
+
sp
|
|
2088
|
+
] }) : col.fkTable ? /* @__PURE__ */ jsxs6(Fragment3, { children: [
|
|
2089
|
+
/* @__PURE__ */ jsxs6(Text6, { dimColor: true, children: [
|
|
2090
|
+
sp,
|
|
2091
|
+
FK_PREFIX
|
|
2092
|
+
] }),
|
|
2093
|
+
/* @__PURE__ */ jsxs6(Text6, { color: colorMap.get(col.fkTable) ?? color, children: [
|
|
2094
|
+
p(col.fkTable, keyW - FK_PREFIX.length),
|
|
2095
|
+
sp
|
|
2096
|
+
] })
|
|
2097
|
+
] }) : /* @__PURE__ */ jsxs6(Text6, { children: [
|
|
2098
|
+
sp,
|
|
2099
|
+
" ".repeat(keyW),
|
|
2100
|
+
sp
|
|
2101
|
+
] }),
|
|
2102
|
+
/* @__PURE__ */ jsx6(Text6, { color, children: "\u2502" })
|
|
2103
|
+
] }, i)),
|
|
2104
|
+
/* @__PURE__ */ jsx6(Text6, { color, children: bot })
|
|
2105
|
+
] });
|
|
2106
|
+
}
|
|
2107
|
+
function ErdView({ data }) {
|
|
2108
|
+
if (data.tables.length === 0) {
|
|
2109
|
+
return /* @__PURE__ */ jsx6(Text6, { dimColor: true, children: "No tables found in the current schema." });
|
|
2110
|
+
}
|
|
2111
|
+
const termW = process.stdout.columns ?? 80;
|
|
2112
|
+
const metrics = data.tables.map(computeMetrics);
|
|
2113
|
+
const colorMap = new Map(
|
|
2114
|
+
data.tables.map((t, i) => [t.name, TABLE_COLORS[i % TABLE_COLORS.length]])
|
|
2115
|
+
);
|
|
2116
|
+
const rows = groupIntoRows(metrics, termW);
|
|
2117
|
+
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(
|
|
2118
|
+
TableBox,
|
|
2119
|
+
{
|
|
2120
|
+
table: data.tables[ti],
|
|
2121
|
+
m: metrics[ti],
|
|
2122
|
+
color: colorMap.get(data.tables[ti].name) ?? BORDER,
|
|
2123
|
+
colorMap
|
|
2124
|
+
}
|
|
2125
|
+
) }, ti)) }, ri)) });
|
|
2126
|
+
}
|
|
2127
|
+
|
|
2128
|
+
// src/ui/components/App.tsx
|
|
2129
|
+
import { Fragment as Fragment4, jsx as jsx7, jsxs as jsxs7 } from "react/jsx-runtime";
|
|
1899
2130
|
var PAGE_SIZE = 50;
|
|
1900
2131
|
var PLACEHOLDER2 = "#a5b4fc";
|
|
1901
2132
|
function activePageSize() {
|
|
@@ -1909,26 +2140,27 @@ function limitLines(s, n) {
|
|
|
1909
2140
|
}
|
|
1910
2141
|
function EntryView({ entry }) {
|
|
1911
2142
|
const showAi = entry.aiResponse !== "" || entry.aiError !== null;
|
|
2143
|
+
const showErd = entry.erdData !== null;
|
|
1912
2144
|
const isShell = entry.query.startsWith("!");
|
|
1913
2145
|
const isCommand = !isShell && (entry.query.startsWith("/") || entry.query.startsWith("\\"));
|
|
1914
2146
|
const label = isShell ? "Shell:" : isCommand ? "Command:" : "Query:";
|
|
1915
|
-
return /* @__PURE__ */
|
|
1916
|
-
/* @__PURE__ */
|
|
1917
|
-
/* @__PURE__ */
|
|
2147
|
+
return /* @__PURE__ */ jsxs7(Box7, { flexDirection: "column", marginBottom: 1, paddingX: 1, children: [
|
|
2148
|
+
/* @__PURE__ */ jsxs7(Box7, { borderStyle: "round", borderColor: theme.accent, paddingX: 1, children: [
|
|
2149
|
+
/* @__PURE__ */ jsxs7(Text7, { color: theme.accent, bold: true, children: [
|
|
1918
2150
|
label,
|
|
1919
2151
|
" "
|
|
1920
2152
|
] }),
|
|
1921
|
-
/* @__PURE__ */
|
|
2153
|
+
/* @__PURE__ */ jsx7(Text7, { dimColor: true, children: entry.query })
|
|
1922
2154
|
] }),
|
|
1923
|
-
/* @__PURE__ */
|
|
1924
|
-
entry.commandMessage && (entry.commandMessage.helpData ? /* @__PURE__ */
|
|
2155
|
+
/* @__PURE__ */ jsx7(Box7, { marginTop: 1, flexDirection: "column", children: isShell ? entry.shellOutput !== null && /* @__PURE__ */ jsx7(Text7, { children: entry.shellOutput || "(no output)" }) : /* @__PURE__ */ jsxs7(Fragment4, { children: [
|
|
2156
|
+
entry.commandMessage && (entry.commandMessage.helpData ? /* @__PURE__ */ jsx7(HelpView, { data: entry.commandMessage.helpData }) : entry.commandMessage.ok ? /* @__PURE__ */ jsxs7(Text7, { color: theme.accent, children: [
|
|
1925
2157
|
"\u2713 ",
|
|
1926
2158
|
entry.commandMessage.text
|
|
1927
|
-
] }) : /* @__PURE__ */
|
|
1928
|
-
showAi ? /* @__PURE__ */
|
|
1929
|
-
/* @__PURE__ */
|
|
1930
|
-
/* @__PURE__ */
|
|
1931
|
-
] }) : !entry.commandMessage && /* @__PURE__ */
|
|
2159
|
+
] }) : /* @__PURE__ */ jsx7(ErrorBox, { message: entry.commandMessage.text })),
|
|
2160
|
+
showErd ? /* @__PURE__ */ jsx7(ErdView, { data: entry.erdData }) : showAi ? /* @__PURE__ */ jsxs7(Box7, { flexDirection: "column", children: [
|
|
2161
|
+
/* @__PURE__ */ jsx7(Text7, { color: theme.accent, bold: true, children: "Explanation:" }),
|
|
2162
|
+
/* @__PURE__ */ jsx7(Box7, { flexDirection: "column", marginTop: 1, children: entry.aiError ? /* @__PURE__ */ jsx7(ErrorBox, { message: entry.aiError }) : /* @__PURE__ */ jsx7(Text7, { color: PLACEHOLDER2, children: entry.aiResponse }) })
|
|
2163
|
+
] }) : !entry.commandMessage && /* @__PURE__ */ jsx7(QueryResult, { state: entry.queryState, elapsed: entry.elapsed, page: entry.page, pageSize: PAGE_SIZE })
|
|
1932
2164
|
] }) })
|
|
1933
2165
|
] });
|
|
1934
2166
|
}
|
|
@@ -1952,6 +2184,8 @@ function App({ connectionState, aiUrl: aiUrl2, aiModel: aiModel2, aiKey: aiKey2,
|
|
|
1952
2184
|
const [aiError, setAiError] = useState3(null);
|
|
1953
2185
|
const [shellOutput, setShellOutput] = useState3(null);
|
|
1954
2186
|
const [isShellRunning, setIsShellRunning] = useState3(false);
|
|
2187
|
+
const [erdData, setErdData] = useState3(null);
|
|
2188
|
+
const [isErdLoading, setIsErdLoading] = useState3(false);
|
|
1955
2189
|
const [completedEntries, setCompletedEntries] = useState3([]);
|
|
1956
2190
|
const entryIdRef = useRef2(0);
|
|
1957
2191
|
const aliasScope = connectionState.status === "connected" ? makeScope(connectionState.driver, connectionState.user, connectionState.host, connectionState.database) : "";
|
|
@@ -2017,8 +2251,29 @@ function App({ connectionState, aiUrl: aiUrl2, aiModel: aiModel2, aiKey: aiKey2,
|
|
|
2017
2251
|
setIsStreaming(false);
|
|
2018
2252
|
}
|
|
2019
2253
|
}
|
|
2254
|
+
async function handleErd() {
|
|
2255
|
+
if (connectionState.status !== "connected") {
|
|
2256
|
+
setCommandMessage({ ok: false, text: "Not connected to a database." });
|
|
2257
|
+
return;
|
|
2258
|
+
}
|
|
2259
|
+
setErdData(null);
|
|
2260
|
+
setIsErdLoading(true);
|
|
2261
|
+
setCommandMessage(null);
|
|
2262
|
+
setQueryState({ status: "idle" });
|
|
2263
|
+
setAiResponse("");
|
|
2264
|
+
setAiError(null);
|
|
2265
|
+
try {
|
|
2266
|
+
const data = await fetchErd(connectionState.client, connectionState.driver);
|
|
2267
|
+
setErdData(data);
|
|
2268
|
+
} catch (err) {
|
|
2269
|
+
setCommandMessage({ ok: false, text: err instanceof Error ? err.message : String(err) });
|
|
2270
|
+
} finally {
|
|
2271
|
+
setIsErdLoading(false);
|
|
2272
|
+
}
|
|
2273
|
+
}
|
|
2020
2274
|
async function handleQuery(sql) {
|
|
2021
2275
|
if (connectionState.status !== "connected") return;
|
|
2276
|
+
setErdData(null);
|
|
2022
2277
|
setAiResponse("");
|
|
2023
2278
|
setAiError(null);
|
|
2024
2279
|
setCommandMessage(null);
|
|
@@ -2076,11 +2331,13 @@ function App({ connectionState, aiUrl: aiUrl2, aiModel: aiModel2, aiKey: aiKey2,
|
|
|
2076
2331
|
page,
|
|
2077
2332
|
aiResponse,
|
|
2078
2333
|
aiError,
|
|
2079
|
-
shellOutput
|
|
2334
|
+
shellOutput,
|
|
2335
|
+
erdData
|
|
2080
2336
|
}
|
|
2081
2337
|
]);
|
|
2082
2338
|
}
|
|
2083
2339
|
async function handleShell(cmd) {
|
|
2340
|
+
setErdData(null);
|
|
2084
2341
|
setShellOutput(null);
|
|
2085
2342
|
setIsShellRunning(true);
|
|
2086
2343
|
setCommandMessage(null);
|
|
@@ -2126,6 +2383,9 @@ function App({ connectionState, aiUrl: aiUrl2, aiModel: aiModel2, aiKey: aiKey2,
|
|
|
2126
2383
|
onChangeDatabase?.(db);
|
|
2127
2384
|
},
|
|
2128
2385
|
onExport: handleExport,
|
|
2386
|
+
onErd: () => {
|
|
2387
|
+
void handleErd();
|
|
2388
|
+
},
|
|
2129
2389
|
onClear: () => {
|
|
2130
2390
|
process.stdout.write("\x1B[2J\x1B[3J\x1B[H");
|
|
2131
2391
|
setCompletedEntries([]);
|
|
@@ -2144,6 +2404,7 @@ function App({ connectionState, aiUrl: aiUrl2, aiModel: aiModel2, aiKey: aiKey2,
|
|
|
2144
2404
|
});
|
|
2145
2405
|
if (result.cleared) return;
|
|
2146
2406
|
setLastQuery(sql);
|
|
2407
|
+
setErdData(null);
|
|
2147
2408
|
setAiResponse("");
|
|
2148
2409
|
setAiError(null);
|
|
2149
2410
|
setElapsed(null);
|
|
@@ -2156,39 +2417,39 @@ function App({ connectionState, aiUrl: aiUrl2, aiModel: aiModel2, aiKey: aiKey2,
|
|
|
2156
2417
|
}
|
|
2157
2418
|
void handleQuery(sql);
|
|
2158
2419
|
}
|
|
2159
|
-
const isLoading = queryState.status === "running" || isStreaming || isShellRunning;
|
|
2420
|
+
const isLoading = queryState.status === "running" || isStreaming || isShellRunning || isErdLoading;
|
|
2160
2421
|
const isConnected = connectionState.status === "connected";
|
|
2161
2422
|
const showAi = aiResponse !== "" || isStreaming || aiError !== null;
|
|
2162
2423
|
const isShellEntry = lastQuery.startsWith("!");
|
|
2163
2424
|
const isCommand = !isShellEntry && (lastQuery.startsWith("/") || lastQuery.startsWith("\\"));
|
|
2164
2425
|
const activeLabel = isShellEntry ? "Shell:" : isCommand ? "Command:" : "Query:";
|
|
2165
|
-
return /* @__PURE__ */
|
|
2166
|
-
/* @__PURE__ */
|
|
2167
|
-
/* @__PURE__ */
|
|
2168
|
-
lastQuery === "" && /* @__PURE__ */
|
|
2169
|
-
lastQuery !== "" && /* @__PURE__ */
|
|
2170
|
-
/* @__PURE__ */
|
|
2171
|
-
/* @__PURE__ */
|
|
2426
|
+
return /* @__PURE__ */ jsxs7(Box7, { flexDirection: "column", children: [
|
|
2427
|
+
/* @__PURE__ */ jsx7(Static, { items: completedEntries, children: (entry) => /* @__PURE__ */ jsx7(EntryView, { entry }, entry.id) }),
|
|
2428
|
+
/* @__PURE__ */ jsxs7(Box7, { flexDirection: "column", paddingX: 1, children: [
|
|
2429
|
+
lastQuery === "" && /* @__PURE__ */ jsx7(Banner, { connectionState }),
|
|
2430
|
+
lastQuery !== "" && /* @__PURE__ */ jsxs7(Box7, { flexDirection: "column", marginBottom: 2, children: [
|
|
2431
|
+
/* @__PURE__ */ jsxs7(Box7, { borderStyle: "round", borderColor: theme.accent, paddingX: 1, children: [
|
|
2432
|
+
/* @__PURE__ */ jsxs7(Text7, { color: theme.accent, bold: true, children: [
|
|
2172
2433
|
activeLabel,
|
|
2173
2434
|
" "
|
|
2174
2435
|
] }),
|
|
2175
|
-
/* @__PURE__ */
|
|
2436
|
+
/* @__PURE__ */ jsx7(Text7, { dimColor: true, children: lastQuery })
|
|
2176
2437
|
] }),
|
|
2177
|
-
/* @__PURE__ */
|
|
2178
|
-
commandMessage && (commandMessage.helpData ? /* @__PURE__ */
|
|
2438
|
+
/* @__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: [
|
|
2439
|
+
commandMessage && (commandMessage.helpData ? /* @__PURE__ */ jsx7(HelpView, { data: commandMessage.helpData }) : commandMessage.ok ? /* @__PURE__ */ jsxs7(Text7, { color: theme.accent, children: [
|
|
2179
2440
|
"\u2713 ",
|
|
2180
2441
|
commandMessage.text
|
|
2181
|
-
] }) : /* @__PURE__ */
|
|
2182
|
-
showAi ? /* @__PURE__ */
|
|
2183
|
-
/* @__PURE__ */
|
|
2184
|
-
/* @__PURE__ */
|
|
2442
|
+
] }) : /* @__PURE__ */ jsx7(ErrorBox, { message: commandMessage.text })),
|
|
2443
|
+
isErdLoading ? /* @__PURE__ */ jsx7(Text7, { dimColor: true, children: "Fetching schema\u2026" }) : erdData ? /* @__PURE__ */ jsx7(ErdView, { data: erdData }) : showAi ? /* @__PURE__ */ jsxs7(Box7, { flexDirection: "column", children: [
|
|
2444
|
+
/* @__PURE__ */ jsx7(Text7, { color: theme.accent, bold: true, children: "Explanation:" }),
|
|
2445
|
+
/* @__PURE__ */ jsx7(Box7, { flexDirection: "column", marginTop: 1, children: aiError ? /* @__PURE__ */ jsx7(ErrorBox, { message: aiError }) : /* @__PURE__ */ jsxs7(Text7, { color: PLACEHOLDER2, children: [
|
|
2185
2446
|
aiResponse,
|
|
2186
|
-
isStreaming && /* @__PURE__ */
|
|
2447
|
+
isStreaming && /* @__PURE__ */ jsx7(Text7, { color: PLACEHOLDER2, children: "\u258B" })
|
|
2187
2448
|
] }) })
|
|
2188
|
-
] }) : !commandMessage && /* @__PURE__ */
|
|
2449
|
+
] }) : !commandMessage && /* @__PURE__ */ jsx7(QueryResult, { state: queryState, elapsed, page, pageSize: activePageSize() })
|
|
2189
2450
|
] }) })
|
|
2190
2451
|
] }),
|
|
2191
|
-
isConnected ? /* @__PURE__ */
|
|
2452
|
+
isConnected ? /* @__PURE__ */ jsx7(
|
|
2192
2453
|
QueryInput,
|
|
2193
2454
|
{
|
|
2194
2455
|
onSubmit: handleSubmit,
|
|
@@ -2200,16 +2461,16 @@ function App({ connectionState, aiUrl: aiUrl2, aiModel: aiModel2, aiKey: aiKey2,
|
|
|
2200
2461
|
aliases,
|
|
2201
2462
|
schema: schema ?? void 0
|
|
2202
2463
|
}
|
|
2203
|
-
) : /* @__PURE__ */
|
|
2204
|
-
(vimEnabled || inputIsShell) && /* @__PURE__ */
|
|
2464
|
+
) : /* @__PURE__ */ jsx7(Text7, { dimColor: true, children: "Not connected. Press Ctrl+C to exit." }),
|
|
2465
|
+
(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}]` : "" }) })
|
|
2205
2466
|
] })
|
|
2206
2467
|
] });
|
|
2207
2468
|
}
|
|
2208
2469
|
|
|
2209
2470
|
// src/ui/components/ConnectionWizard.tsx
|
|
2210
2471
|
import { useState as useState4 } from "react";
|
|
2211
|
-
import { Box as
|
|
2212
|
-
import { jsx as
|
|
2472
|
+
import { Box as Box8, Text as Text8, useInput as useInput3, useStdin as useStdin3 } from "ink";
|
|
2473
|
+
import { jsx as jsx8, jsxs as jsxs8 } from "react/jsx-runtime";
|
|
2213
2474
|
var DRIVERS = ["postgresql", "mysql", "sqlite"];
|
|
2214
2475
|
var LABEL_WIDTH = 10;
|
|
2215
2476
|
function fieldLabels(driver) {
|
|
@@ -2364,36 +2625,36 @@ function ConnectionWizard({ onConnect, initialError }) {
|
|
|
2364
2625
|
{ isActive: isRawModeSupported }
|
|
2365
2626
|
);
|
|
2366
2627
|
const isPassword = (idx) => fields.driver !== "sqlite" && idx === 5;
|
|
2367
|
-
return /* @__PURE__ */
|
|
2368
|
-
/* @__PURE__ */
|
|
2628
|
+
return /* @__PURE__ */ jsxs8(Box8, { flexDirection: "column", paddingX: 2, paddingTop: 2, paddingBottom: 1, children: [
|
|
2629
|
+
/* @__PURE__ */ jsx8(Box8, { marginBottom: 1, children: /* @__PURE__ */ jsx8(Text8, { bold: true, color: theme.accent, children: "Connect to a database" }) }),
|
|
2369
2630
|
labels.map((label, idx) => {
|
|
2370
2631
|
const isFocused = focus === idx;
|
|
2371
2632
|
const isDriver = idx === 0;
|
|
2372
|
-
return /* @__PURE__ */
|
|
2373
|
-
/* @__PURE__ */
|
|
2374
|
-
isDriver ? /* @__PURE__ */
|
|
2375
|
-
i > 0 && /* @__PURE__ */
|
|
2376
|
-
/* @__PURE__ */
|
|
2633
|
+
return /* @__PURE__ */ jsxs8(Box8, { children: [
|
|
2634
|
+
/* @__PURE__ */ jsx8(Text8, { color: isFocused ? theme.accent : void 0, bold: isFocused, children: label.padEnd(LABEL_WIDTH) }),
|
|
2635
|
+
isDriver ? /* @__PURE__ */ jsx8(Box8, { children: DRIVERS.map((d, i) => /* @__PURE__ */ jsxs8(Box8, { children: [
|
|
2636
|
+
i > 0 && /* @__PURE__ */ jsx8(Text8, { children: " " }),
|
|
2637
|
+
/* @__PURE__ */ jsxs8(Text8, { color: fields.driver === d ? theme.accent : void 0, bold: fields.driver === d, children: [
|
|
2377
2638
|
fields.driver === d ? "\u25CF " : "\u25CB ",
|
|
2378
2639
|
d.charAt(0).toUpperCase() + d.slice(1)
|
|
2379
2640
|
] })
|
|
2380
|
-
] }, d)) }) : /* @__PURE__ */
|
|
2381
|
-
/* @__PURE__ */
|
|
2382
|
-
isFocused && /* @__PURE__ */
|
|
2383
|
-
isFocused && isPassword(idx) && keychainHint && /* @__PURE__ */
|
|
2641
|
+
] }, d)) }) : /* @__PURE__ */ jsxs8(Box8, { children: [
|
|
2642
|
+
/* @__PURE__ */ jsx8(Text8, { children: isPassword(idx) ? "\u2022".repeat(getTextValue(idx).length) : getTextValue(idx) }),
|
|
2643
|
+
isFocused && /* @__PURE__ */ jsx8(Text8, { color: theme.accent, bold: true, children: "\u258C" }),
|
|
2644
|
+
isFocused && isPassword(idx) && keychainHint && /* @__PURE__ */ jsx8(Text8, { dimColor: true, children: " (from keychain)" })
|
|
2384
2645
|
] })
|
|
2385
2646
|
] }, label);
|
|
2386
2647
|
}),
|
|
2387
|
-
/* @__PURE__ */
|
|
2648
|
+
/* @__PURE__ */ jsx8(Box8, { marginTop: 1, children: connecting ? /* @__PURE__ */ jsx8(Text8, { dimColor: true, children: "Connecting\u2026" }) : error ? /* @__PURE__ */ jsxs8(Text8, { color: theme.error, children: [
|
|
2388
2649
|
"\u2717 ",
|
|
2389
2650
|
error
|
|
2390
2651
|
] }) : null }),
|
|
2391
|
-
/* @__PURE__ */
|
|
2652
|
+
/* @__PURE__ */ jsx8(Box8, { marginTop: 1, children: /* @__PURE__ */ jsx8(Text8, { dimColor: true, children: "Tab \xB7 \u2191\u2193 navigate Enter connect \u2190\u2192 cycle driver" }) })
|
|
2392
2653
|
] });
|
|
2393
2654
|
}
|
|
2394
2655
|
|
|
2395
2656
|
// src/index.tsx
|
|
2396
|
-
import { jsx as
|
|
2657
|
+
import { jsx as jsx9 } from "react/jsx-runtime";
|
|
2397
2658
|
var { values } = parseArgs({
|
|
2398
2659
|
args: process.argv.slice(2).filter((a) => a !== "--"),
|
|
2399
2660
|
options: {
|
|
@@ -2423,10 +2684,10 @@ function Root({ initialDsn: initialDsn2, aiUrl: aiUrl2, aiModel: aiModel2, aiKey
|
|
|
2423
2684
|
}
|
|
2424
2685
|
}, []);
|
|
2425
2686
|
if (initialDsn2 && !connectionState && !dsnError) {
|
|
2426
|
-
return /* @__PURE__ */
|
|
2687
|
+
return /* @__PURE__ */ jsx9(Box9, { paddingX: 2, paddingTop: 1, children: /* @__PURE__ */ jsx9(Text9, { dimColor: true, children: "Connecting\u2026" }) });
|
|
2427
2688
|
}
|
|
2428
2689
|
if (!connectionState) {
|
|
2429
|
-
return /* @__PURE__ */
|
|
2690
|
+
return /* @__PURE__ */ jsx9(ConnectionWizard, { onConnect: setConnectionState, initialError: dsnError ?? void 0 });
|
|
2430
2691
|
}
|
|
2431
2692
|
async function handleChangeDatabase(database) {
|
|
2432
2693
|
if (connectionState.status !== "connected") return;
|
|
@@ -2436,7 +2697,7 @@ function Root({ initialDsn: initialDsn2, aiUrl: aiUrl2, aiModel: aiModel2, aiKey
|
|
|
2436
2697
|
const next = await connectParams({ ...current.params, database });
|
|
2437
2698
|
setConnectionState(next);
|
|
2438
2699
|
}
|
|
2439
|
-
return /* @__PURE__ */
|
|
2700
|
+
return /* @__PURE__ */ jsx9(
|
|
2440
2701
|
App,
|
|
2441
2702
|
{
|
|
2442
2703
|
connectionState,
|
|
@@ -2450,6 +2711,6 @@ function Root({ initialDsn: initialDsn2, aiUrl: aiUrl2, aiModel: aiModel2, aiKey
|
|
|
2450
2711
|
);
|
|
2451
2712
|
}
|
|
2452
2713
|
render(
|
|
2453
|
-
/* @__PURE__ */
|
|
2714
|
+
/* @__PURE__ */ jsx9(Root, { initialDsn, aiUrl, aiModel, aiKey }),
|
|
2454
2715
|
{ exitOnCtrlC: true }
|
|
2455
2716
|
);
|