pixelkiln 0.81.0 → 0.82.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 +105 -50
- package/dist/cli.js.map +1 -1
- package/dist/client/gallery.css +13 -0
- package/dist/client/gallery.js +270 -7
- package/dist/index.cjs +79 -24
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +74 -19
- package/dist/index.js.map +1 -1
- package/docs/CHARACTERS.md +7 -0
- package/docs/CLI.md +7 -0
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -68,7 +68,7 @@ function exitCodeFor(err) {
|
|
|
68
68
|
|
|
69
69
|
// src/cli/main.ts
|
|
70
70
|
import { existsSync as existsSync37 } from "fs";
|
|
71
|
-
import { readFile as
|
|
71
|
+
import { readFile as readFile33 } from "fs/promises";
|
|
72
72
|
|
|
73
73
|
// src/cli/args.ts
|
|
74
74
|
import path from "path";
|
|
@@ -14628,10 +14628,11 @@ import { existsSync as existsSync26 } from "fs";
|
|
|
14628
14628
|
// src/gallery/snapshot.ts
|
|
14629
14629
|
import { createHash as createHash3 } from "crypto";
|
|
14630
14630
|
import { existsSync as existsSync21 } from "fs";
|
|
14631
|
-
import { readFile as
|
|
14631
|
+
import { readFile as readFile19, stat as stat2 } from "fs/promises";
|
|
14632
14632
|
import path30 from "path";
|
|
14633
14633
|
|
|
14634
14634
|
// src/gallery/edit.ts
|
|
14635
|
+
import { readFile as readFile18, rename as rename9, writeFile as writeFile14 } from "fs/promises";
|
|
14635
14636
|
import path28 from "path";
|
|
14636
14637
|
import { z as z10 } from "zod";
|
|
14637
14638
|
|
|
@@ -14876,9 +14877,62 @@ var HandEditRequestSchema = z10.discriminatedUnion("action", [
|
|
|
14876
14877
|
protocol: z10.number().int().positive()
|
|
14877
14878
|
}).strict()
|
|
14878
14879
|
]);
|
|
14880
|
+
var UNDO_DEPTH = 20;
|
|
14881
|
+
var UndoRequestSchema = z10.object({
|
|
14882
|
+
action: z10.literal("undo-edit"),
|
|
14883
|
+
project: z10.string().min(1).optional(),
|
|
14884
|
+
/** The manifest as the page last saw it; undo refuses a manifest someone else has changed since. */
|
|
14885
|
+
expectedSha256: z10.string().regex(/^[0-9a-f]{64}$/)
|
|
14886
|
+
}).strict();
|
|
14879
14887
|
function createGalleryEditHandler(opts) {
|
|
14880
14888
|
const log2 = opts.onProgress ?? (() => {
|
|
14881
14889
|
});
|
|
14890
|
+
const apply = createEditApplier(opts, log2);
|
|
14891
|
+
const history = /* @__PURE__ */ new Map();
|
|
14892
|
+
const manifestOf = async (project) => {
|
|
14893
|
+
try {
|
|
14894
|
+
return path28.resolve(await opts.manifestFor(typeof project === "string" ? project : void 0));
|
|
14895
|
+
} catch {
|
|
14896
|
+
return null;
|
|
14897
|
+
}
|
|
14898
|
+
};
|
|
14899
|
+
return async (body) => {
|
|
14900
|
+
const undo = UndoRequestSchema.safeParse(body);
|
|
14901
|
+
if (undo.success) {
|
|
14902
|
+
const manifestPath2 = await manifestOf(undo.data.project);
|
|
14903
|
+
if (!manifestPath2) throw new ManifestEditError("no manifest to undo an edit in");
|
|
14904
|
+
const current = await readFile18(manifestPath2, "utf8");
|
|
14905
|
+
if (sha256(current) !== undo.data.expectedSha256) throw new ManifestDriftError(manifestPath2);
|
|
14906
|
+
const stack = history.get(manifestPath2) ?? [];
|
|
14907
|
+
const last = stack[stack.length - 1];
|
|
14908
|
+
if (!last) throw new ManifestEditError("nothing to undo: this gallery has not changed the manifest");
|
|
14909
|
+
if (last.afterSha !== sha256(current)) {
|
|
14910
|
+
history.delete(manifestPath2);
|
|
14911
|
+
throw Object.assign(new Error("the manifest changed outside the gallery since its last edit; undo would discard that change"), { status: 409 });
|
|
14912
|
+
}
|
|
14913
|
+
const tmp = manifestPath2 + ".pixelkiln-undo";
|
|
14914
|
+
await writeFile14(tmp, last.before);
|
|
14915
|
+
await rename9(tmp, manifestPath2);
|
|
14916
|
+
stack.pop();
|
|
14917
|
+
log2(` manifest edit undone in ${path28.relative(process.cwd(), manifestPath2) || manifestPath2}`);
|
|
14918
|
+
return opts.reload();
|
|
14919
|
+
}
|
|
14920
|
+
const manifestPath = await manifestOf(body?.project);
|
|
14921
|
+
const before = manifestPath ? await readFile18(manifestPath, "utf8").catch(() => null) : null;
|
|
14922
|
+
const build = await apply(body);
|
|
14923
|
+
if (manifestPath && before !== null) {
|
|
14924
|
+
const after = await readFile18(manifestPath, "utf8").catch(() => null);
|
|
14925
|
+
if (after !== null && after !== before) {
|
|
14926
|
+
const stack = history.get(manifestPath) ?? [];
|
|
14927
|
+
stack.push({ before, afterSha: sha256(after) });
|
|
14928
|
+
if (stack.length > UNDO_DEPTH) stack.shift();
|
|
14929
|
+
history.set(manifestPath, stack);
|
|
14930
|
+
}
|
|
14931
|
+
}
|
|
14932
|
+
return build;
|
|
14933
|
+
};
|
|
14934
|
+
}
|
|
14935
|
+
function createEditApplier(opts, log2) {
|
|
14882
14936
|
return async (body) => {
|
|
14883
14937
|
const handEdit = HandEditRequestSchema.safeParse(body);
|
|
14884
14938
|
if (handEdit.success) {
|
|
@@ -15220,7 +15274,7 @@ function describeHistory(media, entry, cacheDir) {
|
|
|
15220
15274
|
var MAX_COMPARED_BYTES = 8 * 1024 * 1024;
|
|
15221
15275
|
async function samePixels(a, b) {
|
|
15222
15276
|
try {
|
|
15223
|
-
const [left, right] = await Promise.all([
|
|
15277
|
+
const [left, right] = await Promise.all([readFile19(a), readFile19(b)]);
|
|
15224
15278
|
if (left.length > MAX_COMPARED_BYTES || right.length > MAX_COMPARED_BYTES) return false;
|
|
15225
15279
|
const x = decodePng(left);
|
|
15226
15280
|
const y = decodePng(right);
|
|
@@ -15378,7 +15432,7 @@ async function buildGallerySnapshot(opts) {
|
|
|
15378
15432
|
const media = /* @__PURE__ */ new Map();
|
|
15379
15433
|
const plan = await buildPlan(specs, lock);
|
|
15380
15434
|
const items = [];
|
|
15381
|
-
const manifestText = await
|
|
15435
|
+
const manifestText = await readFile19(loaded.path, "utf8");
|
|
15382
15436
|
const manifestSha256 = sha256(manifestText);
|
|
15383
15437
|
const cacheDir = path30.resolve(path30.dirname(opts.lockPath), ".pixelkiln", "cache");
|
|
15384
15438
|
let rawStyles = {};
|
|
@@ -15730,7 +15784,7 @@ async function buildWorkspaceGallerySnapshot(opts) {
|
|
|
15730
15784
|
root: loaded.root,
|
|
15731
15785
|
provider: loaded.manifest.provider,
|
|
15732
15786
|
account: project.account ?? null,
|
|
15733
|
-
manifestSha256: manifestSha256 ?? sha256(await
|
|
15787
|
+
manifestSha256: manifestSha256 ?? sha256(await readFile19(manifestPath, "utf8")),
|
|
15734
15788
|
historyLimit: historyLimit(loaded.manifest),
|
|
15735
15789
|
entries: Object.keys(lock.entries).length,
|
|
15736
15790
|
items: projectItems.length,
|
|
@@ -15789,7 +15843,7 @@ async function buildWorkspaceGallerySnapshot(opts) {
|
|
|
15789
15843
|
// src/gallery/server.ts
|
|
15790
15844
|
import { randomBytes } from "crypto";
|
|
15791
15845
|
import { createServer as createServer2 } from "http";
|
|
15792
|
-
import { readFile as
|
|
15846
|
+
import { readFile as readFile20 } from "fs/promises";
|
|
15793
15847
|
|
|
15794
15848
|
// src/gallery/page.ts
|
|
15795
15849
|
import { existsSync as existsSync22, readFileSync as readFileSync4 } from "fs";
|
|
@@ -15900,6 +15954,7 @@ ${css}</style>
|
|
|
15900
15954
|
</header>
|
|
15901
15955
|
<main id="root"></main>
|
|
15902
15956
|
<div id="selbar" class="selbar" hidden></div>
|
|
15957
|
+
<div id="toast" class="toast" role="status" aria-live="polite" hidden></div>
|
|
15903
15958
|
<footer>
|
|
15904
15959
|
Click a sprite for its full record; press <kbd>?</kbd> for every keyboard shortcut. This page reads the manifest, lockfile,
|
|
15905
15960
|
and disk only. It never contacts a provider<span id="foot-edit"> and never writes anything</span><span id="foot-editing" hidden>.
|
|
@@ -16103,7 +16158,7 @@ async function serveGallery(opts) {
|
|
|
16103
16158
|
const asset = reviewAssets.get(jobId)?.get(url2.pathname);
|
|
16104
16159
|
if (!asset) return fail(404, "no such review asset");
|
|
16105
16160
|
try {
|
|
16106
|
-
const bytes = await
|
|
16161
|
+
const bytes = await readFile20(asset.path);
|
|
16107
16162
|
res.writeHead(200, {
|
|
16108
16163
|
"Content-Type": asset.contentType,
|
|
16109
16164
|
"Cache-Control": "no-store",
|
|
@@ -16186,7 +16241,7 @@ async function serveGallery(opts) {
|
|
|
16186
16241
|
if (!asset) return fail(404, "no such gallery media");
|
|
16187
16242
|
let bytes;
|
|
16188
16243
|
try {
|
|
16189
|
-
bytes = await
|
|
16244
|
+
bytes = await readFile20(asset.path);
|
|
16190
16245
|
} catch {
|
|
16191
16246
|
return fail(404, "gallery media is no longer on disk; refresh the page");
|
|
16192
16247
|
}
|
|
@@ -16642,10 +16697,10 @@ function ownedReferenceImageId(spec, lock, providerId) {
|
|
|
16642
16697
|
|
|
16643
16698
|
// src/pick/server.ts
|
|
16644
16699
|
import { existsSync as existsSync24 } from "fs";
|
|
16645
|
-
import { readFile as
|
|
16700
|
+
import { readFile as readFile22 } from "fs/promises";
|
|
16646
16701
|
|
|
16647
16702
|
// src/pipeline/init.ts
|
|
16648
|
-
import { readdir, readFile as
|
|
16703
|
+
import { readdir, readFile as readFile21, writeFile as writeFile15 } from "fs/promises";
|
|
16649
16704
|
import { existsSync as existsSync23 } from "fs";
|
|
16650
16705
|
import path31 from "path";
|
|
16651
16706
|
function pngSize(buf) {
|
|
@@ -16675,7 +16730,7 @@ async function scanAssets(root, opts = {}) {
|
|
|
16675
16730
|
const skipped = [];
|
|
16676
16731
|
const seen = /* @__PURE__ */ new Map();
|
|
16677
16732
|
for (const file of files.sort()) {
|
|
16678
|
-
const size = pngSize(await
|
|
16733
|
+
const size = pngSize(await readFile21(file));
|
|
16679
16734
|
if (!size) {
|
|
16680
16735
|
skipped.push(`${file} (not a readable PNG)`);
|
|
16681
16736
|
continue;
|
|
@@ -16743,7 +16798,7 @@ async function writeManifestFile(target, manifest) {
|
|
|
16743
16798
|
if (existsSync23(target)) {
|
|
16744
16799
|
throw new Error(`${target} already exists; refusing to overwrite an existing manifest.`);
|
|
16745
16800
|
}
|
|
16746
|
-
await
|
|
16801
|
+
await writeFile15(target, JSON.stringify(manifest, null, 2) + "\n");
|
|
16747
16802
|
}
|
|
16748
16803
|
|
|
16749
16804
|
// src/pick/sheet.ts
|
|
@@ -17162,7 +17217,7 @@ async function currentArt(entry, spec) {
|
|
|
17162
17217
|
let width = entry.width;
|
|
17163
17218
|
let height = entry.height;
|
|
17164
17219
|
if (contentType === "image/png") {
|
|
17165
|
-
const size = pngSize(await
|
|
17220
|
+
const size = pngSize(await readFile22(file));
|
|
17166
17221
|
if (size) ({ width, height } = size);
|
|
17167
17222
|
}
|
|
17168
17223
|
return { path: file, contentType, width, height };
|
|
@@ -17695,13 +17750,13 @@ function createGenerateHandlers(opts) {
|
|
|
17695
17750
|
}
|
|
17696
17751
|
|
|
17697
17752
|
// src/gallery/editor.ts
|
|
17698
|
-
import { readFile as
|
|
17753
|
+
import { readFile as readFile24 } from "fs/promises";
|
|
17699
17754
|
import path33 from "path";
|
|
17700
17755
|
|
|
17701
17756
|
// src/editor/install.ts
|
|
17702
17757
|
import { createHash as createHash4 } from "crypto";
|
|
17703
17758
|
import { existsSync as existsSync25 } from "fs";
|
|
17704
|
-
import { mkdir as mkdir12, readFile as
|
|
17759
|
+
import { mkdir as mkdir12, readFile as readFile23, rename as rename10, rm as rm10, stat as stat3, writeFile as writeFile16 } from "fs/promises";
|
|
17705
17760
|
import os2 from "os";
|
|
17706
17761
|
import path32 from "path";
|
|
17707
17762
|
|
|
@@ -17785,7 +17840,7 @@ function editorBaseUrl(pin = EDITOR_PIN) {
|
|
|
17785
17840
|
}
|
|
17786
17841
|
async function sha256Of(file) {
|
|
17787
17842
|
try {
|
|
17788
|
-
return createHash4("sha256").update(await
|
|
17843
|
+
return createHash4("sha256").update(await readFile23(file)).digest("hex");
|
|
17789
17844
|
} catch {
|
|
17790
17845
|
return null;
|
|
17791
17846
|
}
|
|
@@ -17859,8 +17914,8 @@ async function installEditor(opts = {}) {
|
|
|
17859
17914
|
const final = path32.join(dir, name);
|
|
17860
17915
|
const tmp = `${final}.${process.pid}.part`;
|
|
17861
17916
|
try {
|
|
17862
|
-
await
|
|
17863
|
-
await
|
|
17917
|
+
await writeFile16(tmp, bytes);
|
|
17918
|
+
await rename10(tmp, final);
|
|
17864
17919
|
} finally {
|
|
17865
17920
|
await rm10(tmp, { force: true });
|
|
17866
17921
|
}
|
|
@@ -17978,7 +18033,7 @@ function createGalleryEditorHandlers(opts = {}) {
|
|
|
17978
18033
|
if (!status.installed) return null;
|
|
17979
18034
|
let bytes;
|
|
17980
18035
|
try {
|
|
17981
|
-
bytes = await
|
|
18036
|
+
bytes = await readFile24(path33.join(dir, name));
|
|
17982
18037
|
} catch {
|
|
17983
18038
|
verified = null;
|
|
17984
18039
|
return null;
|
|
@@ -18445,7 +18500,7 @@ import { existsSync as existsSync28 } from "fs";
|
|
|
18445
18500
|
|
|
18446
18501
|
// src/pipeline/cache-health.ts
|
|
18447
18502
|
import { existsSync as existsSync27 } from "fs";
|
|
18448
|
-
import { readFile as
|
|
18503
|
+
import { readFile as readFile25, readdir as readdir2, rm as rm11 } from "fs/promises";
|
|
18449
18504
|
import path35 from "path";
|
|
18450
18505
|
async function inspectCaches(lock, lockPath, options = {}) {
|
|
18451
18506
|
if (options.prune && !existsSync27(lockPath)) {
|
|
@@ -18473,7 +18528,7 @@ async function inspectCaches(lock, lockPath, options = {}) {
|
|
|
18473
18528
|
await saveCache(remotePath, { version: 1, hashes: {} });
|
|
18474
18529
|
removed.resetRemoteHashCache = true;
|
|
18475
18530
|
} else if (remoteHashes.invalidIds.length) {
|
|
18476
|
-
const cache = parseCache(JSON.parse(await
|
|
18531
|
+
const cache = parseCache(JSON.parse(await readFile25(remotePath, "utf8")));
|
|
18477
18532
|
for (const id of remoteHashes.invalidIds) delete cache.hashes[id];
|
|
18478
18533
|
removed.remoteHashEntries = remoteHashes.invalidIds.length;
|
|
18479
18534
|
await saveCache(remotePath, cache);
|
|
@@ -18517,7 +18572,7 @@ async function inspectContentCache(contentDir, referenced) {
|
|
|
18517
18572
|
const expected = mediaType ? entry.name.slice(0, -4) : "";
|
|
18518
18573
|
let bytes;
|
|
18519
18574
|
try {
|
|
18520
|
-
bytes = await
|
|
18575
|
+
bytes = await readFile25(file);
|
|
18521
18576
|
report.bytes += bytes.length;
|
|
18522
18577
|
} catch (err) {
|
|
18523
18578
|
report.invalid.push({
|
|
@@ -18564,7 +18619,7 @@ async function inspectRemoteHashCache(remotePath) {
|
|
|
18564
18619
|
if (!report.exists) return report;
|
|
18565
18620
|
let cache;
|
|
18566
18621
|
try {
|
|
18567
|
-
cache = parseCache(JSON.parse(await
|
|
18622
|
+
cache = parseCache(JSON.parse(await readFile25(remotePath, "utf8")));
|
|
18568
18623
|
} catch (err) {
|
|
18569
18624
|
report.error = err instanceof Error ? err.message : String(err);
|
|
18570
18625
|
return report;
|
|
@@ -18891,7 +18946,7 @@ async function nearestExistingDirectory(start) {
|
|
|
18891
18946
|
}
|
|
18892
18947
|
|
|
18893
18948
|
// src/pipeline/audit.ts
|
|
18894
|
-
import { readFile as
|
|
18949
|
+
import { readFile as readFile26 } from "fs/promises";
|
|
18895
18950
|
import { existsSync as existsSync31 } from "fs";
|
|
18896
18951
|
import path38 from "path";
|
|
18897
18952
|
function paletteDistance(asset, reference) {
|
|
@@ -18934,7 +18989,7 @@ async function auditStyle(loaded, specs, styleId, lock) {
|
|
|
18934
18989
|
continue;
|
|
18935
18990
|
}
|
|
18936
18991
|
try {
|
|
18937
|
-
const png = decodePng(await
|
|
18992
|
+
const png = decodePng(await readFile26(output.absolutePath));
|
|
18938
18993
|
const palette = extractPalette(png, 12);
|
|
18939
18994
|
assets.push({
|
|
18940
18995
|
assetId: spec.assetId,
|
|
@@ -18961,7 +19016,7 @@ async function auditStyle(loaded, specs, styleId, lock) {
|
|
|
18961
19016
|
const abs = path38.resolve(loaded.root, img.path);
|
|
18962
19017
|
if (!existsSync31(abs)) continue;
|
|
18963
19018
|
try {
|
|
18964
|
-
refPalettes.push(extractPalette(decodePng(await
|
|
19019
|
+
refPalettes.push(extractPalette(decodePng(await readFile26(abs)), 12));
|
|
18965
19020
|
} catch {
|
|
18966
19021
|
}
|
|
18967
19022
|
}
|
|
@@ -19190,7 +19245,7 @@ async function runAudit(args) {
|
|
|
19190
19245
|
|
|
19191
19246
|
// src/cli/commands/pack.ts
|
|
19192
19247
|
import path40 from "path";
|
|
19193
|
-
import { readFile as
|
|
19248
|
+
import { readFile as readFile27 } from "fs/promises";
|
|
19194
19249
|
|
|
19195
19250
|
// src/pipeline/pack.ts
|
|
19196
19251
|
import { readFileSync as readFileSync5 } from "fs";
|
|
@@ -19903,7 +19958,7 @@ async function runPack(args) {
|
|
|
19903
19958
|
if (args.primaryOnly || args.outputRoles.length) {
|
|
19904
19959
|
throw new Error("--primary-only and --output-role require manifest-driven pack");
|
|
19905
19960
|
}
|
|
19906
|
-
const raw = JSON.parse(await
|
|
19961
|
+
const raw = JSON.parse(await readFile27(path40.resolve(args.inputs), "utf8"));
|
|
19907
19962
|
const inputs = resolvePackInputs(raw, args.inputs);
|
|
19908
19963
|
const { png, atlas, skipped, sources } = packSprites(inputs, { columns: args.columns });
|
|
19909
19964
|
const format = sheetFormat(args);
|
|
@@ -20132,7 +20187,7 @@ import path42 from "path";
|
|
|
20132
20187
|
|
|
20133
20188
|
// src/pixellab-utils.ts
|
|
20134
20189
|
import { existsSync as existsSync32 } from "fs";
|
|
20135
|
-
import { mkdir as mkdir13, readFile as
|
|
20190
|
+
import { mkdir as mkdir13, readFile as readFile28, writeFile as writeFile17 } from "fs/promises";
|
|
20136
20191
|
import path41 from "path";
|
|
20137
20192
|
var UNZOOM_MIN_SIDE = 256;
|
|
20138
20193
|
var UNZOOM_MAX_AREA = 2048 * 2048;
|
|
@@ -20144,7 +20199,7 @@ async function unzoomFile(client2, input, opts = {}) {
|
|
|
20144
20199
|
const out = path41.resolve(opts.out ?? defaultUnzoomOut(input));
|
|
20145
20200
|
if (path41.resolve(input) === out) throw new Error("unzoom will not overwrite its own input; pass a different --out");
|
|
20146
20201
|
if (existsSync32(out) && !opts.force) throw new Error(`${out} already exists; pass --force to replace it`);
|
|
20147
|
-
const bytes = await
|
|
20202
|
+
const bytes = await readFile28(input);
|
|
20148
20203
|
const metadata = imageMetadata(bytes);
|
|
20149
20204
|
if (!metadata) throw new Error(`${input} is not a readable PNG or JPEG`);
|
|
20150
20205
|
const { width, height, format } = metadata;
|
|
@@ -20158,7 +20213,7 @@ async function unzoomFile(client2, input, opts = {}) {
|
|
|
20158
20213
|
}
|
|
20159
20214
|
const res = await client2.unzoom({ image: { base64: bytes.toString("base64"), format }, quantize: opts.quantize });
|
|
20160
20215
|
await mkdir13(path41.dirname(out), { recursive: true });
|
|
20161
|
-
await
|
|
20216
|
+
await writeFile17(out, res.png);
|
|
20162
20217
|
return { out, original: res.originalSize, unzoomed: res.unzoomedSize, zoomFactor: res.zoomFactor, usage: res.usage };
|
|
20163
20218
|
}
|
|
20164
20219
|
var FONT_WEIGHTS = ["Bold", "Regular"];
|
|
@@ -20200,8 +20255,8 @@ async function generateFont(client2, opts) {
|
|
|
20200
20255
|
client2.download(job.download_atlas_url)
|
|
20201
20256
|
]);
|
|
20202
20257
|
await mkdir13(path41.dirname(ttf), { recursive: true });
|
|
20203
|
-
await
|
|
20204
|
-
await
|
|
20258
|
+
await writeFile17(ttf, ttfBytes);
|
|
20259
|
+
await writeFile17(atlas, atlasBytes);
|
|
20205
20260
|
return { jobId, ttf, atlas, glyphPx: job.glyph_px ?? null, usage: job.usage };
|
|
20206
20261
|
}
|
|
20207
20262
|
if (Date.now() - started > timeout) {
|
|
@@ -20282,12 +20337,12 @@ async function runFont(args) {
|
|
|
20282
20337
|
|
|
20283
20338
|
// src/cli/commands/quality.ts
|
|
20284
20339
|
import path44 from "path";
|
|
20285
|
-
import { readFile as
|
|
20340
|
+
import { readFile as readFile30 } from "fs/promises";
|
|
20286
20341
|
|
|
20287
20342
|
// src/pipeline/quality-regression.ts
|
|
20288
20343
|
import path43 from "path";
|
|
20289
20344
|
import { existsSync as existsSync33 } from "fs";
|
|
20290
|
-
import { readFile as
|
|
20345
|
+
import { readFile as readFile29 } from "fs/promises";
|
|
20291
20346
|
import { z as z12 } from "zod";
|
|
20292
20347
|
var SHA256_RE = /^[0-9a-f]{64}$/;
|
|
20293
20348
|
var HEX_RE = /^#[0-9a-f]{6}$/;
|
|
@@ -20443,7 +20498,7 @@ async function measureImageQuality(file) {
|
|
|
20443
20498
|
const absolute = path43.resolve(file);
|
|
20444
20499
|
let bytes;
|
|
20445
20500
|
try {
|
|
20446
|
-
bytes = await
|
|
20501
|
+
bytes = await readFile29(absolute);
|
|
20447
20502
|
} catch (error) {
|
|
20448
20503
|
throw new Error(`Cannot read quality image ${absolute}: ${message4(error)}`, { cause: error });
|
|
20449
20504
|
}
|
|
@@ -20530,7 +20585,7 @@ async function snapshotQualityBaseline(inputs, baselinePath, options = {}) {
|
|
|
20530
20585
|
});
|
|
20531
20586
|
const data = Buffer.from(JSON.stringify(baseline, null, 2) + "\n");
|
|
20532
20587
|
if (existsSync33(absolute) && !options.force) {
|
|
20533
|
-
const current = await
|
|
20588
|
+
const current = await readFile29(absolute);
|
|
20534
20589
|
if (!current.equals(data)) {
|
|
20535
20590
|
throw new OverwriteRefusedError(
|
|
20536
20591
|
`Quality baseline already exists with different content: ${absolute}. Pass --force to replace it.`,
|
|
@@ -20545,7 +20600,7 @@ async function readQualityBaseline(baselinePath) {
|
|
|
20545
20600
|
const absolute = path43.resolve(baselinePath);
|
|
20546
20601
|
let raw;
|
|
20547
20602
|
try {
|
|
20548
|
-
raw = JSON.parse(await
|
|
20603
|
+
raw = JSON.parse(await readFile29(absolute, "utf8"));
|
|
20549
20604
|
} catch (error) {
|
|
20550
20605
|
throw new Error(`Could not read quality baseline ${absolute}: ${message4(error)}`, { cause: error });
|
|
20551
20606
|
}
|
|
@@ -20675,7 +20730,7 @@ async function runQuality(args) {
|
|
|
20675
20730
|
if (!args.out) throw new Error("quality snapshot needs --out <pixelkiln.quality.json>.");
|
|
20676
20731
|
let raw;
|
|
20677
20732
|
try {
|
|
20678
|
-
raw = JSON.parse(await
|
|
20733
|
+
raw = JSON.parse(await readFile30(path44.resolve(args.inputs), "utf8"));
|
|
20679
20734
|
} catch (error) {
|
|
20680
20735
|
throw new Error(
|
|
20681
20736
|
`Could not read quality inputs ${path44.resolve(args.inputs)}: ${error instanceof Error ? error.message : String(error)}`,
|
|
@@ -20727,7 +20782,7 @@ import path46 from "path";
|
|
|
20727
20782
|
// src/recipes.ts
|
|
20728
20783
|
import path45 from "path";
|
|
20729
20784
|
import { existsSync as existsSync34 } from "fs";
|
|
20730
|
-
import { readdir as readdir3, readFile as
|
|
20785
|
+
import { readdir as readdir3, readFile as readFile31 } from "fs/promises";
|
|
20731
20786
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
20732
20787
|
import { z as z13 } from "zod";
|
|
20733
20788
|
var SHA256_RE2 = /^[0-9a-f]{64}$/;
|
|
@@ -20915,7 +20970,7 @@ async function readRecipeFile(recipePath, bundled) {
|
|
|
20915
20970
|
const absolute = path45.resolve(recipePath);
|
|
20916
20971
|
let raw;
|
|
20917
20972
|
try {
|
|
20918
|
-
raw = JSON.parse(await
|
|
20973
|
+
raw = JSON.parse(await readFile31(absolute, "utf8"));
|
|
20919
20974
|
} catch (error) {
|
|
20920
20975
|
throw new Error(`Could not read recipe ${absolute}: ${message5(error)}`, { cause: error });
|
|
20921
20976
|
}
|
|
@@ -21057,12 +21112,12 @@ async function installRecipe(target, options = {}) {
|
|
|
21057
21112
|
];
|
|
21058
21113
|
const files = await Promise.all(sources.map(async (file) => ({
|
|
21059
21114
|
path: path45.join(destination, ...file.path.split("/")),
|
|
21060
|
-
data: await
|
|
21115
|
+
data: await readFile31(file.source)
|
|
21061
21116
|
})));
|
|
21062
21117
|
if (!options.force) {
|
|
21063
21118
|
for (const file of files) {
|
|
21064
21119
|
if (!existsSync34(file.path)) continue;
|
|
21065
|
-
const current = await
|
|
21120
|
+
const current = await readFile31(file.path);
|
|
21066
21121
|
if (!current.equals(file.data)) {
|
|
21067
21122
|
throw new OverwriteRefusedError(
|
|
21068
21123
|
`Recipe destination has local changes: ${file.path}. Choose another --out or pass --force to replace declared recipe files.`,
|
|
@@ -21302,7 +21357,7 @@ async function runRefine(args) {
|
|
|
21302
21357
|
// src/cli/commands/skeleton.ts
|
|
21303
21358
|
import path48 from "path";
|
|
21304
21359
|
import { existsSync as existsSync35 } from "fs";
|
|
21305
|
-
import { readFile as
|
|
21360
|
+
import { readFile as readFile32, writeFile as writeFile18 } from "fs/promises";
|
|
21306
21361
|
|
|
21307
21362
|
// src/skeleton-preview.ts
|
|
21308
21363
|
var RIGHT = [255, 140, 40, 255];
|
|
@@ -21418,7 +21473,7 @@ async function runEstimateSkeleton(args) {
|
|
|
21418
21473
|
}
|
|
21419
21474
|
loadEnvFiles(path48.dirname(path48.resolve(args.manifest)));
|
|
21420
21475
|
loadEnvFiles(process.cwd());
|
|
21421
|
-
const bytes = await
|
|
21476
|
+
const bytes = await readFile32(path48.resolve(image));
|
|
21422
21477
|
const metadata = imageMetadata(bytes);
|
|
21423
21478
|
if (!metadata) throw new UsageError(`${image} is not a readable PNG or JPEG`);
|
|
21424
21479
|
const sizeProblem = estimateSkeletonSizeProblem(metadata.width, metadata.height);
|
|
@@ -21430,7 +21485,7 @@ async function runEstimateSkeleton(args) {
|
|
|
21430
21485
|
const frames = args.frames ?? DEFAULT_SCAFFOLD_FRAMES;
|
|
21431
21486
|
const json = JSON.stringify(scaffoldSkeletonSet(res.keypoints, frames), null, 2);
|
|
21432
21487
|
if (args.out) {
|
|
21433
|
-
await
|
|
21488
|
+
await writeFile18(path48.resolve(args.out), json + "\n");
|
|
21434
21489
|
log(` wrote ${args.out}: the estimated pose and ${frames} frames to edit`);
|
|
21435
21490
|
log(` preview it with: pixelkiln skeleton-preview ${args.out} --from ${image}`);
|
|
21436
21491
|
} else {
|
|
@@ -21462,7 +21517,7 @@ async function runSkeletonPreview(args) {
|
|
|
21462
21517
|
if (!existsSync35(keypointsFile)) throw new UsageError(`Keypoints file does not exist yet: ${keypointsFile}`);
|
|
21463
21518
|
let json;
|
|
21464
21519
|
try {
|
|
21465
|
-
json = JSON.parse(await
|
|
21520
|
+
json = JSON.parse(await readFile32(keypointsFile, "utf8"));
|
|
21466
21521
|
} catch (error) {
|
|
21467
21522
|
throw new UsageError(`${keypointsFile} is not valid JSON: ${error instanceof Error ? error.message : String(error)}`);
|
|
21468
21523
|
}
|
|
@@ -21472,13 +21527,13 @@ async function runSkeletonPreview(args) {
|
|
|
21472
21527
|
if (!existsSync35(sourceFile)) {
|
|
21473
21528
|
log(` source image does not exist yet, drawing on a plain ground: ${sourceFile}`);
|
|
21474
21529
|
} else {
|
|
21475
|
-
const bytes = await
|
|
21530
|
+
const bytes = await readFile32(sourceFile);
|
|
21476
21531
|
if (imageMetadata(bytes)?.format !== "png") throw new UsageError(`${sourceFile} must be a PNG to preview over`);
|
|
21477
21532
|
source = decodePng(bytes);
|
|
21478
21533
|
}
|
|
21479
21534
|
}
|
|
21480
21535
|
const out = path48.resolve(args.out ?? keypointsFile.replace(/\.json$/, "") + ".preview.png");
|
|
21481
|
-
await
|
|
21536
|
+
await writeFile18(out, renderSkeletonSheet(set, { source }));
|
|
21482
21537
|
log(` ${label}: ${set.frames.length} frames after the starting pose`);
|
|
21483
21538
|
const shown = path48.relative(process.cwd(), out);
|
|
21484
21539
|
log(` wrote ${shown.startsWith("..") ? out : shown}`);
|
|
@@ -21664,7 +21719,7 @@ async function runVersion() {
|
|
|
21664
21719
|
for (const up of ["../package.json", "../../package.json"]) {
|
|
21665
21720
|
const url = new URL(up, import.meta.url);
|
|
21666
21721
|
if (!existsSync37(url)) continue;
|
|
21667
|
-
const pkg = JSON.parse(await
|
|
21722
|
+
const pkg = JSON.parse(await readFile33(url, "utf8"));
|
|
21668
21723
|
if (pkg.name === "pixelkiln") {
|
|
21669
21724
|
log(`${pkg.name} ${pkg.version}`);
|
|
21670
21725
|
return;
|