@voltade/volty 0.1.10 → 0.1.12
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 +55 -23
- package/package.json +1 -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 existsSync3, mkdirSync as mkdirSync4, readFileSync as
|
|
4
|
+
import { existsSync as existsSync3, mkdirSync as mkdirSync4, readFileSync as readFileSync5, writeFileSync as writeFileSync4 } from "node:fs";
|
|
5
5
|
import { homedir as homedir3 } from "node:os";
|
|
6
6
|
import { join as join4 } from "node:path";
|
|
7
7
|
|
|
@@ -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`);
|
|
@@ -273,6 +274,9 @@ async function logout(config, env) {
|
|
|
273
274
|
return `Logged out of '${env}' (key revoked).`;
|
|
274
275
|
}
|
|
275
276
|
|
|
277
|
+
// src/dispatch.ts
|
|
278
|
+
import { readFileSync as readFileSync3 } from "node:fs";
|
|
279
|
+
|
|
276
280
|
// ../shared/ops/flag-parse.ts
|
|
277
281
|
function acceptsNull(prop) {
|
|
278
282
|
if (prop.type === "null")
|
|
@@ -293,21 +297,21 @@ function coerce(flag, raw, prop0, UsageError) {
|
|
|
293
297
|
return true;
|
|
294
298
|
if (raw === "false")
|
|
295
299
|
return false;
|
|
296
|
-
throw new UsageError(`--${flag} expects true|false
|
|
300
|
+
throw new UsageError(`--${flag} expects true|false`, flag);
|
|
297
301
|
}
|
|
298
302
|
if (raw === undefined)
|
|
299
|
-
throw new UsageError(`--${flag} requires a value
|
|
303
|
+
throw new UsageError(`--${flag} requires a value`, flag);
|
|
300
304
|
if (prop.type === "number" || prop.type === "integer") {
|
|
301
305
|
const n = Number(raw);
|
|
302
306
|
if (Number.isNaN(n))
|
|
303
|
-
throw new UsageError(`--${flag} expects a number
|
|
307
|
+
throw new UsageError(`--${flag} expects a number`, flag);
|
|
304
308
|
return n;
|
|
305
309
|
}
|
|
306
310
|
if (prop.type === "object") {
|
|
307
311
|
try {
|
|
308
312
|
return JSON.parse(raw);
|
|
309
313
|
} catch {
|
|
310
|
-
throw new UsageError(`--${flag} expects JSON
|
|
314
|
+
throw new UsageError(`--${flag} expects JSON`, flag);
|
|
311
315
|
}
|
|
312
316
|
}
|
|
313
317
|
return raw;
|
|
@@ -322,6 +326,16 @@ function jsonArrayValue(raw) {
|
|
|
322
326
|
return null;
|
|
323
327
|
}
|
|
324
328
|
}
|
|
329
|
+
function arrayItems(flag, raw, prop, UsageError) {
|
|
330
|
+
const spread = jsonArrayValue(raw);
|
|
331
|
+
if (spread)
|
|
332
|
+
return spread;
|
|
333
|
+
const items = prop.items ?? {};
|
|
334
|
+
if (items.entityId && raw?.includes(",")) {
|
|
335
|
+
return raw.split(",").map((id) => id.trim()).filter((id) => id !== "");
|
|
336
|
+
}
|
|
337
|
+
return [coerce(flag, raw, items, UsageError)];
|
|
338
|
+
}
|
|
325
339
|
function canonicalFlag(props, flag) {
|
|
326
340
|
if (props[flag])
|
|
327
341
|
return flag;
|
|
@@ -352,11 +366,7 @@ function parseFlagTokens(props, rest, UsageError) {
|
|
|
352
366
|
}
|
|
353
367
|
if (prop.type === "array") {
|
|
354
368
|
const list = input[flag] ?? [];
|
|
355
|
-
|
|
356
|
-
if (spread)
|
|
357
|
-
list.push(...spread);
|
|
358
|
-
else
|
|
359
|
-
list.push(coerce(flag, raw, prop.items ?? {}, UsageError));
|
|
369
|
+
list.push(...arrayItems(flag, raw, prop, UsageError));
|
|
360
370
|
input[flag] = list;
|
|
361
371
|
} else {
|
|
362
372
|
input[flag] = coerce(flag, raw, prop, UsageError);
|
|
@@ -369,16 +379,35 @@ function parseFlagTokens(props, rest, UsageError) {
|
|
|
369
379
|
class CliUsageError extends Error {
|
|
370
380
|
}
|
|
371
381
|
function resolveOp(catalog, argv) {
|
|
372
|
-
const byName = new Map(catalog.map((c) => [c.name, c]));
|
|
382
|
+
const byName = new Map(catalog.ops.map((c) => [c.name, c]));
|
|
373
383
|
for (let n = Math.min(argv.length, 4);n >= 1; n--) {
|
|
374
|
-
const
|
|
384
|
+
const name = argv.slice(0, n).join(" ");
|
|
385
|
+
const op = byName.get(name) ?? byName.get(catalog.renamed[name] ?? "");
|
|
375
386
|
if (op)
|
|
376
|
-
return { op, rest: argv.slice(n) };
|
|
387
|
+
return { op, rest: argv.slice(n), ...op.name !== name && { renamedFrom: name } };
|
|
377
388
|
}
|
|
378
389
|
return null;
|
|
379
390
|
}
|
|
380
391
|
function parseFlags(op, rest) {
|
|
381
|
-
|
|
392
|
+
const props = op.input.properties ?? {};
|
|
393
|
+
const parsed = parseFlagTokens(props, rest, CliUsageError);
|
|
394
|
+
for (const [key, value] of Object.entries(parsed.input)) {
|
|
395
|
+
const prop = props[key];
|
|
396
|
+
if (typeof value === "string" && value.startsWith("@") && prop && isBase64(prop)) {
|
|
397
|
+
parsed.input[key] = readBase64File(key, value.slice(1));
|
|
398
|
+
}
|
|
399
|
+
}
|
|
400
|
+
return parsed;
|
|
401
|
+
}
|
|
402
|
+
function isBase64(prop) {
|
|
403
|
+
return [prop, ...prop.anyOf ?? []].some((branch) => branch.contentEncoding === "base64");
|
|
404
|
+
}
|
|
405
|
+
function readBase64File(flag, path) {
|
|
406
|
+
try {
|
|
407
|
+
return readFileSync3(path).toString("base64");
|
|
408
|
+
} catch (err) {
|
|
409
|
+
throw new CliUsageError(`--${flag}: cannot read ${path} (${err.code ?? "error"})`);
|
|
410
|
+
}
|
|
382
411
|
}
|
|
383
412
|
async function runOp(ctx, op, input) {
|
|
384
413
|
const res = await apiFetch(ctx, pathForOp(op.name), { method: "POST", body: input });
|
|
@@ -511,7 +540,7 @@ function decideProposal(ctx, proposalId, decision, reason) {
|
|
|
511
540
|
}
|
|
512
541
|
|
|
513
542
|
// src/update.ts
|
|
514
|
-
import { mkdirSync as mkdirSync3, readFileSync as
|
|
543
|
+
import { mkdirSync as mkdirSync3, readFileSync as readFileSync4, writeFileSync as writeFileSync3 } from "node:fs";
|
|
515
544
|
import { homedir as homedir2 } from "node:os";
|
|
516
545
|
import { dirname as dirname2, join as join3 } from "node:path";
|
|
517
546
|
var CACHE_PATH = join3(homedir2(), ".config", "volty", "update-check.json");
|
|
@@ -519,7 +548,7 @@ var CHECK_INTERVAL_MS = 24 * 60 * 60 * 1000;
|
|
|
519
548
|
var REGISTRY_LATEST = "https://registry.npmjs.org/@voltade/volty/latest";
|
|
520
549
|
function currentVersion() {
|
|
521
550
|
try {
|
|
522
|
-
const pkg = JSON.parse(
|
|
551
|
+
const pkg = JSON.parse(readFileSync4(join3(import.meta.dirname, "..", "package.json"), "utf8"));
|
|
523
552
|
return pkg.version ?? null;
|
|
524
553
|
} catch {
|
|
525
554
|
return null;
|
|
@@ -537,7 +566,7 @@ function cmpVersion(a, b) {
|
|
|
537
566
|
}
|
|
538
567
|
function readCache() {
|
|
539
568
|
try {
|
|
540
|
-
return JSON.parse(
|
|
569
|
+
return JSON.parse(readFileSync4(CACHE_PATH, "utf8"));
|
|
541
570
|
} catch {
|
|
542
571
|
return null;
|
|
543
572
|
}
|
|
@@ -784,7 +813,7 @@ function handleSkill(rest) {
|
|
|
784
813
|
fail("bundled SKILL.md not found — reinstall the @voltade/volty package");
|
|
785
814
|
const destDir = join4(homedir3(), ".claude", "skills", "volty-cli-ops");
|
|
786
815
|
mkdirSync4(destDir, { recursive: true });
|
|
787
|
-
writeFileSync4(join4(destDir, "SKILL.md"),
|
|
816
|
+
writeFileSync4(join4(destDir, "SKILL.md"), readFileSync5(source, "utf8"));
|
|
788
817
|
process.stdout.write(`Installed the volty-cli-ops skill → ${join4(destDir, "SKILL.md")}
|
|
789
818
|
`);
|
|
790
819
|
}
|
|
@@ -839,13 +868,16 @@ async function main() {
|
|
|
839
868
|
`);
|
|
840
869
|
return;
|
|
841
870
|
}
|
|
842
|
-
const resolved = resolveOp(catalog
|
|
871
|
+
const resolved = resolveOp(catalog, argv);
|
|
843
872
|
if (!resolved) {
|
|
844
873
|
const retired = retiredPrefix(catalog.retired, argv);
|
|
845
874
|
if (retired)
|
|
846
875
|
fail(`\`${retired.name}\` is retired: ${retired.replacement}`);
|
|
847
876
|
fail(`unknown operation '${argv.join(" ")}' — run \`volty help\``);
|
|
848
877
|
}
|
|
878
|
+
if (resolved.renamedFrom)
|
|
879
|
+
process.stderr.write(`${resolved.renamedFrom} is now ${resolved.op.name}
|
|
880
|
+
`);
|
|
849
881
|
if (resolved.rest.includes("--help")) {
|
|
850
882
|
process.stdout.write(`${renderOpHelp(resolved.op)}
|
|
851
883
|
`);
|
package/package.json
CHANGED