@koda-sl/baker-cli 0.34.3 → 0.36.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 +145 -0
- package/dist/cli.js +1 -1
- package/dist/client.d.ts +1 -1
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js.map +1 -1
- package/dist/commands/actions/index.d.ts.map +1 -1
- package/dist/commands/actions/index.js +4 -1
- package/dist/commands/actions/index.js.map +1 -1
- package/dist/commands/actions/status.d.ts +8 -0
- package/dist/commands/actions/status.d.ts.map +1 -0
- package/dist/commands/actions/status.js +38 -0
- package/dist/commands/actions/status.js.map +1 -0
- package/dist/commands/images/crop.d.ts +33 -0
- package/dist/commands/images/crop.d.ts.map +1 -0
- package/dist/commands/images/crop.js +90 -0
- package/dist/commands/images/crop.js.map +1 -0
- package/dist/commands/images/dimensions.d.ts +8 -0
- package/dist/commands/images/dimensions.d.ts.map +1 -0
- package/dist/commands/images/dimensions.js +56 -0
- package/dist/commands/images/dimensions.js.map +1 -0
- package/dist/commands/images/index.d.ts.map +1 -1
- package/dist/commands/images/index.js +20 -2
- package/dist/commands/images/index.js.map +1 -1
- package/dist/commands/images/normalize.d.ts +54 -0
- package/dist/commands/images/normalize.d.ts.map +1 -0
- package/dist/commands/images/normalize.js +252 -0
- package/dist/commands/images/normalize.js.map +1 -0
- package/dist/commands/images/upscale.d.ts +13 -0
- package/dist/commands/images/upscale.d.ts.map +1 -0
- package/dist/commands/images/upscale.js +73 -0
- package/dist/commands/images/upscale.js.map +1 -0
- package/dist/lib/image/color-changer.d.ts +16 -0
- package/dist/lib/image/color-changer.d.ts.map +1 -0
- package/dist/lib/image/color-changer.js +366 -0
- package/dist/lib/image/color-changer.js.map +1 -0
- package/dist/lib/image/color-changer.test.d.ts +2 -0
- package/dist/lib/image/color-changer.test.d.ts.map +1 -0
- package/dist/lib/image/color-changer.test.js +131 -0
- package/dist/lib/image/color-changer.test.js.map +1 -0
- package/dist/lib/image/crop-sprite.d.ts +9 -0
- package/dist/lib/image/crop-sprite.d.ts.map +1 -0
- package/dist/lib/image/crop-sprite.js +13 -0
- package/dist/lib/image/crop-sprite.js.map +1 -0
- package/dist/lib/image/dimensions.d.ts +9 -0
- package/dist/lib/image/dimensions.d.ts.map +1 -0
- package/dist/lib/image/dimensions.js +13 -0
- package/dist/lib/image/dimensions.js.map +1 -0
- package/dist/lib/image/image-processor.d.ts +26 -0
- package/dist/lib/image/image-processor.d.ts.map +1 -0
- package/dist/lib/image/image-processor.js +185 -0
- package/dist/lib/image/image-processor.js.map +1 -0
- package/dist/lib/image/io.d.ts +29 -0
- package/dist/lib/image/io.d.ts.map +1 -0
- package/dist/lib/image/io.js +90 -0
- package/dist/lib/image/io.js.map +1 -0
- package/package.json +5 -1
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
import sharp from "sharp";
|
|
2
|
+
import { applyQuantization, COLOR_RANGE_THRESHOLD, colorDistance, findColorRange, findColorRangeWithThreshold, getDominantEdgeColor, hasTransparency, removeBackground, solidifyEdges, } from "./color-changer.js";
|
|
3
|
+
function hasGradient(data) {
|
|
4
|
+
const uniqueColors = new Set();
|
|
5
|
+
for (let i = 0; i < data.length; i += 4) {
|
|
6
|
+
if (data[i + 3] < 10)
|
|
7
|
+
continue;
|
|
8
|
+
uniqueColors.add(`${data[i]},${data[i + 1]},${data[i + 2]}`);
|
|
9
|
+
}
|
|
10
|
+
return uniqueColors.size > 50;
|
|
11
|
+
}
|
|
12
|
+
async function processGradient(data, info) {
|
|
13
|
+
if (!hasGradient(data))
|
|
14
|
+
return { data, info };
|
|
15
|
+
const solidified = solidifyEdges(data, 0.1);
|
|
16
|
+
const blurred = await sharp(solidified, {
|
|
17
|
+
raw: { channels: 4, width: info.width, height: info.height },
|
|
18
|
+
})
|
|
19
|
+
.png()
|
|
20
|
+
.blur(0.3)
|
|
21
|
+
.toBuffer();
|
|
22
|
+
const result = await sharp(blurred).ensureAlpha().raw().toBuffer({ resolveWithObject: true });
|
|
23
|
+
return { data: result.data, info: result.info };
|
|
24
|
+
}
|
|
25
|
+
function isSvgBuffer(buffer) {
|
|
26
|
+
const head = buffer.subarray(0, Math.min(buffer.length, 512)).toString("utf8").trimStart();
|
|
27
|
+
return head.startsWith("<?xml") ? head.includes("<svg") : head.startsWith("<svg");
|
|
28
|
+
}
|
|
29
|
+
async function processInternal(inputBuffer, isSVG, options) {
|
|
30
|
+
const stages = [];
|
|
31
|
+
const metadata = await sharp(inputBuffer).metadata();
|
|
32
|
+
let alreadyTransparent = false;
|
|
33
|
+
if (metadata.hasAlpha) {
|
|
34
|
+
const { data: alphaData } = await sharp(inputBuffer).raw().toBuffer({ resolveWithObject: true });
|
|
35
|
+
alreadyTransparent = hasTransparency(alphaData, 0.05);
|
|
36
|
+
}
|
|
37
|
+
let { data: processedData, info } = await sharp(inputBuffer)
|
|
38
|
+
.ensureAlpha()
|
|
39
|
+
.raw()
|
|
40
|
+
.toBuffer({ resolveWithObject: true });
|
|
41
|
+
if (options.color) {
|
|
42
|
+
stages.push("recolor");
|
|
43
|
+
processedData = applyQuantization(processedData, 8);
|
|
44
|
+
let dominantEdgeColor = null;
|
|
45
|
+
let colorRange = [];
|
|
46
|
+
if (isSVG) {
|
|
47
|
+
colorRange = findColorRangeWithThreshold(processedData, 5, null);
|
|
48
|
+
}
|
|
49
|
+
else {
|
|
50
|
+
dominantEdgeColor = alreadyTransparent ? null : getDominantEdgeColor(processedData, info.width, info.height);
|
|
51
|
+
colorRange = findColorRange(processedData, dominantEdgeColor);
|
|
52
|
+
}
|
|
53
|
+
let didRemoveBackground = false;
|
|
54
|
+
for (let i = 0; i < processedData.length; i += 4) {
|
|
55
|
+
let alpha = processedData[i + 3];
|
|
56
|
+
if (alpha < 25.5) {
|
|
57
|
+
processedData[i + 3] = 0;
|
|
58
|
+
continue;
|
|
59
|
+
}
|
|
60
|
+
const pixelColor = { r: processedData[i], g: processedData[i + 1], b: processedData[i + 2] };
|
|
61
|
+
if (isSVG) {
|
|
62
|
+
const isLight = pixelColor.r > 240 && pixelColor.g > 240 && pixelColor.b > 240;
|
|
63
|
+
if (isLight) {
|
|
64
|
+
alpha = 0;
|
|
65
|
+
didRemoveBackground = true;
|
|
66
|
+
}
|
|
67
|
+
else {
|
|
68
|
+
const idx = colorRange.findIndex((c) => colorDistance(c, pixelColor) < 5);
|
|
69
|
+
if (idx === -1) {
|
|
70
|
+
alpha = 0;
|
|
71
|
+
didRemoveBackground = true;
|
|
72
|
+
}
|
|
73
|
+
else {
|
|
74
|
+
const levels = [255, 200, 150, 100, 80];
|
|
75
|
+
alpha = levels[idx] ?? 60;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
else if (!alreadyTransparent && dominantEdgeColor && colorDistance(dominantEdgeColor, pixelColor) < 25) {
|
|
80
|
+
alpha = 0;
|
|
81
|
+
didRemoveBackground = true;
|
|
82
|
+
}
|
|
83
|
+
else {
|
|
84
|
+
const idx = colorRange.findIndex((c) => colorDistance(c, pixelColor) < COLOR_RANGE_THRESHOLD);
|
|
85
|
+
if (idx === -1) {
|
|
86
|
+
alpha = 0;
|
|
87
|
+
didRemoveBackground = true;
|
|
88
|
+
}
|
|
89
|
+
else {
|
|
90
|
+
alpha = Math.max(255 - 255 * idx * 0.35, 50);
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
processedData[i] = options.color.r;
|
|
94
|
+
processedData[i + 1] = options.color.g;
|
|
95
|
+
processedData[i + 2] = options.color.b;
|
|
96
|
+
processedData[i + 3] = alpha;
|
|
97
|
+
}
|
|
98
|
+
if (didRemoveBackground && !alreadyTransparent) {
|
|
99
|
+
stages.push("solidify-edges");
|
|
100
|
+
const result = await processGradient(processedData, info);
|
|
101
|
+
processedData = result.data;
|
|
102
|
+
info = result.info;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
else if (options.removeBackground && !alreadyTransparent) {
|
|
106
|
+
stages.push("remove-bg");
|
|
107
|
+
processedData = removeBackground(processedData, info.width, info.height);
|
|
108
|
+
stages.push("solidify-edges");
|
|
109
|
+
const result = await processGradient(processedData, info);
|
|
110
|
+
processedData = result.data;
|
|
111
|
+
info = result.info;
|
|
112
|
+
}
|
|
113
|
+
let pipeline = sharp(processedData, {
|
|
114
|
+
raw: { channels: 4, width: info.width, height: info.height },
|
|
115
|
+
}).png();
|
|
116
|
+
if (options.shrinkToContent) {
|
|
117
|
+
stages.push("trim");
|
|
118
|
+
pipeline = pipeline.trim();
|
|
119
|
+
}
|
|
120
|
+
const outputBuffer = await pipeline.toBuffer();
|
|
121
|
+
return { buffer: outputBuffer, stages };
|
|
122
|
+
}
|
|
123
|
+
function applyResize(buffer, resize) {
|
|
124
|
+
const transparent = { r: 0, g: 0, b: 0, alpha: 0 };
|
|
125
|
+
if (resize.size) {
|
|
126
|
+
return sharp(buffer)
|
|
127
|
+
.resize(resize.size.width, resize.size.height, {
|
|
128
|
+
fit: resize.fit ?? "contain",
|
|
129
|
+
background: transparent,
|
|
130
|
+
})
|
|
131
|
+
.toBuffer();
|
|
132
|
+
}
|
|
133
|
+
return sharp(buffer)
|
|
134
|
+
.resize(resize.width ?? null, resize.height ?? null, { fit: "inside", withoutEnlargement: false })
|
|
135
|
+
.toBuffer();
|
|
136
|
+
}
|
|
137
|
+
export async function processImage(inputBuffer, options = {}) {
|
|
138
|
+
const stages = [];
|
|
139
|
+
const isSVG = isSvgBuffer(inputBuffer);
|
|
140
|
+
if (isSVG && !options.color && !options.removeBackground && !options.shrinkToContent) {
|
|
141
|
+
if (options.resize) {
|
|
142
|
+
stages.push("resize");
|
|
143
|
+
const resized = await applyResize(inputBuffer, options.resize);
|
|
144
|
+
const meta = await sharp(resized).metadata();
|
|
145
|
+
return {
|
|
146
|
+
buffer: resized,
|
|
147
|
+
format: "png",
|
|
148
|
+
width: meta.width ?? 0,
|
|
149
|
+
height: meta.height ?? 0,
|
|
150
|
+
stages,
|
|
151
|
+
};
|
|
152
|
+
}
|
|
153
|
+
const meta = await sharp(inputBuffer).metadata();
|
|
154
|
+
return {
|
|
155
|
+
buffer: inputBuffer,
|
|
156
|
+
format: "svg",
|
|
157
|
+
width: meta.width ?? 0,
|
|
158
|
+
height: meta.height ?? 0,
|
|
159
|
+
stages,
|
|
160
|
+
};
|
|
161
|
+
}
|
|
162
|
+
let workingBuffer = inputBuffer;
|
|
163
|
+
if (isSVG) {
|
|
164
|
+
stages.push("rasterize-svg");
|
|
165
|
+
workingBuffer = await sharp(inputBuffer)
|
|
166
|
+
.png({ compressionLevel: 0, force: true, palette: false, quality: 100 })
|
|
167
|
+
.toBuffer();
|
|
168
|
+
}
|
|
169
|
+
const pass = await processInternal(workingBuffer, isSVG, options);
|
|
170
|
+
stages.push(...pass.stages);
|
|
171
|
+
let processed = pass.buffer;
|
|
172
|
+
if (options.resize) {
|
|
173
|
+
stages.push("resize");
|
|
174
|
+
processed = await applyResize(processed, options.resize);
|
|
175
|
+
}
|
|
176
|
+
const meta = await sharp(processed).metadata();
|
|
177
|
+
return {
|
|
178
|
+
buffer: processed,
|
|
179
|
+
format: "png",
|
|
180
|
+
width: meta.width ?? 0,
|
|
181
|
+
height: meta.height ?? 0,
|
|
182
|
+
stages,
|
|
183
|
+
};
|
|
184
|
+
}
|
|
185
|
+
//# sourceMappingURL=image-processor.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"image-processor.js","sourceRoot":"","sources":["../../../src/lib/image/image-processor.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
export declare function isRemoteUrl(value: string): boolean;
|
|
2
|
+
/**
|
|
3
|
+
* Expand a user-supplied input spec into a list of local file paths.
|
|
4
|
+
* Accepts: single path, glob pattern, or comma-separated list. Inputs that look
|
|
5
|
+
* like remote URLs are returned unchanged so callers can decide whether to
|
|
6
|
+
* fetch them.
|
|
7
|
+
*/
|
|
8
|
+
export declare function expandInputs(spec: string): Promise<string[]>;
|
|
9
|
+
export declare function readImageBuffer(pathOrUrl: string): Promise<Buffer>;
|
|
10
|
+
export declare function isDirectory(path: string): Promise<boolean>;
|
|
11
|
+
/**
|
|
12
|
+
* Resolve the output path for a processed file.
|
|
13
|
+
* - One input + --output=<file> → that file path
|
|
14
|
+
* - One input + --output=<dir> → dir/basename
|
|
15
|
+
* - One input, no --output → input path (in-place)
|
|
16
|
+
* - N inputs + --output=<dir> → dir/basename
|
|
17
|
+
* - N inputs, no --output → each input path (in-place)
|
|
18
|
+
* - N inputs + --output=<file> → validation error before reaching here
|
|
19
|
+
*/
|
|
20
|
+
export declare function resolveOutputPath(inputPath: string, outputArg: string | undefined, options: {
|
|
21
|
+
multipleInputs: boolean;
|
|
22
|
+
newExtension?: string;
|
|
23
|
+
}): Promise<string>;
|
|
24
|
+
/**
|
|
25
|
+
* Write a file atomically: write to a tempfile in the same directory, then
|
|
26
|
+
* rename. Prevents partial writes if the process is killed mid-write.
|
|
27
|
+
*/
|
|
28
|
+
export declare function atomicWrite(targetPath: string, data: Buffer): Promise<void>;
|
|
29
|
+
//# sourceMappingURL=io.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"io.d.ts","sourceRoot":"","sources":["../../../src/lib/image/io.ts"],"names":[],"mappings":"AAOA,wBAAgB,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAElD;AAMD;;;;;GAKG;AACH,wBAAsB,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAoBlE;AAED,wBAAsB,eAAe,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CASxE;AAED,wBAAsB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAOhE;AAED;;;;;;;;GAQG;AACH,wBAAsB,iBAAiB,CACrC,SAAS,EAAE,MAAM,EACjB,SAAS,EAAE,MAAM,GAAG,SAAS,EAC7B,OAAO,EAAE;IAAE,cAAc,EAAE,OAAO,CAAC;IAAC,YAAY,CAAC,EAAE,MAAM,CAAA;CAAE,GAC1D,OAAO,CAAC,MAAM,CAAC,CAUjB;AAED;;;GAGG;AACH,wBAAsB,WAAW,CAAC,UAAU,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAMjF"}
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import { randomBytes } from "node:crypto";
|
|
2
|
+
import { glob as fsGlob, readFile, rename, stat, writeFile } from "node:fs/promises";
|
|
3
|
+
import { dirname, extname, join, resolve } from "node:path";
|
|
4
|
+
const REMOTE_RE = /^https?:\/\//i;
|
|
5
|
+
const GLOB_RE = /[*?[\]{}]/;
|
|
6
|
+
export function isRemoteUrl(value) {
|
|
7
|
+
return REMOTE_RE.test(value);
|
|
8
|
+
}
|
|
9
|
+
function looksLikeGlob(value) {
|
|
10
|
+
return GLOB_RE.test(value);
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Expand a user-supplied input spec into a list of local file paths.
|
|
14
|
+
* Accepts: single path, glob pattern, or comma-separated list. Inputs that look
|
|
15
|
+
* like remote URLs are returned unchanged so callers can decide whether to
|
|
16
|
+
* fetch them.
|
|
17
|
+
*/
|
|
18
|
+
export async function expandInputs(spec) {
|
|
19
|
+
const parts = spec
|
|
20
|
+
.split(",")
|
|
21
|
+
.map((p) => p.trim())
|
|
22
|
+
.filter(Boolean);
|
|
23
|
+
const out = [];
|
|
24
|
+
for (const part of parts) {
|
|
25
|
+
if (isRemoteUrl(part)) {
|
|
26
|
+
out.push(part);
|
|
27
|
+
continue;
|
|
28
|
+
}
|
|
29
|
+
if (looksLikeGlob(part)) {
|
|
30
|
+
for await (const match of fsGlob(part)) {
|
|
31
|
+
if (typeof match === "string")
|
|
32
|
+
out.push(match);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
else {
|
|
36
|
+
out.push(part);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
return out;
|
|
40
|
+
}
|
|
41
|
+
export async function readImageBuffer(pathOrUrl) {
|
|
42
|
+
if (isRemoteUrl(pathOrUrl)) {
|
|
43
|
+
const response = await fetch(pathOrUrl);
|
|
44
|
+
if (!response.ok) {
|
|
45
|
+
throw new Error(`Failed to fetch ${pathOrUrl}: ${response.status} ${response.statusText}`);
|
|
46
|
+
}
|
|
47
|
+
return Buffer.from(await response.arrayBuffer());
|
|
48
|
+
}
|
|
49
|
+
return readFile(pathOrUrl);
|
|
50
|
+
}
|
|
51
|
+
export async function isDirectory(path) {
|
|
52
|
+
try {
|
|
53
|
+
const s = await stat(path);
|
|
54
|
+
return s.isDirectory();
|
|
55
|
+
}
|
|
56
|
+
catch {
|
|
57
|
+
return false;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Resolve the output path for a processed file.
|
|
62
|
+
* - One input + --output=<file> → that file path
|
|
63
|
+
* - One input + --output=<dir> → dir/basename
|
|
64
|
+
* - One input, no --output → input path (in-place)
|
|
65
|
+
* - N inputs + --output=<dir> → dir/basename
|
|
66
|
+
* - N inputs, no --output → each input path (in-place)
|
|
67
|
+
* - N inputs + --output=<file> → validation error before reaching here
|
|
68
|
+
*/
|
|
69
|
+
export async function resolveOutputPath(inputPath, outputArg, options) {
|
|
70
|
+
const base = options.newExtension ? inputPath.slice(0, -extname(inputPath).length) + options.newExtension : inputPath;
|
|
71
|
+
if (!outputArg)
|
|
72
|
+
return base;
|
|
73
|
+
if (options.multipleInputs || (await isDirectory(outputArg))) {
|
|
74
|
+
const filename = base.split("/").pop() ?? "out.png";
|
|
75
|
+
return join(outputArg, filename);
|
|
76
|
+
}
|
|
77
|
+
return outputArg;
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Write a file atomically: write to a tempfile in the same directory, then
|
|
81
|
+
* rename. Prevents partial writes if the process is killed mid-write.
|
|
82
|
+
*/
|
|
83
|
+
export async function atomicWrite(targetPath, data) {
|
|
84
|
+
const absolute = resolve(targetPath);
|
|
85
|
+
const dir = dirname(absolute);
|
|
86
|
+
const tmp = join(dir, `.baker-image-${randomBytes(8).toString("hex")}.tmp`);
|
|
87
|
+
await writeFile(tmp, data);
|
|
88
|
+
await rename(tmp, absolute);
|
|
89
|
+
}
|
|
90
|
+
//# sourceMappingURL=io.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"io.js","sourceRoot":"","sources":["../../../src/lib/image/io.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@koda-sl/baker-cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.36.0",
|
|
4
4
|
"description": "AI-agent-first CLI for interacting with Baker",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -18,10 +18,14 @@
|
|
|
18
18
|
"dependencies": {
|
|
19
19
|
"@t3-oss/env-core": "latest",
|
|
20
20
|
"citty": "latest",
|
|
21
|
+
"image-size": "^2.0.2",
|
|
22
|
+
"quantize": "^1.0.2",
|
|
23
|
+
"sharp": "^0.34.5",
|
|
21
24
|
"zod": "latest"
|
|
22
25
|
},
|
|
23
26
|
"devDependencies": {
|
|
24
27
|
"@types/node": "latest",
|
|
28
|
+
"@types/quantize": "^1.0.2",
|
|
25
29
|
"tsx": "latest",
|
|
26
30
|
"typescript": "latest",
|
|
27
31
|
"vitest": "latest"
|