@goodandready/dsh-image-gen 0.10.7 → 0.10.8
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 +6 -0
- package/README.ru.md +6 -0
- package/lib/index.js +57 -18
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,3 +1,9 @@
|
|
|
1
|
+
|
|
2
|
+
## 🚀 Updates v0.10.8: Lossless JSON Unification, Dual-Output & Strict Validation (#199)
|
|
3
|
+
- **Lossless JSON & Dual-Output Unification**: `upscale_image`, `remove_background`, `blend_images`, and `vectorize_image` now consistently return `toLosslessJson` and formatted markdown `summary` for text-only LLMs.
|
|
4
|
+
- **Strict Input Image Validation**: `extract_design_tokens`, `image_to_css_gradient`, and `check_image_contrast` explicitly validate source image readability instead of silent fallback.
|
|
5
|
+
- **Unit Testing Suite**: Added `test/tool-consistency.test.mjs` covering tokenization, gradient generator, and PWA suite.
|
|
6
|
+
|
|
1
7
|
# 📦 @goodandready/dsh-image-gen
|
|
2
8
|
|
|
3
9
|
<div align="center">
|
package/README.ru.md
CHANGED
|
@@ -116,6 +116,12 @@ graph LR
|
|
|
116
116
|
---
|
|
117
117
|
|
|
118
118
|
|
|
119
|
+
|
|
120
|
+
## 🚀 Обновления v0.10.8: унификация Lossless JSON, Dual-Output и строгая валидация (#199)
|
|
121
|
+
- **Унификация Lossless JSON и Dual-Output**: Инструменты `upscale_image`, `remove_background`, `blend_images`, `vectorize_image` теперь гарантированно возвращают валидный `toLosslessJson` и генерируют структурированный `summary` с превью для текстовых LLM.
|
|
122
|
+
- **Строгая валидация входных изображений**: В инструментах `extract_design_tokens`, `image_to_css_gradient` и `check_image_contrast` добавлена явная проверка существования файла с информативной ошибкой (`Image not found or unreadable: <path>`).
|
|
123
|
+
- **Сквозное модульное тестирование**: Добавлен тест-сьют `test/tool-consistency.test.mjs` для проверки отказоустойчивости дизайн- и PWA-инструментов.
|
|
124
|
+
|
|
119
125
|
## 🚀 Обновления v0.10.4: жизненный цикл Cordis, полнота настроек и интернационализация
|
|
120
126
|
- **Жизненный цикл Cordis (#136)**: регистрация всех 7 инструментов обёрнута в `ctx.effect` для штатной отписки при перезагрузке плагина.
|
|
121
127
|
- **Полнота настроек в GUI (#137)**: в карточку настроек добавлены поля для Replicate, SeaDream, Gemini, Local ComfyUI/A1111, пресетов стилей и LLM-улучшителя.
|
package/lib/index.js
CHANGED
|
@@ -1070,14 +1070,25 @@ export function apply(ctx, config) {
|
|
|
1070
1070
|
const filePath = path.join(outDir, name)
|
|
1071
1071
|
await writeFile(filePath, res.bytes)
|
|
1072
1072
|
const localUrl = '/dsh-image-gen/image?id=' + encodeURIComponent(attachment.attachmentId)
|
|
1073
|
-
|
|
1073
|
+
const summary = buildDualOutputMarkdown({
|
|
1074
|
+
action: 'background removed',
|
|
1075
|
+
filePath,
|
|
1076
|
+
width: res.width || attachment.width,
|
|
1077
|
+
height: res.height || attachment.height,
|
|
1078
|
+
mediaType: 'image/png',
|
|
1079
|
+
provider: 'fal',
|
|
1080
|
+
model: args.model || 'fal-ai/birefnet',
|
|
1081
|
+
attachmentId: attachment.attachmentId,
|
|
1082
|
+
})
|
|
1083
|
+
return toLosslessJson({
|
|
1084
|
+
summary,
|
|
1074
1085
|
path: filePath,
|
|
1075
1086
|
url: localUrl,
|
|
1076
1087
|
width: res.width || attachment.width,
|
|
1077
1088
|
height: res.height || attachment.height,
|
|
1078
1089
|
format: 'png',
|
|
1079
1090
|
attachment,
|
|
1080
|
-
}
|
|
1091
|
+
})
|
|
1081
1092
|
},
|
|
1082
1093
|
}),
|
|
1083
1094
|
)
|
|
@@ -1128,14 +1139,25 @@ export function apply(ctx, config) {
|
|
|
1128
1139
|
const filePath = path.join(outDir, name)
|
|
1129
1140
|
await writeFile(filePath, res.bytes)
|
|
1130
1141
|
const localUrl = '/dsh-image-gen/image?id=' + encodeURIComponent(attachment.attachmentId)
|
|
1131
|
-
|
|
1142
|
+
const summary = buildDualOutputMarkdown({
|
|
1143
|
+
action: `upscaled (${args.scale || 2}x)`,
|
|
1144
|
+
filePath,
|
|
1145
|
+
width: res.width || attachment.width,
|
|
1146
|
+
height: res.height || attachment.height,
|
|
1147
|
+
mediaType: 'image/png',
|
|
1148
|
+
provider: 'fal',
|
|
1149
|
+
model: 'fal-ai/clarity-upscaler',
|
|
1150
|
+
attachmentId: attachment.attachmentId,
|
|
1151
|
+
})
|
|
1152
|
+
return toLosslessJson({
|
|
1153
|
+
summary,
|
|
1132
1154
|
path: filePath,
|
|
1133
1155
|
url: localUrl,
|
|
1134
1156
|
scale: args.scale || 2,
|
|
1135
1157
|
width: res.width || attachment.width,
|
|
1136
1158
|
height: res.height || attachment.height,
|
|
1137
1159
|
attachment,
|
|
1138
|
-
}
|
|
1160
|
+
})
|
|
1139
1161
|
},
|
|
1140
1162
|
}),
|
|
1141
1163
|
)
|
|
@@ -1173,11 +1195,13 @@ export function apply(ctx, config) {
|
|
|
1173
1195
|
await mkdir(outDir, { recursive: true })
|
|
1174
1196
|
const filePath = path.join(outDir, name)
|
|
1175
1197
|
await writeFile(filePath, res.bytes)
|
|
1176
|
-
|
|
1198
|
+
const summary = `### Vectorized SVG Export\n- **File**: ${filePath}\n- **Format**: SVG (XML vector)\n- **Color mode**: ${args.color_mode || 'color'}\n- **Palette size**: ${res.palette ? res.palette.length : 16} colors\n`
|
|
1199
|
+
return toLosslessJson({
|
|
1200
|
+
summary,
|
|
1177
1201
|
path: filePath,
|
|
1178
1202
|
svg: res.svg,
|
|
1179
1203
|
format: 'svg',
|
|
1180
|
-
}
|
|
1204
|
+
})
|
|
1181
1205
|
},
|
|
1182
1206
|
}),
|
|
1183
1207
|
)
|
|
@@ -1232,13 +1256,24 @@ export function apply(ctx, config) {
|
|
|
1232
1256
|
const filePath = path.join(outDir, name)
|
|
1233
1257
|
await writeFile(filePath, res.bytes)
|
|
1234
1258
|
const localUrl = '/dsh-image-gen/image?id=' + encodeURIComponent(attachment.attachmentId)
|
|
1235
|
-
|
|
1259
|
+
const summary = buildDualOutputMarkdown({
|
|
1260
|
+
action: 'blended composition',
|
|
1261
|
+
filePath,
|
|
1262
|
+
width: res.width || attachment.width,
|
|
1263
|
+
height: res.height || attachment.height,
|
|
1264
|
+
mediaType: 'image/png',
|
|
1265
|
+
provider: 'fal',
|
|
1266
|
+
model: 'fal-ai/image-blend',
|
|
1267
|
+
attachmentId: attachment.attachmentId,
|
|
1268
|
+
})
|
|
1269
|
+
return toLosslessJson({
|
|
1270
|
+
summary,
|
|
1236
1271
|
path: filePath,
|
|
1237
1272
|
url: localUrl,
|
|
1238
1273
|
width: res.width || attachment.width,
|
|
1239
1274
|
height: res.height || attachment.height,
|
|
1240
1275
|
attachment,
|
|
1241
|
-
}
|
|
1276
|
+
})
|
|
1242
1277
|
},
|
|
1243
1278
|
}),
|
|
1244
1279
|
)
|
|
@@ -1610,12 +1645,13 @@ export function apply(ctx, config) {
|
|
|
1610
1645
|
if (!colors || colors.length === 0) {
|
|
1611
1646
|
if (args.image) {
|
|
1612
1647
|
const source = await resolveSource(ctx, exec, args.image)
|
|
1613
|
-
if (source
|
|
1614
|
-
|
|
1648
|
+
if (!source || !source.bytes) {
|
|
1649
|
+
throw new Error('Image not found or unreadable: ' + args.image)
|
|
1615
1650
|
}
|
|
1651
|
+
colors = extractSampleColorsFromBuffer(source.bytes)
|
|
1616
1652
|
}
|
|
1617
1653
|
}
|
|
1618
|
-
return extractDesignTokens(colors, { prefix: args.prefix })
|
|
1654
|
+
return toLosslessJson(extractDesignTokens(colors, { prefix: args.prefix }))
|
|
1619
1655
|
},
|
|
1620
1656
|
}),
|
|
1621
1657
|
)
|
|
@@ -1648,12 +1684,13 @@ export function apply(ctx, config) {
|
|
|
1648
1684
|
if (!colors || colors.length === 0) {
|
|
1649
1685
|
if (args.image) {
|
|
1650
1686
|
const source = await resolveSource(ctx, exec, args.image)
|
|
1651
|
-
if (source
|
|
1652
|
-
|
|
1687
|
+
if (!source || !source.bytes) {
|
|
1688
|
+
throw new Error('Image not found or unreadable: ' + args.image)
|
|
1653
1689
|
}
|
|
1690
|
+
colors = extractSampleColorsFromBuffer(source.bytes)
|
|
1654
1691
|
}
|
|
1655
1692
|
}
|
|
1656
|
-
return generateCssGradient(colors, args.type || 'mesh')
|
|
1693
|
+
return toLosslessJson(generateCssGradient(colors, args.type || 'mesh'))
|
|
1657
1694
|
},
|
|
1658
1695
|
}),
|
|
1659
1696
|
)
|
|
@@ -1689,12 +1726,13 @@ export function apply(ctx, config) {
|
|
|
1689
1726
|
if (!colors || colors.length === 0) {
|
|
1690
1727
|
if (args.image) {
|
|
1691
1728
|
const source = await resolveSource(ctx, exec, args.image)
|
|
1692
|
-
if (source
|
|
1693
|
-
|
|
1729
|
+
if (!source || !source.bytes) {
|
|
1730
|
+
throw new Error('Image not found or unreadable: ' + args.image)
|
|
1694
1731
|
}
|
|
1732
|
+
colors = extractSampleColorsFromBuffer(source.bytes)
|
|
1695
1733
|
}
|
|
1696
1734
|
}
|
|
1697
|
-
return checkWcagContrast(colors, args.text_color || '#ffffff')
|
|
1735
|
+
return toLosslessJson(checkWcagContrast(colors, args.text_color || '#ffffff'))
|
|
1698
1736
|
},
|
|
1699
1737
|
}),
|
|
1700
1738
|
)
|
|
@@ -1769,7 +1807,7 @@ export function apply(ctx, config) {
|
|
|
1769
1807
|
},
|
|
1770
1808
|
},
|
|
1771
1809
|
async execute(args, exec) {
|
|
1772
|
-
|
|
1810
|
+
const res = await generatePwaIconSuite({
|
|
1773
1811
|
name: args.name || 'App',
|
|
1774
1812
|
shortName: args.short_name || args.name || 'App',
|
|
1775
1813
|
themeColor: args.theme_color || '#0f172a',
|
|
@@ -1777,6 +1815,7 @@ export function apply(ctx, config) {
|
|
|
1777
1815
|
iconsDir: args.icons_dir || 'icons',
|
|
1778
1816
|
sourcePath: args.image || null,
|
|
1779
1817
|
})
|
|
1818
|
+
return toLosslessJson(res)
|
|
1780
1819
|
},
|
|
1781
1820
|
}),
|
|
1782
1821
|
)
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@goodandready/dsh-image-gen",
|
|
3
|
-
"version": "0.10.
|
|
3
|
+
"version": "0.10.8",
|
|
4
4
|
"description": "Image generation for DeepSeek Harness: a generate_image tool with pluggable providers — the FAL queue, any OpenAI-compatible images API, or a ChatGPT/Grok subscription with no API key at all. The picture is shown inline in the conversation; the model receives either a link (works with any chat model) or the image itself (needs dsh-vision-bridge or a vision-capable model).",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"deepseek-harness",
|