@vatio-ai/cli 0.47.1 → 0.48.1

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 CHANGED
@@ -56,7 +56,7 @@ login | logout Authorize this machine in a browser, or forget it
56
56
  doctor Node, config, workspace and token status
57
57
 
58
58
  push [--env NAME] Validate the workspace, then update a preview
59
- publish [--env NAME] Promote a preview to live
59
+ publish [--env NAME] Promote the latest push to live, or the named preview
60
60
  diff [--env NAME] What this directory would change
61
61
  status Preview and live deployment state
62
62
  rollback Restore the previous live deployment
@@ -64,6 +64,7 @@ tools check Validate the workspace against Vatio's contracts
64
64
 
65
65
  chat "message" [--env NAME] Talk to your own agent; the token is the identity
66
66
  chat transcript|debug|reset|destroy
67
+ chat show CHAT_ID [--json] Any chat in the workspace, with its deployment and tool calls
67
68
 
68
69
  kb list|show|create|rm Knowledge bases
69
70
  kb write|cat|rm-entry Entries, from a file or stdin
package/bin/vatio.mjs CHANGED
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- // The Vatio CLI, as an npm package: `npx vatio push`.
2
+ // The Vatio CLI, as an npm package: `npx @vatio-ai/cli push`.
3
3
  //
4
4
  // Same platform, same API, same ~/.vatio/config.json as the Ruby CLI that
5
5
  // `curl … /install.sh | bash` puts on a machine. Either can drive a workspace,
@@ -31,8 +31,8 @@ const RETIRED = {
31
31
  pull: "was removed: a deployed manifest only ever comes from a push, so it could never\n" +
32
32
  "hand back anything your repository did not already have. Use `vatio diff --env live`,\n" +
33
33
  "or read the manifest at GET /api/v1/:slug/deploy/manifest.",
34
- update: "is npm's job now: `npx vatio@latest` always runs the current release, and\n" +
35
- "`npm install -g vatio@latest` updates a global install."
34
+ update: "is npm's job now: `npx @vatio-ai/cli@latest` always runs the current release, and\n" +
35
+ "`npm install -g @vatio-ai/cli@latest` updates a global install."
36
36
  };
37
37
 
