@pixelvibing/cli 0.38.2 → 0.40.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
CHANGED
|
@@ -21,7 +21,7 @@ Each step it finds done already is skipped.
|
|
|
21
21
|
|---|---|
|
|
22
22
|
| `login`, `logout`, `whoami` | Keep an account token for this machine in the system's credential store, or remove it |
|
|
23
23
|
| `init`, `link` | Make a directory a local project, and name the platform project it generates for |
|
|
24
|
-
| `generate object\|creature\|level-design` | Make art on the platform, after saying
|
|
24
|
+
| `generate object\|creature\|level-design` | Make art on the platform, after saying what it uses of the account's limit, then pull it |
|
|
25
25
|
| `list`, `pull` | List the project's assets by kind, and pull one by id or name into `pixelvibing/out/` |
|
|
26
26
|
| `guide pull\|push\|revise\|show\|versions` | Read and write the project's style guide |
|
|
27
27
|
| `seal` | Seal `pixelvibing/out/` into `pixelvibing/build/assets.eac` |
|
package/dist/pixel-vibing-cli.js
CHANGED
|
@@ -525,18 +525,6 @@ class TooFewCredits extends Error {
|
|
|
525
525
|
this.credits = credits;
|
|
526
526
|
}
|
|
527
527
|
}
|
|
528
|
-
function costIn(prices, kind) {
|
|
529
|
-
const price = prices.kinds[kind];
|
|
530
|
-
if (price === void 0) return null;
|
|
531
|
-
return "credits" in price ? price.credits : price.upTo;
|
|
532
|
-
}
|
|
533
|
-
function costWords(prices, kind) {
|
|
534
|
-
const price = prices.kinds[kind];
|
|
535
|
-
if (price === void 0) return null;
|
|
536
|
-
const most = "credits" in price ? price.credits : price.upTo;
|
|
537
|
-
const credits = `${most} credit${most === 1 ? "" : "s"}`;
|
|
538
|
-
return "credits" in price ? credits : `up to ${credits}, what it does not use given back`;
|
|
539
|
-
}
|
|
540
528
|
const id = (value) => encodeURIComponent(value);
|
|
541
529
|
function createWebApi(fetcher = (input, init2) => fetch(input, init2), base = API_BASE) {
|
|
542
530
|
const call = createCaller(fetcher, base);
|
|
@@ -627,8 +615,10 @@ function createWebApi(fetcher = (input, init2) => fetch(input, init2), base = AP
|
|
|
627
615
|
},
|
|
628
616
|
billing: (before = null) => json2(`/billing${before === null ? "" : `?before=${id(before)}`}`),
|
|
629
617
|
prices: () => json2("/billing/prices"),
|
|
630
|
-
|
|
631
|
-
|
|
618
|
+
/** A pack's checkout, in `currency` when one is named (R4.5). */
|
|
619
|
+
checkoutPack: async (packId, currency) => (await json2(`/billing/packs/${id(packId)}/checkout`, { method: "POST", ...currency === void 0 ? {} : { body: { currency } } })).url,
|
|
620
|
+
/** A plan's checkout, in `currency` when one is named (R4.5). */
|
|
621
|
+
checkoutPlan: async (planId, currency) => (await json2(`/billing/plans/${id(planId)}/checkout`, { method: "POST", ...currency === void 0 ? {} : { body: { currency } } })).url,
|
|
632
622
|
portal: async () => (await json2("/billing/portal", { method: "POST" })).url
|
|
633
623
|
};
|
|
634
624
|
}
|
|
@@ -670,7 +660,7 @@ async function paying(platform, run) {
|
|
|
670
660
|
} catch (error) {
|
|
671
661
|
if (error instanceof TooFewCredits) {
|
|
672
662
|
throw new CliError(
|
|
673
|
-
`this
|
|
663
|
+
`the account's usage limit is reached: this needs more than is left of it, and nothing was started. See the packs and the plans at ${creditsPage(platform.apiUrl)}`
|
|
674
664
|
);
|
|
675
665
|
}
|
|
676
666
|
throw error;
|
|
@@ -3726,9 +3716,6 @@ function jobWords(job) {
|
|
|
3726
3716
|
const stage = jobStage(job);
|
|
3727
3717
|
return stage === "failed" && job.reason !== null ? `failed: ${job.reason}` : stage;
|
|
3728
3718
|
}
|
|
3729
|
-
function costOf(prices, request) {
|
|
3730
|
-
return costIn(prices, request.kind);
|
|
3731
|
-
}
|
|
3732
3719
|
async function startGeneration(api, project, request) {
|
|
3733
3720
|
const ids = {};
|
|
3734
3721
|
for (const [field, images] of Object.entries(request.images ?? {})) {
|
|
@@ -3870,6 +3857,29 @@ function sketchSendProblem(sketch, description) {
|
|
|
3870
3857
|
function sketchBody(sketch, description) {
|
|
3871
3858
|
return { ...sentSketch(sketch, description) };
|
|
3872
3859
|
}
|
|
3860
|
+
function usageOf$1(billing) {
|
|
3861
|
+
return billing.usage ?? { used: 0, limit: billing.credits };
|
|
3862
|
+
}
|
|
3863
|
+
function usedPercent(usage) {
|
|
3864
|
+
if (usage.limit <= 0) return 100;
|
|
3865
|
+
return Math.min(100, Math.max(0, Math.round(usage.used / usage.limit * 100)));
|
|
3866
|
+
}
|
|
3867
|
+
function shareWords(credits, limit) {
|
|
3868
|
+
if (limit <= 0) return "more than is left";
|
|
3869
|
+
const share = credits / limit * 100;
|
|
3870
|
+
if (share > 0 && share < 1) return "less than 1%";
|
|
3871
|
+
return `about ${Math.round(share)}%`;
|
|
3872
|
+
}
|
|
3873
|
+
function leftWords(usage) {
|
|
3874
|
+
return `${100 - usedPercent(usage)}% of your limit left`;
|
|
3875
|
+
}
|
|
3876
|
+
function costShareWords(prices, kind, usage) {
|
|
3877
|
+
const price = prices.kinds[kind];
|
|
3878
|
+
if (price === void 0) return null;
|
|
3879
|
+
const most = "credits" in price ? price.credits : price.upTo;
|
|
3880
|
+
const share = `${shareWords(most, usage.limit)} of your limit`;
|
|
3881
|
+
return "credits" in price ? share : `up to ${share}, what it does not use given back`;
|
|
3882
|
+
}
|
|
3873
3883
|
const LARGEST_FOOTPRINT = {
|
|
3874
3884
|
cols: Math.min(Math.floor(WINDOW_PX.width / SCALES.at(-1)), Math.floor(MAX_ASSEMBLED_PX / TILE_SIZE)),
|
|
3875
3885
|
rows: Math.min(Math.floor(WINDOW_PX.height / SCALES.at(-1)), Math.floor(MAX_ASSEMBLED_PX / TILE_SIZE))
|
|
@@ -4070,15 +4080,17 @@ async function requestOf(context, asked, args) {
|
|
|
4070
4080
|
} else if (stringOf(args, "tiles") !== void 0) throw new CliError("--tiles is a level design's");
|
|
4071
4081
|
return { kind, body, ...references.length > 0 ? { images: { references } } : {}, words };
|
|
4072
4082
|
}
|
|
4073
|
-
async function confirmed(context, platform, what,
|
|
4074
|
-
const
|
|
4075
|
-
const
|
|
4076
|
-
|
|
4083
|
+
async function confirmed(context, platform, what, prices, kind, yes) {
|
|
4084
|
+
const usage = usageOf$1(await platform.web.billing());
|
|
4085
|
+
const share = costShareWords(prices, kind, usage);
|
|
4086
|
+
const priced = share === null ? "using what the platform will say of your limit" : `using ${share}`;
|
|
4087
|
+
context.io.warn(`Making ${what}, ${priced}; ${leftWords(usage)}.
|
|
4077
4088
|
`);
|
|
4078
|
-
if (yes) return;
|
|
4089
|
+
if (yes) return share;
|
|
4079
4090
|
if (!context.io.interactive) throw new CliError("nothing was started: pass --yes to start it without a question");
|
|
4080
4091
|
const said = (await context.io.ask("Start it? [y/N] ")).trim().toLowerCase();
|
|
4081
4092
|
if (said !== "y" && said !== "yes") throw new CliError("nothing was started");
|
|
4093
|
+
return share;
|
|
4082
4094
|
}
|
|
4083
4095
|
async function followed(context, platform, jobId) {
|
|
4084
4096
|
const since = context.services.now();
|
|
@@ -4118,7 +4130,7 @@ const generate = {
|
|
|
4118
4130
|
},
|
|
4119
4131
|
reference: { type: "string", multiple: true, value: "<png>", description: "an image to draw from" },
|
|
4120
4132
|
quality: { type: "string", value: "<quality>", description: "the platform's to choose now; ignored, and said so" },
|
|
4121
|
-
yes: { type: "boolean", short: "y", description: "start it without asking, once
|
|
4133
|
+
yes: { type: "boolean", short: "y", description: "start it without asking, once what it uses of your limit is said" },
|
|
4122
4134
|
as: { type: "string", value: "<name>", description: "land it under this name instead of the platform's" },
|
|
4123
4135
|
aside: { type: "boolean", description: "keep a folder's own map and art under pixelvibing/before-platform/, and write it from the platform" }
|
|
4124
4136
|
},
|
|
@@ -4131,15 +4143,14 @@ const generate = {
|
|
|
4131
4143
|
await checkFolder(local, flagOf(args, "aside"));
|
|
4132
4144
|
const platform = await signedIn(context);
|
|
4133
4145
|
const prices = await platform.web.prices();
|
|
4134
|
-
const
|
|
4135
|
-
await confirmed(context, platform, request.words, costWords(prices, request.kind), flagOf(args, "yes"));
|
|
4146
|
+
const uses = await confirmed(context, platform, request.words, prices, request.kind, flagOf(args, "yes"));
|
|
4136
4147
|
const jobId = await paying(platform, () => startGeneration(platform.web, project, request));
|
|
4137
4148
|
context.io.warn(`Started the job ${jobId}.
|
|
4138
4149
|
`);
|
|
4139
4150
|
const job = await followed(context, platform, jobId);
|
|
4140
4151
|
if (job.state === "failed") throw new CliError(`the generation failed: ${job.reason ?? "the platform gave no reason"}`);
|
|
4141
4152
|
const pulled = await pullAsset(platform, local, jobId, stringOf(args, "as"), { aside: flagOf(args, "aside") });
|
|
4142
|
-
answer(context, { job: jobId,
|
|
4153
|
+
answer(context, { job: jobId, uses, ...pulled }, pulledWords(pulled));
|
|
4143
4154
|
}
|
|
4144
4155
|
};
|
|
4145
4156
|
const mcpHeaders = {
|
|
@@ -4291,7 +4302,7 @@ const guideRevise = {
|
|
|
4291
4302
|
summary: "Ask the platform to revise the style guide by an instruction, then pull it",
|
|
4292
4303
|
usage: "<instruction> [--yes] [--force]",
|
|
4293
4304
|
options: {
|
|
4294
|
-
yes: { type: "boolean", short: "y", description: "start it without asking, once
|
|
4305
|
+
yes: { type: "boolean", short: "y", description: "start it without asking, once what it uses of your limit is said" },
|
|
4295
4306
|
force: { type: "boolean", description: "replace changes to the local copy that were never pushed" }
|
|
4296
4307
|
},
|
|
4297
4308
|
positionals: [1, 1],
|
|
@@ -4302,8 +4313,7 @@ const guideRevise = {
|
|
|
4302
4313
|
if (instruction === "") throw new CliError("say what to change in the style guide");
|
|
4303
4314
|
if (!flagOf(args, "force") && await unpushed(local)) throw new CliError(CHANGED);
|
|
4304
4315
|
const platform = await signedIn(context);
|
|
4305
|
-
|
|
4306
|
-
await confirmed(context, platform, `a revision of the style guide: ${instruction}`, cost, flagOf(args, "yes"));
|
|
4316
|
+
await confirmed(context, platform, `a revision of the style guide: ${instruction}`, await platform.web.prices(), GUIDE_KIND, flagOf(args, "yes"));
|
|
4307
4317
|
const jobId = await paying(platform, () => platform.web.reviseGuide(project, instruction));
|
|
4308
4318
|
context.io.warn(`Started the job ${jobId}.
|
|
4309
4319
|
`);
|
|
@@ -4595,7 +4605,7 @@ const move = {
|
|
|
4595
4605
|
);
|
|
4596
4606
|
}
|
|
4597
4607
|
};
|
|
4598
|
-
const version = "0.
|
|
4608
|
+
const version = "0.40.0";
|
|
4599
4609
|
const manifest = {
|
|
4600
4610
|
version
|
|
4601
4611
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pixelvibing/cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.40.0",
|
|
4
4
|
"description": "PixelVibing: pixel art game assets from the command line, and the Skills that teach coding assistants to make them.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"homepage": "https://pixelvibing.com",
|
|
@@ -36,17 +36,17 @@ pixel-vibing-cli generate icons --names "<name>,<name>,..." --purpose <skill|ite
|
|
|
36
36
|
pixel-vibing-cli generate ui --sketch <file.json> --instruction "<the set, in a line>" --yes --json
|
|
37
37
|
```
|
|
38
38
|
|
|
39
|
-
Each generation
|
|
40
|
-
- **
|
|
41
|
-
`--yes` it asks, and with nobody at the terminal it starts
|
|
42
|
-
a batch will
|
|
39
|
+
Each generation uses part of the account's usage limit for the month.
|
|
40
|
+
- **What it uses.** The command prints the most it uses and what is left, as shares of the
|
|
41
|
+
limit, before it starts. Without `--yes` it asks, and with nobody at the terminal it starts
|
|
42
|
+
nothing. Tell the person how much of their limit a batch will use before you start one.
|
|
43
43
|
- **The instruction.** Describe the thing as a person would: its look, its material, what
|
|
44
44
|
it is for in the game. Describe the thing itself, not a prompt for a model.
|
|
45
45
|
- **The options.**
|
|
46
46
|
- `--size` is an object's footprint in whole tiles, `1x1` unless given.
|
|
47
47
|
- `--tiles` is how many tiles a level design is across, `6x4` unless given.
|
|
48
|
-
- No quality is given: the platform draws each asset at the quality it needs. The
|
|
49
|
-
printed is the most it may
|
|
48
|
+
- No quality is given: the platform draws each asset at the quality it needs. The share
|
|
49
|
+
printed is the most it may use, and what it does not use is given back.
|
|
50
50
|
- `--reference` is a PNG to draw from, repeated for several: at most 8 for an object,
|
|
51
51
|
3 for a creature, a level design or a UI, none for icons. A UI's references are a style
|
|
52
52
|
to follow (frames, materials, a way of drawing), never what to draw.
|
|
@@ -68,8 +68,8 @@ Each generation spends the account's credits.
|
|
|
68
68
|
counts and values in the game.
|
|
69
69
|
- **Success.** The asset is pulled at once. The answer's `files` are where its pictures
|
|
70
70
|
are, relative to `pixelvibing/`.
|
|
71
|
-
- **Failure.**
|
|
72
|
-
|
|
71
|
+
- **Failure.** A reached limit starts nothing and names the page where the person adds to
|
|
72
|
+
it with a pack or a plan: tell them, and do not retry. A failed job prints its reason.
|
|
73
73
|
|
|
74
74
|
## Listing and pulling
|
|
75
75
|
|
|
@@ -31,7 +31,7 @@ Do not change it for one asset: say that in the asset's instruction instead.
|
|
|
31
31
|
changes, bring it up to date too. The whole guide is at most 8000 characters.
|
|
32
32
|
- **Ask the platform.** `pixel-vibing-cli guide revise "<what changed in the game>"
|
|
33
33
|
--yes` revises the guide by that instruction, keeping what it does not change, and
|
|
34
|
-
pulls the result. It
|
|
34
|
+
pulls the result. It uses a sliver of the account's limit.
|
|
35
35
|
3. `pixel-vibing-cli guide push` keeps the file as the guide's next version.
|
|
36
36
|
- If the platform's guide moved on since your pull, nothing is kept.
|
|
37
37
|
- Save your changes aside, run `pixel-vibing-cli guide pull --force`, make them again on
|