@unravel-tech/thing 0.3.0 → 0.4.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 +22 -4
- package/package.json +1 -1
- package/src/index.js +11 -3
package/README.md
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
# @unravel-tech/thing
|
|
2
2
|
|
|
3
|
-
CLI for [thing](https://
|
|
3
|
+
CLI for [thing](https://usething.ai): push, version, and share artifacts (HTML pages, Markdown docs, standalone images and PDFs) from coding agents.
|
|
4
4
|
|
|
5
5
|
```sh
|
|
6
6
|
npm i -g @unravel-tech/thing
|
|
7
|
-
thing login # defaults to https://
|
|
7
|
+
thing login # defaults to https://usething.ai
|
|
8
8
|
thing push report.html --json
|
|
9
9
|
thing push notes.md --json # Markdown gets a styled reader view
|
|
10
10
|
thing push chart.png --json # images and PDFs too
|
|
@@ -38,10 +38,28 @@ the overrides set the server picks your default (e.g. the Unravel org for Unrave
|
|
|
38
38
|
|
|
39
39
|
## MCP
|
|
40
40
|
|
|
41
|
-
|
|
41
|
+
Claude Code, Cursor, Codex, and anything else that speaks Model Context
|
|
42
|
+
Protocol can publish through thing. No terminal login needed: create a token at
|
|
43
|
+
[usething.ai](https://usething.ai) under Settings, then Tokens, and paste this
|
|
44
|
+
into your client's MCP config.
|
|
42
45
|
|
|
43
46
|
```json
|
|
44
|
-
{
|
|
47
|
+
{
|
|
48
|
+
"mcpServers": {
|
|
49
|
+
"thing": {
|
|
50
|
+
"command": "npx",
|
|
51
|
+
"args": ["-y", "@unravel-tech/thing", "mcp"],
|
|
52
|
+
"env": { "THING_TOKEN": "paste-your-token-here" }
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
}
|
|
45
56
|
```
|
|
46
57
|
|
|
58
|
+
The server exposes three tools: `push_artifact` to publish a file or inline
|
|
59
|
+
content and get back a link, `list_artifacts` to see what you have, and
|
|
60
|
+
`whoami` to check which account and team you are pushing to.
|
|
61
|
+
|
|
62
|
+
If you already ran `thing login`, the stored credential is used and
|
|
63
|
+
`THING_TOKEN` can be left out.
|
|
64
|
+
|
|
47
65
|
Requires Node >= 18 or Bun. No runtime dependencies.
|
package/package.json
CHANGED
package/src/index.js
CHANGED
|
@@ -5,7 +5,8 @@ import { homedir } from "node:os";
|
|
|
5
5
|
import { spawn } from "node:child_process";
|
|
6
6
|
import { pathToFileURL } from "node:url";
|
|
7
7
|
|
|
8
|
-
const DEFAULT_SERVER = process.env.THING_SERVER || "https://
|
|
8
|
+
const DEFAULT_SERVER = process.env.THING_SERVER || "https://usething.ai";
|
|
9
|
+
let clientName = "thing-cli/0.3.0";
|
|
9
10
|
const VISIBILITIES = new Set(["team", "public"]);
|
|
10
11
|
|
|
11
12
|
class CliError extends Error {
|
|
@@ -36,6 +37,7 @@ function projectConfigPath(cwd) {
|
|
|
36
37
|
|
|
37
38
|
function loadState(cwd, env = process.env) {
|
|
38
39
|
return {
|
|
40
|
+
env,
|
|
39
41
|
globalPath: configPath(env),
|
|
40
42
|
global: readJson(configPath(env)),
|
|
41
43
|
projectPath: projectConfigPath(cwd),
|
|
@@ -87,9 +89,13 @@ function stripSlash(server) {
|
|
|
87
89
|
}
|
|
88
90
|
|
|
89
91
|
function context(state, flags = {}) {
|
|
92
|
+
const env = state.env ?? process.env;
|
|
90
93
|
return {
|
|
91
|
-
|
|
92
|
-
|
|
94
|
+
// THING_SERVER and THING_TOKEN let an MCP client run this with no prior
|
|
95
|
+
// `thing login`: the whole config is a paste, which is the difference
|
|
96
|
+
// between usable and not for anyone who does not live in a terminal.
|
|
97
|
+
server: stripSlash(flags.server || env.THING_SERVER || state.project.server || state.global.server || DEFAULT_SERVER),
|
|
98
|
+
token: flags.token || env.THING_TOKEN || state.global.token || null,
|
|
93
99
|
team: flags.team || state.project.team || state.global.activeTeam || null,
|
|
94
100
|
project: flags.project || state.project.project || state.global.activeProject || null
|
|
95
101
|
};
|
|
@@ -129,6 +135,7 @@ function formatText(value) {
|
|
|
129
135
|
async function api(ctx, path, options = {}) {
|
|
130
136
|
const headers = {
|
|
131
137
|
Accept: "application/json",
|
|
138
|
+
"X-Thing-Client": clientName,
|
|
132
139
|
...(options.body ? { "Content-Type": "application/json" } : {}),
|
|
133
140
|
...(ctx.token ? { Authorization: `Bearer ${ctx.token}` } : {}),
|
|
134
141
|
...(options.headers || {})
|
|
@@ -481,6 +488,7 @@ async function mcpTool(state, parsed, name, args) {
|
|
|
481
488
|
}
|
|
482
489
|
|
|
483
490
|
async function mcp(parsed, state, io) {
|
|
491
|
+
clientName = "thing-mcp/0.3.0";
|
|
484
492
|
const respond = (id, body) => io.stdout.write(`${JSON.stringify({ jsonrpc: "2.0", id, ...body })}\n`);
|
|
485
493
|
const handle = async (req) => {
|
|
486
494
|
if (req.method === "initialize") {
|