@vatio-ai/cli 0.52.0 → 0.54.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 +1 -1
- package/bin/vatio.mjs +3 -0
- package/lib/api-client.mjs +85 -34
- package/lib/branch.mjs +51 -0
- package/lib/commands/channels.mjs +39 -20
- package/lib/commands/chat.mjs +1 -1
- package/lib/commands/deploy.mjs +17 -12
- package/lib/commands/env.mjs +90 -0
- package/lib/commands/knowledge.mjs +99 -81
- package/lib/commands/mcp.mjs +41 -22
- package/lib/commands/misc.mjs +7 -9
- package/lib/commands/workspace-admin.mjs +66 -30
- package/lib/help.mjs +35 -18
- package/lib/http.mjs +4 -1
- package/lib/support.mjs +23 -10
- package/package.json +1 -1
|
@@ -4,10 +4,13 @@
|
|
|
4
4
|
// vatio.yml is a list of *names*, and a push neither fills nor empties one.
|
|
5
5
|
// That is why this is a command and not part of the manifest.
|
|
6
6
|
//
|
|
7
|
-
//
|
|
8
|
-
//
|
|
9
|
-
//
|
|
10
|
-
// preview,
|
|
7
|
+
// The entries are live. Reads and writes here are as one environment sees
|
|
8
|
+
// them: on a branch, the branch's own (see branch.mjs), which keeps the
|
|
9
|
+
// entries it changed on top of live and answers from them in its preview;
|
|
10
|
+
// otherwise `preview`; `--env live` writes live directly, the way a supervisor
|
|
11
|
+
// in the inbox does. `vatio publish`, or merging the branch's pull request,
|
|
12
|
+
// takes the changes live with the agent -- `vatio kb publish` takes them alone.
|
|
13
|
+
// So: write, try it on the branch's preview, publish.
|
|
11
14
|
//
|
|
12
15
|
// A base holds entries, and an entry is markdown. Either you wrote it, or a
|
|
13
16
|
// site wrote it from a page it read — and a site is one URL or one pattern,
|
|
@@ -16,32 +19,48 @@
|
|
|
16
19
|
import { readFileSync, statSync } from "node:fs";
|
|
17
20
|
|
|
18
21
|
import { deployClient } from "./deploy.mjs";
|
|
19
|
-
import { fail } from "../support.mjs";
|
|
22
|
+
import { fail, takeEnv, takeValue } from "../support.mjs";
|
|
23
|
+
|
|
24
|
+
// Only what reads or writes entries takes an environment; bases and sites
|
|
25
|
+
// belong to the workspace.
|
|
26
|
+
const ENVIRONMENT_SCOPED = new Set(["list", "show", "write", "cat", "rm-entry", "status", "publish"]);
|
|
20
27
|
|
|
21
28
|
export async function kb(config, args) {
|
|
22
29
|
const workspace = config.resolveWorkspaceRequired();
|
|
23
30
|
const client = deployClient(config, workspace);
|
|
24
31
|
const sub = args.shift() ?? "list";
|
|
32
|
+
const env = ENVIRONMENT_SCOPED.has(sub) ? takeEnv(args, { fallback: null, cwd: config.workspaceRoot }) : null;
|
|
33
|
+
const ctx = { client, workspace, env };
|
|
25
34
|
|
|
26
35
|
switch (sub) {
|
|
27
|
-
case "list": return await list(
|
|
28
|
-
case "show": return await show(
|
|
36
|
+
case "list": return await list(ctx);
|
|
37
|
+
case "show": return await show(ctx, args.shift());
|
|
29
38
|
case "create": return await create(client, workspace, args.splice(0));
|
|
30
39
|
case "rm": return await remove(client, workspace, args.shift());
|
|
31
|
-
case "write": return await write(
|
|
32
|
-
case "cat": return await cat(
|
|
33
|
-
case "rm-entry": return await removeEntry(
|
|
40
|
+
case "write": return await write(ctx, args);
|
|
41
|
+
case "cat": return await cat(ctx, args);
|
|
42
|
+
case "rm-entry": return await removeEntry(ctx, args.shift(), args.shift());
|
|
34
43
|
case "follow": return await follow(client, workspace, args.shift(), args.shift());
|
|
35
44
|
case "unfollow": return await unfollow(client, workspace, args.shift(), args.shift());
|
|
36
45
|
case "refresh": return await refresh(client, workspace, args.shift(), args.shift());
|
|
37
|
-
case "status": return await status(
|
|
38
|
-
case "publish": return await publish(
|
|
46
|
+
case "status": return await status(ctx, args.shift());
|
|
47
|
+
case "publish": return await publish(ctx, args.shift());
|
|
39
48
|
case "history": return await history(client, workspace, args.shift());
|
|
40
|
-
case "rollback":
|
|
49
|
+
case "rollback":
|
|
50
|
+
return fail(
|
|
51
|
+
"`vatio kb rollback` was removed. Restore one entry instead: `vatio kb history BASE` lists what " +
|
|
52
|
+
"reached live, `vatio kb cat BASE ENTRY --version N > old.md` prints one, and " +
|
|
53
|
+
"`vatio kb write BASE ENTRY old.md --env live` brings it back."
|
|
54
|
+
);
|
|
41
55
|
default: fail(`Unknown kb subcommand: ${sub}\n\n${usage()}`);
|
|
42
56
|
}
|
|
43
57
|
}
|
|
44
58
|
|
|
59
|
+
// `preview` when the platform chose, for messages.
|
|
60
|
+
function envName(env) {
|
|
61
|
+
return env ?? "preview";
|
|
62
|
+
}
|
|
63
|
+
|
|
45
64
|
function usage() {
|
|
46
65
|
return `usage:
|
|
47
66
|
vatio kb List knowledge bases
|
|
@@ -49,19 +68,21 @@ function usage() {
|
|
|
49
68
|
vatio kb create NAME [NAME...] Create one base, or several
|
|
50
69
|
vatio kb rm NAME Delete a base (must be unreferenced)
|
|
51
70
|
vatio kb write BASE ENTRY [FILE] Write an entry, from FILE or stdin
|
|
52
|
-
vatio kb cat BASE ENTRY
|
|
71
|
+
vatio kb cat BASE ENTRY [--version N] Print an entry's markdown, or one of its versions
|
|
53
72
|
vatio kb rm-entry BASE ENTRY Delete one entry
|
|
54
73
|
vatio kb follow BASE URL Read a site into the base, nightly
|
|
55
74
|
vatio kb unfollow BASE URL Stop reading it, and drop its entries
|
|
56
75
|
vatio kb refresh BASE [URL] Read the sites again now
|
|
57
|
-
vatio kb status BASE What
|
|
58
|
-
vatio kb publish BASE
|
|
59
|
-
vatio kb history BASE
|
|
60
|
-
|
|
76
|
+
vatio kb status BASE What this environment changed that live does not have
|
|
77
|
+
vatio kb publish BASE Take this environment's changes live, without the agent
|
|
78
|
+
vatio kb history BASE What reached live, newest first
|
|
79
|
+
|
|
80
|
+
Entry commands, status and publish take --env NAME; on a branch they default
|
|
81
|
+
to the branch's environment, otherwise to preview. --env live writes live.`;
|
|
61
82
|
}
|
|
62
83
|
|
|
63
|
-
async function list(client, workspace) {
|
|
64
|
-
const bases = asArray((await client.knowledgeBases()).data);
|
|
84
|
+
async function list({ client, workspace, env }) {
|
|
85
|
+
const bases = asArray((await client.knowledgeBases({ environment: env })).data);
|
|
65
86
|
if (bases.length === 0) {
|
|
66
87
|
console.log(`No knowledge bases on workspace ${workspace}`);
|
|
67
88
|
console.log("Create one with `vatio kb create docs`, then add `knowledge: [docs]` to vatio.yml");
|
|
@@ -70,9 +91,10 @@ async function list(client, workspace) {
|
|
|
70
91
|
|
|
71
92
|
console.log(`Knowledge bases on workspace ${workspace} (${bases.length}):`);
|
|
72
93
|
for (const row of bases) {
|
|
94
|
+
const pending = row.pending_changes ? ` ${row.pending_changes} unpublished in ${envName(env)}` : "";
|
|
73
95
|
console.log(
|
|
74
96
|
` ${row.name} entries=${row.entries_count} ready=${row.answerable_count} ` +
|
|
75
|
-
`sites=${row.sites_count}${referenceNote(row)}`
|
|
97
|
+
`sites=${row.sites_count}${pending}${referenceNote(row)}`
|
|
76
98
|
);
|
|
77
99
|
}
|
|
78
100
|
}
|
|
@@ -84,15 +106,17 @@ function referenceNote(row) {
|
|
|
84
106
|
return row.referenced ? "" : " (not referenced by any deployed agent)";
|
|
85
107
|
}
|
|
86
108
|
|
|
87
|
-
async function show(client, workspace, name) {
|
|
109
|
+
async function show({ client, workspace, env }, name) {
|
|
88
110
|
if (!name) fail("usage: vatio kb show NAME");
|
|
89
111
|
|
|
90
|
-
const base = await client.knowledgeBase(name);
|
|
112
|
+
const base = await client.knowledgeBase(name, { environment: env });
|
|
91
113
|
console.log(
|
|
92
114
|
`${base.name} on workspace ${workspace}: entries=${base.entries_count} ` +
|
|
93
115
|
`ready=${base.answerable_count}${referenceNote(base)}`
|
|
94
116
|
);
|
|
95
|
-
|
|
117
|
+
if (base.pending_changes) {
|
|
118
|
+
console.log(` ${base.pending_changes} change(s) in ${envName(env)} that live does not have — \`vatio kb status ${base.name}\``);
|
|
119
|
+
}
|
|
96
120
|
|
|
97
121
|
const sites = asArray(base.sites);
|
|
98
122
|
if (sites.length > 0) {
|
|
@@ -116,23 +140,15 @@ async function show(client, workspace, name) {
|
|
|
116
140
|
return;
|
|
117
141
|
}
|
|
118
142
|
|
|
119
|
-
console.log(
|
|
143
|
+
console.log(`\n entries, as ${envName(env)} sees them:`);
|
|
120
144
|
for (const entry of entries) {
|
|
121
145
|
const origin = entry.written ? "written here" : entry.url;
|
|
122
146
|
const version = entry.version ? ` v${entry.version}` : "";
|
|
123
|
-
|
|
147
|
+
const unpublished = entry.published === false ? " (not live yet)" : "";
|
|
148
|
+
console.log(` ${entry.name}${version} ${entry.state ?? "?"} ${origin}${unpublished}`);
|
|
124
149
|
}
|
|
125
150
|
}
|
|
126
151
|
|
|
127
|
-
// Where live stands, and whether the draft has moved past it.
|
|
128
|
-
function liveNote(base) {
|
|
129
|
-
const live = base.live_snapshot ? `live=publication #${base.live_snapshot}` : "live=never published";
|
|
130
|
-
const pending = base.pending_changes
|
|
131
|
-
? ` ${base.pending_changes} unpublished change${base.pending_changes === 1 ? "" : "s"} — \`vatio kb publish ${base.name}\``
|
|
132
|
-
: "";
|
|
133
|
-
return `${live}${pending}`;
|
|
134
|
-
}
|
|
135
|
-
|
|
136
152
|
// Several names, because the moment this command is most often run is a push
|
|
137
153
|
// that just refused for naming bases that do not exist yet -- and that push
|
|
138
154
|
// names all of them at once. One base per invocation turned a first deploy
|
|
@@ -177,7 +193,7 @@ async function remove(client, workspace, name) {
|
|
|
177
193
|
// vatio kb cat docs horarios > horarios.md
|
|
178
194
|
// $EDITOR horarios.md
|
|
179
195
|
// vatio kb write docs horarios horarios.md
|
|
180
|
-
async function write(client, workspace, args) {
|
|
196
|
+
async function write({ client, workspace, env }, args) {
|
|
181
197
|
const [base, name, file] = args;
|
|
182
198
|
if (!base || !name) fail("usage: vatio kb write BASE ENTRY [FILE] (or pipe the markdown in)");
|
|
183
199
|
if (file && !isFile(file)) fail(`No such file: ${file}`);
|
|
@@ -187,27 +203,33 @@ async function write(client, workspace, args) {
|
|
|
187
203
|
fail("Nothing to write: pass a FILE, or pipe the markdown in on stdin.");
|
|
188
204
|
}
|
|
189
205
|
|
|
190
|
-
const row = await client.writeKnowledgeEntry({ base, name, content });
|
|
206
|
+
const row = await client.writeKnowledgeEntry({ base, name, content, environment: env });
|
|
191
207
|
const version = row.version ? ` (v${row.version})` : "";
|
|
192
|
-
|
|
193
|
-
|
|
208
|
+
if (env === "live") {
|
|
209
|
+
console.log(`Wrote ${row.name}${version} to ${base} on workspace ${workspace}. Live answers with it now.`);
|
|
210
|
+
return;
|
|
211
|
+
}
|
|
212
|
+
console.log(`Wrote ${row.name}${version} to ${base} in ${envName(env)} on workspace ${workspace}`);
|
|
213
|
+
console.log(`${envName(env)} answers with it now; \`vatio publish\` takes it live with the agent.`);
|
|
194
214
|
}
|
|
195
215
|
|
|
196
216
|
// Prints exactly what the platform holds, so a diff against the file you
|
|
197
217
|
// pushed is a real answer to "is what I sent what it has".
|
|
198
|
-
async function cat(client,
|
|
199
|
-
|
|
218
|
+
async function cat({ client, env }, args) {
|
|
219
|
+
const version = takeValue(args, "--version");
|
|
220
|
+
const [base, name] = args;
|
|
221
|
+
if (!base || !name) fail("usage: vatio kb cat BASE ENTRY [--version N]");
|
|
200
222
|
|
|
201
|
-
const row = await client.knowledgeEntry({ base, name });
|
|
223
|
+
const row = await client.knowledgeEntry({ base, name, environment: env, version });
|
|
202
224
|
const content = row.content ?? "";
|
|
203
225
|
process.stdout.write(content.endsWith("\n") ? content : `${content}\n`);
|
|
204
226
|
}
|
|
205
227
|
|
|
206
|
-
async function removeEntry(client, workspace, base, name) {
|
|
228
|
+
async function removeEntry({ client, workspace, env }, base, name) {
|
|
207
229
|
if (!base || !name) fail("usage: vatio kb rm-entry BASE ENTRY");
|
|
208
230
|
|
|
209
|
-
await client.deleteKnowledgeEntry({ base, name });
|
|
210
|
-
console.log(`Deleted entry ${name} from ${base} on workspace ${workspace}`);
|
|
231
|
+
await client.deleteKnowledgeEntry({ base, name, environment: env });
|
|
232
|
+
console.log(`Deleted entry ${name} from ${base} in ${envName(env)} on workspace ${workspace}`);
|
|
211
233
|
}
|
|
212
234
|
|
|
213
235
|
// One URL, and the shape of it is the whole configuration. A URL is that URL;
|
|
@@ -246,65 +268,61 @@ async function refresh(client, workspace, base, url) {
|
|
|
246
268
|
console.log(`Runs in the background — check progress with \`vatio kb show ${base}\``);
|
|
247
269
|
}
|
|
248
270
|
|
|
249
|
-
//
|
|
250
|
-
|
|
271
|
+
// What this environment changed against live, entry by entry -- what
|
|
272
|
+
// publishing it would do, and which entries live changed underneath.
|
|
273
|
+
async function status({ client, workspace, env }, base) {
|
|
251
274
|
if (!base) fail("usage: vatio kb status BASE");
|
|
252
275
|
|
|
253
|
-
const
|
|
276
|
+
const payload = await client.knowledgeChanges(base, { environment: env });
|
|
277
|
+
const changes = asArray(payload.data);
|
|
254
278
|
if (changes.length === 0) {
|
|
255
|
-
console.log(`${base} on workspace ${workspace}:
|
|
279
|
+
console.log(`${base} in ${envName(env)} on workspace ${workspace}: nothing that live does not have`);
|
|
256
280
|
return;
|
|
257
281
|
}
|
|
258
282
|
|
|
259
|
-
console.log(`${base} on workspace ${workspace}: ${changes.length}
|
|
283
|
+
console.log(`${base} in ${envName(env)} on workspace ${workspace}: ${changes.length} change${changes.length === 1 ? "" : "s"} live does not have`);
|
|
260
284
|
for (const change of changes) {
|
|
261
285
|
const from = change.live_version ? `v${change.live_version}` : "—";
|
|
262
|
-
const to = change.
|
|
263
|
-
|
|
286
|
+
const to = change.version ?? change.draft_version;
|
|
287
|
+
const conflict = change.conflict ? " CONFLICT: live changed it after you did" : "";
|
|
288
|
+
console.log(` ${change.change.padEnd(8)} ${change.name} ${from} → v${to}${conflict}`);
|
|
289
|
+
}
|
|
290
|
+
if (changes.some((change) => change.conflict)) {
|
|
291
|
+
console.log(`\nRead each conflicting entry from live (\`vatio kb cat ${base} ENTRY --env live\`), write your change on top, and it clears.`);
|
|
292
|
+
if (payload.review_url) console.log(`Or resolve them side by side: ${payload.review_url}`);
|
|
293
|
+
} else {
|
|
294
|
+
console.log("\n`vatio publish` takes them live with the agent; `vatio kb publish` takes them alone.");
|
|
264
295
|
}
|
|
265
|
-
console.log(`\nPublish with \`vatio kb publish ${base} -m "what changed"\``);
|
|
266
296
|
}
|
|
267
297
|
|
|
268
|
-
async function publish(client, workspace,
|
|
269
|
-
|
|
270
|
-
if (!base) fail("usage: vatio kb publish BASE [-m NOTE]");
|
|
298
|
+
async function publish({ client, workspace, env }, base) {
|
|
299
|
+
if (!base) fail("usage: vatio kb publish BASE [--env NAME]");
|
|
271
300
|
|
|
272
|
-
|
|
273
|
-
const
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
const snapshot = await client.publishKnowledgeBase({ base, note });
|
|
277
|
-
console.log(`Published ${base} on workspace ${workspace} as #${snapshot.number} (${snapshot.entries} entries)`);
|
|
278
|
-
console.log(`Live answers from it now. Undo with \`vatio kb rollback ${base} NUMBER\` — see \`vatio kb history ${base}\`.`);
|
|
301
|
+
const result = await client.publishKnowledgeBase({ base, environment: env });
|
|
302
|
+
const names = asArray(result.published);
|
|
303
|
+
console.log(`Published ${names.length} change${names.length === 1 ? "" : "s"} to ${base} from ${envName(env)} on workspace ${workspace}: ${names.join(", ")}`);
|
|
304
|
+
console.log("Live answers from them now.");
|
|
279
305
|
}
|
|
280
306
|
|
|
307
|
+
// Every version that reached live, newest first. Going back is writing one
|
|
308
|
+
// of them again.
|
|
281
309
|
async function history(client, workspace, base) {
|
|
282
310
|
if (!base) fail("usage: vatio kb history BASE");
|
|
283
311
|
|
|
284
|
-
const
|
|
285
|
-
if (
|
|
286
|
-
console.log(
|
|
312
|
+
const versions = asArray((await client.knowledgeHistory(base)).data);
|
|
313
|
+
if (versions.length === 0) {
|
|
314
|
+
console.log(`Nothing in ${base} on workspace ${workspace} has reached live yet`);
|
|
287
315
|
return;
|
|
288
316
|
}
|
|
289
317
|
|
|
290
|
-
console.log(`
|
|
291
|
-
for (const
|
|
292
|
-
const
|
|
293
|
-
const
|
|
294
|
-
|
|
295
|
-
console.log(` #${snapshot.number} ${snapshot.created_at}${who} entries=${snapshot.entries}${note}${live}`);
|
|
318
|
+
console.log(`What reached live in ${base} on workspace ${workspace}:`);
|
|
319
|
+
for (const row of versions) {
|
|
320
|
+
const who = row.author ? ` ${row.author}` : "";
|
|
321
|
+
const what = row.deleted ? " deleted" : "";
|
|
322
|
+
console.log(` ${row.published_at} ${row.name} v${row.version} ${row.source}${who}${what}`);
|
|
296
323
|
}
|
|
297
324
|
}
|
|
298
325
|
|
|
299
|
-
// Only the pointer moves: the draft, and every later publication, stay.
|
|
300
|
-
async function rollback(client, workspace, base, number) {
|
|
301
|
-
if (!base || !number || !/^\d+$/.test(number)) fail("usage: vatio kb rollback BASE NUMBER");
|
|
302
|
-
|
|
303
|
-
await client.rollbackKnowledgeBase({ base, number });
|
|
304
|
-
console.log(`Live for ${base} on workspace ${workspace} is publication #${number} again`);
|
|
305
|
-
console.log("The draft is untouched; publish again whenever it is ready.");
|
|
306
|
-
}
|
|
307
|
-
|
|
308
326
|
// Blocking on purpose: `vatio kb write docs refunds < refunds.md` should behave
|
|
309
327
|
// like every other filter, and a terminal with nobody piping into it returns ""
|
|
310
328
|
// rather than hanging on a read that will never end.
|
package/lib/commands/mcp.mjs
CHANGED
|
@@ -60,22 +60,31 @@ const COMMANDS = {
|
|
|
60
60
|
push: {
|
|
61
61
|
usage: "[--env NAME]",
|
|
62
62
|
summary:
|
|
63
|
-
"Validate the workspace and update a preview deployment. Never touches live.
|
|
64
|
-
"
|
|
63
|
+
"Validate the workspace and update a preview deployment. Never touches live. On a git branch " +
|
|
64
|
+
"other than the default one it lands on that branch's own environment (fix/pagos -> fix-pagos), " +
|
|
65
|
+
"the same one the branch's pull request deploys to; elsewhere on `preview`.",
|
|
65
66
|
annotations: { readOnlyHint: false }
|
|
66
67
|
},
|
|
67
68
|
publish: {
|
|
68
69
|
usage: "[--env NAME]",
|
|
69
70
|
summary:
|
|
70
|
-
"Promote
|
|
71
|
-
"
|
|
72
|
-
"the
|
|
73
|
-
"
|
|
71
|
+
"Promote an environment to live, with the knowledge changes made in it — what customers see. " +
|
|
72
|
+
"Ask the developer first: this is the one step that changes what real visitors get. Refused " +
|
|
73
|
+
"when the workspace is connected to GitHub: there, live changes only by merging the branch's " +
|
|
74
|
+
"pull request. Refused too when live changed an entry this environment also changed.",
|
|
74
75
|
annotations: { readOnlyHint: false, destructiveHint: true }
|
|
75
76
|
},
|
|
77
|
+
env: {
|
|
78
|
+
usage: "[NAME] | list | rm NAME",
|
|
79
|
+
summary:
|
|
80
|
+
"The environment this workspace is working in — the branch's own on a branch — with its " +
|
|
81
|
+
"publishable token, widget snippet, share link, the knowledge entries it changed and any that " +
|
|
82
|
+
"live changed underneath. Use its token to point an app being developed at this environment.",
|
|
83
|
+
annotations: { readOnlyHint: true }
|
|
84
|
+
},
|
|
76
85
|
rollback: {
|
|
77
86
|
usage: "",
|
|
78
|
-
summary: "
|
|
87
|
+
summary: "Put live back to the previous snapshot — its configuration and its knowledge together. Same weight as publish — ask first.",
|
|
79
88
|
annotations: { readOnlyHint: false, destructiveHint: true }
|
|
80
89
|
},
|
|
81
90
|
chat: {
|
|
@@ -88,35 +97,39 @@ const COMMANDS = {
|
|
|
88
97
|
annotations: { readOnlyHint: false }
|
|
89
98
|
},
|
|
90
99
|
secrets: {
|
|
91
|
-
usage: "list | set KEY VALUE | rm KEY",
|
|
100
|
+
usage: "list | set KEY VALUE | rm KEY [--env NAME]",
|
|
92
101
|
summary:
|
|
93
|
-
"Credentials the workspace's
|
|
94
|
-
"keys, never values."
|
|
102
|
+
"Credentials the workspace's tools read as $env.KEY. Values are write-only — listing shows " +
|
|
103
|
+
"keys, never values. On a branch (or with --env) a value applies to that environment only, " +
|
|
104
|
+
"replacing the one everywhere else: point a branch's tools at staging without touching live.",
|
|
95
105
|
annotations: { readOnlyHint: false }
|
|
96
106
|
},
|
|
97
107
|
kb: {
|
|
98
108
|
usage:
|
|
99
|
-
"[list] | show NAME | create NAME | write BASE ENTRY [FILE] | cat BASE ENTRY
|
|
100
|
-
"follow BASE URL | unfollow BASE URL | refresh BASE [URL] | status BASE |
|
|
101
|
-
"
|
|
109
|
+
"[list] | show NAME | create NAME | write BASE ENTRY [FILE] | cat BASE ENTRY [--version N] | " +
|
|
110
|
+
"rm-entry BASE ENTRY | follow BASE URL | unfollow BASE URL | refresh BASE [URL] | status BASE | " +
|
|
111
|
+
"publish BASE | history BASE (entry commands take --env NAME)",
|
|
102
112
|
summary:
|
|
103
113
|
"Knowledge bases, which belong to the workspace rather than to a deployment: `knowledge:` in " +
|
|
104
|
-
"vatio.yml is a list of names, and a push neither fills nor empties one.
|
|
105
|
-
"preview answers from
|
|
114
|
+
"vatio.yml is a list of names, and a push neither fills nor empties one. The entries are live; " +
|
|
115
|
+
"writes on a branch are changes only that branch's preview answers from, and they go live with " +
|
|
116
|
+
"vatio_publish or the merge of its pull request. `status` names entries live changed underneath: " +
|
|
117
|
+
"read those from live (`cat --env live`), write your change on top, and the conflict clears.",
|
|
106
118
|
annotations: { readOnlyHint: false, openWorldHint: true }
|
|
107
119
|
},
|
|
108
120
|
tokens: {
|
|
109
|
-
usage: "list | create [--env NAME] [--label NAME] | revoke PREFIX",
|
|
121
|
+
usage: "list | create [--env NAME] [--label NAME] [--origin URL]... | origins PREFIX URL... | revoke PREFIX",
|
|
110
122
|
summary:
|
|
111
123
|
"Publishable tokens for the widget and anything built on the SDK. A created token is shown in " +
|
|
112
|
-
"full exactly once."
|
|
124
|
+
"full exactly once. Each token works only from its own allowed origins (--origin, repeatable, or " +
|
|
125
|
+
"`origins PREFIX URL...` to replace the list); the install snippet's token is edited in the console.",
|
|
113
126
|
annotations: { readOnlyHint: false }
|
|
114
127
|
},
|
|
115
128
|
widget: {
|
|
116
129
|
usage: "[--env NAME]",
|
|
117
130
|
summary:
|
|
118
|
-
"What the platform will actually enforce for the widget, the
|
|
119
|
-
"that exist. Read-only:
|
|
131
|
+
"What the platform will actually enforce for the widget, the origins its tokens accept, and the " +
|
|
132
|
+
"tokens that exist. Read-only: the look is edited on the console's Brand page, whose URL it prints.",
|
|
120
133
|
annotations: { readOnlyHint: true }
|
|
121
134
|
},
|
|
122
135
|
whatsapp: {
|
|
@@ -124,7 +137,7 @@ const COMMANDS = {
|
|
|
124
137
|
summary:
|
|
125
138
|
"The workspace's own WhatsApp number, which serves live: whether it is connected, whether Meta " +
|
|
126
139
|
"delivers to it, and whether it is answering — three things that fail separately. `numbers` is " +
|
|
127
|
-
"the other thing: the shared WhatsApp preview, test phones that reach
|
|
140
|
+
"the other thing: the shared WhatsApp preview, test phones that reach the environment they point at (`point PHONE --env NAME`) and need no Meta " +
|
|
128
141
|
"account. A code goes to the handset, so a human has to read it back to you.",
|
|
129
142
|
annotations: { readOnlyHint: false, openWorldHint: true }
|
|
130
143
|
},
|
|
@@ -154,6 +167,7 @@ const WITHHELD = {
|
|
|
154
167
|
const BLOCKED_SUBCOMMANDS = {
|
|
155
168
|
chat: { destroy: "destroys a conversation; ask the developer" },
|
|
156
169
|
kb: { rm: "deletes an indexed base; ask the developer" },
|
|
170
|
+
env: { rm: "removes an environment with its unpublished knowledge changes; ask the developer" },
|
|
157
171
|
whatsapp: { connect: "takes Meta credentials the developer holds", disconnect: "ask the developer" },
|
|
158
172
|
instagram: { connect: "needs Meta's consent screen in a browser", disconnect: "ask the developer" }
|
|
159
173
|
};
|
|
@@ -217,8 +231,13 @@ function initializeResult(params) {
|
|
|
217
231
|
"Start with vatio_docs: it is the contract for vatio.yml, tools, auth, visitor identity and",
|
|
218
232
|
"knowledge, fetched live from the platform, so it is what the platform actually accepts.",
|
|
219
233
|
"",
|
|
220
|
-
"
|
|
221
|
-
"
|
|
234
|
+
"Work on a git branch (a worktree is ideal): every command then uses that branch's own",
|
|
235
|
+
"environment — its agent, its knowledge changes, its secret values — and nothing you do there",
|
|
236
|
+
"reaches live or another branch. vatio_env shows which one and the token to point an app at it.",
|
|
237
|
+
"",
|
|
238
|
+
"The loop is: edit files and knowledge (vatio_kb write), vatio_push, vatio_chat to read the",
|
|
239
|
+
"agent's answer, then publish when the developer says so — by merging the branch's pull request",
|
|
240
|
+
"when GitHub is connected, vatio_publish otherwise. The prompt and the knowledge go live together.",
|
|
222
241
|
"",
|
|
223
242
|
"Anything that needs a browser or a person — login, issue, instagram connect — is not here;",
|
|
224
243
|
"ask the developer to run it in their terminal."
|
package/lib/commands/misc.mjs
CHANGED
|
@@ -2,7 +2,6 @@
|
|
|
2
2
|
|
|
3
3
|
import { existsSync, writeFileSync } from "node:fs";
|
|
4
4
|
import { join } from "node:path";
|
|
5
|
-
import { stringify as stringifyYaml } from "yaml";
|
|
6
5
|
|
|
7
6
|
import { KEYS, SLUG_FORMAT } from "../config.mjs";
|
|
8
7
|
import { MANIFEST_FILE, manifestPath } from "../workspace.mjs";
|
|
@@ -110,10 +109,13 @@ export async function init(config, args) {
|
|
|
110
109
|
}
|
|
111
110
|
|
|
112
111
|
const manifest = join(target, MANIFEST_FILE);
|
|
113
|
-
writeFileSync(manifest, starterManifest(slug
|
|
112
|
+
writeFileSync(manifest, starterManifest(slug));
|
|
114
113
|
|
|
115
114
|
console.log(`Wrote ${manifest}`);
|
|
116
115
|
if (!authorized) console.log(`Local only for now — \`vatio push\` is what creates ${slug} on the platform.`);
|
|
116
|
+
if (!authorized && String(name ?? "").trim() !== "") {
|
|
117
|
+
console.log("The display name is set in the console (the workspace's Brand page) once it exists.");
|
|
118
|
+
}
|
|
117
119
|
console.log("");
|
|
118
120
|
console.log("Next:");
|
|
119
121
|
console.log(` edit ${MANIFEST_FILE}, then \`vatio push\` and \`vatio publish\``);
|
|
@@ -121,14 +123,10 @@ export async function init(config, args) {
|
|
|
121
123
|
}
|
|
122
124
|
|
|
123
125
|
// The smallest file that deploys: which workspace, and what the agent does.
|
|
124
|
-
// The slug is already validated as a slug, so it needs no quoting
|
|
125
|
-
// name is
|
|
126
|
-
function starterManifest(slug
|
|
126
|
+
// The slug is already validated as a slug, so it needs no quoting. The display
|
|
127
|
+
// name is not here: it is a workspace setting, edited in the console.
|
|
128
|
+
function starterManifest(slug) {
|
|
127
129
|
const lines = ["# Which Vatio workspace this directory deploys to.", `workspace: ${slug}`, ""];
|
|
128
|
-
if (String(name ?? "").trim() !== "") {
|
|
129
|
-
lines.push(stringifyYaml({ business: { name: String(name).trim() } }).trimEnd());
|
|
130
|
-
lines.push("");
|
|
131
|
-
}
|
|
132
130
|
lines.push("agent:");
|
|
133
131
|
lines.push(" instructions: |");
|
|
134
132
|
lines.push(" Describe what this agent does and how it should answer.");
|