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.
Files changed (3) hide show
  1. package/README.md +68 -0
  2. package/dist/index.js +153 -0
  3. 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
+ }