vessels 0.2.5 → 0.2.7
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 +63 -0
- package/dist/index.js +111 -30
- package/package.json +2 -4
package/README.md
ADDED
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
# vessels
|
|
2
|
+
|
|
3
|
+
CLI for [Vessels](https://vessels.app) — let your agent reach you.
|
|
4
|
+
|
|
5
|
+
Vessels is the communication layer between AI agents and their human operators. This CLI handles account setup, API key management, and webhook configuration.
|
|
6
|
+
|
|
7
|
+
## Installation
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
npm install -g vessels
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## Setup (Claude Code and AI assistants — fully non-interactive)
|
|
14
|
+
|
|
15
|
+
Two commands. One human step (the OTP from your inbox).
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
# Step 1 — send OTP to your email
|
|
19
|
+
vessels init --email me@example.com
|
|
20
|
+
|
|
21
|
+
# Step 2 — verify and complete setup (run with the code from your inbox)
|
|
22
|
+
vessels init --email me@example.com --otp 847293
|
|
23
|
+
|
|
24
|
+
# Output:
|
|
25
|
+
# VESSELS_API_KEY=vsl_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
|
|
26
|
+
# npm install vessels-sdk
|
|
27
|
+
|
|
28
|
+
# With webhook (optional — add once your server is deployed):
|
|
29
|
+
vessels init --email me@example.com --otp 847293 --webhook-url https://myapp.com/hooks/vessels
|
|
30
|
+
# Also prints: VESSELS_WEBHOOK_SECRET=whsec_xxx
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
`vessels init` creates an account if you don't have one, then creates an API key (and optional webhook endpoint), and prints copy-ready `.env` entries. It's designed for Claude Code or any AI assistant to drive autonomously — the only human touch point is entering the 6-digit OTP.
|
|
34
|
+
|
|
35
|
+
## All commands
|
|
36
|
+
|
|
37
|
+
```
|
|
38
|
+
vessels init --email <email> [--otp <code>] [--name <key-name>] [--webhook-url <url>]
|
|
39
|
+
First-time setup. Run once to send OTP, re-run with --otp to complete.
|
|
40
|
+
|
|
41
|
+
vessels login [--email <email>] [--otp <code>]
|
|
42
|
+
vessels logout
|
|
43
|
+
vessels whoami
|
|
44
|
+
|
|
45
|
+
vessels keys list
|
|
46
|
+
vessels keys create [--name <name>]
|
|
47
|
+
vessels keys revoke <id>
|
|
48
|
+
|
|
49
|
+
vessels webhooks list
|
|
50
|
+
vessels webhooks create --url <https://...> [--events interaction.response,message.user]
|
|
51
|
+
vessels webhooks delete <id>
|
|
52
|
+
vessels webhooks enable <id>
|
|
53
|
+
vessels webhooks disable <id>
|
|
54
|
+
|
|
55
|
+
vessels push --vessel <id> --message <text> --key <vsl_xxx>
|
|
56
|
+
vessels message --vessel <id> --message <text>
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
## Full reference
|
|
60
|
+
|
|
61
|
+
- SDK: [vessels-sdk on npm](https://www.npmjs.com/package/vessels-sdk)
|
|
62
|
+
- Docs: [vessels.app/docs](https://vessels.app/docs)
|
|
63
|
+
- AI-readable reference: [vessels.app/llms-full.txt](https://vessels.app/llms-full.txt)
|
package/dist/index.js
CHANGED
|
@@ -1,14 +1,11 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
3
|
// src/index.ts
|
|
4
|
-
import { createClient } from "@supabase/supabase-js";
|
|
5
4
|
import { readFileSync, writeFileSync, mkdirSync, existsSync } from "fs";
|
|
6
5
|
import { homedir } from "os";
|
|
7
6
|
import { join } from "path";
|
|
8
7
|
import * as readline from "readline/promises";
|
|
9
|
-
var BASE_URL = "https://vessels
|
|
10
|
-
var SUPABASE_URL = "https://vnlrstpwkizhidvwhoom.supabase.co";
|
|
11
|
-
var SUPABASE_ANON_KEY = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6InZubHJzdHB3a2l6aGlkdndob29tIiwicm9sZSI6ImFub24iLCJpYXQiOjE3NzU1ODIzMDgsImV4cCI6MjA5MTE1ODMwOH0.tz1k8MH_1G8M0qZncfFV8eA8NmGKZXvzUk3r1dylAhs";
|
|
8
|
+
var BASE_URL = "https://vessels.app";
|
|
12
9
|
var CONFIG_DIR = join(homedir(), ".vessels");
|
|
13
10
|
var CONFIG_FILE = join(CONFIG_DIR, "config.json");
|
|
14
11
|
function readConfig() {
|
|
@@ -37,11 +34,15 @@ async function getFreshToken() {
|
|
|
37
34
|
if (!isTokenExpired(config.access_token)) return config.access_token;
|
|
38
35
|
if (config.refresh_token) {
|
|
39
36
|
try {
|
|
40
|
-
const
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
37
|
+
const res = await fetch(`${BASE_URL}/api/v1/auth/refresh`, {
|
|
38
|
+
method: "POST",
|
|
39
|
+
headers: { "Content-Type": "application/json" },
|
|
40
|
+
body: JSON.stringify({ refresh_token: config.refresh_token })
|
|
41
|
+
});
|
|
42
|
+
if (res.ok) {
|
|
43
|
+
const data = await res.json();
|
|
44
|
+
writeConfig({ ...config, access_token: data.access_token, refresh_token: data.refresh_token });
|
|
45
|
+
return data.access_token;
|
|
45
46
|
}
|
|
46
47
|
} catch {
|
|
47
48
|
}
|
|
@@ -82,12 +83,16 @@ function parseFlags(args) {
|
|
|
82
83
|
}
|
|
83
84
|
async function cmdLogin(args) {
|
|
84
85
|
const flags = parseFlags(args);
|
|
85
|
-
const supabase = createClient(SUPABASE_URL, SUPABASE_ANON_KEY);
|
|
86
86
|
const email = flags.email || await prompt("Email: ");
|
|
87
87
|
if (!flags.otp) {
|
|
88
|
-
const
|
|
89
|
-
|
|
90
|
-
|
|
88
|
+
const res2 = await fetch(`${BASE_URL}/api/v1/auth/otp/send`, {
|
|
89
|
+
method: "POST",
|
|
90
|
+
headers: { "Content-Type": "application/json" },
|
|
91
|
+
body: JSON.stringify({ email })
|
|
92
|
+
});
|
|
93
|
+
if (!res2.ok) {
|
|
94
|
+
const data2 = await res2.json();
|
|
95
|
+
console.error("Failed to send code:", data2.error);
|
|
91
96
|
process.exit(1);
|
|
92
97
|
}
|
|
93
98
|
console.log(`OTP sent to ${email}.`);
|
|
@@ -97,16 +102,17 @@ async function cmdLogin(args) {
|
|
|
97
102
|
}
|
|
98
103
|
}
|
|
99
104
|
const otp = flags.otp || await prompt("Code: ");
|
|
100
|
-
const
|
|
101
|
-
|
|
105
|
+
const res = await fetch(`${BASE_URL}/api/v1/auth/otp/verify`, {
|
|
106
|
+
method: "POST",
|
|
107
|
+
headers: { "Content-Type": "application/json" },
|
|
108
|
+
body: JSON.stringify({ email, token: otp })
|
|
109
|
+
});
|
|
110
|
+
const data = await res.json();
|
|
111
|
+
if (!res.ok) {
|
|
102
112
|
console.error("Invalid or expired code.");
|
|
103
113
|
process.exit(1);
|
|
104
114
|
}
|
|
105
|
-
writeConfig({
|
|
106
|
-
access_token: data.session.access_token,
|
|
107
|
-
refresh_token: data.session.refresh_token,
|
|
108
|
-
email
|
|
109
|
-
});
|
|
115
|
+
writeConfig({ access_token: data.access_token, refresh_token: data.refresh_token, email });
|
|
110
116
|
await api("/api/v1/me");
|
|
111
117
|
console.log(`Logged in as ${email}`);
|
|
112
118
|
}
|
|
@@ -237,7 +243,7 @@ Sent.`);
|
|
|
237
243
|
const logsData = await api(`/api/v1/webhooks/deliveries?since=${encodeURIComponent(since)}&limit=10`);
|
|
238
244
|
const deliveries = logsData.deliveries ?? [];
|
|
239
245
|
if (!deliveries.length) {
|
|
240
|
-
console.log("\nNo webhook deliveries \u2014 add an endpoint at vessels
|
|
246
|
+
console.log("\nNo webhook deliveries \u2014 add an endpoint at vessels.app/settings/webhooks");
|
|
241
247
|
return;
|
|
242
248
|
}
|
|
243
249
|
console.log(`
|
|
@@ -285,14 +291,93 @@ async function cmdPush(args) {
|
|
|
285
291
|
}
|
|
286
292
|
console.log(`Message sent. vessel_id=${data.vessel_id} message_id=${data.message_id}`);
|
|
287
293
|
}
|
|
294
|
+
async function cmdInit(args) {
|
|
295
|
+
const flags = parseFlags(args);
|
|
296
|
+
const email = flags.email || await prompt("Email: ");
|
|
297
|
+
if (!flags.otp) {
|
|
298
|
+
const res = await fetch(`${BASE_URL}/api/v1/auth/otp/send`, {
|
|
299
|
+
method: "POST",
|
|
300
|
+
headers: { "Content-Type": "application/json" },
|
|
301
|
+
body: JSON.stringify({ email })
|
|
302
|
+
});
|
|
303
|
+
if (!res.ok) {
|
|
304
|
+
const data = await res.json();
|
|
305
|
+
console.error("Failed to send code:", data.error);
|
|
306
|
+
process.exit(1);
|
|
307
|
+
}
|
|
308
|
+
console.log(`
|
|
309
|
+
OTP sent to ${email}.
|
|
310
|
+
`);
|
|
311
|
+
const webhookFlag = flags["webhook-url"] ? ` --webhook-url ${flags["webhook-url"]}` : "";
|
|
312
|
+
const nameFlag = flags.name ? ` --name ${flags.name}` : "";
|
|
313
|
+
console.log(`Run:
|
|
314
|
+
|
|
315
|
+
vessels init --email ${email} --otp <code>${nameFlag}${webhookFlag}
|
|
316
|
+
`);
|
|
317
|
+
return;
|
|
318
|
+
}
|
|
319
|
+
const verifyRes = await fetch(`${BASE_URL}/api/v1/auth/otp/verify`, {
|
|
320
|
+
method: "POST",
|
|
321
|
+
headers: { "Content-Type": "application/json" },
|
|
322
|
+
body: JSON.stringify({ email, token: flags.otp })
|
|
323
|
+
});
|
|
324
|
+
const verifyData = await verifyRes.json();
|
|
325
|
+
if (!verifyRes.ok) {
|
|
326
|
+
console.error("Invalid or expired code.");
|
|
327
|
+
process.exit(1);
|
|
328
|
+
}
|
|
329
|
+
writeConfig({ access_token: verifyData.access_token, refresh_token: verifyData.refresh_token, email });
|
|
330
|
+
await api("/api/v1/me");
|
|
331
|
+
const keyData = await api("/api/v1/keys", {
|
|
332
|
+
method: "POST",
|
|
333
|
+
body: JSON.stringify({ name: flags.name || "default" })
|
|
334
|
+
});
|
|
335
|
+
console.log(`
|
|
336
|
+
Setup complete.
|
|
337
|
+
`);
|
|
338
|
+
console.log(`Add to your .env file:
|
|
339
|
+
`);
|
|
340
|
+
console.log(` VESSELS_API_KEY=${keyData.key}`);
|
|
341
|
+
if (flags["webhook-url"]) {
|
|
342
|
+
const webhookData = await api("/api/v1/webhooks", {
|
|
343
|
+
method: "POST",
|
|
344
|
+
body: JSON.stringify({ url: flags["webhook-url"], events: ["interaction.response", "message.user"] })
|
|
345
|
+
});
|
|
346
|
+
console.log(` VESSELS_WEBHOOK_SECRET=${webhookData.endpoint.secret}`);
|
|
347
|
+
}
|
|
348
|
+
console.log(`
|
|
349
|
+
Install the SDK:
|
|
350
|
+
|
|
351
|
+
npm install vessels-sdk
|
|
352
|
+
`);
|
|
353
|
+
if (!flags["webhook-url"]) {
|
|
354
|
+
console.log(`To receive webhooks (once your server is deployed):
|
|
355
|
+
`);
|
|
356
|
+
console.log(` vessels webhooks create --url https://your-app.com/hooks/vessels
|
|
357
|
+
`);
|
|
358
|
+
}
|
|
359
|
+
console.log(`Full reference: https://vessels.app/llms-full.txt`);
|
|
360
|
+
}
|
|
288
361
|
var [, , cmd, sub, ...rest] = process.argv;
|
|
289
362
|
var HELP = `
|
|
290
|
-
vessels \u2014 CLI for Vessels (vessels
|
|
363
|
+
vessels \u2014 CLI for Vessels (vessels.app)
|
|
364
|
+
|
|
365
|
+
Quick setup (Claude Code / AI agents \u2014 fully non-interactive):
|
|
366
|
+
|
|
367
|
+
vessels init --email me@example.com
|
|
368
|
+
# Vessels emails you a 6-digit code. Then run:
|
|
369
|
+
vessels init --email me@example.com --otp 847293
|
|
370
|
+
# Prints VESSELS_API_KEY=vsl_xxx and npm install vessels-sdk
|
|
371
|
+
|
|
372
|
+
# With a webhook (optional, run once your server is deployed):
|
|
373
|
+
vessels init --email me@example.com --otp 847293 --webhook-url https://myapp.com/hooks/vessels
|
|
291
374
|
|
|
292
375
|
Commands:
|
|
293
|
-
vessels
|
|
294
|
-
|
|
376
|
+
vessels init --email <email> [--otp <code>] [--name <key-name>] [--webhook-url <url>]
|
|
377
|
+
First-time setup: account + API key (+ webhook). Two-step: run once to send OTP,
|
|
378
|
+
re-run with --otp to complete. Prints copy-ready .env entries.
|
|
295
379
|
|
|
380
|
+
vessels login [--email <email>] [--otp <code>]
|
|
296
381
|
vessels logout
|
|
297
382
|
vessels whoami
|
|
298
383
|
|
|
@@ -313,18 +398,14 @@ Commands:
|
|
|
313
398
|
Send a message as the logged-in user and print webhook delivery logs.
|
|
314
399
|
Accepts vessel UUID or external_id (e.g. booking-123).
|
|
315
400
|
|
|
316
|
-
|
|
317
|
-
vessels login --email me@example.com
|
|
318
|
-
# tell your agent the OTP from the email
|
|
319
|
-
vessels login --email me@example.com --otp 847293
|
|
320
|
-
vessels keys create --name my-project
|
|
321
|
-
vessels webhooks create --url https://myapp.com/hooks/vessels
|
|
401
|
+
Full reference: https://vessels.app/llms-full.txt
|
|
322
402
|
`;
|
|
323
403
|
async function main() {
|
|
324
404
|
if (!cmd || cmd === "help" || cmd === "--help" || cmd === "-h") {
|
|
325
405
|
console.log(HELP);
|
|
326
406
|
return;
|
|
327
407
|
}
|
|
408
|
+
if (cmd === "init") return cmdInit([sub, ...rest].filter(Boolean));
|
|
328
409
|
if (cmd === "login" || cmd === "signup") return cmdLogin([sub, ...rest].filter(Boolean));
|
|
329
410
|
if (cmd === "logout") return cmdLogout();
|
|
330
411
|
if (cmd === "whoami") return cmdWhoami();
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "vessels",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.7",
|
|
4
4
|
"description": "Vessels CLI — manage your agent communication layer from the terminal",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -20,7 +20,5 @@
|
|
|
20
20
|
"typescript": "^5",
|
|
21
21
|
"@types/node": "^25.5.2"
|
|
22
22
|
},
|
|
23
|
-
"dependencies": {
|
|
24
|
-
"@supabase/supabase-js": "^2.102.1"
|
|
25
|
-
}
|
|
23
|
+
"dependencies": {}
|
|
26
24
|
}
|