thingd-cli 0.8.0 → 0.10.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/index.d.ts.map +1 -1
- package/dist/index.js +43 -1
- package/dist/install.d.ts.map +1 -1
- package/dist/install.js +116 -30
- 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":";
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAOA,OAAO,EAOL,MAAM,EACN,KAAK,YAAY,EAClB,MAAM,QAAQ,CAAC;AAKhB,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,MAAM,MAAM,aAAa,GAAG;IAC1B,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,MAAM,CAAC,EAAE,YAAY,CAAC;IACtB,MAAM,CAAC,EAAE,YAAY,CAAC;CACvB,CAAC;AAEF,KAAK,UAAU,GAAG;IAChB,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,MAAM,EAAE,OAAO,CAAC;CACjB,CAAC;AAEF,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;CAChB,CAAC;AAmDF,wBAAsB,MAAM,CAC1B,IAAI,WAAwB,EAC5B,OAAO,GAAE,aAAkB,GAC1B,OAAO,CAAC,MAAM,CAAC,CAiEjB;AA+UD,wBAAsB,MAAM,CAC1B,OAAO,EAAE,UAAU,EACnB,QAAQ,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,GACtC,OAAO,CAAC,IAAI,CAAC,CAcf;AA4BD,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,UAAU,GAAG,iBAAiB,CA2BxE"}
|
package/dist/index.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { realpathSync } from "node:fs";
|
|
3
|
+
import { resolve } from "node:path";
|
|
3
4
|
import { pathToFileURL } from "node:url";
|
|
4
5
|
import { Client } from "@modelcontextprotocol/sdk/client/index.js";
|
|
5
6
|
import { StreamableHTTPClientTransport } from "@modelcontextprotocol/sdk/client/streamableHttp.js";
|
|
@@ -44,8 +45,42 @@ Options:
|
|
|
44
45
|
--limit <n> result limit for search and list commands
|
|
45
46
|
-h, --help show help
|
|
46
47
|
`;
|
|
47
|
-
const BOOLEAN_FLAGS = new Set([
|
|
48
|
+
const BOOLEAN_FLAGS = new Set([
|
|
49
|
+
"h",
|
|
50
|
+
"help",
|
|
51
|
+
"json",
|
|
52
|
+
"pretty",
|
|
53
|
+
"allow-unauthenticated",
|
|
54
|
+
"raw",
|
|
55
|
+
"claude",
|
|
56
|
+
"cursor",
|
|
57
|
+
]);
|
|
48
58
|
export async function runCli(args = process.argv.slice(2), options = {}) {
|
|
59
|
+
// Auto-detect and set THINGD_NATIVE_PATH if not already set, to allow global execution
|
|
60
|
+
// to seamlessly locate the native compiled library in the workspace or global node_modules.
|
|
61
|
+
if (!process.env.THINGD_NATIVE_PATH) {
|
|
62
|
+
try {
|
|
63
|
+
const { existsSync } = await import("node:fs");
|
|
64
|
+
const { homedir } = await import("node:os");
|
|
65
|
+
const { join } = await import("node:path");
|
|
66
|
+
const cliDir = join(resolveCliPath(), "..", "..");
|
|
67
|
+
const candidates = [
|
|
68
|
+
join(cliDir, "node_modules", "thingd-native", "dist", "thingd_native.node"),
|
|
69
|
+
join(cliDir, "..", "thingd-native", "dist", "thingd_native.node"),
|
|
70
|
+
join(homedir(), "Space/Programming/personal/thingd/packages/thingd-native/dist/thingd_native.node"),
|
|
71
|
+
join(homedir(), "Space/Programming/personal/thingd-cloud/packages/thingd-native/dist/thingd_native.node"),
|
|
72
|
+
];
|
|
73
|
+
for (const candidate of candidates) {
|
|
74
|
+
if (existsSync(candidate)) {
|
|
75
|
+
process.env.THINGD_NATIVE_PATH = candidate;
|
|
76
|
+
break;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
catch {
|
|
81
|
+
// Ignore detection errors
|
|
82
|
+
}
|
|
83
|
+
}
|
|
49
84
|
const parsed = parseArgs(args);
|
|
50
85
|
const context = {
|
|
51
86
|
parsed,
|
|
@@ -518,6 +553,13 @@ function writeJson(target, data, pretty) {
|
|
|
518
553
|
function writeText(target, text) {
|
|
519
554
|
target.write(text.endsWith("\n") ? text : `${text}\n`);
|
|
520
555
|
}
|
|
556
|
+
function resolveCliPath() {
|
|
557
|
+
const scriptPath = process.argv[1];
|
|
558
|
+
if (!scriptPath) {
|
|
559
|
+
throw new Error("Could not detect thingd CLI path from process.argv[1].");
|
|
560
|
+
}
|
|
561
|
+
return resolve(scriptPath);
|
|
562
|
+
}
|
|
521
563
|
let isMain = false;
|
|
522
564
|
if (process.argv[1]) {
|
|
523
565
|
try {
|
package/dist/install.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"install.d.ts","sourceRoot":"","sources":["../src/install.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"install.d.ts","sourceRoot":"","sources":["../src/install.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAwB7C,wBAAsB,UAAU,CAAC,OAAO,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC,CAqInE"}
|
package/dist/install.js
CHANGED
|
@@ -1,14 +1,81 @@
|
|
|
1
1
|
import { existsSync, readFileSync, writeFileSync } from "node:fs";
|
|
2
2
|
import { homedir, platform } from "node:os";
|
|
3
3
|
import { join, resolve } from "node:path";
|
|
4
|
+
import { createInterface } from "node:readline/promises";
|
|
4
5
|
import pc from "picocolors";
|
|
5
6
|
import { defaultThingdDbPath, ensureThingdDir } from "./paths.js";
|
|
7
|
+
async function askQuestion(query) {
|
|
8
|
+
const rl = createInterface({
|
|
9
|
+
input: process.stdin,
|
|
10
|
+
output: process.stderr,
|
|
11
|
+
});
|
|
12
|
+
try {
|
|
13
|
+
return await rl.question(query);
|
|
14
|
+
}
|
|
15
|
+
finally {
|
|
16
|
+
rl.close();
|
|
17
|
+
}
|
|
18
|
+
}
|
|
6
19
|
export async function runInstall(context) {
|
|
7
20
|
const nodePath = process.execPath;
|
|
8
21
|
const cliPath = resolveCliPath();
|
|
9
|
-
const
|
|
10
|
-
const
|
|
22
|
+
const dbPathDefault = defaultThingdDbPath();
|
|
23
|
+
const driverDefault = detectDriver();
|
|
11
24
|
ensureThingdDir();
|
|
25
|
+
const isRaw = context.parsed.booleans.has("raw") || context.parsed.flags.has("raw");
|
|
26
|
+
const isClaude = context.parsed.booleans.has("claude") || context.parsed.flags.has("claude");
|
|
27
|
+
const isCursor = context.parsed.booleans.has("cursor") || context.parsed.flags.has("cursor");
|
|
28
|
+
if (!isRaw) {
|
|
29
|
+
context.stderr.write(`\n${pc.bold("thingd install")}\n\n`);
|
|
30
|
+
}
|
|
31
|
+
let choice = "1";
|
|
32
|
+
let dbPath = dbPathDefault;
|
|
33
|
+
let driver = driverDefault;
|
|
34
|
+
if (isRaw) {
|
|
35
|
+
choice = "4";
|
|
36
|
+
}
|
|
37
|
+
else if (isClaude && isCursor) {
|
|
38
|
+
choice = "1";
|
|
39
|
+
}
|
|
40
|
+
else if (isClaude) {
|
|
41
|
+
choice = "2";
|
|
42
|
+
}
|
|
43
|
+
else if (isCursor) {
|
|
44
|
+
choice = "3";
|
|
45
|
+
}
|
|
46
|
+
else if (process.stdin.isTTY) {
|
|
47
|
+
// 1. Where to install
|
|
48
|
+
context.stderr.write(`${pc.bold("Where would you like to install the MCP configuration?")}\n`);
|
|
49
|
+
context.stderr.write(` [1] Claude Desktop & Cursor (Default)\n`);
|
|
50
|
+
context.stderr.write(` [2] Claude Desktop only\n`);
|
|
51
|
+
context.stderr.write(` [3] Cursor only\n`);
|
|
52
|
+
context.stderr.write(` [4] Print raw JSON configuration only\n\n`);
|
|
53
|
+
const answerInstall = await askQuestion(`Select option [1-4] (default 1): `);
|
|
54
|
+
choice = answerInstall.trim() || "1";
|
|
55
|
+
context.stderr.write("\n");
|
|
56
|
+
// 2. Database Path
|
|
57
|
+
const answerPath = await askQuestion(`Database path (default ${pc.cyan(dbPathDefault)}): `);
|
|
58
|
+
const chosenPath = answerPath.trim();
|
|
59
|
+
if (chosenPath) {
|
|
60
|
+
dbPath = chosenPath;
|
|
61
|
+
}
|
|
62
|
+
// 3. Driver
|
|
63
|
+
const answerDriver = await askQuestion(`Driver [native / memory] (default ${pc.cyan(driverDefault)}): `);
|
|
64
|
+
const chosenDriver = answerDriver.trim().toLowerCase();
|
|
65
|
+
if (chosenDriver === "native" || chosenDriver === "memory") {
|
|
66
|
+
driver = chosenDriver;
|
|
67
|
+
}
|
|
68
|
+
context.stderr.write("\n");
|
|
69
|
+
}
|
|
70
|
+
// Honor command line options if explicitly passed
|
|
71
|
+
const cliPathOption = context.parsed.flags.get("path")?.at(-1);
|
|
72
|
+
const cliDriverOption = context.parsed.flags.get("driver")?.at(-1);
|
|
73
|
+
if (cliPathOption) {
|
|
74
|
+
dbPath = cliPathOption;
|
|
75
|
+
}
|
|
76
|
+
if (cliDriverOption === "native" || cliDriverOption === "memory") {
|
|
77
|
+
driver = cliDriverOption;
|
|
78
|
+
}
|
|
12
79
|
const globalBin = findGlobalBinPath();
|
|
13
80
|
const config = globalBin
|
|
14
81
|
? {
|
|
@@ -16,34 +83,53 @@ export async function runInstall(context) {
|
|
|
16
83
|
args: ["mcp", "--path", dbPath, "--driver", driver],
|
|
17
84
|
}
|
|
18
85
|
: generateMcpConfig(nodePath, cliPath, dbPath, driver);
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
|
|
86
|
+
if (!isRaw) {
|
|
87
|
+
context.stderr.write(` ${pc.bold("Configuration Details:")}\n`);
|
|
88
|
+
context.stderr.write(` ${pc.green("✓")} Database path: ${pc.cyan(dbPath)}\n`);
|
|
89
|
+
context.stderr.write(` ${pc.green("✓")} Driver: ${pc.cyan(driver)}\n`);
|
|
90
|
+
if (globalBin) {
|
|
91
|
+
context.stderr.write(` ${pc.green("✓")} Command: ${pc.cyan(globalBin)}\n\n`);
|
|
92
|
+
}
|
|
93
|
+
else {
|
|
94
|
+
context.stderr.write(` ${pc.green("✓")} Node: ${pc.cyan(nodePath)}\n`);
|
|
95
|
+
context.stderr.write(` ${pc.green("✓")} CLI: ${pc.cyan(cliPath)}\n\n`);
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
const showClaude = choice === "1" || choice === "2";
|
|
99
|
+
const showCursor = choice === "1" || choice === "3";
|
|
100
|
+
const showRaw = choice === "4";
|
|
101
|
+
if (showClaude) {
|
|
102
|
+
const claudeResult = updateClaudeDesktopConfig(config);
|
|
103
|
+
if (claudeResult.updated) {
|
|
104
|
+
context.stderr.write(` ${pc.bold("Claude Desktop:")}\n`);
|
|
105
|
+
context.stderr.write(` ${pc.green("✓")} Updated ${pc.cyan(claudeResult.path)}\n\n`);
|
|
106
|
+
}
|
|
107
|
+
else if (claudeResult.skipped) {
|
|
108
|
+
context.stderr.write(` ${pc.bold("Claude Desktop:")}\n`);
|
|
109
|
+
context.stderr.write(` ${pc.yellow("⊘")} Skipped: ${claudeResult.reason}\n\n`);
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
if (showCursor) {
|
|
113
|
+
context.stderr.write(` ${pc.bold("Cursor:")}\n`);
|
|
114
|
+
context.stderr.write(` Paste this into Cursor Settings → Features → MCP → Add New MCP Server:\n\n`);
|
|
115
|
+
const fullConfig = {
|
|
116
|
+
mcpServers: {
|
|
117
|
+
thingd: config,
|
|
118
|
+
},
|
|
119
|
+
};
|
|
120
|
+
context.stdout.write(`${JSON.stringify(fullConfig, null, 2)}\n`);
|
|
121
|
+
}
|
|
122
|
+
if (showRaw) {
|
|
123
|
+
const fullConfig = {
|
|
124
|
+
mcpServers: {
|
|
125
|
+
thingd: config,
|
|
126
|
+
},
|
|
127
|
+
};
|
|
128
|
+
context.stdout.write(`${JSON.stringify(fullConfig, null, 2)}\n`);
|
|
129
|
+
}
|
|
130
|
+
if (showClaude || showCursor) {
|
|
131
|
+
context.stderr.write(`\n Restart Claude Desktop to activate. Cursor activates immediately after pasting.\n\n`);
|
|
132
|
+
}
|
|
47
133
|
}
|
|
48
134
|
function findGlobalBinPath() {
|
|
49
135
|
try {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "thingd-cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.10.0",
|
|
4
4
|
"description": "Command-line interface, Interactive TUI Dashboard, and MCP server for thingd.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"author": "Sayan Mohsin",
|
|
@@ -33,7 +33,7 @@
|
|
|
33
33
|
"cli-table3": "^0.6.5",
|
|
34
34
|
"picocolors": "^1.1.1",
|
|
35
35
|
"zod": "^4.4.3",
|
|
36
|
-
"thingd": "0.
|
|
36
|
+
"thingd": "0.10.0"
|
|
37
37
|
},
|
|
38
38
|
"engines": {
|
|
39
39
|
"node": ">=20"
|