@thingd/cli 0.55.0 → 0.56.0
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/interactive.d.ts.map +1 -1
- package/dist/interactive.js +379 -4
- package/package.json +2 -2
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"interactive.d.ts","sourceRoot":"","sources":["../src/interactive.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"interactive.d.ts","sourceRoot":"","sources":["../src/interactive.ts"],"names":[],"mappings":"AAu8FA,wBAAsB,iBAAiB,IAAI,OAAO,CAAC,IAAI,CAAC,CA0FvD"}
|
package/dist/interactive.js
CHANGED
|
@@ -69,6 +69,7 @@ let collections = [];
|
|
|
69
69
|
let streams = [];
|
|
70
70
|
let queues = [];
|
|
71
71
|
let objectsByCollection = new Map();
|
|
72
|
+
const collectionOptions = new Map();
|
|
72
73
|
const expandedSet = new Set(["cat:collections", "cat:streams", "cat:queues"]);
|
|
73
74
|
let cursorIndex = 0;
|
|
74
75
|
let maintenanceCursor = 0;
|
|
@@ -244,7 +245,21 @@ async function fetchResourcesFallback() {
|
|
|
244
245
|
objectsByCollection.clear();
|
|
245
246
|
await Promise.all(collections.map(async (col) => {
|
|
246
247
|
try {
|
|
247
|
-
const
|
|
248
|
+
const opts = collectionOptions.get(col);
|
|
249
|
+
const listOpts = {};
|
|
250
|
+
if (opts?.sortBy) {
|
|
251
|
+
listOpts.sortBy = { field: opts.sortBy, direction: opts.sortDir ?? "asc" };
|
|
252
|
+
}
|
|
253
|
+
if (opts?.limit) {
|
|
254
|
+
listOpts.limit = opts.limit;
|
|
255
|
+
}
|
|
256
|
+
if (opts?.offset) {
|
|
257
|
+
listOpts.offset = opts.offset;
|
|
258
|
+
}
|
|
259
|
+
if (opts?.filter) {
|
|
260
|
+
listOpts.filter = opts.filter;
|
|
261
|
+
}
|
|
262
|
+
const list = await db.listObjects(col, Object.keys(listOpts).length > 0 ? listOpts : undefined);
|
|
248
263
|
objectsByCollection.set(col, list.map((o) => o.id));
|
|
249
264
|
}
|
|
250
265
|
catch {
|
|
@@ -289,7 +304,21 @@ async function fetchResources() {
|
|
|
289
304
|
objectsByCollection.clear();
|
|
290
305
|
for (const col of collections) {
|
|
291
306
|
try {
|
|
292
|
-
const
|
|
307
|
+
const opts = collectionOptions.get(col);
|
|
308
|
+
const listOpts = {};
|
|
309
|
+
if (opts?.sortBy) {
|
|
310
|
+
listOpts.sortBy = { field: opts.sortBy, direction: opts.sortDir ?? "asc" };
|
|
311
|
+
}
|
|
312
|
+
if (opts?.limit) {
|
|
313
|
+
listOpts.limit = opts.limit;
|
|
314
|
+
}
|
|
315
|
+
if (opts?.offset) {
|
|
316
|
+
listOpts.offset = opts.offset;
|
|
317
|
+
}
|
|
318
|
+
if (opts?.filter) {
|
|
319
|
+
listOpts.filter = opts.filter;
|
|
320
|
+
}
|
|
321
|
+
const list = await db.listObjects(col, Object.keys(listOpts).length > 0 ? listOpts : undefined);
|
|
293
322
|
objectsByCollection.set(col, list.map((o) => o.id));
|
|
294
323
|
}
|
|
295
324
|
catch {
|
|
@@ -758,6 +787,27 @@ async function loadContent(node) {
|
|
|
758
787
|
const ref = node.ref;
|
|
759
788
|
const objs = objectsByCollection.get(ref.name) ?? [];
|
|
760
789
|
let res = `${pc.bold(ref.name)} ${pc.dim(`(${objs.length} objects)`)}\n\n`;
|
|
790
|
+
// Schema info
|
|
791
|
+
try {
|
|
792
|
+
const schemas = await db.schema(ref.name);
|
|
793
|
+
if (schemas.length > 0) {
|
|
794
|
+
const fields = schemas[0]?.fields ?? [];
|
|
795
|
+
if (fields.length > 0) {
|
|
796
|
+
res += `${pc.bold("Fields")}\n`;
|
|
797
|
+
for (const f of fields) {
|
|
798
|
+
const icon = f.nullable ? pc.dim("⊙") : pc.cyan("◎");
|
|
799
|
+
const sample = f.sampleValues.length > 0
|
|
800
|
+
? pc.dim(` e.g. ${String(f.sampleValues[0]).slice(0, 20)}`)
|
|
801
|
+
: "";
|
|
802
|
+
res += ` ${icon} ${f.name}: ${f.type}${sample}\n`;
|
|
803
|
+
}
|
|
804
|
+
res += "\n";
|
|
805
|
+
}
|
|
806
|
+
}
|
|
807
|
+
}
|
|
808
|
+
catch {
|
|
809
|
+
// Schema not available for this store
|
|
810
|
+
}
|
|
761
811
|
if (objs.length === 0) {
|
|
762
812
|
res += pc.dim("No objects in this collection.");
|
|
763
813
|
}
|
|
@@ -1041,7 +1091,7 @@ function draw() {
|
|
|
1041
1091
|
help = ` ${pc.dim("↑↓")} nav ${pc.dim("enter")} connect ${pc.dim("q")} quit `;
|
|
1042
1092
|
}
|
|
1043
1093
|
else {
|
|
1044
|
-
help = ` ${pc.dim("↑↓")} nav ${pc.dim("←→")} toggle ${pc.dim("c")} create ${pc.dim("e")} edit ${pc.dim("d")} delete ${pc.dim("/")} search ${pc.dim("n")} neighbors ${pc.dim("i")} info ${pc.dim("r")} refresh ${pc.dim("s")} switch ${pc.dim("l")} logout ${pc.dim("q")} quit `;
|
|
1094
|
+
help = ` ${pc.dim("↑↓")} nav ${pc.dim("←→")} toggle ${pc.dim("c")} create ${pc.dim("e")} edit ${pc.dim("d")} delete ${pc.dim("/")} search ${pc.dim("n")} neighbors ${pc.dim("N")} nlq ${pc.dim("a")} agg ${pc.dim("t")} ts ${pc.dim("o")} options ${pc.dim("b")} batch ${pc.dim("i")} info ${pc.dim("r")} refresh ${pc.dim("s")} switch ${pc.dim("l")} logout ${pc.dim("q")} quit `;
|
|
1045
1095
|
}
|
|
1046
1096
|
buf += `${pc.dim("─".repeat(W))}\n`;
|
|
1047
1097
|
buf += padToWidth(help, W);
|
|
@@ -1661,6 +1711,316 @@ async function handleNeighbors(selected) {
|
|
|
1661
1711
|
draw();
|
|
1662
1712
|
});
|
|
1663
1713
|
}
|
|
1714
|
+
async function handleAggregate(selected) {
|
|
1715
|
+
const defaultCol = selected?.type === "collection"
|
|
1716
|
+
? (selected.ref?.name ?? "")
|
|
1717
|
+
: selected?.type === "object"
|
|
1718
|
+
? (selected.ref?.collection ?? "")
|
|
1719
|
+
: "";
|
|
1720
|
+
openForm("Aggregate", [
|
|
1721
|
+
{
|
|
1722
|
+
id: "function",
|
|
1723
|
+
label: "Function",
|
|
1724
|
+
value: "count",
|
|
1725
|
+
options: ["count", "sum", "avg", "min", "max"],
|
|
1726
|
+
},
|
|
1727
|
+
{
|
|
1728
|
+
id: "collection",
|
|
1729
|
+
label: "Collection",
|
|
1730
|
+
value: defaultCol,
|
|
1731
|
+
options: collections,
|
|
1732
|
+
allowCustom: true,
|
|
1733
|
+
},
|
|
1734
|
+
{ id: "field", label: "Field (for sum/avg/min/max)", placeholder: "field name" },
|
|
1735
|
+
{ id: "groupBy", label: "Group By (optional field)", placeholder: "field name" },
|
|
1736
|
+
{ id: "filter", label: "Filter (optional JSON)", placeholder: '{"status":"active"}' },
|
|
1737
|
+
], async (vals) => {
|
|
1738
|
+
const func = vals.function || "count";
|
|
1739
|
+
const collection = (vals.collection || "").trim();
|
|
1740
|
+
if (!collection) {
|
|
1741
|
+
throw new Error("Collection is required.");
|
|
1742
|
+
}
|
|
1743
|
+
const field = (vals.field || "").trim() || undefined;
|
|
1744
|
+
const groupBy = (vals.groupBy || "").trim() || undefined;
|
|
1745
|
+
const filter = vals.filter?.trim() ? JSON.parse(vals.filter.trim()) : undefined;
|
|
1746
|
+
const options = { groupBy, filter };
|
|
1747
|
+
const a = db.aggregate;
|
|
1748
|
+
const result = func === "count"
|
|
1749
|
+
? await a.count(collection, options)
|
|
1750
|
+
: func === "sum"
|
|
1751
|
+
? await a.sum(collection, field, options)
|
|
1752
|
+
: func === "avg"
|
|
1753
|
+
? await a.avg(collection, field, options)
|
|
1754
|
+
: func === "min"
|
|
1755
|
+
? await a.min(collection, field, options)
|
|
1756
|
+
: await a.max(collection, field, options);
|
|
1757
|
+
const lines = [
|
|
1758
|
+
` ${pc.bold("Aggregate")} ${pc.cyan(func)} ${pc.dim(`on ${collection}`)}`,
|
|
1759
|
+
"",
|
|
1760
|
+
` ${pc.dim("Total:")} ${pc.bold(String(result.total))}`,
|
|
1761
|
+
"",
|
|
1762
|
+
];
|
|
1763
|
+
if (result.groups && result.groups.length > 0) {
|
|
1764
|
+
lines.push(` ${pc.bold("Groups")}`);
|
|
1765
|
+
const maxVal = Math.max(...result.groups.map((g) => g.value));
|
|
1766
|
+
for (const g of result.groups) {
|
|
1767
|
+
const barLen = Math.max(1, Math.round((g.value / maxVal) * 20));
|
|
1768
|
+
const bar = pc.cyan("█".repeat(barLen));
|
|
1769
|
+
lines.push(` ${g.key}: ${bar} ${pc.dim(String(g.value))}`);
|
|
1770
|
+
}
|
|
1771
|
+
}
|
|
1772
|
+
viewerLines = lines;
|
|
1773
|
+
loadedItemId = "aggregate_result";
|
|
1774
|
+
draw();
|
|
1775
|
+
});
|
|
1776
|
+
}
|
|
1777
|
+
async function handleTimeseries(selected) {
|
|
1778
|
+
const defaultCol = selected?.type === "collection"
|
|
1779
|
+
? (selected.ref?.name ?? "")
|
|
1780
|
+
: selected?.type === "object"
|
|
1781
|
+
? (selected.ref?.collection ?? "")
|
|
1782
|
+
: "";
|
|
1783
|
+
openForm("Time Series", [
|
|
1784
|
+
{
|
|
1785
|
+
id: "function",
|
|
1786
|
+
label: "Function",
|
|
1787
|
+
value: "count",
|
|
1788
|
+
options: ["count", "sum", "avg", "min", "max"],
|
|
1789
|
+
},
|
|
1790
|
+
{
|
|
1791
|
+
id: "collection",
|
|
1792
|
+
label: "Collection",
|
|
1793
|
+
value: defaultCol,
|
|
1794
|
+
options: collections,
|
|
1795
|
+
allowCustom: true,
|
|
1796
|
+
},
|
|
1797
|
+
{ id: "field", label: "Field (optional)", placeholder: "field name" },
|
|
1798
|
+
{
|
|
1799
|
+
id: "bucket",
|
|
1800
|
+
label: "Bucket",
|
|
1801
|
+
value: "day",
|
|
1802
|
+
options: ["hour", "day", "week", "month"],
|
|
1803
|
+
},
|
|
1804
|
+
{ id: "from", label: "From (ISO date, optional)", placeholder: "2024-01-01" },
|
|
1805
|
+
{ id: "to", label: "To (ISO date, optional)", placeholder: "2024-12-31" },
|
|
1806
|
+
{ id: "filter", label: "Filter (optional JSON)", placeholder: '{"status":"active"}' },
|
|
1807
|
+
], async (vals) => {
|
|
1808
|
+
const func = vals.function || "count";
|
|
1809
|
+
const collection = (vals.collection || "").trim();
|
|
1810
|
+
if (!collection) {
|
|
1811
|
+
throw new Error("Collection is required.");
|
|
1812
|
+
}
|
|
1813
|
+
const field = (vals.field || "").trim() || undefined;
|
|
1814
|
+
const bucket = (vals.bucket || "day");
|
|
1815
|
+
const from = (vals.from || "").trim() || undefined;
|
|
1816
|
+
const to = (vals.to || "").trim() || undefined;
|
|
1817
|
+
const filter = vals.filter?.trim() ? JSON.parse(vals.filter.trim()) : undefined;
|
|
1818
|
+
const result = await db.timeseries(collection, {
|
|
1819
|
+
function: func,
|
|
1820
|
+
field,
|
|
1821
|
+
bucket,
|
|
1822
|
+
from,
|
|
1823
|
+
to,
|
|
1824
|
+
filter,
|
|
1825
|
+
});
|
|
1826
|
+
const lines = [
|
|
1827
|
+
` ${pc.bold("Time Series")} ${pc.cyan(func)} ${pc.dim(`on ${collection}, ${bucket}ly`)}`,
|
|
1828
|
+
"",
|
|
1829
|
+
];
|
|
1830
|
+
if (result.buckets.length === 0) {
|
|
1831
|
+
lines.push(pc.dim("No data for the selected range."));
|
|
1832
|
+
}
|
|
1833
|
+
else {
|
|
1834
|
+
const maxVal = Math.max(...result.buckets.map((b) => b.value));
|
|
1835
|
+
for (const b of result.buckets) {
|
|
1836
|
+
const barLen = Math.max(1, Math.round((b.value / maxVal) * 20));
|
|
1837
|
+
const bar = pc.green("█".repeat(barLen));
|
|
1838
|
+
lines.push(` ${b.label}: ${bar} ${pc.dim(String(b.value))}`);
|
|
1839
|
+
}
|
|
1840
|
+
}
|
|
1841
|
+
viewerLines = lines;
|
|
1842
|
+
loadedItemId = "timeseries_result";
|
|
1843
|
+
draw();
|
|
1844
|
+
});
|
|
1845
|
+
}
|
|
1846
|
+
async function handleNlq(selected) {
|
|
1847
|
+
const defaultCol = selected?.type === "collection"
|
|
1848
|
+
? (selected.ref?.name ?? "")
|
|
1849
|
+
: selected?.type === "object"
|
|
1850
|
+
? (selected.ref?.collection ?? "")
|
|
1851
|
+
: "";
|
|
1852
|
+
openForm("Natural Language Query", [
|
|
1853
|
+
{ id: "question", label: "Question", placeholder: "How many active users?" },
|
|
1854
|
+
{
|
|
1855
|
+
id: "collection",
|
|
1856
|
+
label: "Collection (optional)",
|
|
1857
|
+
value: defaultCol,
|
|
1858
|
+
options: collections,
|
|
1859
|
+
allowCustom: true,
|
|
1860
|
+
},
|
|
1861
|
+
], async (vals) => {
|
|
1862
|
+
const question = (vals.question || "").trim();
|
|
1863
|
+
if (!question) {
|
|
1864
|
+
throw new Error("Question is required.");
|
|
1865
|
+
}
|
|
1866
|
+
const collection = (vals.collection || "").trim() || undefined;
|
|
1867
|
+
const result = await db.nlq.query(question, {
|
|
1868
|
+
collection,
|
|
1869
|
+
});
|
|
1870
|
+
const intent = result.intent;
|
|
1871
|
+
const lines = [
|
|
1872
|
+
` ${pc.bold("NLQ Result")}`,
|
|
1873
|
+
` ${pc.dim(`Question: ${question}`)}`,
|
|
1874
|
+
"",
|
|
1875
|
+
` ${result.answer}`,
|
|
1876
|
+
"",
|
|
1877
|
+
];
|
|
1878
|
+
if (intent) {
|
|
1879
|
+
lines.push(` ${pc.dim("Interpreted as:")} ${intent.action} ${pc.dim("on")} ${pc.cyan(intent.collection)}`);
|
|
1880
|
+
if (intent.function) {
|
|
1881
|
+
lines.push(` ${pc.dim("Function:")} ${intent.function}`);
|
|
1882
|
+
}
|
|
1883
|
+
if (intent.field) {
|
|
1884
|
+
lines.push(` ${pc.dim("Field:")} ${intent.field}`);
|
|
1885
|
+
}
|
|
1886
|
+
if (intent.query) {
|
|
1887
|
+
lines.push(` ${pc.dim("Query:")} ${intent.query}`);
|
|
1888
|
+
}
|
|
1889
|
+
}
|
|
1890
|
+
if (result.data !== undefined && result.data !== null) {
|
|
1891
|
+
lines.push("", highlightJson(result.data));
|
|
1892
|
+
}
|
|
1893
|
+
viewerLines = lines;
|
|
1894
|
+
loadedItemId = "nlq_result";
|
|
1895
|
+
draw();
|
|
1896
|
+
});
|
|
1897
|
+
}
|
|
1898
|
+
async function handleCollectionOptions(selected) {
|
|
1899
|
+
const colName = selected?.type === "collection"
|
|
1900
|
+
? (selected.ref?.name ?? "")
|
|
1901
|
+
: selected?.type === "object"
|
|
1902
|
+
? (selected.ref?.collection ?? "")
|
|
1903
|
+
: "";
|
|
1904
|
+
if (!colName) {
|
|
1905
|
+
viewerLines = [pc.yellow("Select a collection first, then press [o] to set listing options.")];
|
|
1906
|
+
loadedItemId = "options_info";
|
|
1907
|
+
draw();
|
|
1908
|
+
return;
|
|
1909
|
+
}
|
|
1910
|
+
const current = collectionOptions.get(colName) ?? {};
|
|
1911
|
+
openForm(`Listing Options: ${colName}`, [
|
|
1912
|
+
{
|
|
1913
|
+
id: "sortBy",
|
|
1914
|
+
label: "Sort By",
|
|
1915
|
+
value: current.sortBy ?? "",
|
|
1916
|
+
options: ["", "id", "created_at", "updated_at", "version"],
|
|
1917
|
+
allowCustom: true,
|
|
1918
|
+
},
|
|
1919
|
+
{
|
|
1920
|
+
id: "sortDir",
|
|
1921
|
+
label: "Sort Direction",
|
|
1922
|
+
value: current.sortDir ?? "asc",
|
|
1923
|
+
options: ["asc", "desc"],
|
|
1924
|
+
},
|
|
1925
|
+
{ id: "limit", label: "Limit", value: String(current.limit ?? ""), placeholder: "50" },
|
|
1926
|
+
{ id: "offset", label: "Offset", value: String(current.offset ?? ""), placeholder: "0" },
|
|
1927
|
+
{
|
|
1928
|
+
id: "filter",
|
|
1929
|
+
label: "Filter (JSON)",
|
|
1930
|
+
value: current.filter ? JSON.stringify(current.filter) : "",
|
|
1931
|
+
placeholder: '{"status":"active"}',
|
|
1932
|
+
},
|
|
1933
|
+
], async (vals) => {
|
|
1934
|
+
const opts = {};
|
|
1935
|
+
if (vals.sortBy) {
|
|
1936
|
+
opts.sortBy = vals.sortBy;
|
|
1937
|
+
opts.sortDir = vals.sortDir || "asc";
|
|
1938
|
+
}
|
|
1939
|
+
if (vals.limit) {
|
|
1940
|
+
opts.limit = parseInt(vals.limit, 10) || 50;
|
|
1941
|
+
}
|
|
1942
|
+
if (vals.offset) {
|
|
1943
|
+
opts.offset = parseInt(vals.offset, 10) || 0;
|
|
1944
|
+
}
|
|
1945
|
+
if (vals.filter?.trim()) {
|
|
1946
|
+
opts.filter = JSON.parse(vals.filter.trim());
|
|
1947
|
+
}
|
|
1948
|
+
if (Object.keys(opts).length > 0) {
|
|
1949
|
+
collectionOptions.set(colName, opts);
|
|
1950
|
+
}
|
|
1951
|
+
else {
|
|
1952
|
+
collectionOptions.delete(colName);
|
|
1953
|
+
}
|
|
1954
|
+
await fetchResources();
|
|
1955
|
+
const tree = buildTree();
|
|
1956
|
+
const idx = tree.findIndex((n) => n.id === `col:${colName}`);
|
|
1957
|
+
if (idx !== -1) {
|
|
1958
|
+
cursorIndex = idx;
|
|
1959
|
+
}
|
|
1960
|
+
const n = tree[cursorIndex];
|
|
1961
|
+
if (n) {
|
|
1962
|
+
scheduleLoad(n);
|
|
1963
|
+
}
|
|
1964
|
+
});
|
|
1965
|
+
}
|
|
1966
|
+
async function handleBatchOps(selected) {
|
|
1967
|
+
const colName = selected?.type === "collection"
|
|
1968
|
+
? (selected.ref?.name ?? "")
|
|
1969
|
+
: selected?.type === "object"
|
|
1970
|
+
? (selected.ref?.collection ?? "")
|
|
1971
|
+
: "";
|
|
1972
|
+
if (!colName) {
|
|
1973
|
+
viewerLines = [pc.yellow("Select a collection first, then press [b] for batch operations.")];
|
|
1974
|
+
loadedItemId = "batch_info";
|
|
1975
|
+
draw();
|
|
1976
|
+
return;
|
|
1977
|
+
}
|
|
1978
|
+
openForm(`Batch Ops: ${colName}`, [
|
|
1979
|
+
{
|
|
1980
|
+
id: "action",
|
|
1981
|
+
label: "Action",
|
|
1982
|
+
value: "put",
|
|
1983
|
+
options: ["put", "delete"],
|
|
1984
|
+
},
|
|
1985
|
+
{
|
|
1986
|
+
id: "input",
|
|
1987
|
+
label: "JSON File Path or IDs (comma-sep for delete)",
|
|
1988
|
+
placeholder: "/path/to/file.json or id1,id2,id3",
|
|
1989
|
+
},
|
|
1990
|
+
], async (vals) => {
|
|
1991
|
+
const action = vals.action || "";
|
|
1992
|
+
const input = (vals.input || "").trim();
|
|
1993
|
+
if (!input) {
|
|
1994
|
+
throw new Error("Input is required.");
|
|
1995
|
+
}
|
|
1996
|
+
if (action === "put") {
|
|
1997
|
+
const data = JSON.parse(await fs.promises.readFile(input, "utf-8"));
|
|
1998
|
+
const objects = Array.isArray(data) ? data : (data.objects ?? [data]);
|
|
1999
|
+
const result = await db.putBatch(colName, objects);
|
|
2000
|
+
viewerLines = [
|
|
2001
|
+
` ${pc.bold("Batch Put Complete")}`,
|
|
2002
|
+
` ${pc.dim(`Collection: ${colName}`)}`,
|
|
2003
|
+
` ${pc.dim(`Objects: ${result.length}`)}`,
|
|
2004
|
+
];
|
|
2005
|
+
loadedItemId = "batch_result";
|
|
2006
|
+
draw();
|
|
2007
|
+
}
|
|
2008
|
+
else if (action === "delete") {
|
|
2009
|
+
const ids = input
|
|
2010
|
+
.split(",")
|
|
2011
|
+
.map((s) => s.trim())
|
|
2012
|
+
.filter(Boolean);
|
|
2013
|
+
const count = await db.deleteBatch(colName, ids);
|
|
2014
|
+
viewerLines = [
|
|
2015
|
+
` ${pc.bold("Batch Delete Complete")}`,
|
|
2016
|
+
` ${pc.dim(`Collection: ${colName}`)}`,
|
|
2017
|
+
` ${pc.dim(`Deleted: ${count} objects`)}`,
|
|
2018
|
+
];
|
|
2019
|
+
loadedItemId = "batch_result";
|
|
2020
|
+
draw();
|
|
2021
|
+
}
|
|
2022
|
+
});
|
|
2023
|
+
}
|
|
1664
2024
|
async function handleMaintenance() {
|
|
1665
2025
|
// Cycle through maintenance operations with each press of 'm'
|
|
1666
2026
|
const operations = ["health", "checkpoint", "backup"];
|
|
@@ -1956,9 +2316,24 @@ function setupKeypress() {
|
|
|
1956
2316
|
else if (str === "i" || str === "I") {
|
|
1957
2317
|
await handleInfo();
|
|
1958
2318
|
}
|
|
1959
|
-
else if (str === "n"
|
|
2319
|
+
else if (str === "n") {
|
|
1960
2320
|
await handleNeighbors(tree[cursorIndex]);
|
|
1961
2321
|
}
|
|
2322
|
+
else if (str === "N") {
|
|
2323
|
+
await handleNlq(tree[cursorIndex]);
|
|
2324
|
+
}
|
|
2325
|
+
else if (str === "a" || str === "A") {
|
|
2326
|
+
await handleAggregate(tree[cursorIndex]);
|
|
2327
|
+
}
|
|
2328
|
+
else if (str === "t" || str === "T") {
|
|
2329
|
+
await handleTimeseries(tree[cursorIndex]);
|
|
2330
|
+
}
|
|
2331
|
+
else if (str === "o" || str === "O") {
|
|
2332
|
+
await handleCollectionOptions(tree[cursorIndex]);
|
|
2333
|
+
}
|
|
2334
|
+
else if (str === "b" || str === "B") {
|
|
2335
|
+
await handleBatchOps(tree[cursorIndex]);
|
|
2336
|
+
}
|
|
1962
2337
|
else if (str === "m" || str === "M") {
|
|
1963
2338
|
await handleMaintenance();
|
|
1964
2339
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@thingd/cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.56.0",
|
|
4
4
|
"description": "CLI, Interactive TUI Dashboard, and MCP server for thingd — a fast object-first data engine for applications and AI agents.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"homepage": "https://engine.thingd.cloud",
|
|
@@ -45,7 +45,7 @@
|
|
|
45
45
|
"cli-table3": "^0.6.5",
|
|
46
46
|
"picocolors": "^1.1.1",
|
|
47
47
|
"zod": "^4.4.3",
|
|
48
|
-
"@thingd/sdk": "0.
|
|
48
|
+
"@thingd/sdk": "0.56.0"
|
|
49
49
|
},
|
|
50
50
|
"engines": {
|
|
51
51
|
"node": ">=24.0.0"
|