thingd-cli 0.7.0 → 0.9.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/README.md CHANGED
@@ -2,9 +2,9 @@
2
2
 
3
3
  [![npm version](https://badge.fury.io/js/thingd-cli.svg)](https://www.npmjs.com/package/thingd-cli)
4
4
 
5
- Admin and operator CLI for [thingd](https://www.npmjs.com/package/thingd).
5
+ Command-line interface, Interactive TUI Dashboard, and Model Context Protocol (MCP) server for [thingd](https://www.npmjs.com/package/thingd).
6
6
 
7
- This package provides the `thingd` binary. It uses the public `thingd` SDK for store access and can connect to a local store or a remote sidecar through `THINGD_URL`.
7
+ This package provides the unified `thingd` binary, which serves as a persistent stdio/HTTP MCP server for AI editors (Cursor, Claude Desktop), an interactive terminal UI dashboard for database operations, and a scriptable JSON utility to inspect and manage local or remote databases.
8
8
 
9
9
  ## Installation
10
10
 
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAKA,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;AA0CF,wBAAsB,MAAM,CAC1B,IAAI,WAAwB,EAC5B,OAAO,GAAE,aAAkB,GAC1B,OAAO,CAAC,MAAM,CAAC,CAiCjB;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,CAiBxE"}
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;AA0CF,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,4 +1,6 @@
1
1
  #!/usr/bin/env node
2
+ import { realpathSync } from "node:fs";
3
+ import { resolve } from "node:path";
2
4
  import { pathToFileURL } from "node:url";
3
5
  import { Client } from "@modelcontextprotocol/sdk/client/index.js";
4
6
  import { StreamableHTTPClientTransport } from "@modelcontextprotocol/sdk/client/streamableHttp.js";
@@ -45,6 +47,31 @@ Options:
45
47
  `;
46
48
  const BOOLEAN_FLAGS = new Set(["h", "help", "json", "pretty", "allow-unauthenticated"]);
47
49
  export async function runCli(args = process.argv.slice(2), options = {}) {
50
+ // Auto-detect and set THINGD_NATIVE_PATH if not already set, to allow global execution
51
+ // to seamlessly locate the native compiled library in the workspace or global node_modules.
52
+ if (!process.env.THINGD_NATIVE_PATH) {
53
+ try {
54
+ const { existsSync } = await import("node:fs");
55
+ const { homedir } = await import("node:os");
56
+ const { join } = await import("node:path");
57
+ const cliDir = join(resolveCliPath(), "..", "..");
58
+ const candidates = [
59
+ join(cliDir, "node_modules", "thingd-native", "dist", "thingd_native.node"),
60
+ join(cliDir, "..", "thingd-native", "dist", "thingd_native.node"),
61
+ join(homedir(), "Space/Programming/personal/thingd/packages/thingd-native/dist/thingd_native.node"),
62
+ join(homedir(), "Space/Programming/personal/thingd-cloud/packages/thingd-native/dist/thingd_native.node"),
63
+ ];
64
+ for (const candidate of candidates) {
65
+ if (existsSync(candidate)) {
66
+ process.env.THINGD_NATIVE_PATH = candidate;
67
+ break;
68
+ }
69
+ }
70
+ }
71
+ catch {
72
+ // Ignore detection errors
73
+ }
74
+ }
48
75
  const parsed = parseArgs(args);
49
76
  const context = {
50
77
  parsed,
@@ -359,13 +386,24 @@ export function resolveConnection(context) {
359
386
  const url = stringFlag(context.parsed, "url") ?? context.env.THINGD_URL;
360
387
  const path = url ?? stringFlag(context.parsed, "path") ?? context.env.THINGD_PATH ?? defaultThingdDbPath();
361
388
  const cloud = isCloudPath(path);
362
- const driver = parseDriver(stringFlag(context.parsed, "driver") ?? context.env.THINGD_DRIVER);
389
+ let driver = parseDriver(stringFlag(context.parsed, "driver") ?? context.env.THINGD_DRIVER);
390
+ if (!driver) {
391
+ if (cloud) {
392
+ driver = "cloud";
393
+ }
394
+ else if (path !== ":memory:") {
395
+ driver = "native";
396
+ }
397
+ else {
398
+ driver = "memory";
399
+ }
400
+ }
363
401
  if (!cloud && path === defaultThingdDbPath()) {
364
402
  ensureThingdDir();
365
403
  }
366
404
  return {
367
405
  path,
368
- driver: driver ?? (cloud ? "cloud" : undefined),
406
+ driver,
369
407
  authToken: stringFlag(context.parsed, "auth-token") ?? context.env.THINGD_AUTH_TOKEN,
370
408
  cloud,
371
409
  };
@@ -506,6 +544,22 @@ function writeJson(target, data, pretty) {
506
544
  function writeText(target, text) {
507
545
  target.write(text.endsWith("\n") ? text : `${text}\n`);
508
546
  }
509
- if (process.argv[1] && import.meta.url === pathToFileURL(process.argv[1]).href) {
547
+ function resolveCliPath() {
548
+ const scriptPath = process.argv[1];
549
+ if (!scriptPath) {
550
+ throw new Error("Could not detect thingd CLI path from process.argv[1].");
551
+ }
552
+ return resolve(scriptPath);
553
+ }
554
+ let isMain = false;
555
+ if (process.argv[1]) {
556
+ try {
557
+ isMain = import.meta.url === pathToFileURL(realpathSync(process.argv[1])).href;
558
+ }
559
+ catch {
560
+ // Ignore realpath resolution errors.
561
+ }
562
+ }
563
+ if (isMain) {
510
564
  process.exitCode = await runCli();
511
565
  }
package/dist/mcp.d.ts.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"mcp.d.ts","sourceRoot":"","sources":["../src/mcp.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,KAAK,UAAU,EAAU,MAAM,YAAY,CAAC;AAGrD,wBAAsB,MAAM,CAAC,OAAO,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC,CAY/D"}
1
+ {"version":3,"file":"mcp.d.ts","sourceRoot":"","sources":["../src/mcp.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,KAAK,UAAU,EAA6B,MAAM,YAAY,CAAC;AAGxE,wBAAsB,MAAM,CAAC,OAAO,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC,CAkB/D"}
package/dist/mcp.js CHANGED
@@ -1,11 +1,16 @@
1
1
  import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
2
- import { withDb } from "./index.js";
2
+ import { resolveConnection, withDb } from "./index.js";
3
3
  import { createThingdMcpServer } from "./mcp/index.js";
4
4
  export async function runMcp(context) {
5
+ const connection = resolveConnection(context);
5
6
  await withDb(context, async (db) => {
6
7
  // We pass empty options to createThingdMcpServer so it uses default audit behavior
7
8
  const server = createThingdMcpServer(db);
8
9
  const transport = new StdioServerTransport();
10
+ context.stderr.write(`\nthingd stdio MCP server started successfully.\n`);
11
+ context.stderr.write(` ✓ Database: ${connection.path}\n`);
12
+ context.stderr.write(` ✓ Driver: ${connection.driver ?? "memory"}\n`);
13
+ context.stderr.write(` ✓ Transport: Stdio (listening silently on stdin)\n\n`);
9
14
  await server.connect(transport);
10
15
  // Keep the process alive and the database connection open
11
16
  // so the MCP server can continue to receive messages over stdio.
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "thingd-cli",
3
- "version": "0.7.0",
4
- "description": "Admin and operator CLI for thingd.",
3
+ "version": "0.9.0",
4
+ "description": "Command-line interface, Interactive TUI Dashboard, and MCP server for thingd.",
5
5
  "type": "module",
6
6
  "author": "Sayan Mohsin",
7
7
  "license": "Apache-2.0",
@@ -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.7.0"
36
+ "thingd": "0.9.0"
37
37
  },
38
38
  "engines": {
39
39
  "node": ">=20"