@voltade/volty 0.1.17 → 0.1.19
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/dist/volty.js +33 -11
- package/package.json +1 -1
- package/skill/volty-cli-ops/SKILL.md +3 -1
package/dist/volty.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
3
|
// bin/volty.ts
|
|
4
|
-
import { existsSync as
|
|
4
|
+
import { existsSync as existsSync4, mkdirSync as mkdirSync4, readFileSync as readFileSync5, writeFileSync as writeFileSync5 } from "node:fs";
|
|
5
5
|
import { homedir as homedir3 } from "node:os";
|
|
6
6
|
import { join as join4 } from "node:path";
|
|
7
7
|
|
|
@@ -268,7 +268,7 @@ async function logout(config, env) {
|
|
|
268
268
|
}
|
|
269
269
|
|
|
270
270
|
// src/dispatch.ts
|
|
271
|
-
import { readFileSync as readFileSync3, writeFileSync as writeFileSync3 } from "node:fs";
|
|
271
|
+
import { existsSync as existsSync3, readFileSync as readFileSync3, writeFileSync as writeFileSync3 } from "node:fs";
|
|
272
272
|
|
|
273
273
|
// ../shared/ops/flag-parse.ts
|
|
274
274
|
function acceptsNull(prop) {
|
|
@@ -354,9 +354,9 @@ function parseFlagTokens(props, rest, UsageError) {
|
|
|
354
354
|
throw new UsageError(`unknown flag --${raw0}`);
|
|
355
355
|
let raw = match[2];
|
|
356
356
|
const next = rest[i + 1];
|
|
357
|
-
|
|
357
|
+
const takes = valueBranch(prop).type === "boolean" ? next === "true" || next === "false" : !next?.startsWith("--");
|
|
358
|
+
if (raw === undefined && next !== undefined && takes)
|
|
358
359
|
raw = rest[++i];
|
|
359
|
-
}
|
|
360
360
|
if (prop.type === "array") {
|
|
361
361
|
const list = input[flag] ?? [];
|
|
362
362
|
list.push(...arrayItems(flag, raw, prop, UsageError));
|
|
@@ -406,12 +406,29 @@ function parseFlags(op, rest) {
|
|
|
406
406
|
const parsed = parseFlagTokens(props, rest, CliUsageError);
|
|
407
407
|
for (const [key, value] of Object.entries(parsed.input)) {
|
|
408
408
|
const prop = props[key];
|
|
409
|
-
if (typeof value
|
|
409
|
+
if (typeof value !== "string" || !value.startsWith("@") || !prop)
|
|
410
|
+
continue;
|
|
411
|
+
if (isBase64(prop))
|
|
410
412
|
parsed.input[key] = readBase64File(key, value.slice(1));
|
|
411
|
-
|
|
413
|
+
else if (isText(prop))
|
|
414
|
+
parsed.input[key] = readTextFlag(key, value.slice(1)) ?? value;
|
|
412
415
|
}
|
|
413
416
|
return parsed;
|
|
414
417
|
}
|
|
418
|
+
function isText(prop) {
|
|
419
|
+
return [prop, ...prop.anyOf ?? []].some((branch) => branch.type === "string" && !branch.enum);
|
|
420
|
+
}
|
|
421
|
+
function readTextFlag(flag, path) {
|
|
422
|
+
if (path === "-")
|
|
423
|
+
return readFileSync3(0, "utf8");
|
|
424
|
+
if (!existsSync3(path))
|
|
425
|
+
return null;
|
|
426
|
+
try {
|
|
427
|
+
return readFileSync3(path, "utf8");
|
|
428
|
+
} catch (err) {
|
|
429
|
+
throw new CliUsageError(`--${flag}: cannot read ${path} (${err.code ?? "error"})`);
|
|
430
|
+
}
|
|
431
|
+
}
|
|
415
432
|
function isBase64(prop) {
|
|
416
433
|
return [prop, ...prop.anyOf ?? []].some((branch) => branch.contentEncoding === "base64");
|
|
417
434
|
}
|
|
@@ -478,14 +495,19 @@ function opUsage(op) {
|
|
|
478
495
|
}
|
|
479
496
|
return parts.join(" ");
|
|
480
497
|
}
|
|
481
|
-
function renderCatalog(catalog) {
|
|
482
|
-
const
|
|
498
|
+
function renderCatalog(catalog, group) {
|
|
499
|
+
const shown = group ? catalog.filter((op) => op.name === group || op.name.startsWith(`${group} `)) : catalog;
|
|
500
|
+
if (group && shown.length === 0) {
|
|
501
|
+
const groups = [...new Set(catalog.map((op) => op.name.split(" ")[0]))].toSorted();
|
|
502
|
+
return `No operations in '${group}'. Groups: ${groups.join(", ")}`;
|
|
503
|
+
}
|
|
504
|
+
const lines = shown.toSorted((a, b) => a.name.localeCompare(b.name)).map((op) => ` ${op.name} — ${op.description}`);
|
|
483
505
|
return [
|
|
484
506
|
"Run a Volty platform operation: volty <operation> [--flags] [--json]",
|
|
485
507
|
"",
|
|
486
508
|
...lines,
|
|
487
509
|
"",
|
|
488
|
-
"`volty <operation> --help` shows usage; `--json` returns the machine-readable result."
|
|
510
|
+
"`volty help <group>` lists one group (`volty help chat-flow`); `volty <operation> --help` shows usage; `--json` returns the machine-readable result. A text flag takes a file as `--source=@flow.ts`, or stdin as `--source=@-`."
|
|
489
511
|
].join(`
|
|
490
512
|
`);
|
|
491
513
|
}
|
|
@@ -837,7 +859,7 @@ function handleSkill(rest) {
|
|
|
837
859
|
join4(import.meta.dirname, "..", "skill", "volty-cli-ops", "SKILL.md"),
|
|
838
860
|
join4(import.meta.dirname, "..", "..", ".claude", "skills", "volty-cli-ops", "SKILL.md")
|
|
839
861
|
];
|
|
840
|
-
const source = candidates.find((p) =>
|
|
862
|
+
const source = candidates.find((p) => existsSync4(p));
|
|
841
863
|
if (!source)
|
|
842
864
|
fail("bundled SKILL.md not found — reinstall the @voltade/volty package");
|
|
843
865
|
const destDir = join4(homedir3(), ".claude", "skills", "volty-cli-ops");
|
|
@@ -893,7 +915,7 @@ async function main() {
|
|
|
893
915
|
return handleChanges(rest, ctx);
|
|
894
916
|
const catalog = await fetchCatalog(ctx, env, !cacheFlag.present);
|
|
895
917
|
if (!cmd || cmd === "help" || cmd === "--help") {
|
|
896
|
-
process.stdout.write(`${renderCatalog(catalog.ops)}
|
|
918
|
+
process.stdout.write(`${renderCatalog(catalog.ops, rest.length ? rest.join(" ") : undefined)}
|
|
897
919
|
`);
|
|
898
920
|
return;
|
|
899
921
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: volty-cli-ops
|
|
3
|
-
description: "Drive Volty's agent with the `volty` CLI: run a real agent turn in one command on either lane (a contact message or a staff session) and read what the model saw and did. Use whenever you need to exercise the live agent end to end: does an inbound trigger the right reply, learning or proposal, can Volty read or operate a connected system (CRM, MCP server, drive, channel), why did a tool call come back wrong. Reproducing a reported behaviour costs one command, so reach for it before theorising. Triggers: 'test the agent', 'trigger a wake', 'wake-sync', 'session-sync', 'ask Volty on prod', 'what did the agent do with X', 'run a real LLM turn', 'reproduce this inbound', 'can Volty see X?'."
|
|
3
|
+
description: "Drive Volty's agent with the `volty` CLI: run a real agent turn in one command on either lane (a contact message or a staff session) and read what the model saw and did. Use whenever you need to exercise the live agent end to end: does an inbound trigger the right reply, learning or proposal, can Volty read or operate a connected system (CRM, MCP server, drive, channel), why did a tool call come back wrong. Reproducing a reported behaviour costs one command, so reach for it before theorising. Also use it to create or configure a web chat channel from Claude Code. Triggers: 'set up a web chat', 'change the web chat settings', 'test the agent', 'trigger a wake', 'wake-sync', 'session-sync', 'ask Volty on prod', 'what did the agent do with X', 'run a real LLM turn', 'reproduce this inbound', 'can Volty see X?'."
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# volty CLI
|
|
@@ -19,6 +19,8 @@ This skill says which lane to use and what to keep to on prod. The commands and
|
|
|
19
19
|
- `debug wake-sync --web-chat <channel id>` writes as a website visitor on a web chat channel, without the form's captcha: the contact lane on web chat. The chat is filed in the Sandbox inbox, where only testers see it, and Volty follows the web chat inbox's instructions, so you test that channel's setup without its staff seeing the test. You must be in the web chat channel's inbox.
|
|
20
20
|
- `debug session-sync` runs a turn on the internal Volty chat as you: the staff lane.
|
|
21
21
|
|
|
22
|
+
To create or change a web chat (its look, websites, the visitor's phone and email settings, the logo), use the `widgets` ops: `volty docs` has a "Setting up a web chat" section with the order to run them in. Read the settings back with `widgets get` after a change, and test the chat with `debug wake-sync --web-chat` before saying it works.
|
|
23
|
+
|
|
22
24
|
Use the lane the behaviour was reported on. On the contact lane Volty declines to list internal records to a contact, as it should, so "can Volty read our CRM or MCP server" belongs on the staff lane; asked on the contact lane, that refusal looks like a broken feature.
|
|
23
25
|
|
|
24
26
|
## On prod
|