@thingd/cli 0.57.0 → 0.58.1
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.d.ts.map +1 -1
- package/dist/index.js +37 -0
- package/dist/interactive.d.ts.map +1 -1
- package/dist/interactive.js +104 -1
- package/package.json +2 -2
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAQA,OAAO,EAUL,MAAM,EACN,KAAK,YAAY,EAClB,MAAM,aAAa,CAAC;AASrB,KAAK,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAAC;AAEjD,KAAK,YAAY,GAAG;IAClB,KAAK,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;CAC5B,CAAC;AAEF,KAAK,YAAY,GAAG,MAAM,CAAC,cAAc,CAAC;AAE1C,MAAM,MAAM,aAAa,GAAG;IAC1B,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,MAAM,CAAC,EAAE,YAAY,CAAC;IACtB,MAAM,CAAC,EAAE,YAAY,CAAC;IACtB,KAAK,CAAC,EAAE,YAAY,CAAC;CACtB,CAAC;AAEF,MAAM,MAAM,UAAU,GAAG;IACvB,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,KAAK,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC;IAC7B,QAAQ,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;CACvB,CAAC;AAEF,MAAM,MAAM,UAAU,GAAG;IACvB,MAAM,EAAE,UAAU,CAAC;IACnB,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,EAAE,YAAY,CAAC;IACrB,MAAM,EAAE,YAAY,CAAC;IACrB,KAAK,EAAE,YAAY,CAAC;IACpB,MAAM,EAAE,OAAO,CAAC;CACjB,CAAC;AAsCF,MAAM,MAAM,iBAAiB,GAAG;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,CAAC,EAAE,YAAY,CAAC;IACtB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,EAAE,OAAO,CAAC;IACf,sDAAsD;IACtD,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB,CAAC;AAwFF,wBAAsB,MAAM,CAC1B,IAAI,WAAwB,EAC5B,OAAO,GAAE,aAAkB,GAC1B,OAAO,CAAC,MAAM,CAAC,CA8EjB;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAQA,OAAO,EAUL,MAAM,EACN,KAAK,YAAY,EAClB,MAAM,aAAa,CAAC;AASrB,KAAK,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAAC;AAEjD,KAAK,YAAY,GAAG;IAClB,KAAK,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;CAC5B,CAAC;AAEF,KAAK,YAAY,GAAG,MAAM,CAAC,cAAc,CAAC;AAE1C,MAAM,MAAM,aAAa,GAAG;IAC1B,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,MAAM,CAAC,EAAE,YAAY,CAAC;IACtB,MAAM,CAAC,EAAE,YAAY,CAAC;IACtB,KAAK,CAAC,EAAE,YAAY,CAAC;CACtB,CAAC;AAEF,MAAM,MAAM,UAAU,GAAG;IACvB,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,KAAK,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC;IAC7B,QAAQ,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;CACvB,CAAC;AAEF,MAAM,MAAM,UAAU,GAAG;IACvB,MAAM,EAAE,UAAU,CAAC;IACnB,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,EAAE,YAAY,CAAC;IACrB,MAAM,EAAE,YAAY,CAAC;IACrB,KAAK,EAAE,YAAY,CAAC;IACpB,MAAM,EAAE,OAAO,CAAC;CACjB,CAAC;AAsCF,MAAM,MAAM,iBAAiB,GAAG;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,CAAC,EAAE,YAAY,CAAC;IACtB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,EAAE,OAAO,CAAC;IACf,sDAAsD;IACtD,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB,CAAC;AAwFF,wBAAsB,MAAM,CAC1B,IAAI,WAAwB,EAC5B,OAAO,GAAE,aAAkB,GAC1B,OAAO,CAAC,MAAM,CAAC,CA8EjB;AA08BD,wBAAsB,MAAM,CAC1B,OAAO,EAAE,UAAU,EACnB,QAAQ,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,GACtC,OAAO,CAAC,IAAI,CAAC,CAef;AA4BD,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,UAAU,GAAG,iBAAiB,CAqDxE;AAiDD,wBAAgB,OAAO,CAAC,MAAM,EAAE,UAAU,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAEjE;AAED,wBAAgB,UAAU,CAAC,MAAM,EAAE,UAAU,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAE/E;AAED,wBAAgB,WAAW,CAAC,MAAM,EAAE,UAAU,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE,GAAG,SAAS,CAGlF;AAED,wBAAgB,YAAY,CAAC,MAAM,EAAE,UAAU,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAMrE;AAED,wBAAgB,aAAa,CAAC,MAAM,EAAE,UAAU,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAEnF;AAED,wBAAgB,aAAa,CAAC,MAAM,EAAE,UAAU,EAAE,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAMrF;AAyFD,wBAAgB,SAAS,CAAC,MAAM,EAAE,YAAY,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,GAAG,IAAI,CAEpF;AAED,wBAAgB,SAAS,CAAC,MAAM,EAAE,YAAY,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI,CAElE"}
|
package/dist/index.js
CHANGED
|
@@ -290,6 +290,10 @@ async function runCommand(context) {
|
|
|
290
290
|
await runBackup(context);
|
|
291
291
|
return;
|
|
292
292
|
}
|
|
293
|
+
if (command === "completions") {
|
|
294
|
+
await runCompletions(context);
|
|
295
|
+
return;
|
|
296
|
+
}
|
|
293
297
|
if (command === "db") {
|
|
294
298
|
const sub = context.parsed.tokens[1];
|
|
295
299
|
if (!sub) {
|
|
@@ -381,6 +385,39 @@ async function runDbIntegrity(context) {
|
|
|
381
385
|
}
|
|
382
386
|
});
|
|
383
387
|
}
|
|
388
|
+
async function runCompletions(context) {
|
|
389
|
+
const shell = optionalToken(context.parsed, 1) ?? "bash";
|
|
390
|
+
const cmds = [
|
|
391
|
+
"status",
|
|
392
|
+
"search",
|
|
393
|
+
"mcp",
|
|
394
|
+
"cloud",
|
|
395
|
+
"objects",
|
|
396
|
+
"events",
|
|
397
|
+
"collections",
|
|
398
|
+
"streams",
|
|
399
|
+
"queues",
|
|
400
|
+
"links",
|
|
401
|
+
"schema",
|
|
402
|
+
"nlq",
|
|
403
|
+
"aggregate",
|
|
404
|
+
"timeseries",
|
|
405
|
+
"metrics",
|
|
406
|
+
"dashboard",
|
|
407
|
+
"export",
|
|
408
|
+
"import",
|
|
409
|
+
"snapshot",
|
|
410
|
+
"backup",
|
|
411
|
+
"db",
|
|
412
|
+
"completions",
|
|
413
|
+
];
|
|
414
|
+
const script = shell === "zsh"
|
|
415
|
+
? `#compdef thingd\ncompdef _thingd thingd\n_thingd() {\n _describe 'thingd commands' ${JSON.stringify(cmds.map((c) => `${c}:thingd ${c}`))}\n}\n`
|
|
416
|
+
: shell === "fish"
|
|
417
|
+
? `complete -c thingd -f\n${cmds.map((c) => `complete -c thingd -n '__fish_use_subcommand' -a ${c}`).join("\n")}\n`
|
|
418
|
+
: `_thingd() {\n local cur=${"${COMP_WORDS[COMP_CWORD]}"}\n if [ $COMP_CWORD -eq 1 ]; then\n COMPREPLY=($(compgen -W "${cmds.join(" ")}" -- "$cur"))\n fi\n}\ncomplete -F _thingd thingd\n`;
|
|
419
|
+
writeText(context.stdout, script);
|
|
420
|
+
}
|
|
384
421
|
async function runStatus(context) {
|
|
385
422
|
const connection = resolveConnection(context);
|
|
386
423
|
if (!connection.cloud) {
|
|
@@ -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":"AAitGA,wBAAsB,iBAAiB,IAAI,OAAO,CAAC,IAAI,CAAC,CA0FvD"}
|
package/dist/interactive.js
CHANGED
|
@@ -93,6 +93,21 @@ let eventAppendRateHistory = [];
|
|
|
93
93
|
let viewerLines = ["Select an item to view details."];
|
|
94
94
|
let viewerScroll = 0;
|
|
95
95
|
let showHelp = false;
|
|
96
|
+
const loading = false;
|
|
97
|
+
const toasts = [];
|
|
98
|
+
function addToast(msg) {
|
|
99
|
+
toasts.push(msg);
|
|
100
|
+
if (toasts.length > 3) {
|
|
101
|
+
toasts.shift();
|
|
102
|
+
}
|
|
103
|
+
setTimeout(() => {
|
|
104
|
+
const idx = toasts.indexOf(msg);
|
|
105
|
+
if (idx !== -1) {
|
|
106
|
+
toasts.splice(idx, 1);
|
|
107
|
+
draw();
|
|
108
|
+
}
|
|
109
|
+
}, 3000);
|
|
110
|
+
}
|
|
96
111
|
let lastNeighborsRef = "";
|
|
97
112
|
let loadedItemId = "";
|
|
98
113
|
let loadTimer = null;
|
|
@@ -1130,10 +1145,18 @@ function draw() {
|
|
|
1130
1145
|
help = ` ${pc.dim("↑↓")} nav ${pc.dim("enter")} connect ${pc.dim("q")} quit `;
|
|
1131
1146
|
}
|
|
1132
1147
|
else {
|
|
1133
|
-
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")}
|
|
1148
|
+
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")} opts ${pc.dim("b")} batch ${pc.dim("x")} export ${pc.dim("p")} import ${pc.dim("w")} web ${pc.dim("i")} info ${pc.dim("r")} refresh ${pc.dim("s")} switch ${pc.dim("l")} logout ${pc.dim("q")} quit `;
|
|
1134
1149
|
}
|
|
1135
1150
|
buf += `${pc.dim("─".repeat(W))}\n`;
|
|
1136
1151
|
buf += padToWidth(help, W);
|
|
1152
|
+
if (loading) {
|
|
1153
|
+
buf += `\n${pc.cyan("◇")} ${pc.dim("Working...")}`;
|
|
1154
|
+
}
|
|
1155
|
+
if (toasts.length > 0) {
|
|
1156
|
+
for (const t of toasts) {
|
|
1157
|
+
buf += `\n ${pc.green("●")} ${pc.dim(t)}`;
|
|
1158
|
+
}
|
|
1159
|
+
}
|
|
1137
1160
|
// Clear to end
|
|
1138
1161
|
buf += "\u001B[J";
|
|
1139
1162
|
if (showHelp) {
|
|
@@ -1447,6 +1470,7 @@ async function handleCreate(selected) {
|
|
|
1447
1470
|
await db.put(target, { id, ...data });
|
|
1448
1471
|
expandedSet.add("cat:collections");
|
|
1449
1472
|
expandedSet.add(`col:${target}`);
|
|
1473
|
+
addToast(`Created object ${id} in ${target}`);
|
|
1450
1474
|
}
|
|
1451
1475
|
else if (kind === "event") {
|
|
1452
1476
|
if (!vals.payload?.trim()) {
|
|
@@ -1454,6 +1478,7 @@ async function handleCreate(selected) {
|
|
|
1454
1478
|
}
|
|
1455
1479
|
await db.events.append(target, { type: vals.payload.trim() });
|
|
1456
1480
|
expandedSet.add("cat:streams");
|
|
1481
|
+
addToast(`Appended event to ${target}`);
|
|
1457
1482
|
}
|
|
1458
1483
|
else if (kind === "queue") {
|
|
1459
1484
|
if (!vals.payload?.trim()) {
|
|
@@ -1462,6 +1487,7 @@ async function handleCreate(selected) {
|
|
|
1462
1487
|
const data = parsePayload(vals.payload);
|
|
1463
1488
|
await db.queue(target).push(data);
|
|
1464
1489
|
expandedSet.add("cat:queues");
|
|
1490
|
+
addToast(`Pushed job to queue ${target}`);
|
|
1465
1491
|
}
|
|
1466
1492
|
else if (kind === "link") {
|
|
1467
1493
|
const toRef = (vals.objId || "").trim();
|
|
@@ -1488,6 +1514,7 @@ async function handleCreate(selected) {
|
|
|
1488
1514
|
linkType = (vals.payload || "").trim() || "related";
|
|
1489
1515
|
}
|
|
1490
1516
|
await db.links.create(target, linkType, toRef, weight, metadataJson);
|
|
1517
|
+
addToast(`Created link: ${target} ${linkType} ${toRef}`);
|
|
1491
1518
|
}
|
|
1492
1519
|
else {
|
|
1493
1520
|
throw new Error("Kind must be 'object', 'event', 'queue', or 'link'.");
|
|
@@ -1593,6 +1620,7 @@ async function handleDelete(selected) {
|
|
|
1593
1620
|
if (result && !result.deleted) {
|
|
1594
1621
|
throw new Error(`Object '${ref.id}' not found in collection '${ref.collection}'`);
|
|
1595
1622
|
}
|
|
1623
|
+
addToast(`Deleted object ${ref.id}`);
|
|
1596
1624
|
});
|
|
1597
1625
|
}
|
|
1598
1626
|
else if (selected.type === "queue" && selected.ref) {
|
|
@@ -1637,6 +1665,7 @@ async function handleDelete(selected) {
|
|
|
1637
1665
|
if (!ok) {
|
|
1638
1666
|
throw new Error(`Link '${linkId}' not found.`);
|
|
1639
1667
|
}
|
|
1668
|
+
addToast(`Deleted link ${linkId}`);
|
|
1640
1669
|
});
|
|
1641
1670
|
}
|
|
1642
1671
|
else if (selected.type === "job" && selected.ref) {
|
|
@@ -2153,6 +2182,71 @@ async function handleBatchOps(selected) {
|
|
|
2153
2182
|
}
|
|
2154
2183
|
});
|
|
2155
2184
|
}
|
|
2185
|
+
async function handleExport(selected) {
|
|
2186
|
+
const colName = selected?.type === "collection"
|
|
2187
|
+
? (selected.ref?.name ?? "")
|
|
2188
|
+
: selected?.type === "object"
|
|
2189
|
+
? (selected.ref?.collection ?? "")
|
|
2190
|
+
: "";
|
|
2191
|
+
if (!colName) {
|
|
2192
|
+
viewerLines = [pc.yellow("Select a collection first, then press [x] to export.")];
|
|
2193
|
+
loadedItemId = "export_info";
|
|
2194
|
+
draw();
|
|
2195
|
+
return;
|
|
2196
|
+
}
|
|
2197
|
+
openForm(`Export: ${colName}`, [{ id: "path", label: "Output File Path", placeholder: "/tmp/export.jsonl" }], async (vals) => {
|
|
2198
|
+
const filePath = (vals.path || "").trim();
|
|
2199
|
+
if (!filePath) {
|
|
2200
|
+
throw new Error("File path is required.");
|
|
2201
|
+
}
|
|
2202
|
+
const objs = await db.listObjects(colName);
|
|
2203
|
+
const lines = objs.map((o) => JSON.stringify(o)).join("\n");
|
|
2204
|
+
await fs.promises.writeFile(filePath, lines, "utf-8");
|
|
2205
|
+
addToast(`Exported ${objs.length} objects to ${filePath}`);
|
|
2206
|
+
});
|
|
2207
|
+
}
|
|
2208
|
+
async function handleImport(selected) {
|
|
2209
|
+
const colName = selected?.type === "collection"
|
|
2210
|
+
? (selected.ref?.name ?? "")
|
|
2211
|
+
: selected?.type === "object"
|
|
2212
|
+
? (selected.ref?.collection ?? "")
|
|
2213
|
+
: "";
|
|
2214
|
+
if (!colName) {
|
|
2215
|
+
viewerLines = [pc.yellow("Select a collection first, then press [p] to import.")];
|
|
2216
|
+
loadedItemId = "import_info";
|
|
2217
|
+
draw();
|
|
2218
|
+
return;
|
|
2219
|
+
}
|
|
2220
|
+
openForm(`Import: ${colName}`, [{ id: "path", label: "Input File Path (JSONL)", placeholder: "/tmp/export.jsonl" }], async (vals) => {
|
|
2221
|
+
const filePath = (vals.path || "").trim();
|
|
2222
|
+
if (!filePath) {
|
|
2223
|
+
throw new Error("File path is required.");
|
|
2224
|
+
}
|
|
2225
|
+
const text = await fs.promises.readFile(filePath, "utf-8");
|
|
2226
|
+
const objects = text
|
|
2227
|
+
.split("\n")
|
|
2228
|
+
.filter(Boolean)
|
|
2229
|
+
.map((line) => JSON.parse(line));
|
|
2230
|
+
const result = await db.putBatch(colName, objects);
|
|
2231
|
+
addToast(`Imported ${result.length} objects into ${colName}`);
|
|
2232
|
+
});
|
|
2233
|
+
}
|
|
2234
|
+
async function handleDashboard() {
|
|
2235
|
+
const bin = process.argv[1] || "thingd";
|
|
2236
|
+
const args = ["dashboard", "--driver", driver];
|
|
2237
|
+
if (dbPath) {
|
|
2238
|
+
args.push("--path", dbPath);
|
|
2239
|
+
}
|
|
2240
|
+
if (authToken) {
|
|
2241
|
+
args.push("--auth-token", authToken);
|
|
2242
|
+
}
|
|
2243
|
+
const child = spawn(bin, args, {
|
|
2244
|
+
stdio: "inherit",
|
|
2245
|
+
detached: true,
|
|
2246
|
+
});
|
|
2247
|
+
child.unref();
|
|
2248
|
+
addToast(`Launching dashboard: ${bin} dashboard`);
|
|
2249
|
+
}
|
|
2156
2250
|
async function handleMaintenance() {
|
|
2157
2251
|
// Cycle through maintenance operations with each press of 'm'
|
|
2158
2252
|
const operations = ["health", "checkpoint", "backup"];
|
|
@@ -2480,6 +2574,15 @@ function setupKeypress() {
|
|
|
2480
2574
|
else if (str === "b" || str === "B") {
|
|
2481
2575
|
await handleBatchOps(tree[cursorIndex]);
|
|
2482
2576
|
}
|
|
2577
|
+
else if (str === "x" || str === "X") {
|
|
2578
|
+
await handleExport(tree[cursorIndex]);
|
|
2579
|
+
}
|
|
2580
|
+
else if (str === "p" || str === "P") {
|
|
2581
|
+
await handleImport(tree[cursorIndex]);
|
|
2582
|
+
}
|
|
2583
|
+
else if (str === "w" || str === "W") {
|
|
2584
|
+
await handleDashboard();
|
|
2585
|
+
}
|
|
2483
2586
|
else if (str === "m" || str === "M") {
|
|
2484
2587
|
await handleMaintenance();
|
|
2485
2588
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@thingd/cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.58.1",
|
|
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.58.1"
|
|
49
49
|
},
|
|
50
50
|
"engines": {
|
|
51
51
|
"node": ">=24.0.0"
|