@vatio-ai/cli 0.47.0 → 0.48.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 CHANGED
@@ -1,44 +1,87 @@
1
1
  # @vatio-ai/cli
2
2
 
3
- The CLI for [Vatio](https://vatio.ai) — deploy and manage AI agent workspaces.
3
+ The CLI for [Vatio](https://vatio.ai) — a production runtime for
4
+ customer-facing AI agents. Describe an agent in one `vatio.yml` and deploy it to
5
+ web chat, WhatsApp and Instagram; Vatio runs the conversation, the contacts, the
6
+ identity, the safeguards and the handoff to a human.
4
7
 
5
8
  ```bash
6
9
  npx @vatio-ai/cli init my-agent
7
10
  npx @vatio-ai/cli push
8
11
  ```
9
12
 
10
- No runtime to install first: if you have Node, you have this.
13
+ No runtime to install first: if you have Node 20 or newer, you have this.
11
14
 
12
15
  The package is `@vatio-ai/cli`; the command it installs is `vatio`. So
13
16
  `npm install -g @vatio-ai/cli` gives you `vatio push`, and `npx @vatio-ai/cli push`
14
17
  is the same thing without installing anything.
15
18
 
19
+ ## If you are a coding agent
20
+
21
+ ```bash
22
+ vatio mcp # MCP over stdio
23
+ vatio docs # the whole developer contract as markdown, live from Vatio
24
+ ```
25
+
26
+ `vatio mcp` is the short path: it hands you the contract and the deploy commands
27
+ over MCP, with no browser step. Failing that, `vatio docs` prints the same
28
+ contract that [docs.vatio.ai/docs.md](https://docs.vatio.ai/docs.md) serves, and
29
+ `vatio docs --save` writes it next to the workspace.
30
+
31
+ Don't guess `vatio.yml` keys. Unknown root keys fail validation, and the rules
32
+ that judge a workspace live on the server — so the printed contract is the
33
+ current one by construction.
34
+
16
35
  ## What a workspace is
17
36
 
18
- A directory with a `vatio.yml` in it. That file says which Vatio workspace the
19
- directory deploys to, what the agent does, and how the widget looks; `tools/`,
20
- `lib/` and `auth/` next to it are plain JavaScript the agent runs.
37
+ A directory with a `vatio.yml` in it:
38
+
39
+ ```text
40
+ support-agent/
41
+ vatio.yml # required: the agent, its tools, its knowledge
42
+ tools/*.yml # one HTTP request each, described in YAML
43
+ identity.pub # public key that verifies the JWT saying who a visitor is
44
+ ```
21
45
 
22
- Nothing constrains where that directory lives — an agent can sit inside the
23
- repository of the backend it calls, and every command except `init` finds it by
24
- walking up from the current directory. There is no `--workspace` flag.
46
+ Only create the files you need. Nothing constrains where that directory lives —
47
+ an agent can sit inside the repository of the backend it calls, and every
48
+ command except `init` finds it by walking up from the current directory. There
49
+ is no `--workspace` flag.
25
50
 
26
51
  ## Commands
27
52
 
28
53
  ```
29
- init [SLUG] [--name NAME] Create vatio.yml here, and the remote to match
30
- login [--base-url URL] Authorize this machine in a browser
54
+ init [SLUG] Create vatio.yml here, and the remote to match
55
+ login | logout Authorize this machine in a browser, or forget it
56
+ doctor Node, config, workspace and token status
57
+
31
58
  push [--env NAME] Validate the workspace, then update a preview
32
- publish [--env NAME] Promote a preview to live
59
+ publish [--env NAME] Promote the latest push to live, or the named preview
33
60
  diff [--env NAME] What this directory would change
34
61
  status Preview and live deployment state
35
62
  rollback Restore the previous live deployment
36
63
  tools check Validate the workspace against Vatio's contracts
37
- secrets list|set|rm Credentials your tools read as ctx.env
38
- tokens list|create|revoke Publishable tokens for the widget and the SDK
39
- widget [--env NAME] What the platform enforces, and the tokens there are
40
- config show|set|unset base_url and token, per developer
41
- doctor Node, config, workspace and token status
64
+
65
+ chat "message" [--env NAME] Talk to your own agent; the token is the identity
66
+ chat transcript|debug|reset|destroy
67
+ chat show CHAT_ID [--json] Any chat in the workspace, with its deployment and tool calls
68
+
69
+ kb list|show|create|rm Knowledge bases
70
+ kb write|cat|rm-entry Entries, from a file or stdin
71
+ kb follow|unfollow|refresh Read a site into a base, nightly
72
+
73
+ secrets list|set|rm Credentials your tools read
74
+ tokens list|create|revoke Publishable tokens for the widget and the SDK
75
+ widget [--env NAME] What the platform enforces, and the tokens there are
76
+ auth --new-key Keypair that signs the visitor's JWT
77
+
78
+ whatsapp ... Shared preview number, or your own business number
79
+ instagram ... Shared sandbox, or your own account
80
+
81
+ docs [--save [PATH]] The whole developer contract
82
+ mcp Speak MCP over stdio, for a coding agent
83
+ issue "what should change" Send a change request, workspace attached
84
+ config show|set|unset base_url and token, per developer
42
85
  ```
43
86
 
44
87
  `--env NAME` targets a deployment: `live`, `preview`, or a named preview like
@@ -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/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/package.json CHANGED
@@ -1,8 +1,14 @@
1
1
  {
2
2
  "name": "@vatio-ai/cli",
3
- "version": "0.47.0",
3
+ "version": "0.48.0",
4
4
  "description": "Vatio CLI — deploy and manage Vatio agent workspaces",
5
- "keywords": ["vatio", "agent", "ai", "cli", "deploy"],
5
+ "keywords": [
6
+ "vatio",
7
+ "agent",
8
+ "ai",
9
+ "cli",
10
+ "deploy"
11
+ ],
6
12
  "homepage": "https://vatio.ai",
7
13
  "bugs": "https://docs.vatio.ai",
8
14
  "license": "SEE LICENSE IN LICENSE.txt",