@voltade/volty 0.1.31 → 0.1.33
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 +29 -8
- package/package.json +1 -1
- package/skill/volty-cli-ops/SKILL.md +1 -0
package/dist/volty.js
CHANGED
|
@@ -300,6 +300,9 @@ async function logout(config, env) {
|
|
|
300
300
|
// src/dispatch.ts
|
|
301
301
|
import { existsSync as existsSync3, readFileSync as readFileSync3, writeFileSync as writeFileSync3 } from "node:fs";
|
|
302
302
|
|
|
303
|
+
// ../shared/ops/dry-run.ts
|
|
304
|
+
var DRY_RUN_HEADER = "x-volty-dry-run";
|
|
305
|
+
|
|
303
306
|
// ../shared/ops/flag-parse.ts
|
|
304
307
|
function acceptsNull(prop) {
|
|
305
308
|
if (prop.type === "null")
|
|
@@ -434,6 +437,21 @@ function resolveOp(catalog, argv) {
|
|
|
434
437
|
}
|
|
435
438
|
return null;
|
|
436
439
|
}
|
|
440
|
+
function takeBool(argv, name) {
|
|
441
|
+
const rest = argv.filter((t) => t !== name);
|
|
442
|
+
return { present: rest.length !== argv.length, rest };
|
|
443
|
+
}
|
|
444
|
+
function takeConfirm(op, argv) {
|
|
445
|
+
if (op.annotations.destructiveHint !== true)
|
|
446
|
+
return { rest: argv, dryRun: false };
|
|
447
|
+
const confirm = takeBool(argv, "--confirm");
|
|
448
|
+
if (confirm.present)
|
|
449
|
+
return { rest: confirm.rest, dryRun: false };
|
|
450
|
+
if (op.dryRun !== true) {
|
|
451
|
+
throw new CliUsageError(`\`${op.name}\` is destructive: run it again with --confirm to do it`);
|
|
452
|
+
}
|
|
453
|
+
return { rest: confirm.rest, dryRun: true };
|
|
454
|
+
}
|
|
437
455
|
function parseFlags(op, rest) {
|
|
438
456
|
const props = op.input.properties ?? {};
|
|
439
457
|
const parsed = parseFlagTokens(props, rest, CliUsageError);
|
|
@@ -472,8 +490,9 @@ function readBase64File(flag, path) {
|
|
|
472
490
|
throw new CliUsageError(`--${flag}: cannot read ${path} (${err.code ?? "error"})`);
|
|
473
491
|
}
|
|
474
492
|
}
|
|
475
|
-
async function runOp(ctx, op, input) {
|
|
476
|
-
const
|
|
493
|
+
async function runOp(ctx, op, input, dryRun = false) {
|
|
494
|
+
const headers = dryRun ? { [DRY_RUN_HEADER]: "1" } : undefined;
|
|
495
|
+
const res = await apiFetch(ctx, pathForOp(op.name), { method: "POST", body: input, headers });
|
|
477
496
|
return { status: res.status, ok: res.ok, body: res.body };
|
|
478
497
|
}
|
|
479
498
|
function saveOutFile(body, path) {
|
|
@@ -1177,10 +1196,6 @@ function takeValue(argv, name) {
|
|
|
1177
1196
|
}
|
|
1178
1197
|
return { value, rest };
|
|
1179
1198
|
}
|
|
1180
|
-
function takeBool(argv, name) {
|
|
1181
|
-
const rest = argv.filter((t) => t !== name);
|
|
1182
|
-
return { present: rest.length !== argv.length, rest };
|
|
1183
|
-
}
|
|
1184
1199
|
async function handleAuth(rest, config, env, orgOverride) {
|
|
1185
1200
|
const sub = rest[0];
|
|
1186
1201
|
if (sub === "login") {
|
|
@@ -1593,18 +1608,24 @@ async function main() {
|
|
|
1593
1608
|
if (out.rest.length !== resolved.rest.length && !out.value)
|
|
1594
1609
|
fail("--out needs a path, as in --out=./logo.png");
|
|
1595
1610
|
let parsed;
|
|
1611
|
+
let dryRun = false;
|
|
1596
1612
|
try {
|
|
1597
|
-
|
|
1613
|
+
const confirm = takeConfirm(resolved.op, out.rest);
|
|
1614
|
+
dryRun = confirm.dryRun;
|
|
1615
|
+
parsed = parseFlags(resolved.op, confirm.rest);
|
|
1598
1616
|
} catch (err) {
|
|
1599
1617
|
if (err instanceof CliUsageError)
|
|
1600
1618
|
fail(err.message);
|
|
1601
1619
|
throw err;
|
|
1602
1620
|
}
|
|
1603
|
-
const result = await runOp(ctx, resolved.op, parsed.input);
|
|
1621
|
+
const result = await runOp(ctx, resolved.op, parsed.input, dryRun);
|
|
1604
1622
|
if (!result.ok)
|
|
1605
1623
|
failResult(resolved.op.name, result.body, result.status, parsed.json);
|
|
1606
1624
|
if (out.value === undefined) {
|
|
1607
1625
|
process.stdout.write(`${renderResult(result.body, parsed.json)}
|
|
1626
|
+
`);
|
|
1627
|
+
if (dryRun && !parsed.json)
|
|
1628
|
+
process.stdout.write(`Dry run: run it again with --confirm to do it.
|
|
1608
1629
|
`);
|
|
1609
1630
|
return;
|
|
1610
1631
|
}
|
package/package.json
CHANGED
|
@@ -26,6 +26,7 @@ Use the lane the behaviour was reported on. On the contact lane Volty declines t
|
|
|
26
26
|
## On prod
|
|
27
27
|
|
|
28
28
|
- A key reaches one org and calls operations only; `--org` gets each org you belong to its own key the first time. A call a key cannot make is refused with a sentence naming why; report that sentence instead of working around it. `volty keys create <name>` mints a narrower named key for a script (`volty docs` has the flags).
|
|
29
|
+
- An op that deletes for good runs only with `--confirm`. Run it without first: the CLI prints the dry run the server answers and changes nothing. Show that plan to the user and add `--confirm` only once they agree. Sending a broadcast is never done by key; the refusal names the Broadcasts page, so pass it on.
|
|
29
30
|
- Name the org on every command (`--env prod --org <id>`, or `VOLTY_ENV` and `VOLTY_ORG` in the process), and read the stderr line the CLI prints before each command to check it names the org you meant. Act only in the org the user named.
|
|
30
31
|
- Test through the Sandbox, where a reply to the synthetic contact is recorded as sent and never leaves. A real conversation is never a test target.
|
|
31
32
|
- Run `volty debug sandbox-cleanup --all --env prod --org <id>` when you finish.
|