vessels 0.2.1 → 0.2.3

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 (2) hide show
  1. package/dist/index.js +83 -13
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -37,7 +37,10 @@ async function api(path, options = {}) {
37
37
  }
38
38
  });
39
39
  const data = await res.json();
40
- if (!res.ok) throw new Error(data.error ?? `HTTP ${res.status}`);
40
+ if (!res.ok) {
41
+ const hint = res.status === 401 ? ` Run: vessels login --email <email>` : "";
42
+ throw new Error((data.error ?? `HTTP ${res.status}`) + hint);
43
+ }
41
44
  return data;
42
45
  }
43
46
  function prompt(question) {
@@ -108,11 +111,12 @@ async function cmdKeysList() {
108
111
  console.log(`${k.prefix}\u2026 ${used}${name} [${k.id}]`);
109
112
  }
110
113
  }
111
- async function cmdKeysCreate(name) {
112
- if (!name) name = await prompt("Key name (optional): ");
114
+ async function cmdKeysCreate(args) {
115
+ const flags = parseFlags(args);
116
+ const name = flags.name || (args[0] && !args[0].startsWith("--") ? args[0] : null) || null;
113
117
  const data = await api("/api/v1/keys", {
114
118
  method: "POST",
115
- body: JSON.stringify({ name: name || null })
119
+ body: JSON.stringify({ name })
116
120
  });
117
121
  console.log(`
118
122
  API key created. Copy it now \u2014 it won't be shown again.
@@ -120,6 +124,7 @@ API key created. Copy it now \u2014 it won't be shown again.
120
124
  console.log(` ${data.key}
121
125
  `);
122
126
  if (data.name) console.log(`Name: ${data.name}`);
127
+ console.log(`VESSELS_API_KEY=${data.key}`);
123
128
  }
124
129
  async function cmdKeysRevoke(id) {
125
130
  await api(`/api/v1/keys/${id}`, { method: "DELETE" });
@@ -179,18 +184,72 @@ async function cmdWebhooksToggle(id, active) {
179
184
  });
180
185
  console.log(`Webhook ${data.endpoint.id} ${data.endpoint.active ? "enabled" : "disabled"}.`);
181
186
  }
182
- async function cmdPush(args) {
183
- const flags = {};
184
- for (let i = 0; i < args.length; i++) {
185
- if (args[i].startsWith("--")) flags[args[i].slice(2)] = args[i + 1] ?? "";
187
+ var UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
188
+ async function resolveVesselId(input) {
189
+ if (UUID_RE.test(input)) return input;
190
+ const data = await api("/api/v1/vessels?limit=200&archived=true");
191
+ const vessel = (data.vessels ?? []).find((v) => v.external_id === input);
192
+ if (!vessel) {
193
+ console.error(`Vessel not found: ${input}`);
194
+ process.exit(1);
186
195
  }
196
+ return vessel.id;
197
+ }
198
+ async function cmdMessage(args) {
199
+ const flags = parseFlags(args);
200
+ if (!flags.vessel || !flags.message) {
201
+ console.error("Usage: vessels message --vessel <id> --message <text>");
202
+ process.exit(1);
203
+ }
204
+ const vesselId = await resolveVesselId(flags.vessel);
205
+ const since = new Date(Date.now() - 5e3).toISOString();
206
+ const data = await api(`/api/v1/vessels/${vesselId}/messages`, {
207
+ method: "POST",
208
+ body: JSON.stringify({ message: flags.message })
209
+ });
210
+ console.log(`
211
+ Sent.`);
212
+ console.log(` vessel_id ${vesselId}`);
213
+ console.log(` message_id ${data.message_id}`);
214
+ const logsData = await api(`/api/v1/webhooks/deliveries?since=${encodeURIComponent(since)}&limit=10`);
215
+ const deliveries = logsData.deliveries ?? [];
216
+ if (!deliveries.length) {
217
+ console.log("\nNo webhook deliveries \u2014 add an endpoint at vessels-two.vercel.app/settings/webhooks");
218
+ return;
219
+ }
220
+ console.log(`
221
+ Webhook deliveries (${deliveries.length}):
222
+ `);
223
+ for (const d of deliveries) {
224
+ const ok = d.response_status !== null && d.response_status >= 200 && d.response_status < 300;
225
+ const icon = ok ? "\u2713" : "\u2717";
226
+ const status = d.response_status ?? "no response";
227
+ const url = d.endpoint_url ?? "(deleted endpoint)";
228
+ const retry = d.attempt > 1 ? ` \xB7 attempt ${d.attempt}` : "";
229
+ const time = new Date(d.delivered_at).toLocaleTimeString([], { timeStyle: "medium" });
230
+ console.log(` ${icon} ${status} ${url}`);
231
+ console.log(` ${d.event_type}${retry} \xB7 ${time}`);
232
+ if (d.response_body) {
233
+ const body = d.response_body.length > 300 ? d.response_body.slice(0, 300) + "\u2026" : d.response_body;
234
+ console.log(`
235
+ ${body.split("\n").join("\n ")}`);
236
+ }
237
+ console.log();
238
+ }
239
+ }
240
+ async function cmdPush(args) {
241
+ const flags = parseFlags(args);
187
242
  const apiKey = flags.key ?? process.env.VESSELS_API_KEY;
188
243
  if (!apiKey) {
189
244
  console.error("Provide an API key via --key or VESSELS_API_KEY env var");
190
245
  process.exit(1);
191
246
  }
192
- const message = flags.message ?? await prompt("Message: ");
193
- const vessel = flags.vessel ?? await prompt("Vessel ID (or press enter for default): ");
247
+ if (!flags.message) {
248
+ console.error("Usage: vessels push --vessel <id> --message <text> --key <api_key>");
249
+ process.exit(1);
250
+ }
251
+ const message = flags.message;
252
+ const vessel = flags.vessel ?? void 0;
194
253
  const res = await fetch(`${BASE_URL}/api/v1/push`, {
195
254
  method: "POST",
196
255
  headers: { "Content-Type": "application/json", Authorization: `Bearer ${apiKey}` },
@@ -215,7 +274,7 @@ Commands:
215
274
  vessels whoami
216
275
 
217
276
  vessels keys list
218
- vessels keys create [name]
277
+ vessels keys create [--name <name>]
219
278
  vessels keys revoke <id>
220
279
 
221
280
  vessels webhooks list
@@ -227,11 +286,15 @@ Commands:
227
286
  vessels push --vessel <id> --message <text> --key <api_key>
228
287
  (--key can be omitted if VESSELS_API_KEY is set)
229
288
 
289
+ vessels message --vessel <id> --message <text>
290
+ Send a message as the logged-in user and print webhook delivery logs.
291
+ Accepts vessel UUID or external_id (e.g. booking-123).
292
+
230
293
  Agent/Claude Code setup (fully non-interactive):
231
294
  vessels login --email me@example.com
232
295
  # tell your agent the OTP from the email
233
296
  vessels login --email me@example.com --otp 847293
234
- vessels keys create my-project
297
+ vessels keys create --name my-project
235
298
  vessels webhooks create --url https://myapp.com/hooks/vessels
236
299
  `;
237
300
  async function main() {
@@ -244,7 +307,7 @@ async function main() {
244
307
  if (cmd === "whoami") return cmdWhoami();
245
308
  if (cmd === "keys") {
246
309
  if (sub === "list" || !sub) return cmdKeysList();
247
- if (sub === "create") return cmdKeysCreate(rest[0]);
310
+ if (sub === "create") return cmdKeysCreate(rest);
248
311
  if (sub === "revoke") {
249
312
  if (!rest[0]) {
250
313
  console.error("Usage: vessels keys revoke <id>");
@@ -252,6 +315,9 @@ async function main() {
252
315
  }
253
316
  return cmdKeysRevoke(rest[0]);
254
317
  }
318
+ console.error(`Unknown subcommand: keys ${sub}
319
+ Run: vessels help`);
320
+ process.exit(1);
255
321
  }
256
322
  if (cmd === "webhooks") {
257
323
  if (sub === "list" || !sub) return cmdWebhooksList();
@@ -277,8 +343,12 @@ async function main() {
277
343
  }
278
344
  return cmdWebhooksToggle(rest[0], false);
279
345
  }
346
+ console.error(`Unknown subcommand: webhooks ${sub}
347
+ Run: vessels help`);
348
+ process.exit(1);
280
349
  }
281
350
  if (cmd === "push") return cmdPush([sub, ...rest].filter(Boolean));
351
+ if (cmd === "message") return cmdMessage([sub, ...rest].filter(Boolean));
282
352
  console.error(`Unknown command: ${cmd}
283
353
  Run: vessels help`);
284
354
  process.exit(1);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vessels",
3
- "version": "0.2.1",
3
+ "version": "0.2.3",
4
4
  "description": "Vessels CLI — manage your agent communication layer from the terminal",
5
5
  "type": "module",
6
6
  "bin": {