@voltade/volty 0.1.9 → 0.1.11
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/dist/volty.js +28 -17
- package/package.json +1 -1
- package/skill/volty-cli-ops/SKILL.md +1 -1
package/README.md
CHANGED
|
@@ -46,7 +46,7 @@ Open Claude Code anywhere and ask in plain language. The skill you installed in
|
|
|
46
46
|
- *"Why didn't the agent learn anything from that conversation?"*
|
|
47
47
|
- *"Clean up the test conversations on prod."*
|
|
48
48
|
|
|
49
|
-
Claude knows the safety rules: tests run
|
|
49
|
+
Claude knows the safety rules: tests run on your workspace's Sandbox from a synthetic contact, whose replies are recorded in the thread but never sent, so nothing can reach a real contact. Claude cleans up after itself when it's done, and anything left over is removed after 24 hours.
|
|
50
50
|
|
|
51
51
|
## Upgrading
|
|
52
52
|
|
package/dist/volty.js
CHANGED
|
@@ -58,8 +58,8 @@ async function fetchCatalog(ctx, env, useCache = true) {
|
|
|
58
58
|
if (useCache && existsSync(path)) {
|
|
59
59
|
try {
|
|
60
60
|
const cached = JSON.parse(readFileSync(path, "utf8"));
|
|
61
|
-
if (Date.now() - cached.at < CATALOG_TTL_MS && cached.
|
|
62
|
-
return
|
|
61
|
+
if (Date.now() - cached.at < CATALOG_TTL_MS && cached.renamed)
|
|
62
|
+
return cached;
|
|
63
63
|
} catch {}
|
|
64
64
|
}
|
|
65
65
|
const res = await apiFetch(ctx, "/api/v/_catalog");
|
|
@@ -68,11 +68,12 @@ async function fetchCatalog(ctx, env, useCache = true) {
|
|
|
68
68
|
}
|
|
69
69
|
const ops = res.body.catalog;
|
|
70
70
|
const retired = res.body.retired ?? {};
|
|
71
|
+
const renamed = res.body.renamed ?? {};
|
|
71
72
|
try {
|
|
72
73
|
mkdirSync(tmpdir(), { recursive: true });
|
|
73
|
-
writeFileSync(path, JSON.stringify({ at: Date.now(), ops, retired }));
|
|
74
|
+
writeFileSync(path, JSON.stringify({ at: Date.now(), ops, retired, renamed }));
|
|
74
75
|
} catch {}
|
|
75
|
-
return { ops, retired };
|
|
76
|
+
return { ops, retired, renamed };
|
|
76
77
|
}
|
|
77
78
|
async function fetchOrgs(ctx, env, useCache = true) {
|
|
78
79
|
const path = join(tmpdir(), `volty-orgs-${env}.json`);
|
|
@@ -293,21 +294,21 @@ function coerce(flag, raw, prop0, UsageError) {
|
|
|
293
294
|
return true;
|
|
294
295
|
if (raw === "false")
|
|
295
296
|
return false;
|
|
296
|
-
throw new UsageError(`--${flag} expects true|false
|
|
297
|
+
throw new UsageError(`--${flag} expects true|false`, flag);
|
|
297
298
|
}
|
|
298
299
|
if (raw === undefined)
|
|
299
|
-
throw new UsageError(`--${flag} requires a value
|
|
300
|
+
throw new UsageError(`--${flag} requires a value`, flag);
|
|
300
301
|
if (prop.type === "number" || prop.type === "integer") {
|
|
301
302
|
const n = Number(raw);
|
|
302
303
|
if (Number.isNaN(n))
|
|
303
|
-
throw new UsageError(`--${flag} expects a number
|
|
304
|
+
throw new UsageError(`--${flag} expects a number`, flag);
|
|
304
305
|
return n;
|
|
305
306
|
}
|
|
306
307
|
if (prop.type === "object") {
|
|
307
308
|
try {
|
|
308
309
|
return JSON.parse(raw);
|
|
309
310
|
} catch {
|
|
310
|
-
throw new UsageError(`--${flag} expects JSON
|
|
311
|
+
throw new UsageError(`--${flag} expects JSON`, flag);
|
|
311
312
|
}
|
|
312
313
|
}
|
|
313
314
|
return raw;
|
|
@@ -322,6 +323,16 @@ function jsonArrayValue(raw) {
|
|
|
322
323
|
return null;
|
|
323
324
|
}
|
|
324
325
|
}
|
|
326
|
+
function arrayItems(flag, raw, prop, UsageError) {
|
|
327
|
+
const spread = jsonArrayValue(raw);
|
|
328
|
+
if (spread)
|
|
329
|
+
return spread;
|
|
330
|
+
const items = prop.items ?? {};
|
|
331
|
+
if (items.entityId && raw?.includes(",")) {
|
|
332
|
+
return raw.split(",").map((id) => id.trim()).filter((id) => id !== "");
|
|
333
|
+
}
|
|
334
|
+
return [coerce(flag, raw, items, UsageError)];
|
|
335
|
+
}
|
|
325
336
|
function canonicalFlag(props, flag) {
|
|
326
337
|
if (props[flag])
|
|
327
338
|
return flag;
|
|
@@ -352,11 +363,7 @@ function parseFlagTokens(props, rest, UsageError) {
|
|
|
352
363
|
}
|
|
353
364
|
if (prop.type === "array") {
|
|
354
365
|
const list = input[flag] ?? [];
|
|
355
|
-
|
|
356
|
-
if (spread)
|
|
357
|
-
list.push(...spread);
|
|
358
|
-
else
|
|
359
|
-
list.push(coerce(flag, raw, prop.items ?? {}, UsageError));
|
|
366
|
+
list.push(...arrayItems(flag, raw, prop, UsageError));
|
|
360
367
|
input[flag] = list;
|
|
361
368
|
} else {
|
|
362
369
|
input[flag] = coerce(flag, raw, prop, UsageError);
|
|
@@ -369,11 +376,12 @@ function parseFlagTokens(props, rest, UsageError) {
|
|
|
369
376
|
class CliUsageError extends Error {
|
|
370
377
|
}
|
|
371
378
|
function resolveOp(catalog, argv) {
|
|
372
|
-
const byName = new Map(catalog.map((c) => [c.name, c]));
|
|
379
|
+
const byName = new Map(catalog.ops.map((c) => [c.name, c]));
|
|
373
380
|
for (let n = Math.min(argv.length, 4);n >= 1; n--) {
|
|
374
|
-
const
|
|
381
|
+
const name = argv.slice(0, n).join(" ");
|
|
382
|
+
const op = byName.get(name) ?? byName.get(catalog.renamed[name] ?? "");
|
|
375
383
|
if (op)
|
|
376
|
-
return { op, rest: argv.slice(n) };
|
|
384
|
+
return { op, rest: argv.slice(n), ...op.name !== name && { renamedFrom: name } };
|
|
377
385
|
}
|
|
378
386
|
return null;
|
|
379
387
|
}
|
|
@@ -839,13 +847,16 @@ async function main() {
|
|
|
839
847
|
`);
|
|
840
848
|
return;
|
|
841
849
|
}
|
|
842
|
-
const resolved = resolveOp(catalog
|
|
850
|
+
const resolved = resolveOp(catalog, argv);
|
|
843
851
|
if (!resolved) {
|
|
844
852
|
const retired = retiredPrefix(catalog.retired, argv);
|
|
845
853
|
if (retired)
|
|
846
854
|
fail(`\`${retired.name}\` is retired: ${retired.replacement}`);
|
|
847
855
|
fail(`unknown operation '${argv.join(" ")}' — run \`volty help\``);
|
|
848
856
|
}
|
|
857
|
+
if (resolved.renamedFrom)
|
|
858
|
+
process.stderr.write(`${resolved.renamedFrom} is now ${resolved.op.name}
|
|
859
|
+
`);
|
|
849
860
|
if (resolved.rest.includes("--help")) {
|
|
850
861
|
process.stdout.write(`${renderOpHelp(resolved.op)}
|
|
851
862
|
`);
|
package/package.json
CHANGED
|
@@ -23,6 +23,6 @@ Use the lane the behaviour was reported on. On the contact lane Volty declines t
|
|
|
23
23
|
## On prod
|
|
24
24
|
|
|
25
25
|
- 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.
|
|
26
|
-
- Test through the
|
|
26
|
+
- 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.
|
|
27
27
|
- Run `volty debug sandbox-cleanup --all --env prod --org <id>` when you finish.
|
|
28
28
|
- A `{pending:true}` result means the turn outran the wait, not that it failed: poll for it (`volty docs` names the command) instead of sending the message again.
|