pixelkiln 0.21.0 → 0.22.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/dist/cli.js +204 -38
- package/dist/cli.js.map +1 -1
- package/dist/index.cjs +180 -14
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +50 -11
- package/dist/index.d.ts +50 -11
- package/dist/index.js +188 -22
- package/dist/index.js.map +1 -1
- package/docs/CLI.md +7 -2
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
// src/cli.ts
|
|
4
4
|
import path26 from "path";
|
|
5
5
|
import { existsSync as existsSync21 } from "fs";
|
|
6
|
-
import { readFile as
|
|
6
|
+
import { readFile as readFile22 } from "fs/promises";
|
|
7
7
|
|
|
8
8
|
// src/env.ts
|
|
9
9
|
import { readFileSync, existsSync } from "fs";
|
|
@@ -7790,7 +7790,7 @@ async function runPicker(provider, lock, lockPath, opts = {}) {
|
|
|
7790
7790
|
// src/gallery/snapshot.ts
|
|
7791
7791
|
import { createHash as createHash3 } from "crypto";
|
|
7792
7792
|
import { existsSync as existsSync16 } from "fs";
|
|
7793
|
-
import { stat as stat3 } from "fs/promises";
|
|
7793
|
+
import { readFile as readFile15, stat as stat3 } from "fs/promises";
|
|
7794
7794
|
import path20 from "path";
|
|
7795
7795
|
|
|
7796
7796
|
// src/workspace.ts
|
|
@@ -7980,8 +7980,13 @@ var ManifestEditSchema = z5.discriminatedUnion("action", [
|
|
|
7980
7980
|
expectedSha256: HexSha,
|
|
7981
7981
|
patch: z5.object({
|
|
7982
7982
|
/** Candidates per generation, written to the provider's own option. */
|
|
7983
|
-
candidates: z5.number().int().min(1).max(64)
|
|
7984
|
-
|
|
7983
|
+
candidates: z5.number().int().min(1).max(64).optional(),
|
|
7984
|
+
/** Empty clears the style's own value (inherit, or the default). */
|
|
7985
|
+
promptPrefix: z5.string().optional(),
|
|
7986
|
+
promptSuffix: z5.string().optional(),
|
|
7987
|
+
/** `#rrggbb` values; null or empty clears the style's own palette. */
|
|
7988
|
+
palette: z5.array(z5.string().regex(/^#?[0-9a-f]{6}$/i, "expected a six-digit hex colour")).max(256).nullable().optional()
|
|
7989
|
+
}).strict().refine((patch) => Object.keys(patch).length > 0, { message: "nothing to change" })
|
|
7985
7990
|
}).strict()
|
|
7986
7991
|
]);
|
|
7987
7992
|
var ManifestDriftError = class extends Error {
|
|
@@ -8019,16 +8024,25 @@ function applyEdit(raw, edit) {
|
|
|
8019
8024
|
if (edit.action === "patch-style") {
|
|
8020
8025
|
const style = raw.styles && Object.hasOwn(raw.styles, edit.styleId) ? raw.styles[edit.styleId] : void 0;
|
|
8021
8026
|
if (!style) throw new ManifestEditError(`style "${edit.styleId}" is not declared by the manifest`);
|
|
8022
|
-
const
|
|
8023
|
-
|
|
8024
|
-
|
|
8025
|
-
|
|
8026
|
-
|
|
8027
|
-
|
|
8027
|
+
const { patch: patch2 } = edit;
|
|
8028
|
+
if (patch2.candidates !== void 0) {
|
|
8029
|
+
const provider = styleProvider(raw, edit.styleId);
|
|
8030
|
+
const option = CANDIDATE_OPTION[provider];
|
|
8031
|
+
if (!option) {
|
|
8032
|
+
throw new ManifestEditError(
|
|
8033
|
+
provider === "pixellab" ? "PixelLab's candidate count follows the generator and size: map and pixflux return one image; a 1dir style returns 4\u201364 for its size" : `provider "${provider}" has no candidate-count option`
|
|
8034
|
+
);
|
|
8035
|
+
}
|
|
8036
|
+
const options = { ...style.providerOptions ?? {} };
|
|
8037
|
+
options[provider] = { ...options[provider] ?? {}, [option]: patch2.candidates };
|
|
8038
|
+
style.providerOptions = options;
|
|
8039
|
+
}
|
|
8040
|
+
if (patch2.promptPrefix !== void 0) setOrDelete(style, "promptPrefix", patch2.promptPrefix || null);
|
|
8041
|
+
if (patch2.promptSuffix !== void 0) setOrDelete(style, "promptSuffix", patch2.promptSuffix || null);
|
|
8042
|
+
if (patch2.palette !== void 0) {
|
|
8043
|
+
const colors = (patch2.palette ?? []).map((color) => "#" + color.replace(/^#/, "").toLowerCase());
|
|
8044
|
+
setOrDelete(style, "palette", colors.length ? colors : null);
|
|
8028
8045
|
}
|
|
8029
|
-
const options = { ...style.providerOptions ?? {} };
|
|
8030
|
-
options[provider] = { ...options[provider] ?? {}, [option]: edit.patch.candidates };
|
|
8031
|
-
style.providerOptions = options;
|
|
8032
8046
|
return;
|
|
8033
8047
|
}
|
|
8034
8048
|
if (edit.action === "add-asset") {
|
|
@@ -8253,6 +8267,14 @@ async function buildGallerySnapshot(opts) {
|
|
|
8253
8267
|
const media = /* @__PURE__ */ new Map();
|
|
8254
8268
|
const plan = await buildPlan(specs, lock);
|
|
8255
8269
|
const items = [];
|
|
8270
|
+
const manifestText = await readFile15(loaded.path, "utf8");
|
|
8271
|
+
const manifestSha256 = sha256(manifestText);
|
|
8272
|
+
let rawStyles = {};
|
|
8273
|
+
try {
|
|
8274
|
+
const raw = JSON.parse(manifestText);
|
|
8275
|
+
if (raw && typeof raw === "object" && raw.styles && typeof raw.styles === "object") rawStyles = raw.styles;
|
|
8276
|
+
} catch {
|
|
8277
|
+
}
|
|
8256
8278
|
for (const planItem of plan.items) {
|
|
8257
8279
|
const { spec, key } = planItem;
|
|
8258
8280
|
const entry = lock.entries[key];
|
|
@@ -8387,6 +8409,8 @@ async function buildGallerySnapshot(opts) {
|
|
|
8387
8409
|
const counts = new Set(styleItems.filter((item) => item.declared && item.candidates !== null).map((item) => item.candidates));
|
|
8388
8410
|
const provider = style ? style.provider ?? loaded.manifest.provider : styleItems[0]?.provider ?? loaded.manifest.provider;
|
|
8389
8411
|
const actionableItems = styleItems.filter((item) => item.declared && (item.state === "missing" || item.state === "stale" || item.state === "failed"));
|
|
8412
|
+
const declaredItems = styleItems.filter((item) => item.declared);
|
|
8413
|
+
const rawStyle = Object.hasOwn(rawStyles, id) ? rawStyles[id] : void 0;
|
|
8390
8414
|
return {
|
|
8391
8415
|
id,
|
|
8392
8416
|
project: null,
|
|
@@ -8395,11 +8419,20 @@ async function buildGallerySnapshot(opts) {
|
|
|
8395
8419
|
provider,
|
|
8396
8420
|
generator: style?.generator ?? styleItems[0]?.generator ?? "map",
|
|
8397
8421
|
outDir: style?.outDir ?? "",
|
|
8422
|
+
promptPrefix: style?.promptPrefix ?? "",
|
|
8423
|
+
promptSuffix: style?.promptSuffix ?? "",
|
|
8398
8424
|
palette: style?.palette ?? [],
|
|
8399
8425
|
quality: Boolean(style?.quality),
|
|
8400
8426
|
tags: style?.tags ?? [],
|
|
8427
|
+
extends: typeof rawStyle?.extends === "string" ? rawStyle.extends : null,
|
|
8428
|
+
ownFields: rawStyle ? Object.keys(rawStyle).filter((key) => key !== "extends") : [],
|
|
8401
8429
|
items: styleItems.length,
|
|
8402
8430
|
spendByUnit: spend,
|
|
8431
|
+
regenerate: {
|
|
8432
|
+
assets: declaredItems.length,
|
|
8433
|
+
cost: declaredItems.reduce((sum, item) => sum + (item.estimatedCost ?? 0), 0),
|
|
8434
|
+
costUnit: declaredItems[0]?.costUnit ?? styleItems[0]?.costUnit ?? "generations"
|
|
8435
|
+
},
|
|
8403
8436
|
candidates: counts.size === 1 ? [...counts][0] : null,
|
|
8404
8437
|
candidatesEditable: Boolean(style) && Object.hasOwn(CANDIDATE_OPTION, provider),
|
|
8405
8438
|
actionable: {
|
|
@@ -8420,7 +8453,7 @@ async function buildGallerySnapshot(opts) {
|
|
|
8420
8453
|
root,
|
|
8421
8454
|
provider: loaded.manifest.provider,
|
|
8422
8455
|
account: null,
|
|
8423
|
-
manifestSha256
|
|
8456
|
+
manifestSha256,
|
|
8424
8457
|
entries: Object.keys(lock.entries).length,
|
|
8425
8458
|
items: items.length,
|
|
8426
8459
|
spendByUnit: spendByUnit(lock),
|
|
@@ -8457,6 +8490,7 @@ async function buildWorkspaceGallerySnapshot(opts) {
|
|
|
8457
8490
|
const lock = await loadLock(lockPath);
|
|
8458
8491
|
let projectItems = [];
|
|
8459
8492
|
let projectStyles = [];
|
|
8493
|
+
let manifestSha256 = null;
|
|
8460
8494
|
if (!excluded) {
|
|
8461
8495
|
const specs = await resolveSpecs(loaded, { styles: styleFilter, assets: assetFilter });
|
|
8462
8496
|
normalizeLockOutputPaths(lock, specs);
|
|
@@ -8469,6 +8503,7 @@ async function buildWorkspaceGallerySnapshot(opts) {
|
|
|
8469
8503
|
now: opts.now
|
|
8470
8504
|
});
|
|
8471
8505
|
for (const [id, file] of build.media) media.set(id, file);
|
|
8506
|
+
manifestSha256 = build.snapshot.project?.manifestSha256 ?? null;
|
|
8472
8507
|
projectItems = build.snapshot.items.map((item) => ({
|
|
8473
8508
|
...item,
|
|
8474
8509
|
id: `${project.id}:${item.key}`,
|
|
@@ -8486,7 +8521,7 @@ async function buildWorkspaceGallerySnapshot(opts) {
|
|
|
8486
8521
|
root: loaded.root,
|
|
8487
8522
|
provider: loaded.manifest.provider,
|
|
8488
8523
|
account: project.account ?? null,
|
|
8489
|
-
manifestSha256: await
|
|
8524
|
+
manifestSha256: manifestSha256 ?? sha256(await readFile15(manifestPath, "utf8")),
|
|
8490
8525
|
entries: Object.keys(lock.entries).length,
|
|
8491
8526
|
items: projectItems.length,
|
|
8492
8527
|
spendByUnit: spendByUnit(lock),
|
|
@@ -8544,7 +8579,7 @@ async function buildWorkspaceGallerySnapshot(opts) {
|
|
|
8544
8579
|
import { spawn as spawn2 } from "child_process";
|
|
8545
8580
|
import { randomBytes } from "crypto";
|
|
8546
8581
|
import { createServer as createServer2 } from "http";
|
|
8547
|
-
import { readFile as
|
|
8582
|
+
import { readFile as readFile16 } from "fs/promises";
|
|
8548
8583
|
|
|
8549
8584
|
// src/gallery/page.ts
|
|
8550
8585
|
function renderGallery(snapshot, opts = {}) {
|
|
@@ -8741,6 +8776,12 @@ function renderGallery(snapshot, opts = {}) {
|
|
|
8741
8776
|
.shead .cand { display:inline-flex; align-items:center; gap:6px; font-size:12px; color:var(--dim); }
|
|
8742
8777
|
.shead .cand input { width:56px; background:var(--panel-deep); border:1px solid var(--line); color:var(--text);
|
|
8743
8778
|
padding:2px 6px; font:12px/1.4 inherit; border-radius:0; }
|
|
8779
|
+
form.edit.style-form { margin:0 0 14px; }
|
|
8780
|
+
form.edit .blast { padding:8px 10px; border:1px solid var(--line); font-size:12.5px; color:var(--dim); }
|
|
8781
|
+
form.edit .blast.hot { border-color:var(--warn); color:var(--text); }
|
|
8782
|
+
form.edit .blast b { color:var(--warn); font-weight:600; }
|
|
8783
|
+
form.edit .pal { margin-top:4px; }
|
|
8784
|
+
.style .notice { margin:0 0 14px; }
|
|
8744
8785
|
#jobs { width:min(100%,var(--content)); margin:0 auto; padding:0 22px 12px; display:grid; gap:6px; }
|
|
8745
8786
|
#jobs:empty { display:none; }
|
|
8746
8787
|
.job { border:1px solid var(--line); background:var(--panel-deep); padding:8px 12px; display:grid;
|
|
@@ -9192,7 +9233,8 @@ function renderHeader() {
|
|
|
9192
9233
|
t.lastChild.append(el('b', null, n), document.createTextNode(' lock ' + (n === 1 ? 'entry' : 'entries')));
|
|
9193
9234
|
const declared = snap.items.filter((i) => i.declared).length;
|
|
9194
9235
|
t.append(el('span', null, declared + ' declared by ' + (snap.workspace ? 'a manifest' : 'the manifest')));
|
|
9195
|
-
|
|
9236
|
+
const recorded = fmtSpend(snap.totals.spendByUnit);
|
|
9237
|
+
t.append(el('span', null, recorded === 'no spend recorded' ? recorded : recorded + ' recorded'));
|
|
9196
9238
|
if (snap.filter.styles.length || snap.filter.assets.length) {
|
|
9197
9239
|
t.append(el('span', 'state-warn', 'filtered: ' +
|
|
9198
9240
|
[snap.filter.styles.length ? '--style ' + snap.filter.styles.join(',') : '',
|
|
@@ -9386,7 +9428,12 @@ function renderMain(items) {
|
|
|
9386
9428
|
g.onclick = () => generateDialog(snap.items.filter((i) => i.project === s.project && s.actionable.keys.includes(i.key)), { project: s.project });
|
|
9387
9429
|
tools.append(g);
|
|
9388
9430
|
}
|
|
9431
|
+
const styleKey = 'style:' + (s.project || '') + ':' + s.id;
|
|
9389
9432
|
if (EDITABLE && s.outDir) {
|
|
9433
|
+
const es = el('button', null, ui.editing === styleKey ? 'Cancel' : 'Edit style');
|
|
9434
|
+
es.type = 'button';
|
|
9435
|
+
es.onclick = () => { ui.editing = ui.editing === styleKey ? null : styleKey; ui.notice = null; render(); };
|
|
9436
|
+
tools.append(es);
|
|
9390
9437
|
const add = el('button', 'add', ui.editing === addKey ? 'Cancel' : '+ Add asset');
|
|
9391
9438
|
add.type = 'button';
|
|
9392
9439
|
add.onclick = () => { ui.editing = ui.editing === addKey ? null : addKey; render(); };
|
|
@@ -9394,6 +9441,8 @@ function renderMain(items) {
|
|
|
9394
9441
|
}
|
|
9395
9442
|
if (tools.childNodes.length) head.append(tools);
|
|
9396
9443
|
wrap.append(head);
|
|
9444
|
+
if (ui.notice && ui.notice.id === styleKey) wrap.append(el('div', 'notice', ui.notice.text));
|
|
9445
|
+
if (ui.editing === styleKey) wrap.append(styleForm(s));
|
|
9397
9446
|
if (ui.editing === addKey) wrap.append(addAssetForm(s));
|
|
9398
9447
|
}
|
|
9399
9448
|
const grid = el('div', 'grid');
|
|
@@ -9627,6 +9676,123 @@ function openCompare() {
|
|
|
9627
9676
|
|
|
9628
9677
|
// ---- editing (only when the server minted a session) ---------------------
|
|
9629
9678
|
|
|
9679
|
+
// Styles a parent edit reaches: every descendant (via extends) that does not
|
|
9680
|
+
// declare the field itself. Child-wins means an omitted field is inherited,
|
|
9681
|
+
// so the count follows the manifest's own rule rather than guessing.
|
|
9682
|
+
function inheritorsOf(style, field) {
|
|
9683
|
+
const byId = new Map(snap.styles.filter((x) => x.project === style.project).map((x) => [x.id, x]));
|
|
9684
|
+
const out = [];
|
|
9685
|
+
for (const other of byId.values()) {
|
|
9686
|
+
if (other.id === style.id) continue;
|
|
9687
|
+
let cur = other, blocked = false, hops = 0;
|
|
9688
|
+
while (cur && cur.id !== style.id && hops++ < 32) {
|
|
9689
|
+
if (cur.ownFields.includes(field)) { blocked = true; break; }
|
|
9690
|
+
cur = cur.extends ? byId.get(cur.extends) : null;
|
|
9691
|
+
}
|
|
9692
|
+
if (cur && cur.id === style.id && !blocked) out.push(other.id);
|
|
9693
|
+
}
|
|
9694
|
+
return out;
|
|
9695
|
+
}
|
|
9696
|
+
function blastRadius(style, fields) {
|
|
9697
|
+
const styleIds = new Set([style.id]);
|
|
9698
|
+
for (const field of fields) for (const id of inheritorsOf(style, field)) styleIds.add(id);
|
|
9699
|
+
const affected = snap.items.filter((i) => i.project === style.project && i.declared && styleIds.has(i.styleId));
|
|
9700
|
+
const units = new Map();
|
|
9701
|
+
for (const i of affected) if (i.estimatedCost !== null) units.set(i.costUnit, (units.get(i.costUnit) || 0) + i.estimatedCost);
|
|
9702
|
+
return {
|
|
9703
|
+
styles: [...styleIds],
|
|
9704
|
+
assets: affected.length,
|
|
9705
|
+
cost: [...units].map(([unit, n]) => fmtCost(unit, Math.round(n * 100) / 100)).join(' + '),
|
|
9706
|
+
};
|
|
9707
|
+
}
|
|
9708
|
+
const parsePalette = (value) => value.split(/[s,]+/).map((c) => c.trim()).filter(Boolean)
|
|
9709
|
+
.map((c) => '#' + c.replace(/^#/, '').toLowerCase());
|
|
9710
|
+
const paletteValid = (colors) => colors.every((c) => /^#[0-9a-f]{6}$/.test(c));
|
|
9711
|
+
|
|
9712
|
+
function styleForm(style) {
|
|
9713
|
+
const pr = snap.workspace ? snap.workspace.projects.find((x) => x.id === style.project) : snap.project;
|
|
9714
|
+
const own = (field) => style.ownFields.includes(field);
|
|
9715
|
+
const provenance = (field) => own(field) ? 'set on this style'
|
|
9716
|
+
: style.extends ? 'inherited from ' + style.extends + ' \u2014 saving sets a value on this style itself; ' + style.extends + ' is unchanged'
|
|
9717
|
+
: 'default \u2014 saving sets a value on this style itself';
|
|
9718
|
+
const form = el('form', 'edit style-form');
|
|
9719
|
+
form.append(el('h3', null, 'Edit style ' + style.id));
|
|
9720
|
+
const prefix = el('input'); prefix.type = 'text'; prefix.value = style.promptPrefix; prefix.placeholder = 'none';
|
|
9721
|
+
const suffix = el('input'); suffix.type = 'text'; suffix.value = style.promptSuffix; suffix.placeholder = 'none';
|
|
9722
|
+
const palette = el('input'); palette.type = 'text'; palette.value = style.palette.join(', '); palette.placeholder = '#rrggbb, #rrggbb \u2014 leave empty for no forced palette';
|
|
9723
|
+
const swatches = el('div', 'pal');
|
|
9724
|
+
const drawSwatches = () => {
|
|
9725
|
+
swatches.textContent = '';
|
|
9726
|
+
for (const c of parsePalette(palette.value)) { const i = el('i'); i.style.background = c; i.title = c; swatches.append(i); }
|
|
9727
|
+
};
|
|
9728
|
+
drawSwatches();
|
|
9729
|
+
form.append(
|
|
9730
|
+
field('prompt prefix', prefix, 'Prepended to every asset prompt in this style. ' + provenance('promptPrefix')),
|
|
9731
|
+
field('prompt suffix', suffix, 'Appended to every asset prompt in this style. ' + provenance('promptSuffix')),
|
|
9732
|
+
field('palette', palette, 'Forced colours where the provider supports them (pixflux). ' + provenance('palette')),
|
|
9733
|
+
swatches,
|
|
9734
|
+
);
|
|
9735
|
+
const blast = el('div', 'blast');
|
|
9736
|
+
const changed = () => {
|
|
9737
|
+
const out = [];
|
|
9738
|
+
if (prefix.value !== style.promptPrefix) out.push('promptPrefix');
|
|
9739
|
+
if (suffix.value !== style.promptSuffix) out.push('promptSuffix');
|
|
9740
|
+
if (parsePalette(palette.value).join(',') !== style.palette.map((c) => c.toLowerCase()).join(',')) out.push('palette');
|
|
9741
|
+
return out;
|
|
9742
|
+
};
|
|
9743
|
+
const updateBlast = () => {
|
|
9744
|
+
const fields = changed();
|
|
9745
|
+
drawSwatches();
|
|
9746
|
+
if (!fields.length) { blast.className = 'blast'; blast.textContent = 'No changes yet. A style change alters the request for every asset that uses it.'; return; }
|
|
9747
|
+
const r = blastRadius(style, fields);
|
|
9748
|
+
blast.className = 'blast hot';
|
|
9749
|
+
blast.textContent = '';
|
|
9750
|
+
const others = r.styles.filter((id) => id !== style.id);
|
|
9751
|
+
blast.append(el('b', null, 'Affects ' + r.assets + (r.assets === 1 ? ' asset' : ' assets')));
|
|
9752
|
+
blast.append(document.createTextNode(others.length
|
|
9753
|
+
? ' in ' + style.id + ' and ' + others.length + (others.length === 1 ? ' style that inherits it (' : ' styles that inherit it (') + others.join(', ') + ').'
|
|
9754
|
+
: ' in ' + style.id + '.'));
|
|
9755
|
+
blast.append(document.createTextNode(' Generated ones become stale; regenerating all of them is about ' + (r.cost || 'nothing') + '. Nothing is spent until you generate.'));
|
|
9756
|
+
};
|
|
9757
|
+
for (const input of [prefix, suffix, palette]) input.addEventListener('input', updateBlast);
|
|
9758
|
+
updateBlast();
|
|
9759
|
+
form.append(blast);
|
|
9760
|
+
const actions = el('div', 'actions');
|
|
9761
|
+
const save = el('button', 'primary', 'Save to manifest'); save.type = 'submit';
|
|
9762
|
+
const cancel = el('button', null, 'Cancel'); cancel.type = 'button'; cancel.onclick = () => { ui.editing = null; render(); };
|
|
9763
|
+
const msg = el('span', 'msg');
|
|
9764
|
+
actions.append(save, cancel, msg);
|
|
9765
|
+
form.append(actions);
|
|
9766
|
+
form.onsubmit = async (e) => {
|
|
9767
|
+
e.preventDefault();
|
|
9768
|
+
const fields = changed();
|
|
9769
|
+
if (!fields.length) { ui.editing = null; render(); return; }
|
|
9770
|
+
const colors = parsePalette(palette.value);
|
|
9771
|
+
if (fields.includes('palette') && !paletteValid(colors)) { msg.className = 'msg bad'; msg.textContent = 'palette must be six-digit hex colours'; return; }
|
|
9772
|
+
const patch = {};
|
|
9773
|
+
if (fields.includes('promptPrefix')) patch.promptPrefix = prefix.value;
|
|
9774
|
+
if (fields.includes('promptSuffix')) patch.promptSuffix = suffix.value;
|
|
9775
|
+
if (fields.includes('palette')) patch.palette = colors;
|
|
9776
|
+
save.disabled = true; msg.className = 'msg'; msg.textContent = 'saving\u2026';
|
|
9777
|
+
const r = blastRadius(style, fields);
|
|
9778
|
+
try {
|
|
9779
|
+
const body = { action: 'patch-style', styleId: style.id, expectedSha256: pr.manifestSha256, patch };
|
|
9780
|
+
if (style.project) body.project = style.project;
|
|
9781
|
+
snap = await postEdit(body);
|
|
9782
|
+
ui.editing = null;
|
|
9783
|
+
ui.notice = { id: 'style:' + (style.project || '') + ':' + style.id,
|
|
9784
|
+
text: 'Saved. The request for ' + r.assets + (r.assets === 1 ? ' asset' : ' assets') + ' changed' + (r.cost ? ' \u2014 about ' + r.cost + ' to regenerate.' : '.') + ' Nothing is spent until you generate.' };
|
|
9785
|
+
render();
|
|
9786
|
+
} catch (err) {
|
|
9787
|
+
save.disabled = false;
|
|
9788
|
+
msg.className = 'msg bad';
|
|
9789
|
+
msg.textContent = err.message + (err.status === 409 ? ' \u2014 press Refresh.' : '');
|
|
9790
|
+
}
|
|
9791
|
+
};
|
|
9792
|
+
setTimeout(() => prefix.focus(), 0);
|
|
9793
|
+
return form;
|
|
9794
|
+
}
|
|
9795
|
+
|
|
9630
9796
|
function addAssetForm(style) {
|
|
9631
9797
|
const pr = snap.workspace ? snap.workspace.projects.find((x) => x.id === style.project) : snap.project;
|
|
9632
9798
|
const siblings = snap.styles.filter((x) => x.project === style.project);
|
|
@@ -10352,7 +10518,7 @@ async function serveGallery(opts) {
|
|
|
10352
10518
|
const asset = reviewAssets.get(jobId)?.get(url2.pathname);
|
|
10353
10519
|
if (!asset) return fail(404, "no such review asset");
|
|
10354
10520
|
try {
|
|
10355
|
-
const bytes = await
|
|
10521
|
+
const bytes = await readFile16(asset.path);
|
|
10356
10522
|
res.writeHead(200, {
|
|
10357
10523
|
"Content-Type": asset.contentType,
|
|
10358
10524
|
"Cache-Control": "no-store",
|
|
@@ -10401,7 +10567,7 @@ async function serveGallery(opts) {
|
|
|
10401
10567
|
if (!asset) return fail(404, "no such gallery media");
|
|
10402
10568
|
let bytes;
|
|
10403
10569
|
try {
|
|
10404
|
-
bytes = await
|
|
10570
|
+
bytes = await readFile16(asset.path);
|
|
10405
10571
|
} catch {
|
|
10406
10572
|
return fail(404, "gallery media is no longer on disk; refresh the page");
|
|
10407
10573
|
}
|
|
@@ -10691,7 +10857,7 @@ function createGenerateHandlers(opts) {
|
|
|
10691
10857
|
}
|
|
10692
10858
|
|
|
10693
10859
|
// src/pipeline/salvage.ts
|
|
10694
|
-
import { readFile as
|
|
10860
|
+
import { readFile as readFile17 } from "fs/promises";
|
|
10695
10861
|
import { existsSync as existsSync17 } from "fs";
|
|
10696
10862
|
import path21 from "path";
|
|
10697
10863
|
function providerClaimId(provider, objectId) {
|
|
@@ -10703,7 +10869,7 @@ async function loadClaims(lockPaths, opts = {}) {
|
|
|
10703
10869
|
if (!existsSync17(p)) throw new Error(`Claim lockfile not found: ${p}`);
|
|
10704
10870
|
let parsed;
|
|
10705
10871
|
try {
|
|
10706
|
-
parsed = parseLock(JSON.parse(await
|
|
10872
|
+
parsed = parseLock(JSON.parse(await readFile17(p, "utf8")));
|
|
10707
10873
|
} catch {
|
|
10708
10874
|
throw new Error(`Claim lockfile is malformed: ${p}`);
|
|
10709
10875
|
}
|
|
@@ -10984,7 +11150,7 @@ async function workspaceStatus(ws, dir) {
|
|
|
10984
11150
|
|
|
10985
11151
|
// src/pipeline/cache-health.ts
|
|
10986
11152
|
import { existsSync as existsSync18 } from "fs";
|
|
10987
|
-
import { readFile as
|
|
11153
|
+
import { readFile as readFile18, readdir as readdir2, rm as rm8 } from "fs/promises";
|
|
10988
11154
|
import path22 from "path";
|
|
10989
11155
|
async function inspectCaches(lock, lockPath, options = {}) {
|
|
10990
11156
|
if (options.prune && !existsSync18(lockPath)) {
|
|
@@ -11014,7 +11180,7 @@ async function inspectCaches(lock, lockPath, options = {}) {
|
|
|
11014
11180
|
await saveCache(remotePath, { version: 1, hashes: {} });
|
|
11015
11181
|
removed.resetRemoteHashCache = true;
|
|
11016
11182
|
} else if (remoteHashes.invalidIds.length) {
|
|
11017
|
-
const cache = parseCache(JSON.parse(await
|
|
11183
|
+
const cache = parseCache(JSON.parse(await readFile18(remotePath, "utf8")));
|
|
11018
11184
|
for (const id of remoteHashes.invalidIds) delete cache.hashes[id];
|
|
11019
11185
|
removed.remoteHashEntries = remoteHashes.invalidIds.length;
|
|
11020
11186
|
await saveCache(remotePath, cache);
|
|
@@ -11058,7 +11224,7 @@ async function inspectContentCache(contentDir, referenced) {
|
|
|
11058
11224
|
const expected = mediaType ? entry.name.slice(0, -4) : "";
|
|
11059
11225
|
let bytes;
|
|
11060
11226
|
try {
|
|
11061
|
-
bytes = await
|
|
11227
|
+
bytes = await readFile18(file);
|
|
11062
11228
|
report.bytes += bytes.length;
|
|
11063
11229
|
} catch (err) {
|
|
11064
11230
|
report.invalid.push({
|
|
@@ -11105,7 +11271,7 @@ async function inspectRemoteHashCache(remotePath) {
|
|
|
11105
11271
|
if (!report.exists) return report;
|
|
11106
11272
|
let cache;
|
|
11107
11273
|
try {
|
|
11108
|
-
cache = parseCache(JSON.parse(await
|
|
11274
|
+
cache = parseCache(JSON.parse(await readFile18(remotePath, "utf8")));
|
|
11109
11275
|
} catch (err) {
|
|
11110
11276
|
report.error = err instanceof Error ? err.message : String(err);
|
|
11111
11277
|
return report;
|
|
@@ -11376,7 +11542,7 @@ function isRecord2(value) {
|
|
|
11376
11542
|
}
|
|
11377
11543
|
|
|
11378
11544
|
// src/pick/salvage-server.ts
|
|
11379
|
-
import { mkdir as mkdir6, writeFile as writeFile9, readFile as
|
|
11545
|
+
import { mkdir as mkdir6, writeFile as writeFile9, readFile as readFile19 } from "fs/promises";
|
|
11380
11546
|
import path23 from "path";
|
|
11381
11547
|
|
|
11382
11548
|
// src/pick/salvage-sheet.ts
|
|
@@ -11629,7 +11795,7 @@ async function runSalvage(provider, orphans, ctx, opts = {}) {
|
|
|
11629
11795
|
}
|
|
11630
11796
|
}
|
|
11631
11797
|
await applyTags(provider, decisions, existingTags, { onProgress: log2 });
|
|
11632
|
-
const raw = JSON.parse(await
|
|
11798
|
+
const raw = JSON.parse(await readFile19(ctx.manifestPath, "utf8"));
|
|
11633
11799
|
for (const id of importedAssetIds) raw.assets[id] = ctx.manifest.assets[id];
|
|
11634
11800
|
await writeFile9(ctx.manifestPath, JSON.stringify(raw, null, 2) + "\n");
|
|
11635
11801
|
await saveLock(ctx.lockPath, ctx.lock);
|
|
@@ -11641,7 +11807,7 @@ async function runSalvage(provider, orphans, ctx, opts = {}) {
|
|
|
11641
11807
|
// src/recipes.ts
|
|
11642
11808
|
import path24 from "path";
|
|
11643
11809
|
import { existsSync as existsSync19 } from "fs";
|
|
11644
|
-
import { readdir as readdir3, readFile as
|
|
11810
|
+
import { readdir as readdir3, readFile as readFile20 } from "fs/promises";
|
|
11645
11811
|
import { fileURLToPath } from "url";
|
|
11646
11812
|
import { z as z7 } from "zod";
|
|
11647
11813
|
var SHA256_RE = /^[0-9a-f]{64}$/;
|
|
@@ -11829,7 +11995,7 @@ async function readRecipeFile(recipePath, bundled) {
|
|
|
11829
11995
|
const absolute = path24.resolve(recipePath);
|
|
11830
11996
|
let raw;
|
|
11831
11997
|
try {
|
|
11832
|
-
raw = JSON.parse(await
|
|
11998
|
+
raw = JSON.parse(await readFile20(absolute, "utf8"));
|
|
11833
11999
|
} catch (error) {
|
|
11834
12000
|
throw new Error(`Could not read recipe ${absolute}: ${message4(error)}`, { cause: error });
|
|
11835
12001
|
}
|
|
@@ -11971,12 +12137,12 @@ async function installRecipe(target, options = {}) {
|
|
|
11971
12137
|
];
|
|
11972
12138
|
const files = await Promise.all(sources.map(async (file) => ({
|
|
11973
12139
|
path: path24.join(destination, ...file.path.split("/")),
|
|
11974
|
-
data: await
|
|
12140
|
+
data: await readFile20(file.source)
|
|
11975
12141
|
})));
|
|
11976
12142
|
if (!options.force) {
|
|
11977
12143
|
for (const file of files) {
|
|
11978
12144
|
if (!existsSync19(file.path)) continue;
|
|
11979
|
-
const current = await
|
|
12145
|
+
const current = await readFile20(file.path);
|
|
11980
12146
|
if (!current.equals(file.data)) {
|
|
11981
12147
|
throw new Error(
|
|
11982
12148
|
`Recipe destination has local changes: ${file.path}. Choose another --out or pass --force to replace declared recipe files.`
|
|
@@ -12001,7 +12167,7 @@ async function installRecipe(target, options = {}) {
|
|
|
12001
12167
|
// src/pipeline/quality-regression.ts
|
|
12002
12168
|
import path25 from "path";
|
|
12003
12169
|
import { existsSync as existsSync20 } from "fs";
|
|
12004
|
-
import { readFile as
|
|
12170
|
+
import { readFile as readFile21 } from "fs/promises";
|
|
12005
12171
|
import { z as z8 } from "zod";
|
|
12006
12172
|
var SHA256_RE2 = /^[0-9a-f]{64}$/;
|
|
12007
12173
|
var HEX_RE = /^#[0-9a-f]{6}$/;
|
|
@@ -12157,7 +12323,7 @@ async function measureImageQuality(file) {
|
|
|
12157
12323
|
const absolute = path25.resolve(file);
|
|
12158
12324
|
let bytes;
|
|
12159
12325
|
try {
|
|
12160
|
-
bytes = await
|
|
12326
|
+
bytes = await readFile21(absolute);
|
|
12161
12327
|
} catch (error) {
|
|
12162
12328
|
throw new Error(`Cannot read quality image ${absolute}: ${message5(error)}`, { cause: error });
|
|
12163
12329
|
}
|
|
@@ -12244,7 +12410,7 @@ async function snapshotQualityBaseline(inputs, baselinePath, options = {}) {
|
|
|
12244
12410
|
});
|
|
12245
12411
|
const data = Buffer.from(JSON.stringify(baseline, null, 2) + "\n");
|
|
12246
12412
|
if (existsSync20(absolute) && !options.force) {
|
|
12247
|
-
const current = await
|
|
12413
|
+
const current = await readFile21(absolute);
|
|
12248
12414
|
if (!current.equals(data)) {
|
|
12249
12415
|
throw new Error(`Quality baseline already exists with different content: ${absolute}. Pass --force to replace it.`);
|
|
12250
12416
|
}
|
|
@@ -12256,7 +12422,7 @@ async function readQualityBaseline(baselinePath) {
|
|
|
12256
12422
|
const absolute = path25.resolve(baselinePath);
|
|
12257
12423
|
let raw;
|
|
12258
12424
|
try {
|
|
12259
|
-
raw = JSON.parse(await
|
|
12425
|
+
raw = JSON.parse(await readFile21(absolute, "utf8"));
|
|
12260
12426
|
} catch (error) {
|
|
12261
12427
|
throw new Error(`Could not read quality baseline ${absolute}: ${message5(error)}`, { cause: error });
|
|
12262
12428
|
}
|
|
@@ -13054,7 +13220,7 @@ async function main() {
|
|
|
13054
13220
|
}
|
|
13055
13221
|
if (args.command === "--version" || args.command === "-v") {
|
|
13056
13222
|
const pkg = JSON.parse(
|
|
13057
|
-
await
|
|
13223
|
+
await readFile22(new URL("../package.json", import.meta.url), "utf8")
|
|
13058
13224
|
);
|
|
13059
13225
|
log(`${pkg.name} ${pkg.version}`);
|
|
13060
13226
|
return;
|
|
@@ -13065,7 +13231,7 @@ async function main() {
|
|
|
13065
13231
|
if (!args.out) throw new Error("quality snapshot needs --out <pixelkiln.quality.json>.");
|
|
13066
13232
|
let raw;
|
|
13067
13233
|
try {
|
|
13068
|
-
raw = JSON.parse(await
|
|
13234
|
+
raw = JSON.parse(await readFile22(path26.resolve(args.inputs), "utf8"));
|
|
13069
13235
|
} catch (error) {
|
|
13070
13236
|
throw new Error(
|
|
13071
13237
|
`Could not read quality inputs ${path26.resolve(args.inputs)}: ${error instanceof Error ? error.message : String(error)}`,
|
|
@@ -13356,7 +13522,7 @@ async function main() {
|
|
|
13356
13522
|
if (args.primaryOnly || args.outputRoles.length) {
|
|
13357
13523
|
throw new Error("--primary-only and --output-role require manifest-driven pack");
|
|
13358
13524
|
}
|
|
13359
|
-
const raw = JSON.parse(await
|
|
13525
|
+
const raw = JSON.parse(await readFile22(path26.resolve(args.inputs), "utf8"));
|
|
13360
13526
|
const inputs = resolvePackInputs(raw, args.inputs);
|
|
13361
13527
|
const { png, atlas, skipped, sources } = packSprites(inputs, { columns: args.columns });
|
|
13362
13528
|
const base = path26.resolve(args.out.replace(/\.png$/, ""));
|