38
38
  async function main(argv) {
@@ -10,11 +10,11 @@ import { existsSync, readFileSync, rmSync, writeFileSync } from "node:fs";
10
10
  import { join } from "node:path";
11
11
 
12
12
  import { ApiClient } from "../api-client.mjs";
13
- import { fail, sleep, takeEnv, takeValue } from "../support.mjs";
13
+ import { fail, sleep, takeEnv, takeFlag, takeValue } from "../support.mjs";
14
14
 
15
15
  export const STATE_FILE = ".vatio-chat.json";
16
16
 
17
- const SUBCOMMANDS = new Set(["transcript", "debug", "reset", "destroy", "delete", "help"]);
17
+ const SUBCOMMANDS = new Set(["show", "transcript", "debug", "reset", "destroy", "delete", "help"]);
18
18
  const REMOVED_FLAGS = ["--channel", "--from", "--as", "--sandbox-url"];
19
19
 
20
20
  export async function chat(config, args) {
@@ -30,14 +30,17 @@ export async function chat(config, args) {
30
30
 
31
31
  const environment = takeEnv(args, { fallback: "preview" });
32
32
  const timeout = Number(takeValue(args, "--timeout") ?? 120);
33
- const last = Number(takeValue(args, "--last") ?? 10);
33
+ const lastValue = takeValue(args, "--last");
34
+ const last = Number(lastValue ?? 10);
35
+ const json = takeFlag(args, "--json");
34
36
  const apiUrl = takeValue(args, "--api-url");
35
37
  const token = takeValue(args, "--token");
36
38
 
37
- const options = { environment, timeout, last, apiUrl, token };
39
+ const options = { environment, timeout, last, lastGiven: lastValue != null, json, apiUrl, token };
38
40
  const sub = SUBCOMMANDS.has(args[0]) ? args.shift() : null;
39
41
 
40
42
  if (sub === "help") return console.log(chatHelp());
43
+ if (sub === "show") return await showChat(config, options, args);
41
44
  if (sub === "transcript") return await transcript(config, options);
42
45
  if (sub === "debug") return await debugChat(config, options);
43
46
  if (sub === "reset") return await resetChat(config, options);
@@ -54,6 +57,7 @@ function chatHelp() {
54
57
  vatio chat "message" [--env NAME] [--timeout N]
55
58
  vatio chat transcript [--last N]
56
59
  vatio chat debug [--last N]
60
+ vatio chat show CHAT_ID [--last N] [--json]
57
61
  vatio chat reset
58
62
  vatio chat destroy CHAT_ID
59
63
 
@@ -61,6 +65,10 @@ function chatHelp() {
61
65
  name like pr-42. A chat against live is a real conversation and shows up in
62
66
  your inbox.
63
67
 
68
+ \`show\` reads any chat in the workspace by id -- one a visitor had on the web,
69
+ WhatsApp or Instagram, not only yours -- with the environment and deployment
70
+ that answered it, and every tool call.
71
+
64
72
  The open chat per deployment is remembered in ${STATE_FILE}, so a second
65
73
  \`vatio chat\` continues the first. \`reset\` starts over as a visitor the
66
74
  workspace has never met.`;
@@ -200,6 +208,66 @@ async function debugChat(config, options) {
200
208
  }
201
209
  }
202
210
 
211
+ // Every message, not the first page: a chat worth reading by id is usually one
212
+ // that went wrong somewhere in the middle.
213
+ async function allMessages(api, chatId) {
214
+ const messages = [];
215
+ let after = null;
216
+ for (;;) {
217
+ const payload = await api.chatMessages({ chatId, after, limit: 200 });
218
+ const page = Array.isArray(payload.data) ? payload.data : [];
219
+ messages.push(...page);
220
+ if (page.length < 200) return messages;
221
+ after = page[page.length - 1].id;
222
+ }
223
+ }
224
+
225
+ async function showChat(config, options, args) {
226
+ const chatId = args.shift();
227
+ if (!chatId || !/^\d+$/.test(chatId)) fail("Usage: vatio chat show CHAT_ID [--last N] [--json]");
228
+
229
+ const api = client(config, options);
230
+ const chat = await api.showChat({ chatId });
231
+ let messages = await allMessages(api, chatId);
232
+ if (options.lastGiven) messages = messages.slice(-options.last);
233
+
234
+ if (options.json) return console.log(JSON.stringify({ chat, messages }, null, 2));
235
+
236
+ const header = [
237
+ `Chat ${chat.chat_id}`,
238
+ chat.channel,
239
+ chat.environment,
240
+ chat.deployment_id && `deployment #${chat.deployment_id}`,
241
+ `agent ${chat.agent_slug}`
242
+ ];
243
+ console.log(header.filter(Boolean).join(" · "));
244
+ console.log(`Started ${chat.created_at}, last activity ${chat.updated_at}`);
245
+ if (chat.identity) console.log(`Identity: ${JSON.stringify(chat.identity)}`);
246
+ console.log("");
247
+
248
+ for (const message of messages) {
249
+ const content = String(message.content ?? "").trim();
250
+ if (message.role === "system") {
251
+ console.log(`[system] ${content.length} characters of prompt (--json prints it)`);
252
+ continue;
253
+ }
254
+ if (message.role === "tool") {
255
+ console.log(` [tool result] ${truncate(content, 400)}`);
256
+ continue;
257
+ }
258
+ const flags = message.discarded ? " (discarded)" : "";
259
+ if (content !== "" || flags) console.log(`[${message.role}]${flags} ${content}`);
260
+ for (const call of Array.isArray(message.tool_calls) ? message.tool_calls : []) {
261
+ console.log(` -> ${call.name}(${truncate(JSON.stringify(call.arguments ?? {}), 400)})`);
262
+ }
263
+ }
264
+ if (messages.length === 0) console.log("(no messages)");
265
+ }
266
+
267
+ function truncate(text, max) {
268
+ return text.length > max ? `${text.slice(0, max)}…` : text;
269
+ }
270
+
203
271
  async function resetChat(config, options) {
204
272
  const apiUrl = config.resolveApiUrl({ explicit: options.apiUrl });
205
273
  const payload = await openChat(config, options, {
@@ -145,14 +145,17 @@ export async function push(config, args) {
145
145
 
146
146
  export async function publish(config, args) {
147
147
  // Here `--env` names the preview being promoted, not a destination: the
148
- // destination of a publish is always live.
148
+ // destination of a publish is always live. Without it the platform promotes
149
+ // the most recent push, whichever preview it landed on.
149
150
  const environment = takeEnv(args, { fallback: null });
150
151
  const workspace = config.resolveWorkspaceRequired();
151
152
  const payload = await deployClient(config, workspace).publish({
152
153
  createdBy: process.env.USER ?? null,
153
154
  environment
154
155
  });
155
- console.log(`Published live deployment #${payload.deployment_id} (git_sha=${JSON.stringify(payload.git_sha ?? null)})`);
156
+ const from = asArray(payload.published_from);
157
+ const source = from.length > 0 ? ` from ${from.join(", ")}` : "";
158
+ console.log(`Published live deployment #${payload.deployment_id}${source} (git_sha=${JSON.stringify(payload.git_sha ?? null)})`);
156
159
  }
157
160
 
158
161
  export async function rollback(config) {
@@ -67,7 +67,8 @@ const COMMANDS = {
67
67
  publish: {
68
68
  usage: "[--env NAME]",
69
69
  summary:
70
- "Promote a preview to live, which is what customers see. Ask the developer first: this is " +
70
+ "Promote the latest push to live (or the preview `--env` names), which is what customers " +
71
+ "see. Ask the developer first: this is " +
71
72
  "the one step that changes what real visitors get.",
72
73
  annotations: { readOnlyHint: false, destructiveHint: true }
73
74
  },
@@ -77,11 +78,12 @@ const COMMANDS = {
77
78
  annotations: { readOnlyHint: false, destructiveHint: true }
78
79
  },
79
80
  chat: {
80
- usage: '"message" | transcript | debug | reset [--env NAME]',
81
+ usage: '"message" | transcript | debug | reset [--env NAME] | show CHAT_ID [--json]',
81
82
  summary:
82
83
  "Talk to the deployed agent as the developer holding the token, and read the transcript. " +
83
84
  "`debug` shows the developer view, including tool calls. `--env live` is a real conversation " +
84
- "that appears in the inbox.",
85
+ "that appears in the inbox. `show CHAT_ID` reads any chat in the workspace — a visitor's on " +
86
+ "the web or WhatsApp too — with the environment and deployment that answered it.",
85
87
  annotations: { readOnlyHint: false }
86
88
  },
87
89
  secrets: {
package/lib/config.mjs CHANGED
@@ -2,7 +2,7 @@
2
2
  // ~/.vatio/config.json, or $VATIO_HOME/config.json.
3
3
  //
4
4
  // Deliberately the same file and the same keys. Someone who already ran
5
- // `vatio login` through the curl installer can run `npx vatio push` without
5
+ // `vatio login` through the curl installer can run `npx @vatio-ai/cli push` without
6
6
  // logging in again, and can go back, because neither client owns the
7
7
  // credential -- the developer's home does.
8
8
  //
package/lib/help.mjs CHANGED
@@ -24,7 +24,8 @@ flag, the directory decides.
24
24
 
25
25
  Deploy:
26
26
  push [--env NAME] Validate the workspace, then update a preview
27
- publish [--env NAME] Promote a preview to live. --env names which one
27
+ publish [--env NAME] Promote the latest push to live. --env promotes
28
+ a specific preview instead
28
29
  rollback Restore the previous live deployment
29
30
  status Preview and live deployment state
30
31
  diff [--env NAME] What this directory would change (default: preview)
@@ -35,6 +36,8 @@ flag, the directory decides.
35
36
  Talk to your agent (as yourself — the token is the identity):
36
37
  chat "message" [--env NAME] preview by default; --env live is real
37
38
  chat transcript|debug|reset [--last N]
39
+ chat show CHAT_ID [--json] Any chat in the workspace (web, WhatsApp, ...) with
40
+ its channel, environment, deployment and tool calls
38
41
  chat destroy CHAT_ID
39
42
 
40
43
  Knowledge:
package/lib/version.mjs CHANGED
@@ -1,4 +1,4 @@
1
- // Read from package.json rather than written twice: `npx vatio` resolves a
1
+ // Read from package.json rather than written twice: `npx @vatio-ai/cli` resolves a
2
2
  // version from the registry, and a constant in here could disagree with the
3
3
  // one the developer actually downloaded.
4
4
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vatio-ai/cli",
3
- "version": "0.47.1",
3
+ "version": "0.48.1",
4
4
  "description": "Vatio CLI — deploy and manage Vatio agent workspaces",
5
5
  "keywords": [
6
6
  "vatio",