thingd-cli 0.1.0 → 0.3.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 +131 -28
- package/dist/index.d.ts +21 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +88 -22
- package/dist/interactive.d.ts +2 -0
- package/dist/interactive.d.ts.map +1 -0
- package/dist/interactive.js +1540 -0
- package/dist/mcp.d.ts +3 -0
- package/dist/mcp.d.ts.map +1 -0
- package/dist/mcp.js +14 -0
- package/package.json +5 -2
package/README.md
CHANGED
|
@@ -1,50 +1,153 @@
|
|
|
1
1
|
# thingd-cli
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
[](https://www.npmjs.com/package/thingd-cli)
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
`thingd` SDK for store access and can connect to a local store or
|
|
7
|
-
a remote sidecar through `THINGD_URL`.
|
|
5
|
+
Admin and operator CLI for [thingd](https://www.npmjs.com/package/thingd).
|
|
8
6
|
|
|
9
|
-
|
|
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`.
|
|
8
|
+
|
|
9
|
+
## Installation
|
|
10
|
+
|
|
11
|
+
Install globally via npm to use the `thingd` command anywhere:
|
|
10
12
|
|
|
11
13
|
```bash
|
|
12
|
-
|
|
13
|
-
pnpm --filter thingd-cli test
|
|
14
|
+
npm install -g thingd-cli
|
|
14
15
|
```
|
|
15
16
|
|
|
16
|
-
|
|
17
|
+
Or run it on the fly using `npx`:
|
|
17
18
|
|
|
18
19
|
```bash
|
|
19
|
-
thingd
|
|
20
|
-
thingd objects put decisions rust-core --text "Use Rust for the core engine."
|
|
21
|
-
thingd objects get decisions rust-core
|
|
22
|
-
thingd events append project:thingd decision.made --text "Picked the CLI shape."
|
|
23
|
-
thingd events list project:thingd
|
|
24
|
-
thingd queues push embed --payload '{"object":"docs/readme"}'
|
|
25
|
-
thingd queues claim embed
|
|
20
|
+
npx thingd-cli
|
|
26
21
|
```
|
|
27
22
|
|
|
28
|
-
|
|
23
|
+
## Two Modes of Operation
|
|
24
|
+
|
|
25
|
+
The CLI is designed to support both human operators and automated scripts through two distinct modes:
|
|
26
|
+
|
|
27
|
+
1. **Interactive Dashboard (TUI)**: Run `thingd` without any arguments to launch a beautiful, interactive terminal UI. Perfect for exploring collections, editing objects, and managing queues manually.
|
|
28
|
+
2. **Non-Interactive CLI**: Run `thingd <command>` for one-off operations. This mode intentionally emits JSON so it is easy to use from shell scripts, CI/CD pipelines, and AI-agent workflows.
|
|
29
|
+
|
|
30
|
+
---
|
|
31
|
+
|
|
32
|
+
## 1. Interactive Dashboard (TUI)
|
|
29
33
|
|
|
34
|
+
To start the interactive dashboard, simply run:
|
|
30
35
|
```bash
|
|
31
|
-
|
|
32
|
-
THINGD_AUTH_TOKEN=change-me
|
|
33
|
-
thingd status
|
|
34
|
-
thingd tools
|
|
36
|
+
thingd
|
|
35
37
|
```
|
|
36
38
|
|
|
37
|
-
|
|
39
|
+
### Connection Mode
|
|
40
|
+
Upon launch, you will be prompted to select a connection driver:
|
|
41
|
+
- `Memory`: An ephemeral, in-memory instance (great for quick testing).
|
|
42
|
+
- `Native`: Connects directly to a local SQLite `.db` file (requires a file path).
|
|
43
|
+
- `Cloud`: Connects to a remote ThingD cluster (requires a URL and an optional Bearer Token).
|
|
44
|
+
|
|
45
|
+
### Keyboard Shortcuts
|
|
46
|
+
Once connected, the TUI provides a dual-pane layout: a navigation sidebar on the left and a detailed viewer/editor on the right.
|
|
47
|
+
|
|
48
|
+
| Shortcut | Action |
|
|
49
|
+
|----------|--------|
|
|
50
|
+
| `↑` / `↓` (or `k` / `j`) | Navigate the tree vertically |
|
|
51
|
+
| `←` / `→` (or `h` / `l`) | Expand or collapse folders (Collections, Streams, Queues) |
|
|
52
|
+
| `Enter` | Expand node or open a folder |
|
|
53
|
+
| `c` | **Create** a new Object, Event, or push a Queue job |
|
|
54
|
+
| `e` | **Edit** an Object or retry a Queue job |
|
|
55
|
+
| `d` | **Delete** an Object or Ack/Resolve a Queue job |
|
|
56
|
+
| `/` (or `f`) | **Global Semantic Search** across the database |
|
|
57
|
+
| `i` | **Info**: View Connection Info & Cloud Cluster Status |
|
|
58
|
+
| `r` | **Refresh** data from the database |
|
|
59
|
+
| `s` | **Switch** database connections |
|
|
60
|
+
| `q` | **Quit** |
|
|
61
|
+
|
|
62
|
+
---
|
|
63
|
+
|
|
64
|
+
## 2. Non-Interactive CLI
|
|
65
|
+
|
|
66
|
+
For scripts and automation, you can bypass the TUI entirely.
|
|
67
|
+
|
|
68
|
+
### Common Options
|
|
69
|
+
You can configure the connection via environment variables or CLI flags:
|
|
38
70
|
|
|
39
71
|
```txt
|
|
40
72
|
--url <url> remote thingd URL. Defaults to THINGD_URL
|
|
41
|
-
--auth-token <tok>
|
|
42
|
-
--path <path>
|
|
43
|
-
--driver <driver>
|
|
44
|
-
--pretty
|
|
45
|
-
--limit <n>
|
|
73
|
+
--auth-token <tok> remote bearer token. Defaults to THINGD_AUTH_TOKEN
|
|
74
|
+
--path <path> local database path. Defaults to THINGD_PATH or :memory:
|
|
75
|
+
--driver <driver> memory, native, or cloud
|
|
76
|
+
--pretty pretty-print JSON output
|
|
77
|
+
--limit <n> result limit for search and list commands
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
### Claude Desktop & MCP Integration
|
|
81
|
+
|
|
82
|
+
The `thingd` CLI has a built-in `mcp` subcommand that exposes an MCP server over `stdio`. This allows Claude Desktop to securely connect to your `thingd` database.
|
|
83
|
+
|
|
84
|
+
**Connecting to a Local Database:**
|
|
85
|
+
To let Claude read and write to a local `thingd.db` file, add this to your `claude_desktop_config.json`:
|
|
86
|
+
|
|
87
|
+
```json
|
|
88
|
+
{
|
|
89
|
+
"mcpServers": {
|
|
90
|
+
"thingd-local": {
|
|
91
|
+
"command": "thingd",
|
|
92
|
+
"args": ["mcp", "--path", "/absolute/path/to/thingd.db", "--driver", "native"]
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
**Bridging Claude to the Cloud:**
|
|
99
|
+
Claude Desktop natively only supports local `stdio` servers. However, `thingd mcp` can act as a bridge! If you provide a `--url`, the CLI will launch locally but seamlessly proxy all of Claude's requests to your remote cluster:
|
|
100
|
+
|
|
101
|
+
```json
|
|
102
|
+
{
|
|
103
|
+
"mcpServers": {
|
|
104
|
+
"thingd-cloud": {
|
|
105
|
+
"command": "thingd",
|
|
106
|
+
"args": ["mcp", "--url", "https://your-thingd-cloud.com/mcp", "--auth-token", "your-secret-token"]
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
### Command Reference
|
|
113
|
+
|
|
114
|
+
**Metrics & Discovery**
|
|
115
|
+
```bash
|
|
116
|
+
thingd metrics # Get total counts (objects, events, activeJobs, deadJobs)
|
|
117
|
+
thingd status # Check cluster health (requires --url)
|
|
118
|
+
thingd tools # List available MCP tools (requires --url)
|
|
119
|
+
thingd collections list # List all collection names
|
|
120
|
+
thingd streams list # List all stream names
|
|
121
|
+
thingd queues list-all # List all queue names
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
**Search**
|
|
125
|
+
```bash
|
|
126
|
+
thingd search "my query" [--collection <name>] [--limit <n>]
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
**Objects**
|
|
130
|
+
```bash
|
|
131
|
+
thingd objects put decisions rust-core --text "Use Rust for the core engine."
|
|
132
|
+
thingd objects put decisions rust-core --data '{"status":"active"}'
|
|
133
|
+
thingd objects get decisions rust-core
|
|
134
|
+
thingd objects delete decisions rust-core
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
**Events**
|
|
138
|
+
```bash
|
|
139
|
+
thingd events append project:thingd decision.made --text "Picked the CLI shape."
|
|
140
|
+
thingd events list project:thingd
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
**Queues**
|
|
144
|
+
```bash
|
|
145
|
+
thingd queues push embed --payload '{"object":"docs/readme"}'
|
|
146
|
+
thingd queues claim embed
|
|
147
|
+
thingd queues ack embed <jobId>
|
|
148
|
+
thingd queues nack embed <jobId> --error "failed to fetch" --delay-ms 5000
|
|
149
|
+
thingd queues list embed
|
|
150
|
+
thingd queues dead embed
|
|
46
151
|
```
|
|
47
152
|
|
|
48
|
-
The first CLI version intentionally emits JSON so it is easy to use from shell
|
|
49
|
-
scripts, tests, and AI-agent workflows.
|
|
50
153
|
|
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
+
import { ThingD, type ThingDDriver } from "thingd";
|
|
2
3
|
type CliEnv = Record<string, string | undefined>;
|
|
3
4
|
type WritableLike = {
|
|
4
5
|
write(chunk: string): void;
|
|
@@ -8,6 +9,26 @@ export type RunCliOptions = {
|
|
|
8
9
|
stdout?: WritableLike;
|
|
9
10
|
stderr?: WritableLike;
|
|
10
11
|
};
|
|
12
|
+
type ParsedArgs = {
|
|
13
|
+
tokens: string[];
|
|
14
|
+
flags: Map<string, string[]>;
|
|
15
|
+
booleans: Set<string>;
|
|
16
|
+
};
|
|
17
|
+
export type CliContext = {
|
|
18
|
+
parsed: ParsedArgs;
|
|
19
|
+
env: CliEnv;
|
|
20
|
+
stdout: WritableLike;
|
|
21
|
+
stderr: WritableLike;
|
|
22
|
+
pretty: boolean;
|
|
23
|
+
};
|
|
24
|
+
export type ConnectionOptions = {
|
|
25
|
+
path: string;
|
|
26
|
+
driver?: ThingDDriver;
|
|
27
|
+
authToken?: string;
|
|
28
|
+
cloud: boolean;
|
|
29
|
+
};
|
|
11
30
|
export declare function runCli(args?: string[], options?: RunCliOptions): Promise<number>;
|
|
31
|
+
export declare function withDb(context: CliContext, callback: (db: ThingD) => Promise<void>): Promise<void>;
|
|
32
|
+
export declare function resolveConnection(context: CliContext): ConnectionOptions;
|
|
12
33
|
export {};
|
|
13
34
|
//# sourceMappingURL=index.d.ts.map
|
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":";AAKA,OAAO,EAOL,MAAM,EACN,KAAK,YAAY,EAClB,MAAM,QAAQ,CAAC;AAIhB,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;AAuCF,wBAAsB,MAAM,CAC1B,IAAI,WAAwB,EAC5B,OAAO,GAAE,aAAkB,GAC1B,OAAO,CAAC,MAAM,CAAC,CAiCjB;AAmUD,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,CAYxE"}
|
package/dist/index.js
CHANGED
|
@@ -3,6 +3,8 @@ import { pathToFileURL } from "node:url";
|
|
|
3
3
|
import { Client } from "@modelcontextprotocol/sdk/client/index.js";
|
|
4
4
|
import { StreamableHTTPClientTransport } from "@modelcontextprotocol/sdk/client/streamableHttp.js";
|
|
5
5
|
import { ThingD, } from "thingd";
|
|
6
|
+
import { runInteractiveCli } from "./interactive.js";
|
|
7
|
+
import { runMcp } from "./mcp.js";
|
|
6
8
|
const HELP_TEXT = `thingd
|
|
7
9
|
|
|
8
10
|
Admin and operator CLI for thingd.
|
|
@@ -17,18 +19,22 @@ Usage:
|
|
|
17
19
|
thingd objects delete <collection> <id>
|
|
18
20
|
thingd events append <stream> <type> [--text <text>] [--data '{"field":"value"}']
|
|
19
21
|
thingd events list [stream] [--limit <n>]
|
|
22
|
+
thingd collections list
|
|
23
|
+
thingd streams list
|
|
24
|
+
thingd queues list-all
|
|
20
25
|
thingd queues push <queue> --payload '{"key":"value"}'
|
|
21
26
|
thingd queues claim <queue> [--lease-ms <ms>]
|
|
22
27
|
thingd queues ack <queue> <jobId>
|
|
23
28
|
thingd queues nack <queue> <jobId> [--error <message>] [--delay-ms <ms>]
|
|
24
29
|
thingd queues list <queue> [--limit <n>]
|
|
25
30
|
thingd queues dead <queue> [--limit <n>]
|
|
31
|
+
thingd metrics
|
|
26
32
|
|
|
27
33
|
Options:
|
|
28
34
|
--url <url> remote thingd URL. Defaults to THINGD_URL
|
|
29
35
|
--auth-token <tok> remote bearer token. Defaults to THINGD_AUTH_TOKEN
|
|
30
36
|
--path <path> local database path. Defaults to THINGD_PATH or :memory:
|
|
31
|
-
--driver <driver> memory, native, or
|
|
37
|
+
--driver <driver> memory, native, or cloud
|
|
32
38
|
--pretty pretty-print JSON output
|
|
33
39
|
--limit <n> result limit for search and list commands
|
|
34
40
|
-h, --help show help
|
|
@@ -44,10 +50,14 @@ export async function runCli(args = process.argv.slice(2), options = {}) {
|
|
|
44
50
|
pretty: hasFlag(parsed, "pretty"),
|
|
45
51
|
};
|
|
46
52
|
try {
|
|
47
|
-
if (hasFlag(parsed, "help") || hasFlag(parsed, "h")
|
|
53
|
+
if (hasFlag(parsed, "help") || hasFlag(parsed, "h")) {
|
|
48
54
|
writeText(context.stdout, HELP_TEXT);
|
|
49
55
|
return 0;
|
|
50
56
|
}
|
|
57
|
+
if (parsed.tokens.length === 0) {
|
|
58
|
+
await runInteractiveCli();
|
|
59
|
+
return 0;
|
|
60
|
+
}
|
|
51
61
|
await runCommand(context);
|
|
52
62
|
return 0;
|
|
53
63
|
}
|
|
@@ -72,6 +82,10 @@ async function runCommand(context) {
|
|
|
72
82
|
await runSearch(context);
|
|
73
83
|
return;
|
|
74
84
|
}
|
|
85
|
+
if (command === "mcp") {
|
|
86
|
+
await runMcp(context);
|
|
87
|
+
return;
|
|
88
|
+
}
|
|
75
89
|
if (command === "objects") {
|
|
76
90
|
await runObjects(context);
|
|
77
91
|
return;
|
|
@@ -80,15 +94,27 @@ async function runCommand(context) {
|
|
|
80
94
|
await runEvents(context);
|
|
81
95
|
return;
|
|
82
96
|
}
|
|
97
|
+
if (command === "collections") {
|
|
98
|
+
await runCollections(context);
|
|
99
|
+
return;
|
|
100
|
+
}
|
|
101
|
+
if (command === "streams") {
|
|
102
|
+
await runStreams(context);
|
|
103
|
+
return;
|
|
104
|
+
}
|
|
83
105
|
if (command === "queues") {
|
|
84
106
|
await runQueues(context);
|
|
85
107
|
return;
|
|
86
108
|
}
|
|
109
|
+
if (command === "metrics") {
|
|
110
|
+
await runMetrics(context);
|
|
111
|
+
return;
|
|
112
|
+
}
|
|
87
113
|
throw new Error(`Unknown command: ${command}`);
|
|
88
114
|
}
|
|
89
115
|
async function runStatus(context) {
|
|
90
116
|
const connection = resolveConnection(context);
|
|
91
|
-
if (!connection.
|
|
117
|
+
if (!connection.cloud) {
|
|
92
118
|
writeJson(context.stdout, {
|
|
93
119
|
mode: "local",
|
|
94
120
|
driver: connection.driver ?? "memory",
|
|
@@ -96,28 +122,28 @@ async function runStatus(context) {
|
|
|
96
122
|
}, context.pretty);
|
|
97
123
|
return;
|
|
98
124
|
}
|
|
99
|
-
const baseUrl =
|
|
125
|
+
const baseUrl = resolveCloudBaseUrl(connection.path);
|
|
100
126
|
const [health, cluster] = await Promise.all([
|
|
101
127
|
fetchJson(new URL("/healthz", baseUrl), connection.authToken),
|
|
102
128
|
fetchJson(new URL("/cluster/status", baseUrl), connection.authToken),
|
|
103
129
|
]);
|
|
104
130
|
writeJson(context.stdout, {
|
|
105
|
-
mode: "
|
|
106
|
-
url:
|
|
131
|
+
mode: "cloud",
|
|
132
|
+
url: resolveCloudMcpUrl(connection.path),
|
|
107
133
|
health,
|
|
108
134
|
cluster,
|
|
109
135
|
}, context.pretty);
|
|
110
136
|
}
|
|
111
137
|
async function runTools(context) {
|
|
112
138
|
const connection = resolveConnection(context);
|
|
113
|
-
if (!connection.
|
|
139
|
+
if (!connection.cloud) {
|
|
114
140
|
throw new Error("tools requires --url or THINGD_URL because tools are exposed by the MCP runtime");
|
|
115
141
|
}
|
|
116
142
|
const client = new Client({
|
|
117
143
|
name: "thingd-cli",
|
|
118
144
|
version: "0.1.0",
|
|
119
145
|
});
|
|
120
|
-
const transport = new StreamableHTTPClientTransport(new URL(
|
|
146
|
+
const transport = new StreamableHTTPClientTransport(new URL(resolveCloudMcpUrl(connection.path)), {
|
|
121
147
|
requestInit: connection.authToken
|
|
122
148
|
? {
|
|
123
149
|
headers: {
|
|
@@ -194,10 +220,50 @@ async function runEvents(context) {
|
|
|
194
220
|
throw new Error(`Unknown events action: ${action}`);
|
|
195
221
|
});
|
|
196
222
|
}
|
|
223
|
+
async function runCollections(context) {
|
|
224
|
+
const action = requiredToken(context.parsed, 1, "collections action");
|
|
225
|
+
await withDb(context, async (db) => {
|
|
226
|
+
if (action === "list") {
|
|
227
|
+
writeJson(context.stdout, await db.listCollections(), context.pretty);
|
|
228
|
+
return;
|
|
229
|
+
}
|
|
230
|
+
throw new Error(`Unknown collections action: ${action}`);
|
|
231
|
+
});
|
|
232
|
+
}
|
|
233
|
+
async function runStreams(context) {
|
|
234
|
+
const action = requiredToken(context.parsed, 1, "streams action");
|
|
235
|
+
await withDb(context, async (db) => {
|
|
236
|
+
if (action === "list") {
|
|
237
|
+
writeJson(context.stdout, await db.listStreams(), context.pretty);
|
|
238
|
+
return;
|
|
239
|
+
}
|
|
240
|
+
throw new Error(`Unknown streams action: ${action}`);
|
|
241
|
+
});
|
|
242
|
+
}
|
|
243
|
+
async function runMetrics(context) {
|
|
244
|
+
await withDb(context, async (db) => {
|
|
245
|
+
const [objects, events, activeJobs, deadJobs] = await Promise.all([
|
|
246
|
+
db.countObjects(),
|
|
247
|
+
db.countEvents(),
|
|
248
|
+
db.countActiveJobs(),
|
|
249
|
+
db.countDeadJobs(),
|
|
250
|
+
]);
|
|
251
|
+
writeJson(context.stdout, {
|
|
252
|
+
objects,
|
|
253
|
+
events,
|
|
254
|
+
activeJobs,
|
|
255
|
+
deadJobs,
|
|
256
|
+
}, context.pretty);
|
|
257
|
+
});
|
|
258
|
+
}
|
|
197
259
|
async function runQueues(context) {
|
|
198
260
|
const action = requiredToken(context.parsed, 1, "queues action");
|
|
199
|
-
const queueName = requiredToken(context.parsed, 2, "queue");
|
|
200
261
|
await withDb(context, async (db) => {
|
|
262
|
+
if (action === "list-all") {
|
|
263
|
+
writeJson(context.stdout, await db.listQueues(), context.pretty);
|
|
264
|
+
return;
|
|
265
|
+
}
|
|
266
|
+
const queueName = requiredToken(context.parsed, 2, "queue");
|
|
201
267
|
const queue = db.queue(queueName);
|
|
202
268
|
if (action === "push") {
|
|
203
269
|
const payload = parseJsonRecord(requiredFlag(context.parsed, "payload"));
|
|
@@ -239,11 +305,11 @@ async function runQueues(context) {
|
|
|
239
305
|
throw new Error(`Unknown queues action: ${action}`);
|
|
240
306
|
});
|
|
241
307
|
}
|
|
242
|
-
async function withDb(context, callback) {
|
|
308
|
+
export async function withDb(context, callback) {
|
|
243
309
|
const connection = resolveConnection(context);
|
|
244
310
|
const db = await ThingD.open({
|
|
245
311
|
path: connection.path,
|
|
246
|
-
url: connection.
|
|
312
|
+
url: connection.cloud ? connection.path : undefined,
|
|
247
313
|
driver: connection.driver,
|
|
248
314
|
authToken: connection.authToken,
|
|
249
315
|
});
|
|
@@ -275,16 +341,16 @@ function buildMemoryEvent(parsed, type) {
|
|
|
275
341
|
...(text === undefined ? {} : { text }),
|
|
276
342
|
};
|
|
277
343
|
}
|
|
278
|
-
function resolveConnection(context) {
|
|
344
|
+
export function resolveConnection(context) {
|
|
279
345
|
const url = stringFlag(context.parsed, "url") ?? context.env.THINGD_URL;
|
|
280
346
|
const path = url ?? stringFlag(context.parsed, "path") ?? context.env.THINGD_PATH ?? ":memory:";
|
|
281
|
-
const
|
|
347
|
+
const cloud = isCloudPath(path);
|
|
282
348
|
const driver = parseDriver(stringFlag(context.parsed, "driver") ?? context.env.THINGD_DRIVER);
|
|
283
349
|
return {
|
|
284
350
|
path,
|
|
285
|
-
driver: driver ?? (
|
|
351
|
+
driver: driver ?? (cloud ? "cloud" : undefined),
|
|
286
352
|
authToken: stringFlag(context.parsed, "auth-token") ?? context.env.THINGD_AUTH_TOKEN,
|
|
287
|
-
|
|
353
|
+
cloud,
|
|
288
354
|
};
|
|
289
355
|
}
|
|
290
356
|
function parseArgs(args) {
|
|
@@ -366,7 +432,7 @@ function parseDriver(value) {
|
|
|
366
432
|
if (value === undefined) {
|
|
367
433
|
return undefined;
|
|
368
434
|
}
|
|
369
|
-
if (value === "memory" || value === "native" || value === "
|
|
435
|
+
if (value === "memory" || value === "native" || value === "cloud") {
|
|
370
436
|
return value;
|
|
371
437
|
}
|
|
372
438
|
throw new Error(`Unsupported driver: ${value}`);
|
|
@@ -384,24 +450,24 @@ function compactOptions(options) {
|
|
|
384
450
|
function limitItems(items, limit) {
|
|
385
451
|
return limit === undefined ? items : items.slice(0, limit);
|
|
386
452
|
}
|
|
387
|
-
function
|
|
453
|
+
function isCloudPath(path) {
|
|
388
454
|
return path.startsWith("http://") || path.startsWith("https://") || path.startsWith("thingd://");
|
|
389
455
|
}
|
|
390
|
-
function
|
|
391
|
-
const url = new URL(
|
|
456
|
+
function resolveCloudMcpUrl(value) {
|
|
457
|
+
const url = new URL(normalizeCloudUrl(value));
|
|
392
458
|
if (url.pathname === "" || url.pathname === "/") {
|
|
393
459
|
url.pathname = "/mcp";
|
|
394
460
|
}
|
|
395
461
|
return url.toString();
|
|
396
462
|
}
|
|
397
|
-
function
|
|
398
|
-
const url = new URL(
|
|
463
|
+
function resolveCloudBaseUrl(value) {
|
|
464
|
+
const url = new URL(normalizeCloudUrl(value));
|
|
399
465
|
if (url.pathname === "/mcp") {
|
|
400
466
|
url.pathname = "/";
|
|
401
467
|
}
|
|
402
468
|
return url.toString();
|
|
403
469
|
}
|
|
404
|
-
function
|
|
470
|
+
function normalizeCloudUrl(value) {
|
|
405
471
|
return value.startsWith("thingd://") ? `http://${value.slice("thingd://".length)}` : value;
|
|
406
472
|
}
|
|
407
473
|
async function fetchJson(url, authToken) {
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"interactive.d.ts","sourceRoot":"","sources":["../src/interactive.ts"],"names":[],"mappings":"AA2jDA,wBAAsB,iBAAiB,IAAI,OAAO,CAAC,IAAI,CAAC,CA4BvD"}
|