@goodandready/dsh-image-gen 0.11.0 → 0.11.1
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/lib/client.js +104 -135
- package/lib/fallback-router.js +25 -3
- package/lib/index.js +255 -138
- package/lib/provider-utils.js +0 -2
- package/lib/providers.js +9 -30
- package/lib/settings-route.js +112 -0
- package/lib/tools/anchor.js +1 -2
- package/lib/tools/editing.js +2 -34
- package/lib/tools/frontend.js +2 -35
- package/lib/tools/generation-pack.js +2 -4
- package/lib/tools/generation.js +2 -23
- package/lib/tools/inspect.js +6 -45
- package/lib/tools/pattern.js +10 -0
- package/lib/tools/processing-advanced.js +0 -32
- package/lib/tools/processing-basic.js +2 -25
- package/lib/tools/style-matrix.js +1 -2
- package/lib/tools/theme-pair.js +0 -1
- package/lib/tools/ui-asset.js +1 -1
- package/lib/updater.js +0 -9
- package/lib/vault.js +3 -3
- package/package.json +7 -1
package/lib/providers.js
CHANGED
|
@@ -4,28 +4,18 @@
|
|
|
4
4
|
|
|
5
5
|
// Utilities and constants extracted to provider-utils.js (#239)
|
|
6
6
|
import {
|
|
7
|
-
resolveApiKeyCandidates,
|
|
8
|
-
PROVIDER_MAX_COUNTS,
|
|
9
|
-
clampProviderCount,
|
|
10
|
-
buildEndpointUrl,
|
|
11
|
-
createAbortError,
|
|
12
|
-
estimateSharpnessAndVariance,
|
|
13
|
-
quantizePalette,
|
|
14
|
-
formatA1111Parameters,
|
|
15
|
-
computeGenerationHash,
|
|
16
|
-
PROVIDER_KEYS,
|
|
17
|
-
fallbackOrder,
|
|
18
|
-
calculateBackoff,
|
|
19
7
|
isFatalClientError,
|
|
20
8
|
formatErrorMessage,
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
IMAGE_SIZES,
|
|
24
|
-
OUTPUT_FORMATS,
|
|
25
|
-
SIZE_PIXELS,
|
|
26
|
-
normalizeCount,
|
|
9
|
+
formatA1111Parameters,
|
|
10
|
+
quantizePalette,
|
|
27
11
|
} from './provider-utils.js'
|
|
28
12
|
|
|
13
|
+
import {
|
|
14
|
+
falAuthHeader,
|
|
15
|
+
submitJob,
|
|
16
|
+
pollStatus,
|
|
17
|
+
} from './providers/shared-helpers.js'
|
|
18
|
+
|
|
29
19
|
// Per-backend factories (#218)
|
|
30
20
|
import { createFalGenerator } from './providers/backends/fal.js'
|
|
31
21
|
import { createCustomGenerator } from './providers/backends/custom.js'
|
|
@@ -49,18 +39,7 @@ export {
|
|
|
49
39
|
extractComfyNodeErrors,
|
|
50
40
|
} from './providers/shared-helpers.js'
|
|
51
41
|
|
|
52
|
-
|
|
53
|
-
falAuthHeader,
|
|
54
|
-
normalizeMediaType,
|
|
55
|
-
submitJob,
|
|
56
|
-
pollStatus,
|
|
57
|
-
buildEditForm,
|
|
58
|
-
estimateCost,
|
|
59
|
-
pxSize,
|
|
60
|
-
snapToMultipleOf64,
|
|
61
|
-
snapDimensions,
|
|
62
|
-
extractComfyNodeErrors,
|
|
63
|
-
} from './providers/shared-helpers.js'
|
|
42
|
+
|
|
64
43
|
|
|
65
44
|
// Re-export utilities so existing imports from './providers.js' continue to work
|
|
66
45
|
export {
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
// lib/settings-route.js
|
|
2
|
+
// REST endpoints for plugin settings (/dsh-image-gen/config, /dsh-image-gen/status) (#295, #300).
|
|
3
|
+
// Provides HTTP read/write fallback when DSH core is accessed over network.
|
|
4
|
+
|
|
5
|
+
import { isTrustedLocalRequest } from './security.js'
|
|
6
|
+
import { publicConfig, plainConfig, Config } from './index.js'
|
|
7
|
+
|
|
8
|
+
export function registerSettingsRoutes(ctx, { live, getSettingsApi, setLiveConfig }) {
|
|
9
|
+
// 1. GET /dsh-image-gen/status
|
|
10
|
+
ctx.effect(() => ctx.webServer.register({
|
|
11
|
+
kind: 'exact',
|
|
12
|
+
path: '/dsh-image-gen/status',
|
|
13
|
+
handler: async (req, res) => {
|
|
14
|
+
if (req.method !== 'GET') {
|
|
15
|
+
res.writeHead(405, { 'Content-Type': 'application/json' })
|
|
16
|
+
res.end(JSON.stringify({ error: 'GET only' }))
|
|
17
|
+
return
|
|
18
|
+
}
|
|
19
|
+
if (!isTrustedLocalRequest(req)) {
|
|
20
|
+
res.writeHead(403, { 'Content-Type': 'application/json' })
|
|
21
|
+
res.end(JSON.stringify({ error: 'forbidden' }))
|
|
22
|
+
return
|
|
23
|
+
}
|
|
24
|
+
const cfg = publicConfig(live())
|
|
25
|
+
res.writeHead(200, { 'Content-Type': 'application/json' })
|
|
26
|
+
res.end(JSON.stringify({
|
|
27
|
+
ok: true,
|
|
28
|
+
provider: cfg.provider,
|
|
29
|
+
model: cfg.model,
|
|
30
|
+
enabled: cfg.enabled,
|
|
31
|
+
config: cfg,
|
|
32
|
+
}))
|
|
33
|
+
},
|
|
34
|
+
}), 'dsh-image-gen: status route')
|
|
35
|
+
|
|
36
|
+
// 2. GET & PUT /dsh-image-gen/config
|
|
37
|
+
ctx.effect(() => ctx.webServer.register({
|
|
38
|
+
kind: 'exact',
|
|
39
|
+
path: '/dsh-image-gen/config',
|
|
40
|
+
handler: async (req, res) => {
|
|
41
|
+
if (req.method === 'GET') {
|
|
42
|
+
if (!isTrustedLocalRequest(req)) {
|
|
43
|
+
res.writeHead(403, { 'Content-Type': 'application/json' })
|
|
44
|
+
res.end(JSON.stringify({ error: 'forbidden' }))
|
|
45
|
+
return
|
|
46
|
+
}
|
|
47
|
+
res.writeHead(200, { 'Content-Type': 'application/json' })
|
|
48
|
+
res.end(JSON.stringify({ ok: true, config: publicConfig(live()) }))
|
|
49
|
+
return
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
if (req.method !== 'PUT') {
|
|
53
|
+
res.writeHead(405, { 'Content-Type': 'application/json' })
|
|
54
|
+
res.end(JSON.stringify({ error: 'GET or PUT only' }))
|
|
55
|
+
return
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
if (!isTrustedLocalRequest(req)) {
|
|
59
|
+
res.writeHead(403, { 'Content-Type': 'application/json' })
|
|
60
|
+
res.end(JSON.stringify({ error: 'forbidden' }))
|
|
61
|
+
return
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
const chunks = []
|
|
65
|
+
req.on('data', (c) => chunks.push(c))
|
|
66
|
+
req.on('end', async () => {
|
|
67
|
+
let payload
|
|
68
|
+
try {
|
|
69
|
+
payload = JSON.parse(Buffer.concat(chunks).toString('utf8') || '{}')
|
|
70
|
+
} catch {
|
|
71
|
+
res.writeHead(400, { 'Content-Type': 'application/json' })
|
|
72
|
+
res.end(JSON.stringify({ ok: false, error: 'invalid JSON' }))
|
|
73
|
+
return
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
const raw = payload && typeof payload.config === 'object' && payload.config !== null ? payload.config : payload
|
|
77
|
+
if (!raw || typeof raw !== 'object' || Array.isArray(raw)) {
|
|
78
|
+
res.writeHead(400, { 'Content-Type': 'application/json' })
|
|
79
|
+
res.end(JSON.stringify({ ok: false, error: 'body must be a JSON object' }))
|
|
80
|
+
return
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
const allowedKeys = new Set(Object.keys(Config.dict || {}))
|
|
84
|
+
for (const k of Object.keys(raw)) {
|
|
85
|
+
if (!allowedKeys.has(k)) {
|
|
86
|
+
res.writeHead(400, { 'Content-Type': 'application/json' })
|
|
87
|
+
res.end(JSON.stringify({ ok: false, error: `unknown config field: ${k}` }))
|
|
88
|
+
return
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
try {
|
|
93
|
+
const base = plainConfig(live()) || {}
|
|
94
|
+
const merged = Config({ ...base, ...raw })
|
|
95
|
+
const settingsApi = getSettingsApi ? getSettingsApi() : null
|
|
96
|
+
if (settingsApi && typeof settingsApi.replace === 'function') {
|
|
97
|
+
await settingsApi.replace(merged)
|
|
98
|
+
} else if (settingsApi && typeof settingsApi.update === 'function') {
|
|
99
|
+
await settingsApi.update(raw)
|
|
100
|
+
} else if (typeof setLiveConfig === 'function') {
|
|
101
|
+
setLiveConfig(merged)
|
|
102
|
+
}
|
|
103
|
+
res.writeHead(200, { 'Content-Type': 'application/json' })
|
|
104
|
+
res.end(JSON.stringify({ ok: true, config: publicConfig(merged) }))
|
|
105
|
+
} catch (err) {
|
|
106
|
+
res.writeHead(400, { 'Content-Type': 'application/json' })
|
|
107
|
+
res.end(JSON.stringify({ ok: false, error: String(err?.message || err) }))
|
|
108
|
+
}
|
|
109
|
+
})
|
|
110
|
+
},
|
|
111
|
+
}), 'dsh-image-gen: config route')
|
|
112
|
+
}
|
package/lib/tools/anchor.js
CHANGED
|
@@ -4,7 +4,6 @@
|
|
|
4
4
|
import { defineTool } from '@deepseek-ai/dsh-tools'
|
|
5
5
|
import {
|
|
6
6
|
setSessionAnchor,
|
|
7
|
-
getSessionAnchor,
|
|
8
7
|
clearSessionAnchor,
|
|
9
8
|
normalizeAnchorStrength,
|
|
10
9
|
} from '../anchor-helpers.js'
|
|
@@ -102,7 +101,7 @@ export function registerAnchorTools(ctx, deps) {
|
|
|
102
101
|
if (resolveSource && (imageRef.startsWith('sha256:') || !imageRef.startsWith('http'))) {
|
|
103
102
|
try {
|
|
104
103
|
await resolveSource(ctx, exec, imageRef)
|
|
105
|
-
} catch
|
|
104
|
+
} catch {
|
|
106
105
|
// Best effort check; non-blocking if remote URL or future attachment
|
|
107
106
|
}
|
|
108
107
|
}
|
package/lib/tools/editing.js
CHANGED
|
@@ -3,49 +3,17 @@ import { renderToolOutput } from "../attachment-helper.js"
|
|
|
3
3
|
|
|
4
4
|
import { defineTool } from '@deepseek-ai/dsh-tools'
|
|
5
5
|
import { polishPrompt } from '../prompt-polisher.js'
|
|
6
|
-
import path from 'node:path'
|
|
7
|
-
import { mkdir, writeFile } from 'node:fs/promises'
|
|
8
6
|
import {
|
|
9
|
-
computeGenerationHash,
|
|
10
|
-
IMAGE_SIZES,
|
|
11
|
-
OUTPUT_FORMATS,
|
|
12
|
-
PROVIDER_KEYS,
|
|
13
|
-
buildSidecar,
|
|
14
7
|
makeProviders,
|
|
15
|
-
ASPECT_RATIOS,
|
|
16
|
-
pixelDiff,
|
|
17
8
|
normalizeCount,
|
|
18
|
-
tryGenerate,
|
|
19
|
-
fallbackOrder,
|
|
20
|
-
embedPngMetadata,
|
|
21
|
-
removeBackgroundFal,
|
|
22
|
-
upscaleImageFal,
|
|
23
|
-
traceToSvg,
|
|
24
|
-
estimateCost,
|
|
25
|
-
estimateSharpnessAndVariance,
|
|
26
|
-
applyStylePreset,
|
|
27
|
-
resolveStylePreset,
|
|
28
|
-
blendImagesFal,
|
|
29
9
|
toLosslessJson,
|
|
30
|
-
saveAttachmentSafe,
|
|
31
10
|
editImageDirect,
|
|
32
11
|
varyImageDirect,
|
|
33
12
|
} from '../providers.js'
|
|
34
|
-
import { resolveConversationImage, analyzeImageWithVision
|
|
35
|
-
import {
|
|
36
|
-
import { executeWithQualityGate } from '../quality-gate.js'
|
|
37
|
-
import { calculateGenerationCost, recordSpend, assertBudgetAvailable } from '../cost-meter.js'
|
|
13
|
+
import { resolveConversationImage, analyzeImageWithVision } from '../resolve-image.js'
|
|
14
|
+
import { calculateGenerationCost, assertBudgetAvailable } from '../cost-meter.js'
|
|
38
15
|
import { trackAndAssertLoopGuard } from '../loop-guard.js'
|
|
39
16
|
import { sanitizeErrorAndLogs } from '../security.js'
|
|
40
|
-
import { getCachedGeneration, setCachedGeneration } from '../generation-cache.js'
|
|
41
|
-
import {
|
|
42
|
-
extractDesignTokens,
|
|
43
|
-
generateCssGradient,
|
|
44
|
-
checkWcagContrast,
|
|
45
|
-
optimizeSvgContent,
|
|
46
|
-
generatePwaIconSuite,
|
|
47
|
-
extractSampleColorsFromBuffer,
|
|
48
|
-
} from '../frontend-assets.js'
|
|
49
17
|
|
|
50
18
|
|
|
51
19
|
export function registerEditingTools(ctx, deps) {
|
package/lib/tools/frontend.js
CHANGED
|
@@ -2,51 +2,18 @@ import { renderToolOutput } from "../attachment-helper.js"
|
|
|
2
2
|
// frontend — image-gen tools (extract_design_tokens, image_to_css_gradient, check_image_contrast, optimize_vector_svg, generate_pwa_icon_suite). Extracted from apply() (#216).
|
|
3
3
|
|
|
4
4
|
import { defineTool } from '@deepseek-ai/dsh-tools'
|
|
5
|
-
import
|
|
6
|
-
import { mkdir, writeFile } from 'node:fs/promises'
|
|
7
|
-
import {
|
|
8
|
-
computeGenerationHash,
|
|
9
|
-
IMAGE_SIZES,
|
|
10
|
-
tryGenerate,
|
|
11
|
-
fallbackOrder,
|
|
12
|
-
embedPngMetadata,
|
|
13
|
-
removeBackgroundFal,
|
|
14
|
-
upscaleImageFal,
|
|
15
|
-
traceToSvg,
|
|
16
|
-
estimateCost,
|
|
17
|
-
estimateSharpnessAndVariance,
|
|
18
|
-
applyStylePreset,
|
|
19
|
-
resolveStylePreset,
|
|
20
|
-
blendImagesFal,
|
|
21
|
-
toLosslessJson,
|
|
22
|
-
saveAttachmentSafe,
|
|
23
|
-
} from '../providers.js'
|
|
24
|
-
import { resolveConversationImage, analyzeImageWithVision, buildDualOutputMarkdown } from '../resolve-image.js'
|
|
25
|
-
import { sanitizeNegativePrompt, supportsNegativePrompt } from '../negative-sanitizer.js'
|
|
26
|
-
import { executeWithQualityGate } from '../quality-gate.js'
|
|
27
|
-
import { calculateGenerationCost, recordSpend, assertBudgetAvailable } from '../cost-meter.js'
|
|
28
|
-
import { trackAndAssertLoopGuard } from '../loop-guard.js'
|
|
5
|
+
import { toLosslessJson } from '../providers.js'
|
|
29
6
|
import { sanitizeErrorAndLogs } from '../security.js'
|
|
30
|
-
import { getCachedGeneration, setCachedGeneration } from '../generation-cache.js'
|
|
31
7
|
import {
|
|
32
8
|
extractDesignTokens,
|
|
33
9
|
generateCssGradient,
|
|
34
10
|
checkWcagContrast,
|
|
35
11
|
optimizeSvgContent,
|
|
36
12
|
generatePwaIconSuite,
|
|
37
|
-
extractSampleColorsFromBuffer,
|
|
38
13
|
} from '../frontend-assets.js'
|
|
39
14
|
|
|
40
|
-
|
|
41
15
|
export function registerFrontendTools(ctx, deps) {
|
|
42
|
-
const {
|
|
43
|
-
config,
|
|
44
|
-
live,
|
|
45
|
-
saveAndAttachResult,
|
|
46
|
-
resolveSource,
|
|
47
|
-
slugify,
|
|
48
|
-
resolveApiKey,
|
|
49
|
-
} = deps
|
|
16
|
+
const { resolveSource } = deps
|
|
50
17
|
ctx.effect(() => {
|
|
51
18
|
ctx.tools.register(
|
|
52
19
|
defineTool({
|
|
@@ -4,8 +4,7 @@ import { toLosslessJson } from '../providers.js'
|
|
|
4
4
|
import { slugify } from '../index.js'
|
|
5
5
|
|
|
6
6
|
export function registerGenerationPackTool(ctx, deps) {
|
|
7
|
-
|
|
8
|
-
|
|
7
|
+
|
|
9
8
|
ctx.effect(() => {
|
|
10
9
|
ctx.tools.register(
|
|
11
10
|
defineTool({
|
|
@@ -30,8 +29,7 @@ export function registerGenerationPackTool(ctx, deps) {
|
|
|
30
29
|
},
|
|
31
30
|
async execute(args, exec) {
|
|
32
31
|
const ratios = Array.isArray(args.aspect_ratios) && args.aspect_ratios.length ? args.aspect_ratios : ['1:1', '16:9', '9:16']
|
|
33
|
-
|
|
34
|
-
const generateTool = ctx.tools.get('generate_image')
|
|
32
|
+
const generateTool = ctx.tools.get('generate_image')
|
|
35
33
|
const results = []
|
|
36
34
|
const warnings = []
|
|
37
35
|
const seedBase = Math.floor(Math.random() * 100000)
|
package/lib/tools/generation.js
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { polishPrompt } from '../prompt-polisher.js'
|
|
2
1
|
import { registerGenerationPackTool } from './generation-pack.js'
|
|
3
2
|
|
|
4
3
|
/** Run an array of async task functions with a concurrency cap */
|
|
@@ -29,46 +28,26 @@ import {
|
|
|
29
28
|
buildSidecar,
|
|
30
29
|
makeProviders,
|
|
31
30
|
ASPECT_RATIOS,
|
|
32
|
-
pixelDiff,
|
|
33
31
|
normalizeCount,
|
|
34
|
-
tryGenerate,
|
|
35
|
-
fallbackOrder,
|
|
36
32
|
embedPngMetadata,
|
|
37
|
-
removeBackgroundFal,
|
|
38
|
-
upscaleImageFal,
|
|
39
|
-
traceToSvg,
|
|
40
|
-
estimateCost,
|
|
41
|
-
estimateSharpnessAndVariance,
|
|
42
|
-
applyStylePreset,
|
|
43
33
|
resolveStylePreset,
|
|
44
|
-
blendImagesFal,
|
|
45
34
|
toLosslessJson,
|
|
46
35
|
saveAttachmentSafe,
|
|
47
36
|
} from '../providers.js'
|
|
48
|
-
import {
|
|
37
|
+
import { buildDualOutputMarkdown } from '../resolve-image.js'
|
|
49
38
|
import { sanitizeNegativePrompt, supportsNegativePrompt } from '../negative-sanitizer.js'
|
|
50
39
|
import { executeWithQualityGate } from '../quality-gate.js'
|
|
51
40
|
import { calculateGenerationCost, recordSpend, assertBudgetAvailable } from '../cost-meter.js'
|
|
52
41
|
import { trackAndAssertLoopGuard } from '../loop-guard.js'
|
|
53
|
-
import { sanitizeErrorAndLogs } from '../security.js'
|
|
54
42
|
import { getCachedGeneration, setCachedGeneration } from '../generation-cache.js'
|
|
55
43
|
import { resolveFallbackChain, executeWithFallback } from '../fallback-router.js'
|
|
56
44
|
import { getSessionAnchor, applyAnchorPromptHints } from '../anchor-helpers.js'
|
|
57
|
-
import {
|
|
58
|
-
extractDesignTokens,
|
|
59
|
-
generateCssGradient,
|
|
60
|
-
checkWcagContrast,
|
|
61
|
-
optimizeSvgContent,
|
|
62
|
-
generatePwaIconSuite,
|
|
63
|
-
extractSampleColorsFromBuffer,
|
|
64
|
-
} from '../frontend-assets.js'
|
|
65
45
|
|
|
66
46
|
|
|
67
47
|
export function registerGenerationTools(ctx, deps) {
|
|
68
48
|
const {
|
|
69
49
|
config,
|
|
70
50
|
live,
|
|
71
|
-
saveAndAttachResult,
|
|
72
51
|
resolveSource,
|
|
73
52
|
slugify,
|
|
74
53
|
resolveApiKey,
|
|
@@ -269,7 +248,7 @@ export function registerGenerationTools(ctx, deps) {
|
|
|
269
248
|
// Subscriptions service is optional: without it, subscription providers
|
|
270
249
|
// gracefully decline while other providers continue functioning.
|
|
271
250
|
let subscriptionImages
|
|
272
|
-
try { subscriptionImages = ctx.get && ctx.get('subscriptionImages') } catch
|
|
251
|
+
try { subscriptionImages = ctx.get && ctx.get('subscriptionImages') } catch { subscriptionImages = undefined }
|
|
273
252
|
|
|
274
253
|
const source = args.source_image ? await resolveSource(ctx, exec, args.source_image) : undefined
|
|
275
254
|
const mask = args.mask ? await resolveSource(ctx, exec, args.mask) : undefined
|
package/lib/tools/inspect.js
CHANGED
|
@@ -2,52 +2,13 @@ import { renderToolOutput } from "../attachment-helper.js"
|
|
|
2
2
|
// inspect — image-gen tools (compare_images, inspect_image_quality). Extracted from apply() (#216).
|
|
3
3
|
|
|
4
4
|
import { defineTool } from '@deepseek-ai/dsh-tools'
|
|
5
|
-
import path from 'node:path'
|
|
6
|
-
import { mkdir, writeFile } from 'node:fs/promises'
|
|
7
5
|
import {
|
|
8
|
-
computeGenerationHash,
|
|
9
|
-
IMAGE_SIZES,
|
|
10
6
|
pixelDiff,
|
|
11
|
-
tryGenerate,
|
|
12
|
-
fallbackOrder,
|
|
13
|
-
embedPngMetadata,
|
|
14
|
-
removeBackgroundFal,
|
|
15
|
-
upscaleImageFal,
|
|
16
|
-
traceToSvg,
|
|
17
|
-
estimateCost,
|
|
18
7
|
estimateSharpnessAndVariance,
|
|
19
|
-
applyStylePreset,
|
|
20
|
-
resolveStylePreset,
|
|
21
|
-
blendImagesFal,
|
|
22
|
-
toLosslessJson,
|
|
23
|
-
saveAttachmentSafe,
|
|
24
8
|
} from '../providers.js'
|
|
25
|
-
import { resolveConversationImage, analyzeImageWithVision, buildDualOutputMarkdown } from '../resolve-image.js'
|
|
26
|
-
import { sanitizeNegativePrompt, supportsNegativePrompt } from '../negative-sanitizer.js'
|
|
27
|
-
import { executeWithQualityGate } from '../quality-gate.js'
|
|
28
|
-
import { calculateGenerationCost, recordSpend, assertBudgetAvailable } from '../cost-meter.js'
|
|
29
|
-
import { trackAndAssertLoopGuard } from '../loop-guard.js'
|
|
30
|
-
import { sanitizeErrorAndLogs } from '../security.js'
|
|
31
|
-
import { getCachedGeneration, setCachedGeneration } from '../generation-cache.js'
|
|
32
|
-
import {
|
|
33
|
-
extractDesignTokens,
|
|
34
|
-
generateCssGradient,
|
|
35
|
-
checkWcagContrast,
|
|
36
|
-
optimizeSvgContent,
|
|
37
|
-
generatePwaIconSuite,
|
|
38
|
-
extractSampleColorsFromBuffer,
|
|
39
|
-
} from '../frontend-assets.js'
|
|
40
|
-
|
|
41
9
|
|
|
42
10
|
export function registerInspectTools(ctx, deps) {
|
|
43
|
-
const {
|
|
44
|
-
config,
|
|
45
|
-
live,
|
|
46
|
-
saveAndAttachResult,
|
|
47
|
-
resolveSource,
|
|
48
|
-
slugify,
|
|
49
|
-
resolveApiKey,
|
|
50
|
-
} = deps
|
|
11
|
+
const { resolveSource } = deps
|
|
51
12
|
ctx.effect(() => {
|
|
52
13
|
ctx.tools.register(
|
|
53
14
|
defineTool({
|
|
@@ -58,8 +19,8 @@ export function registerInspectTools(ctx, deps) {
|
|
|
58
19
|
image_b: { type: 'string', required: true, description: 'Path or attachment id of the second image.' },
|
|
59
20
|
},
|
|
60
21
|
output: {
|
|
61
|
-
|
|
62
|
-
|
|
22
|
+
render: (_args, value) => renderToolOutput(value),
|
|
23
|
+
schema: {
|
|
63
24
|
type: 'object',
|
|
64
25
|
additionalProperties: false,
|
|
65
26
|
properties: {
|
|
@@ -86,8 +47,8 @@ export function registerInspectTools(ctx, deps) {
|
|
|
86
47
|
expected_elements: { type: 'string', description: 'What elements should be present and verified.' },
|
|
87
48
|
},
|
|
88
49
|
output: {
|
|
89
|
-
|
|
90
|
-
|
|
50
|
+
render: (_args, value) => renderToolOutput(value),
|
|
51
|
+
schema: {
|
|
91
52
|
type: 'object',
|
|
92
53
|
additionalProperties: false,
|
|
93
54
|
properties: {
|
|
@@ -109,6 +70,6 @@ export function registerInspectTools(ctx, deps) {
|
|
|
109
70
|
}
|
|
110
71
|
},
|
|
111
72
|
}),
|
|
112
|
-
|
|
73
|
+
)
|
|
113
74
|
}, 'dsh-image-gen: tool inspect_image_quality')
|
|
114
75
|
}
|
package/lib/tools/pattern.js
CHANGED
|
@@ -11,6 +11,8 @@ import {
|
|
|
11
11
|
buildSeamlessPrompt,
|
|
12
12
|
buildPatternCss,
|
|
13
13
|
normalizeDensity,
|
|
14
|
+
scoreEdgeWrap,
|
|
15
|
+
tilePixels,
|
|
14
16
|
} from '../pattern-helpers.js'
|
|
15
17
|
|
|
16
18
|
export function registerPatternTools(ctx, deps) {
|
|
@@ -97,6 +99,14 @@ export function registerPatternTools(ctx, deps) {
|
|
|
97
99
|
const filePath = path.join(outDir, name)
|
|
98
100
|
await writeFile(filePath, gen.bytes)
|
|
99
101
|
|
|
102
|
+
if (gen.bytes && gen.width && gen.height) {
|
|
103
|
+
const seamScore = scoreEdgeWrap(new Uint8Array(gen.bytes), gen.width, gen.height)
|
|
104
|
+
const tiled = tilePixels(new Uint8Array(gen.bytes), gen.width, gen.height, 4, 2, 2)
|
|
105
|
+
if (exec?.logger?.debug) {
|
|
106
|
+
exec.logger.debug(`[dsh-image-gen] Pattern seam score: ${seamScore}, 2x2 width: ${tiled.width}`)
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
|
|
100
110
|
const [tilePx] = sizeToPixels(size)
|
|
101
111
|
const css = buildPatternCss({ className: stem, sizePx: tilePx, imagePath: `./${name}` })
|
|
102
112
|
const cssPath = path.join(outDir, `${stem}.css`)
|
|
@@ -7,48 +7,16 @@ import { defineTool } from '@deepseek-ai/dsh-tools'
|
|
|
7
7
|
import path from 'node:path'
|
|
8
8
|
import { mkdir, writeFile } from 'node:fs/promises'
|
|
9
9
|
import {
|
|
10
|
-
computeGenerationHash,
|
|
11
|
-
IMAGE_SIZES,
|
|
12
|
-
tryGenerate,
|
|
13
|
-
fallbackOrder,
|
|
14
|
-
embedPngMetadata,
|
|
15
|
-
removeBackgroundFal,
|
|
16
|
-
upscaleImageFal,
|
|
17
|
-
traceToSvg,
|
|
18
|
-
estimateCost,
|
|
19
|
-
estimateSharpnessAndVariance,
|
|
20
|
-
applyStylePreset,
|
|
21
|
-
resolveStylePreset,
|
|
22
|
-
blendImagesFal,
|
|
23
10
|
toLosslessJson,
|
|
24
11
|
saveAttachmentSafe,
|
|
25
12
|
} from '../providers.js'
|
|
26
|
-
import { resolveConversationImage, analyzeImageWithVision, buildDualOutputMarkdown } from '../resolve-image.js'
|
|
27
|
-
import { sanitizeNegativePrompt, supportsNegativePrompt } from '../negative-sanitizer.js'
|
|
28
|
-
import { executeWithQualityGate } from '../quality-gate.js'
|
|
29
|
-
import { calculateGenerationCost, recordSpend, assertBudgetAvailable } from '../cost-meter.js'
|
|
30
|
-
import { trackAndAssertLoopGuard } from '../loop-guard.js'
|
|
31
13
|
import { sanitizeErrorAndLogs } from '../security.js'
|
|
32
|
-
import { getCachedGeneration, setCachedGeneration } from '../generation-cache.js'
|
|
33
|
-
import {
|
|
34
|
-
extractDesignTokens,
|
|
35
|
-
generateCssGradient,
|
|
36
|
-
checkWcagContrast,
|
|
37
|
-
optimizeSvgContent,
|
|
38
|
-
generatePwaIconSuite,
|
|
39
|
-
extractSampleColorsFromBuffer,
|
|
40
|
-
} from '../frontend-assets.js'
|
|
41
|
-
|
|
42
|
-
|
|
43
14
|
|
|
44
15
|
export function registerProcessingAdvancedTools(ctx, deps) {
|
|
45
16
|
const {
|
|
46
|
-
config,
|
|
47
17
|
live,
|
|
48
|
-
saveAndAttachResult,
|
|
49
18
|
resolveSource,
|
|
50
19
|
slugify,
|
|
51
|
-
resolveApiKey,
|
|
52
20
|
} = deps
|
|
53
21
|
|
|
54
22
|
ctx.effect(() => {
|
|
@@ -7,44 +7,21 @@ import { defineTool } from '@deepseek-ai/dsh-tools'
|
|
|
7
7
|
import path from 'node:path'
|
|
8
8
|
import { mkdir, writeFile } from 'node:fs/promises'
|
|
9
9
|
import {
|
|
10
|
-
computeGenerationHash,
|
|
11
|
-
IMAGE_SIZES,
|
|
12
|
-
tryGenerate,
|
|
13
|
-
fallbackOrder,
|
|
14
|
-
embedPngMetadata,
|
|
15
10
|
removeBackgroundFal,
|
|
16
11
|
upscaleImageFal,
|
|
17
12
|
traceToSvg,
|
|
18
|
-
estimateCost,
|
|
19
|
-
estimateSharpnessAndVariance,
|
|
20
|
-
applyStylePreset,
|
|
21
|
-
resolveStylePreset,
|
|
22
13
|
blendImagesFal,
|
|
23
14
|
toLosslessJson,
|
|
24
15
|
saveAttachmentSafe,
|
|
25
16
|
} from '../providers.js'
|
|
26
|
-
import {
|
|
27
|
-
import {
|
|
28
|
-
import { executeWithQualityGate } from '../quality-gate.js'
|
|
29
|
-
import { calculateGenerationCost, recordSpend, assertBudgetAvailable } from '../cost-meter.js'
|
|
17
|
+
import { buildDualOutputMarkdown } from '../resolve-image.js'
|
|
18
|
+
import { assertBudgetAvailable } from '../cost-meter.js'
|
|
30
19
|
import { trackAndAssertLoopGuard } from '../loop-guard.js'
|
|
31
20
|
import { sanitizeErrorAndLogs } from '../security.js'
|
|
32
|
-
import { getCachedGeneration, setCachedGeneration } from '../generation-cache.js'
|
|
33
|
-
import {
|
|
34
|
-
extractDesignTokens,
|
|
35
|
-
generateCssGradient,
|
|
36
|
-
checkWcagContrast,
|
|
37
|
-
optimizeSvgContent,
|
|
38
|
-
generatePwaIconSuite,
|
|
39
|
-
extractSampleColorsFromBuffer,
|
|
40
|
-
} from '../frontend-assets.js'
|
|
41
|
-
|
|
42
21
|
|
|
43
22
|
export function registerProcessingTools(ctx, deps) {
|
|
44
23
|
const {
|
|
45
|
-
config,
|
|
46
24
|
live,
|
|
47
|
-
saveAndAttachResult,
|
|
48
25
|
resolveSource,
|
|
49
26
|
slugify,
|
|
50
27
|
resolveApiKey,
|
|
@@ -14,7 +14,6 @@ import {
|
|
|
14
14
|
} from '../providers.js'
|
|
15
15
|
import { resolveFallbackChain, executeWithFallback } from '../fallback-router.js'
|
|
16
16
|
import {
|
|
17
|
-
DEFAULT_MATRIX_STYLES,
|
|
18
17
|
normalizeMatrixStyles,
|
|
19
18
|
buildMatrixCellPrompt,
|
|
20
19
|
formatMatrixMarkdown,
|
|
@@ -127,7 +126,7 @@ export function registerStyleMatrixTools(ctx, deps) {
|
|
|
127
126
|
|
|
128
127
|
const provider = PROVIDER_KEYS.includes(cfg.provider) ? cfg.provider : 'fal'
|
|
129
128
|
let subscriptionImages
|
|
130
|
-
try { subscriptionImages = ctx.get && ctx.get('subscriptionImages') } catch
|
|
129
|
+
try { subscriptionImages = ctx.get && ctx.get('subscriptionImages') } catch { subscriptionImages = undefined }
|
|
131
130
|
|
|
132
131
|
const chain = resolveFallbackChain(provider, cfg.fallbackProviders, PROVIDER_KEYS)
|
|
133
132
|
const quadrantIds = ['A', 'B', 'C', 'D']
|
package/lib/tools/theme-pair.js
CHANGED
package/lib/tools/ui-asset.js
CHANGED
|
@@ -123,7 +123,7 @@ export function registerUiAssetTools(ctx, deps) {
|
|
|
123
123
|
|
|
124
124
|
const provider = PROVIDER_KEYS.includes(cfg.provider) ? cfg.provider : 'fal'
|
|
125
125
|
let subscriptionImages
|
|
126
|
-
try { subscriptionImages = ctx.get && ctx.get('subscriptionImages') } catch
|
|
126
|
+
try { subscriptionImages = ctx.get && ctx.get('subscriptionImages') } catch { subscriptionImages = undefined }
|
|
127
127
|
|
|
128
128
|
const providers = makeProviders(
|
|
129
129
|
{ fetchImpl: fetch, resolveKey: (ref) => resolveApiKey(ctx, ref), cfg, subscriptionImages },
|
package/lib/updater.js
CHANGED
|
@@ -3,7 +3,6 @@ import { existsSync, readFileSync } from 'node:fs'
|
|
|
3
3
|
import { readFile } from 'node:fs/promises'
|
|
4
4
|
import { homedir } from 'node:os'
|
|
5
5
|
import { basename, dirname, isAbsolute, resolve } from 'node:path'
|
|
6
|
-
import { fileURLToPath } from 'node:url'
|
|
7
6
|
import { isLoopbackAddress, isPrivateLanAddress, extractHostName } from './security.js'
|
|
8
7
|
|
|
9
8
|
/**
|
|
@@ -21,14 +20,6 @@ function header(request, name) {
|
|
|
21
20
|
return Array.isArray(value) ? value[0] : value
|
|
22
21
|
}
|
|
23
22
|
|
|
24
|
-
function isLoopback(value) {
|
|
25
|
-
return isLoopbackAddress(value)
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
function isPrivateLan(value) {
|
|
29
|
-
return isPrivateLanAddress(value)
|
|
30
|
-
}
|
|
31
|
-
|
|
32
23
|
export function isTrustedUpdateRequest(request) {
|
|
33
24
|
if (header(request, UPDATE_HEADER) !== '1') return false
|
|
34
25
|
const remote = request.socket?.remoteAddress
|
package/lib/vault.js
CHANGED
|
@@ -111,10 +111,10 @@ export async function deleteVaultEntry(id) {
|
|
|
111
111
|
if (entry && entry.path) {
|
|
112
112
|
try {
|
|
113
113
|
unlinkSync(entry.path)
|
|
114
|
-
} catch
|
|
114
|
+
} catch { /* ignore missing file */ }
|
|
115
115
|
try {
|
|
116
116
|
unlinkSync(entry.path.replace(/\.[^.]+$/, '.json'))
|
|
117
|
-
} catch
|
|
117
|
+
} catch { /* ignore missing sidecar */ }
|
|
118
118
|
}
|
|
119
119
|
|
|
120
120
|
await writeHistory(entries)
|
|
@@ -161,7 +161,7 @@ export function registerVaultRoutes(ctx) {
|
|
|
161
161
|
for await (const chunk of req) chunks.push(chunk)
|
|
162
162
|
const body = JSON.parse(Buffer.concat(chunks).toString('utf-8'))
|
|
163
163
|
id = body.id
|
|
164
|
-
} catch
|
|
164
|
+
} catch { /* body parse error */ }
|
|
165
165
|
}
|
|
166
166
|
|
|
167
167
|
if (!id) {
|