vellum-cli 0.1.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 +68 -0
- package/dist/index.js +153 -0
- package/package.json +36 -0
package/README.md
ADDED
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
# @vellum/cli
|
|
2
|
+
|
|
3
|
+
The `vellum` CLI. Lets an agent (or a human) publish an HTML artifact to a
|
|
4
|
+
Vellum server.
|
|
5
|
+
|
|
6
|
+
## Install
|
|
7
|
+
|
|
8
|
+
```bash
|
|
9
|
+
# one-off, no install
|
|
10
|
+
npx vellum-cli push --help
|
|
11
|
+
|
|
12
|
+
# or install the `vellum` command globally
|
|
13
|
+
npm i -g vellum-cli
|
|
14
|
+
vellum push --help
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
Requires Node 18+. The package is self-contained (`@vellum/core` is bundled in),
|
|
18
|
+
so it has no runtime dependencies.
|
|
19
|
+
|
|
20
|
+
## Configuration
|
|
21
|
+
|
|
22
|
+
Connection settings come from flags, falling back to env vars:
|
|
23
|
+
|
|
24
|
+
| Flag | Env var | Description |
|
|
25
|
+
| ------------ | ---------------- | ---------------------------- |
|
|
26
|
+
| `--url` | `VELLUM_URL` | Server base URL |
|
|
27
|
+
| `--api-key` | `VELLUM_API_KEY` | Shared API key (`X-Api-Key`) |
|
|
28
|
+
|
|
29
|
+
## Commands
|
|
30
|
+
|
|
31
|
+
### `vellum push [file]`
|
|
32
|
+
|
|
33
|
+
Create an artifact from HTML. Reads from `<file>` if given, otherwise from
|
|
34
|
+
stdin. Pass `--page-id <id>` to append a new version to an existing page.
|
|
35
|
+
|
|
36
|
+
```bash
|
|
37
|
+
# new page from a file
|
|
38
|
+
vellum push artifact.html
|
|
39
|
+
|
|
40
|
+
# new page from stdin
|
|
41
|
+
echo '<!doctype html><h1>Hello</h1>' | vellum push
|
|
42
|
+
|
|
43
|
+
# add a version to an existing page, print raw JSON
|
|
44
|
+
vellum push artifact.html --page-id pg_123 --json
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
On success it prints the new version number, the human view URL, and the raw
|
|
48
|
+
URL. With `--json` it prints the server's `CreateVersionResponse` verbatim.
|
|
49
|
+
|
|
50
|
+
## Development
|
|
51
|
+
|
|
52
|
+
From the repo root, Bun runs the TypeScript source directly (no build):
|
|
53
|
+
|
|
54
|
+
```bash
|
|
55
|
+
bun run cli push --help
|
|
56
|
+
# or directly
|
|
57
|
+
bun run packages/cli/src/index.ts push --help
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
## Publishing
|
|
61
|
+
|
|
62
|
+
`bun run build` bundles the source + `@vellum/core` into a single
|
|
63
|
+
node-compatible `dist/index.js` (run automatically on `npm publish` via the
|
|
64
|
+
`prepack` hook). The published `bin` is `vellum`.
|
|
65
|
+
|
|
66
|
+
```bash
|
|
67
|
+
npm publish # builds via prepack, publishes vellum-cli
|
|
68
|
+
```
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
// src/config.ts
|
|
4
|
+
class ConfigError extends Error {
|
|
5
|
+
}
|
|
6
|
+
function resolveConfig(flags) {
|
|
7
|
+
const baseUrl = flags.url ?? process.env.VELLUM_URL;
|
|
8
|
+
const apiKey = flags.apiKey ?? process.env.VELLUM_API_KEY;
|
|
9
|
+
if (!baseUrl) {
|
|
10
|
+
throw new ConfigError("Missing server URL. Pass --url or set VELLUM_URL.");
|
|
11
|
+
}
|
|
12
|
+
if (!apiKey) {
|
|
13
|
+
throw new ConfigError("Missing API key. Pass --api-key or set VELLUM_API_KEY.");
|
|
14
|
+
}
|
|
15
|
+
return { baseUrl, apiKey };
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
// src/commands/push.ts
|
|
19
|
+
import { readFile } from "node:fs/promises";
|
|
20
|
+
import { parseArgs } from "node:util";
|
|
21
|
+
// ../core/src/client.ts
|
|
22
|
+
class VellumApiError extends Error {
|
|
23
|
+
status;
|
|
24
|
+
code;
|
|
25
|
+
constructor(status, code) {
|
|
26
|
+
super(`Vellum API error ${status}: ${code}`);
|
|
27
|
+
this.status = status;
|
|
28
|
+
this.code = code;
|
|
29
|
+
this.name = "VellumApiError";
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
class VellumClient {
|
|
34
|
+
baseUrl;
|
|
35
|
+
apiKey;
|
|
36
|
+
fetchImpl;
|
|
37
|
+
constructor(opts) {
|
|
38
|
+
this.baseUrl = opts.baseUrl.replace(/\/+$/, "");
|
|
39
|
+
this.apiKey = opts.apiKey;
|
|
40
|
+
this.fetchImpl = opts.fetch ?? globalThis.fetch;
|
|
41
|
+
}
|
|
42
|
+
async createPage(html, opts = {}) {
|
|
43
|
+
const url = new URL(`${this.baseUrl}/v1/pages`);
|
|
44
|
+
if (opts.pageId)
|
|
45
|
+
url.searchParams.set("page_id", opts.pageId);
|
|
46
|
+
const res = await this.fetchImpl(url, {
|
|
47
|
+
method: "POST",
|
|
48
|
+
headers: {
|
|
49
|
+
"Content-Type": "text/html; charset=utf-8",
|
|
50
|
+
"X-Api-Key": this.apiKey
|
|
51
|
+
},
|
|
52
|
+
body: html
|
|
53
|
+
});
|
|
54
|
+
if (!res.ok) {
|
|
55
|
+
const code = await res.json().then((b) => b.error).catch(() => res.statusText);
|
|
56
|
+
throw new VellumApiError(res.status, code);
|
|
57
|
+
}
|
|
58
|
+
return await res.json();
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
// src/commands/push.ts
|
|
62
|
+
var HELP = `vellum push — create a Vellum artifact from HTML
|
|
63
|
+
|
|
64
|
+
Usage:
|
|
65
|
+
vellum push <file.html> [options]
|
|
66
|
+
cat page.html | vellum push [options]
|
|
67
|
+
|
|
68
|
+
Options:
|
|
69
|
+
--page-id <id> Append a new version to an existing page
|
|
70
|
+
--url <url> Server base URL (env: VELLUM_URL)
|
|
71
|
+
--api-key <key> Shared API key (env: VELLUM_API_KEY)
|
|
72
|
+
--json Print the raw JSON response
|
|
73
|
+
-h, --help Show this help`;
|
|
74
|
+
async function readStdin() {
|
|
75
|
+
const chunks = [];
|
|
76
|
+
for await (const chunk of process.stdin)
|
|
77
|
+
chunks.push(chunk);
|
|
78
|
+
return Buffer.concat(chunks).toString("utf8");
|
|
79
|
+
}
|
|
80
|
+
async function pushCommand(argv) {
|
|
81
|
+
const { values, positionals } = parseArgs({
|
|
82
|
+
args: argv,
|
|
83
|
+
allowPositionals: true,
|
|
84
|
+
options: {
|
|
85
|
+
"page-id": { type: "string" },
|
|
86
|
+
url: { type: "string" },
|
|
87
|
+
"api-key": { type: "string" },
|
|
88
|
+
json: { type: "boolean", default: false },
|
|
89
|
+
help: { type: "boolean", short: "h", default: false }
|
|
90
|
+
}
|
|
91
|
+
});
|
|
92
|
+
if (values.help) {
|
|
93
|
+
console.log(HELP);
|
|
94
|
+
return 0;
|
|
95
|
+
}
|
|
96
|
+
const file = positionals[0];
|
|
97
|
+
const html = file ? await readFile(file, "utf8") : await readStdin();
|
|
98
|
+
if (!html.trim()) {
|
|
99
|
+
console.error("Error: no HTML provided (empty file or stdin).");
|
|
100
|
+
return 1;
|
|
101
|
+
}
|
|
102
|
+
const { baseUrl, apiKey } = resolveConfig({
|
|
103
|
+
url: values.url,
|
|
104
|
+
apiKey: values["api-key"]
|
|
105
|
+
});
|
|
106
|
+
const client2 = new VellumClient({ baseUrl, apiKey });
|
|
107
|
+
const res = await client2.createPage(html, { pageId: values["page-id"] });
|
|
108
|
+
if (values.json) {
|
|
109
|
+
console.log(JSON.stringify(res, null, 2));
|
|
110
|
+
} else {
|
|
111
|
+
console.log(`✓ v${res.version_number} created`);
|
|
112
|
+
console.log(` view: ${res.view_url}`);
|
|
113
|
+
console.log(` raw: ${res.raw_url}`);
|
|
114
|
+
}
|
|
115
|
+
return 0;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
// src/index.ts
|
|
119
|
+
var HELP2 = `vellum — CLI for the Vellum artifact store
|
|
120
|
+
|
|
121
|
+
Usage:
|
|
122
|
+
vellum <command> [options]
|
|
123
|
+
|
|
124
|
+
Commands:
|
|
125
|
+
push Create an artifact (page) from HTML (file or stdin)
|
|
126
|
+
|
|
127
|
+
Run 'vellum <command> --help' for command-specific options.`;
|
|
128
|
+
var commands = {
|
|
129
|
+
push: pushCommand
|
|
130
|
+
};
|
|
131
|
+
async function main() {
|
|
132
|
+
const [, , cmd, ...rest] = process.argv;
|
|
133
|
+
if (!cmd || cmd === "-h" || cmd === "--help" || cmd === "help") {
|
|
134
|
+
console.log(HELP2);
|
|
135
|
+
return cmd ? 0 : 1;
|
|
136
|
+
}
|
|
137
|
+
const handler = commands[cmd];
|
|
138
|
+
if (!handler) {
|
|
139
|
+
console.error(`Unknown command: ${cmd}
|
|
140
|
+
`);
|
|
141
|
+
console.error(HELP2);
|
|
142
|
+
return 1;
|
|
143
|
+
}
|
|
144
|
+
return handler(rest);
|
|
145
|
+
}
|
|
146
|
+
main().then((code) => process.exit(code)).catch((err) => {
|
|
147
|
+
if (err instanceof ConfigError) {
|
|
148
|
+
console.error(`Error: ${err.message}`);
|
|
149
|
+
} else {
|
|
150
|
+
console.error(err instanceof Error ? `Error: ${err.message}` : err);
|
|
151
|
+
}
|
|
152
|
+
process.exit(1);
|
|
153
|
+
});
|
package/package.json
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "vellum-cli",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "The vellum CLI — publish agent-authored HTML artifacts to a Vellum server.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"license": "MIT",
|
|
7
|
+
"bin": {
|
|
8
|
+
"vellum": "dist/index.js"
|
|
9
|
+
},
|
|
10
|
+
"files": [
|
|
11
|
+
"dist",
|
|
12
|
+
"README.md"
|
|
13
|
+
],
|
|
14
|
+
"engines": {
|
|
15
|
+
"node": ">=18"
|
|
16
|
+
},
|
|
17
|
+
"keywords": [
|
|
18
|
+
"vellum",
|
|
19
|
+
"cli",
|
|
20
|
+
"html",
|
|
21
|
+
"artifacts",
|
|
22
|
+
"agents"
|
|
23
|
+
],
|
|
24
|
+
"publishConfig": {
|
|
25
|
+
"access": "public"
|
|
26
|
+
},
|
|
27
|
+
"scripts": {
|
|
28
|
+
"start": "bun run src/index.ts",
|
|
29
|
+
"build": "bun build src/index.ts --target=node --format=esm --outfile=dist/index.js",
|
|
30
|
+
"prepack": "bun run build",
|
|
31
|
+
"typecheck": "tsc -p tsconfig.json --noEmit"
|
|
32
|
+
},
|
|
33
|
+
"devDependencies": {
|
|
34
|
+
"@vellum/core": "workspace:*"
|
|
35
|
+
}
|
|
36
|
+
}
|