mcp-hydrocoder-image 1.0.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/LICENSE +21 -0
- package/README.md +454 -0
- package/bin/install-skills.js +115 -0
- package/dist/api/geminiClient.d.ts +57 -0
- package/dist/api/geminiClient.d.ts.map +1 -0
- package/dist/api/geminiClient.js +341 -0
- package/dist/api/geminiClient.js.map +1 -0
- package/dist/api/geminiTextClient.d.ts +44 -0
- package/dist/api/geminiTextClient.d.ts.map +1 -0
- package/dist/api/geminiTextClient.js +202 -0
- package/dist/api/geminiTextClient.js.map +1 -0
- package/dist/business/fileManager.d.ts +20 -0
- package/dist/business/fileManager.d.ts.map +1 -0
- package/dist/business/fileManager.js +76 -0
- package/dist/business/fileManager.js.map +1 -0
- package/dist/business/inputValidator.d.ts +44 -0
- package/dist/business/inputValidator.d.ts.map +1 -0
- package/dist/business/inputValidator.js +213 -0
- package/dist/business/inputValidator.js.map +1 -0
- package/dist/business/responseBuilder.d.ts +21 -0
- package/dist/business/responseBuilder.d.ts.map +1 -0
- package/dist/business/responseBuilder.js +166 -0
- package/dist/business/responseBuilder.js.map +1 -0
- package/dist/business/structuredPromptGenerator.d.ts +56 -0
- package/dist/business/structuredPromptGenerator.d.ts.map +1 -0
- package/dist/business/structuredPromptGenerator.js +218 -0
- package/dist/business/structuredPromptGenerator.js.map +1 -0
- package/dist/index.d.ts +12 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +30 -0
- package/dist/index.js.map +1 -0
- package/dist/server/errorHandler.d.ts +29 -0
- package/dist/server/errorHandler.d.ts.map +1 -0
- package/dist/server/errorHandler.js +99 -0
- package/dist/server/errorHandler.js.map +1 -0
- package/dist/server/mcpServer.d.ts +159 -0
- package/dist/server/mcpServer.d.ts.map +1 -0
- package/dist/server/mcpServer.js +434 -0
- package/dist/server/mcpServer.js.map +1 -0
- package/dist/server-main.d.ts +5 -0
- package/dist/server-main.d.ts.map +1 -0
- package/dist/server-main.js +37 -0
- package/dist/server-main.js.map +1 -0
- package/dist/types/mcp.d.ts +121 -0
- package/dist/types/mcp.d.ts.map +1 -0
- package/dist/types/mcp.js +22 -0
- package/dist/types/mcp.js.map +1 -0
- package/dist/types/result.d.ts +27 -0
- package/dist/types/result.d.ts.map +1 -0
- package/dist/types/result.js +27 -0
- package/dist/types/result.js.map +1 -0
- package/dist/utils/config.d.ts +29 -0
- package/dist/utils/config.d.ts.map +1 -0
- package/dist/utils/config.js +56 -0
- package/dist/utils/config.js.map +1 -0
- package/dist/utils/errors.d.ts +84 -0
- package/dist/utils/errors.d.ts.map +1 -0
- package/dist/utils/errors.js +215 -0
- package/dist/utils/errors.js.map +1 -0
- package/dist/utils/logger.d.ts +80 -0
- package/dist/utils/logger.d.ts.map +1 -0
- package/dist/utils/logger.js +186 -0
- package/dist/utils/logger.js.map +1 -0
- package/dist/utils/security.d.ts +50 -0
- package/dist/utils/security.d.ts.map +1 -0
- package/dist/utils/security.js +116 -0
- package/dist/utils/security.js.map +1 -0
- package/package.json +89 -0
- package/skills/image-generation/SKILL.md +131 -0
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* File Manager for handling image file operations
|
|
3
|
+
* Provides functionality for saving images and managing directories
|
|
4
|
+
*/
|
|
5
|
+
import { promises as fs, mkdirSync } from 'node:fs';
|
|
6
|
+
import * as path from 'node:path';
|
|
7
|
+
import { Err, Ok } from '../types/result.js';
|
|
8
|
+
import { FileOperationError } from '../utils/errors.js';
|
|
9
|
+
// Constants for file naming and error messages
|
|
10
|
+
const FILE_NAME_PREFIX = 'image';
|
|
11
|
+
const DEFAULT_EXTENSION = '.png';
|
|
12
|
+
const RANDOM_RANGE = 1000;
|
|
13
|
+
const ERROR_MESSAGES = {
|
|
14
|
+
SAVE_FAILED: 'Failed to save image file',
|
|
15
|
+
DIRECTORY_CREATION_FAILED: 'Failed to create directory',
|
|
16
|
+
PERMISSION_SUGGESTION: 'Check output directory permissions and disk space',
|
|
17
|
+
PATH_SUGGESTION: 'Check directory path validity and write permissions',
|
|
18
|
+
};
|
|
19
|
+
/**
|
|
20
|
+
* Ensures that the specified directory exists, creating it if necessary
|
|
21
|
+
* @param dirPath Path to the directory
|
|
22
|
+
* @returns Result indicating success or failure
|
|
23
|
+
*/
|
|
24
|
+
function ensureDirectoryExists(dirPath) {
|
|
25
|
+
try {
|
|
26
|
+
// Use mkdirSync with recursive option to create all necessary parent directories
|
|
27
|
+
mkdirSync(dirPath, { recursive: true });
|
|
28
|
+
return Ok(undefined);
|
|
29
|
+
}
|
|
30
|
+
catch (error) {
|
|
31
|
+
return Err(new FileOperationError(`${ERROR_MESSAGES.DIRECTORY_CREATION_FAILED}: ${error instanceof Error ? error.message : 'Unknown error'}`));
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Generates a unique filename based on timestamp and random component
|
|
36
|
+
* @returns Generated filename in the format: gemini-image-{timestamp}.png
|
|
37
|
+
*/
|
|
38
|
+
function generateFileName() {
|
|
39
|
+
const timestamp = Date.now();
|
|
40
|
+
const random = Math.floor(Math.random() * RANDOM_RANGE);
|
|
41
|
+
return `${FILE_NAME_PREFIX}-${timestamp}-${random}${DEFAULT_EXTENSION}`;
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Creates a file manager for image file operations
|
|
45
|
+
* @returns FileManager implementation
|
|
46
|
+
*/
|
|
47
|
+
export function createFileManager() {
|
|
48
|
+
return {
|
|
49
|
+
/**
|
|
50
|
+
* Saves image data to the specified file path
|
|
51
|
+
* @param imageData Buffer containing the image data
|
|
52
|
+
* @param outputPath Absolute path where the image should be saved
|
|
53
|
+
* @param format Image format (used for validation)
|
|
54
|
+
* @returns Result containing the saved file path or an error
|
|
55
|
+
*/
|
|
56
|
+
async saveImage(imageData, outputPath, _format) {
|
|
57
|
+
try {
|
|
58
|
+
// Ensure the directory exists
|
|
59
|
+
const directory = path.dirname(outputPath);
|
|
60
|
+
const dirResult = ensureDirectoryExists(directory);
|
|
61
|
+
if (!dirResult.success) {
|
|
62
|
+
return Err(dirResult.error);
|
|
63
|
+
}
|
|
64
|
+
// Save the file
|
|
65
|
+
await fs.writeFile(outputPath, imageData);
|
|
66
|
+
return Ok(outputPath);
|
|
67
|
+
}
|
|
68
|
+
catch (error) {
|
|
69
|
+
return Err(new FileOperationError(`${ERROR_MESSAGES.SAVE_FAILED}: ${error instanceof Error ? error.message : 'Unknown error'}`));
|
|
70
|
+
}
|
|
71
|
+
},
|
|
72
|
+
ensureDirectoryExists,
|
|
73
|
+
generateFileName,
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
//# sourceMappingURL=fileManager.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fileManager.js","sourceRoot":"","sources":["../../src/business/fileManager.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,QAAQ,IAAI,EAAE,EAAE,SAAS,EAAE,MAAM,SAAS,CAAA;AACnD,OAAO,KAAK,IAAI,MAAM,WAAW,CAAA;AAEjC,OAAO,EAAE,GAAG,EAAE,EAAE,EAAE,MAAM,oBAAoB,CAAA;AAC5C,OAAO,EAAE,kBAAkB,EAAE,MAAM,oBAAoB,CAAA;AAEvD,+CAA+C;AAC/C,MAAM,gBAAgB,GAAG,OAAgB,CAAA;AACzC,MAAM,iBAAiB,GAAG,MAAe,CAAA;AACzC,MAAM,YAAY,GAAG,IAAa,CAAA;AAElC,MAAM,cAAc,GAAG;IACrB,WAAW,EAAE,2BAA2B;IACxC,yBAAyB,EAAE,4BAA4B;IACvD,qBAAqB,EAAE,mDAAmD;IAC1E,eAAe,EAAE,qDAAqD;CAC9D,CAAA;AAeV;;;;GAIG;AACH,SAAS,qBAAqB,CAAC,OAAe;IAC5C,IAAI,CAAC;QACH,iFAAiF;QACjF,SAAS,CAAC,OAAO,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAA;QACvC,OAAO,EAAE,CAAC,SAAS,CAAC,CAAA;IACtB,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,OAAO,GAAG,CACR,IAAI,kBAAkB,CACpB,GAAG,cAAc,CAAC,yBAAyB,KAAK,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,eAAe,EAAE,CAC3G,CACF,CAAA;IACH,CAAC;AACH,CAAC;AAED;;;GAGG;AACH,SAAS,gBAAgB;IACvB,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,EAAE,CAAA;IAC5B,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,EAAE,GAAG,YAAY,CAAC,CAAA;IACvD,OAAO,GAAG,gBAAgB,IAAI,SAAS,IAAI,MAAM,GAAG,iBAAiB,EAAE,CAAA;AACzE,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,iBAAiB;IAC/B,OAAO;QACL;;;;;;WAMG;QACH,KAAK,CAAC,SAAS,CACb,SAAiB,EACjB,UAAkB,EAClB,OAAgB;YAEhB,IAAI,CAAC;gBACH,8BAA8B;gBAC9B,MAAM,SAAS,GAAG,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,CAAA;gBAC1C,MAAM,SAAS,GAAG,qBAAqB,CAAC,SAAS,CAAC,CAAA;gBAClD,IAAI,CAAC,SAAS,CAAC,OAAO,EAAE,CAAC;oBACvB,OAAO,GAAG,CAAC,SAAS,CAAC,KAAK,CAAC,CAAA;gBAC7B,CAAC;gBAED,gBAAgB;gBAChB,MAAM,EAAE,CAAC,SAAS,CAAC,UAAU,EAAE,SAAS,CAAC,CAAA;gBAEzC,OAAO,EAAE,CAAC,UAAU,CAAC,CAAA;YACvB,CAAC;YAAC,OAAO,KAAK,EAAE,CAAC;gBACf,OAAO,GAAG,CACR,IAAI,kBAAkB,CACpB,GAAG,cAAc,CAAC,WAAW,KAAK,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,eAAe,EAAE,CAC7F,CACF,CAAA;YACH,CAAC;QACH,CAAC;QAED,qBAAqB;QACrB,gBAAgB;KACjB,CAAA;AACH,CAAC"}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Input validation module for MCP server
|
|
3
|
+
* Validates user inputs according to Gemini API and business requirements
|
|
4
|
+
*/
|
|
5
|
+
import type { GenerateImageParams } from '../types/mcp.js';
|
|
6
|
+
import type { Result } from '../types/result.js';
|
|
7
|
+
import { InputValidationError } from '../utils/errors.js';
|
|
8
|
+
/**
|
|
9
|
+
* Validates prompt text for length constraints
|
|
10
|
+
*/
|
|
11
|
+
export declare function validatePrompt(prompt: string): Result<string, InputValidationError>;
|
|
12
|
+
/**
|
|
13
|
+
* Validates base64 encoded image data
|
|
14
|
+
* @param imageData - Base64 encoded image string
|
|
15
|
+
* @param mimeType - MIME type of the image
|
|
16
|
+
* @returns Result with validated Buffer or error
|
|
17
|
+
*/
|
|
18
|
+
export declare function validateBase64Image(imageData?: string, mimeType?: string): Result<Buffer | undefined, InputValidationError>;
|
|
19
|
+
/**
|
|
20
|
+
* Validates an array of base64 encoded images
|
|
21
|
+
* @param images - Array of image objects with data and mimeType
|
|
22
|
+
* @returns Result with success or error
|
|
23
|
+
*/
|
|
24
|
+
export declare function validateBase64Images(images: Array<{
|
|
25
|
+
data: string;
|
|
26
|
+
mimeType: string;
|
|
27
|
+
}>): Result<void, InputValidationError>;
|
|
28
|
+
/**
|
|
29
|
+
* Validates an array of input image paths
|
|
30
|
+
* @param paths - Array of image file paths
|
|
31
|
+
* @returns Result with success or error
|
|
32
|
+
*/
|
|
33
|
+
export declare function validateImagePaths(paths: string[]): Result<void, InputValidationError>;
|
|
34
|
+
/**
|
|
35
|
+
* Validates input image path
|
|
36
|
+
* @param imagePath - Path to the input image file
|
|
37
|
+
* @returns Result with validated path or error
|
|
38
|
+
*/
|
|
39
|
+
export declare function validateImagePath(imagePath?: string): Result<string | undefined, InputValidationError>;
|
|
40
|
+
/**
|
|
41
|
+
* Validates complete GenerateImageParams object
|
|
42
|
+
*/
|
|
43
|
+
export declare function validateGenerateImageParams(params: GenerateImageParams): Result<GenerateImageParams, InputValidationError>;
|
|
44
|
+
//# sourceMappingURL=inputValidator.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"inputValidator.d.ts","sourceRoot":"","sources":["../../src/business/inputValidator.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAIH,OAAO,KAAK,EAAe,mBAAmB,EAAE,MAAM,iBAAiB,CAAA;AAEvE,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,oBAAoB,CAAA;AAEhD,OAAO,EAAE,oBAAoB,EAAE,MAAM,oBAAoB,CAAA;AAiCzD;;GAEG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,oBAAoB,CAAC,CAanF;AAED;;;;;GAKG;AACH,wBAAgB,mBAAmB,CACjC,SAAS,CAAC,EAAE,MAAM,EAClB,QAAQ,CAAC,EAAE,MAAM,GAChB,MAAM,CAAC,MAAM,GAAG,SAAS,EAAE,oBAAoB,CAAC,CAuDlD;AAED;;;;GAIG;AACH,wBAAgB,oBAAoB,CAClC,MAAM,EAAE,KAAK,CAAC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,CAAC,GAChD,MAAM,CAAC,IAAI,EAAE,oBAAoB,CAAC,CAyBpC;AAED;;;;GAIG;AACH,wBAAgB,kBAAkB,CAChC,KAAK,EAAE,MAAM,EAAE,GACd,MAAM,CAAC,IAAI,EAAE,oBAAoB,CAAC,CAuBpC;AAED;;;;GAIG;AACH,wBAAgB,iBAAiB,CAC/B,SAAS,CAAC,EAAE,MAAM,GACjB,MAAM,CAAC,MAAM,GAAG,SAAS,EAAE,oBAAoB,CAAC,CA6BlD;AAED;;GAEG;AACH,wBAAgB,2BAA2B,CACzC,MAAM,EAAE,mBAAmB,GAC1B,MAAM,CAAC,mBAAmB,EAAE,oBAAoB,CAAC,CA2GnD"}
|
|
@@ -0,0 +1,213 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Input validation module for MCP server
|
|
3
|
+
* Validates user inputs according to Gemini API and business requirements
|
|
4
|
+
*/
|
|
5
|
+
import { existsSync } from 'node:fs';
|
|
6
|
+
import { extname } from 'node:path';
|
|
7
|
+
import { IMAGE_QUALITY_VALUES } from '../types/mcp.js';
|
|
8
|
+
import { Err, Ok } from '../types/result.js';
|
|
9
|
+
import { InputValidationError } from '../utils/errors.js';
|
|
10
|
+
// Constants for validation limits
|
|
11
|
+
const PROMPT_MIN_LENGTH = 1;
|
|
12
|
+
const PROMPT_MAX_LENGTH = 4000;
|
|
13
|
+
const MAX_IMAGE_SIZE = 10 * 1024 * 1024; // 10MB in bytes
|
|
14
|
+
const SUPPORTED_MIME_TYPES = ['image/jpeg', 'image/png', 'image/webp', 'image/gif', 'image/bmp'];
|
|
15
|
+
const SUPPORTED_ASPECT_RATIOS = [
|
|
16
|
+
'1:1',
|
|
17
|
+
'1:4',
|
|
18
|
+
'1:8',
|
|
19
|
+
'2:3',
|
|
20
|
+
'3:2',
|
|
21
|
+
'3:4',
|
|
22
|
+
'4:1',
|
|
23
|
+
'4:3',
|
|
24
|
+
'4:5',
|
|
25
|
+
'5:4',
|
|
26
|
+
'8:1',
|
|
27
|
+
'9:16',
|
|
28
|
+
'16:9',
|
|
29
|
+
'21:9',
|
|
30
|
+
];
|
|
31
|
+
const SUPPORTED_QUALITY_VALUES = IMAGE_QUALITY_VALUES;
|
|
32
|
+
/**
|
|
33
|
+
* Converts bytes to MB with proper formatting
|
|
34
|
+
*/
|
|
35
|
+
function formatFileSize(bytes) {
|
|
36
|
+
return (bytes / (1024 * 1024)).toFixed(1);
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Validates prompt text for length constraints
|
|
40
|
+
*/
|
|
41
|
+
export function validatePrompt(prompt) {
|
|
42
|
+
if (prompt.length < PROMPT_MIN_LENGTH || prompt.length > PROMPT_MAX_LENGTH) {
|
|
43
|
+
return Err(new InputValidationError(`Prompt must be between ${PROMPT_MIN_LENGTH} and ${PROMPT_MAX_LENGTH} characters. Current length: ${prompt.length}`, prompt.length === 0
|
|
44
|
+
? 'Please provide a descriptive prompt for image generation.'
|
|
45
|
+
: `Please shorten your prompt by ${prompt.length - PROMPT_MAX_LENGTH} characters.`));
|
|
46
|
+
}
|
|
47
|
+
return Ok(prompt);
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Validates base64 encoded image data
|
|
51
|
+
* @param imageData - Base64 encoded image string
|
|
52
|
+
* @param mimeType - MIME type of the image
|
|
53
|
+
* @returns Result with validated Buffer or error
|
|
54
|
+
*/
|
|
55
|
+
export function validateBase64Image(imageData, mimeType) {
|
|
56
|
+
// If no image data provided, it's valid (optional parameter)
|
|
57
|
+
if (!imageData) {
|
|
58
|
+
return Ok(undefined);
|
|
59
|
+
}
|
|
60
|
+
// Validate MIME type if provided
|
|
61
|
+
if (mimeType && !SUPPORTED_MIME_TYPES.includes(mimeType)) {
|
|
62
|
+
return Err(new InputValidationError(`Unsupported MIME type: ${mimeType}. Supported types: ${SUPPORTED_MIME_TYPES.join(', ')}`, `Please provide an image with one of these MIME types: ${SUPPORTED_MIME_TYPES.join(', ')}`));
|
|
63
|
+
}
|
|
64
|
+
// Check if it's valid base64
|
|
65
|
+
// Remove data URI prefix if present
|
|
66
|
+
const base64Regex = /^[A-Za-z0-9+/]*={0,2}$/;
|
|
67
|
+
const cleanedData = imageData.replace(/^data:image\/[a-z]+;base64,/, '');
|
|
68
|
+
if (!base64Regex.test(cleanedData)) {
|
|
69
|
+
return Err(new InputValidationError('Invalid base64 format', 'Please provide a valid base64 encoded image string'));
|
|
70
|
+
}
|
|
71
|
+
// Decode and check size
|
|
72
|
+
let buffer;
|
|
73
|
+
try {
|
|
74
|
+
buffer = Buffer.from(cleanedData, 'base64');
|
|
75
|
+
if (buffer.length > MAX_IMAGE_SIZE) {
|
|
76
|
+
const sizeInMB = formatFileSize(buffer.length);
|
|
77
|
+
const limitInMB = formatFileSize(MAX_IMAGE_SIZE);
|
|
78
|
+
return Err(new InputValidationError(`Image size exceeds ${limitInMB}MB limit. Current size: ${sizeInMB}MB`, `Please compress your image or reduce its resolution to stay below ${limitInMB}MB`));
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
catch (_error) {
|
|
82
|
+
return Err(new InputValidationError('Failed to decode base64 image', 'Please ensure the image is properly base64 encoded'));
|
|
83
|
+
}
|
|
84
|
+
return Ok(buffer);
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Validates an array of base64 encoded images
|
|
88
|
+
* @param images - Array of image objects with data and mimeType
|
|
89
|
+
* @returns Result with success or error
|
|
90
|
+
*/
|
|
91
|
+
export function validateBase64Images(images) {
|
|
92
|
+
if (images.length === 0) {
|
|
93
|
+
return Err(new InputValidationError('inputImages array must not be empty', 'Provide at least one image in the inputImages array'));
|
|
94
|
+
}
|
|
95
|
+
for (let i = 0; i < images.length; i++) {
|
|
96
|
+
const img = images[i];
|
|
97
|
+
if (!img)
|
|
98
|
+
continue;
|
|
99
|
+
const result = validateBase64Image(img.data, img.mimeType);
|
|
100
|
+
if (!result.success) {
|
|
101
|
+
return Err(new InputValidationError(`inputImages[${i}]: ${result.error.message}`, result.error.suggestion));
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
return Ok(undefined);
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* Validates an array of input image paths
|
|
108
|
+
* @param paths - Array of image file paths
|
|
109
|
+
* @returns Result with success or error
|
|
110
|
+
*/
|
|
111
|
+
export function validateImagePaths(paths) {
|
|
112
|
+
if (paths.length === 0) {
|
|
113
|
+
return Err(new InputValidationError('inputImagePaths array must not be empty', 'Provide at least one file path in the inputImagePaths array'));
|
|
114
|
+
}
|
|
115
|
+
for (let i = 0; i < paths.length; i++) {
|
|
116
|
+
const result = validateImagePath(paths[i]);
|
|
117
|
+
if (!result.success) {
|
|
118
|
+
return Err(new InputValidationError(`inputImagePaths[${i}]: ${result.error.message}`, result.error.suggestion));
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
return Ok(undefined);
|
|
122
|
+
}
|
|
123
|
+
/**
|
|
124
|
+
* Validates input image path
|
|
125
|
+
* @param imagePath - Path to the input image file
|
|
126
|
+
* @returns Result with validated path or error
|
|
127
|
+
*/
|
|
128
|
+
export function validateImagePath(imagePath) {
|
|
129
|
+
// If no path provided, it's valid (optional parameter)
|
|
130
|
+
if (!imagePath) {
|
|
131
|
+
return Ok(undefined);
|
|
132
|
+
}
|
|
133
|
+
// Check if file exists
|
|
134
|
+
if (!existsSync(imagePath)) {
|
|
135
|
+
return Err(new InputValidationError(`Input image file not found: ${imagePath}`, 'Please provide a valid absolute path to an existing image file'));
|
|
136
|
+
}
|
|
137
|
+
// Check file extension
|
|
138
|
+
const ext = extname(imagePath).toLowerCase();
|
|
139
|
+
const supportedExtensions = ['.jpg', '.jpeg', '.png', '.webp', '.gif', '.bmp'];
|
|
140
|
+
if (!supportedExtensions.includes(ext)) {
|
|
141
|
+
return Err(new InputValidationError(`Unsupported image format: ${ext}. Supported formats: ${supportedExtensions.join(', ')}`, `Please provide an image with one of these extensions: ${supportedExtensions.join(', ')}`));
|
|
142
|
+
}
|
|
143
|
+
return Ok(imagePath);
|
|
144
|
+
}
|
|
145
|
+
/**
|
|
146
|
+
* Validates complete GenerateImageParams object
|
|
147
|
+
*/
|
|
148
|
+
export function validateGenerateImageParams(params) {
|
|
149
|
+
// Validate prompt
|
|
150
|
+
const promptResult = validatePrompt(params.prompt);
|
|
151
|
+
if (!promptResult.success) {
|
|
152
|
+
return Err(promptResult.error);
|
|
153
|
+
}
|
|
154
|
+
// Validate input image path if provided
|
|
155
|
+
const imagePathResult = validateImagePath(params.inputImagePath);
|
|
156
|
+
if (!imagePathResult.success) {
|
|
157
|
+
return Err(imagePathResult.error);
|
|
158
|
+
}
|
|
159
|
+
// Validate blendImages parameter
|
|
160
|
+
if (params.blendImages !== undefined && typeof params.blendImages !== 'boolean') {
|
|
161
|
+
return Err(new InputValidationError('blendImages must be a boolean value', 'Use true or false for blendImages parameter to enable/disable multi-image blending'));
|
|
162
|
+
}
|
|
163
|
+
// Validate maintainCharacterConsistency parameter
|
|
164
|
+
if (params.maintainCharacterConsistency !== undefined &&
|
|
165
|
+
typeof params.maintainCharacterConsistency !== 'boolean') {
|
|
166
|
+
return Err(new InputValidationError('maintainCharacterConsistency must be a boolean value', 'Use true or false for maintainCharacterConsistency parameter to enable/disable character consistency'));
|
|
167
|
+
}
|
|
168
|
+
// Validate useWorldKnowledge parameter
|
|
169
|
+
if (params.useWorldKnowledge !== undefined && typeof params.useWorldKnowledge !== 'boolean') {
|
|
170
|
+
return Err(new InputValidationError('useWorldKnowledge must be a boolean value', 'Use true or false for useWorldKnowledge parameter to enable/disable world knowledge integration'));
|
|
171
|
+
}
|
|
172
|
+
// Validate mutual exclusivity of image input methods
|
|
173
|
+
const imageInputCount = [
|
|
174
|
+
params.inputImagePath,
|
|
175
|
+
params.inputImage,
|
|
176
|
+
params.inputImages,
|
|
177
|
+
params.inputImagePaths,
|
|
178
|
+
].filter(Boolean).length;
|
|
179
|
+
if (imageInputCount > 1) {
|
|
180
|
+
return Err(new InputValidationError('Only one image input method can be used at a time: inputImagePath, inputImage, inputImages, or inputImagePaths', 'Choose one: inputImagePath (single file), inputImage (single base64), inputImagePaths (multiple files), or inputImages (multiple base64)'));
|
|
181
|
+
}
|
|
182
|
+
// Validate inputImages array if provided
|
|
183
|
+
if (params.inputImages) {
|
|
184
|
+
const imagesResult = validateBase64Images(params.inputImages);
|
|
185
|
+
if (!imagesResult.success) {
|
|
186
|
+
return Err(imagesResult.error);
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
// Validate inputImagePaths array if provided
|
|
190
|
+
if (params.inputImagePaths) {
|
|
191
|
+
const pathsResult = validateImagePaths(params.inputImagePaths);
|
|
192
|
+
if (!pathsResult.success) {
|
|
193
|
+
return Err(pathsResult.error);
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
// Validate input image data if provided
|
|
197
|
+
if (params.inputImage || params.inputImageMimeType) {
|
|
198
|
+
const imageResult = validateBase64Image(params.inputImage, params.inputImageMimeType);
|
|
199
|
+
if (!imageResult.success) {
|
|
200
|
+
return Err(imageResult.error);
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
// Validate aspectRatio parameter
|
|
204
|
+
if (params.aspectRatio && !SUPPORTED_ASPECT_RATIOS.includes(params.aspectRatio)) {
|
|
205
|
+
return Err(new InputValidationError(`Invalid aspect ratio: ${params.aspectRatio}. Supported values: ${SUPPORTED_ASPECT_RATIOS.join(', ')}`, `Please use one of the supported aspect ratios: ${SUPPORTED_ASPECT_RATIOS.join(', ')}`));
|
|
206
|
+
}
|
|
207
|
+
// Validate quality parameter
|
|
208
|
+
if (params.quality !== undefined && !SUPPORTED_QUALITY_VALUES.includes(params.quality)) {
|
|
209
|
+
return Err(new InputValidationError(`Invalid quality value: "${params.quality}". Supported values: ${SUPPORTED_QUALITY_VALUES.join(', ')}`, `Please use one of the supported quality values: ${SUPPORTED_QUALITY_VALUES.join(', ')}`));
|
|
210
|
+
}
|
|
211
|
+
return Ok(params);
|
|
212
|
+
}
|
|
213
|
+
//# sourceMappingURL=inputValidator.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"inputValidator.js","sourceRoot":"","sources":["../../src/business/inputValidator.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Response Builder for MCP structured content responses
|
|
3
|
+
* Converts generation results and errors into MCP-compatible response format
|
|
4
|
+
*/
|
|
5
|
+
import type { GeneratedImageResult } from '../api/geminiClient.js';
|
|
6
|
+
import type { McpToolResponse } from '../types/mcp.js';
|
|
7
|
+
import { type BaseError } from '../utils/errors.js';
|
|
8
|
+
/**
|
|
9
|
+
* Interface for response builder functionality
|
|
10
|
+
*/
|
|
11
|
+
export interface ResponseBuilder {
|
|
12
|
+
buildSuccessResponse(generationResult: GeneratedImageResult, filePath: string): McpToolResponse;
|
|
13
|
+
buildBase64SuccessResponse(generationResult: GeneratedImageResult, filePath: string, base64Data: string): McpToolResponse;
|
|
14
|
+
buildErrorResponse(error: BaseError | Error): McpToolResponse;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Creates a response builder with MCP structured content support
|
|
18
|
+
* @returns ResponseBuilder implementation
|
|
19
|
+
*/
|
|
20
|
+
export declare function createResponseBuilder(): ResponseBuilder;
|
|
21
|
+
//# sourceMappingURL=responseBuilder.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"responseBuilder.d.ts","sourceRoot":"","sources":["../../src/business/responseBuilder.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,wBAAwB,CAAA;AAClE,OAAO,KAAK,EAAE,eAAe,EAAqB,MAAM,iBAAiB,CAAA;AACzE,OAAO,EACL,KAAK,SAAS,EAOf,MAAM,oBAAoB,CAAA;AAmB3B;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B,oBAAoB,CAAC,gBAAgB,EAAE,oBAAoB,EAAE,QAAQ,EAAE,MAAM,GAAG,eAAe,CAAA;IAC/F,0BAA0B,CACxB,gBAAgB,EAAE,oBAAoB,EACtC,QAAQ,EAAE,MAAM,EAChB,UAAU,EAAE,MAAM,GACjB,eAAe,CAAA;IAClB,kBAAkB,CAAC,KAAK,EAAE,SAAS,GAAG,KAAK,GAAG,eAAe,CAAA;CAC9D;AA+DD;;;GAGG;AACH,wBAAgB,qBAAqB,IAAI,eAAe,CA0GvD"}
|
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Response Builder for MCP structured content responses
|
|
3
|
+
* Converts generation results and errors into MCP-compatible response format
|
|
4
|
+
*/
|
|
5
|
+
import * as path from 'node:path';
|
|
6
|
+
import { ConfigError, FileOperationError, GeminiAPIError, InputValidationError, NetworkError, SecurityError, } from '../utils/errors.js';
|
|
7
|
+
// Constants for MIME types and error handling
|
|
8
|
+
const MIME_TYPES = {
|
|
9
|
+
PNG: 'image/png',
|
|
10
|
+
JPEG: 'image/jpeg',
|
|
11
|
+
WEBP: 'image/webp',
|
|
12
|
+
};
|
|
13
|
+
const FILE_EXTENSIONS = {
|
|
14
|
+
PNG: ['.png'],
|
|
15
|
+
JPEG: ['.jpg', '.jpeg'],
|
|
16
|
+
WEBP: ['.webp'],
|
|
17
|
+
};
|
|
18
|
+
const DEFAULT_MIME_TYPE = MIME_TYPES.PNG;
|
|
19
|
+
const UNKNOWN_ERROR_CODE = 'UNKNOWN_ERROR';
|
|
20
|
+
const DEFAULT_ERROR_SUGGESTION = 'Please try again or contact support if the problem persists';
|
|
21
|
+
/**
|
|
22
|
+
* Determines MIME type based on file extension
|
|
23
|
+
* @param filePath Path to the image file
|
|
24
|
+
* @returns MIME type string
|
|
25
|
+
*/
|
|
26
|
+
function getMimeTypeFromPath(filePath) {
|
|
27
|
+
const ext = path.extname(filePath).toLowerCase();
|
|
28
|
+
if (FILE_EXTENSIONS.PNG.includes(ext)) {
|
|
29
|
+
return MIME_TYPES.PNG;
|
|
30
|
+
}
|
|
31
|
+
if (FILE_EXTENSIONS.JPEG.includes(ext)) {
|
|
32
|
+
return MIME_TYPES.JPEG;
|
|
33
|
+
}
|
|
34
|
+
if (FILE_EXTENSIONS.WEBP.includes(ext)) {
|
|
35
|
+
return MIME_TYPES.WEBP;
|
|
36
|
+
}
|
|
37
|
+
return DEFAULT_MIME_TYPE;
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Converts various error types to structured error format
|
|
41
|
+
* @param error Error to convert
|
|
42
|
+
* @returns Structured error object
|
|
43
|
+
*/
|
|
44
|
+
function convertErrorToStructured(error) {
|
|
45
|
+
const baseError = {
|
|
46
|
+
timestamp: new Date().toISOString(),
|
|
47
|
+
};
|
|
48
|
+
if (error instanceof InputValidationError ||
|
|
49
|
+
error instanceof FileOperationError ||
|
|
50
|
+
error instanceof GeminiAPIError ||
|
|
51
|
+
error instanceof NetworkError ||
|
|
52
|
+
error instanceof ConfigError ||
|
|
53
|
+
error instanceof SecurityError) {
|
|
54
|
+
return {
|
|
55
|
+
...baseError,
|
|
56
|
+
code: error.code,
|
|
57
|
+
message: error.message,
|
|
58
|
+
suggestion: error.suggestion,
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
// Handle unknown errors
|
|
62
|
+
return {
|
|
63
|
+
...baseError,
|
|
64
|
+
code: UNKNOWN_ERROR_CODE,
|
|
65
|
+
message: error.message || 'An unknown error occurred',
|
|
66
|
+
suggestion: DEFAULT_ERROR_SUGGESTION,
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Creates a response builder with MCP structured content support
|
|
71
|
+
* @returns ResponseBuilder implementation
|
|
72
|
+
*/
|
|
73
|
+
export function createResponseBuilder() {
|
|
74
|
+
return {
|
|
75
|
+
/**
|
|
76
|
+
* Builds a successful structured content response with file path
|
|
77
|
+
* @param generationResult Result from image generation
|
|
78
|
+
* @param filePath Absolute path to the saved image file (required)
|
|
79
|
+
* @returns MCP tool response with structured content containing file path
|
|
80
|
+
*/
|
|
81
|
+
buildSuccessResponse(generationResult, filePath) {
|
|
82
|
+
// File-based implementation: Always return file path, never base64
|
|
83
|
+
// This avoids MCP token limit issues (25,000 tokens max)
|
|
84
|
+
const mimeType = getMimeTypeFromPath(filePath);
|
|
85
|
+
const fileName = path.basename(filePath);
|
|
86
|
+
const structuredContent = {
|
|
87
|
+
type: 'resource',
|
|
88
|
+
resource: {
|
|
89
|
+
uri: `file://${filePath}`,
|
|
90
|
+
name: fileName,
|
|
91
|
+
mimeType,
|
|
92
|
+
},
|
|
93
|
+
metadata: {
|
|
94
|
+
model: generationResult.metadata.model,
|
|
95
|
+
processingTime: 0, // Not tracked in simplified version
|
|
96
|
+
contextMethod: 'structured_prompt',
|
|
97
|
+
timestamp: generationResult.metadata.timestamp.toISOString(),
|
|
98
|
+
},
|
|
99
|
+
};
|
|
100
|
+
return {
|
|
101
|
+
content: [
|
|
102
|
+
{
|
|
103
|
+
type: 'text',
|
|
104
|
+
text: JSON.stringify(structuredContent),
|
|
105
|
+
},
|
|
106
|
+
],
|
|
107
|
+
isError: false,
|
|
108
|
+
};
|
|
109
|
+
},
|
|
110
|
+
/**
|
|
111
|
+
* Builds a successful response that includes base64 image data alongside file path
|
|
112
|
+
* @param generationResult Result from image generation
|
|
113
|
+
* @param filePath Absolute path to the saved image file
|
|
114
|
+
* @param base64Data Base64 encoded image data
|
|
115
|
+
* @returns MCP tool response with both file URI and base64 data
|
|
116
|
+
*/
|
|
117
|
+
buildBase64SuccessResponse(generationResult, filePath, base64Data) {
|
|
118
|
+
const mimeType = getMimeTypeFromPath(filePath);
|
|
119
|
+
const fileName = path.basename(filePath);
|
|
120
|
+
const responseData = {
|
|
121
|
+
type: 'resource',
|
|
122
|
+
resource: {
|
|
123
|
+
uri: `file://${filePath}`,
|
|
124
|
+
name: fileName,
|
|
125
|
+
mimeType,
|
|
126
|
+
},
|
|
127
|
+
base64Data,
|
|
128
|
+
metadata: {
|
|
129
|
+
model: generationResult.metadata.model,
|
|
130
|
+
processingTime: 0,
|
|
131
|
+
contextMethod: 'structured_prompt',
|
|
132
|
+
timestamp: generationResult.metadata.timestamp.toISOString(),
|
|
133
|
+
},
|
|
134
|
+
};
|
|
135
|
+
return {
|
|
136
|
+
content: [
|
|
137
|
+
{
|
|
138
|
+
type: 'text',
|
|
139
|
+
text: JSON.stringify(responseData),
|
|
140
|
+
},
|
|
141
|
+
],
|
|
142
|
+
isError: false,
|
|
143
|
+
};
|
|
144
|
+
},
|
|
145
|
+
/**
|
|
146
|
+
* Builds an error response in structured content format
|
|
147
|
+
* @param error Error that occurred during processing
|
|
148
|
+
* @returns MCP tool response with structured error
|
|
149
|
+
*/
|
|
150
|
+
buildErrorResponse(error) {
|
|
151
|
+
const structuredError = {
|
|
152
|
+
error: convertErrorToStructured(error),
|
|
153
|
+
};
|
|
154
|
+
return {
|
|
155
|
+
content: [
|
|
156
|
+
{
|
|
157
|
+
type: 'text',
|
|
158
|
+
text: JSON.stringify(structuredError),
|
|
159
|
+
},
|
|
160
|
+
],
|
|
161
|
+
isError: true,
|
|
162
|
+
};
|
|
163
|
+
},
|
|
164
|
+
};
|
|
165
|
+
}
|
|
166
|
+
//# sourceMappingURL=responseBuilder.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"responseBuilder.js","sourceRoot":"","sources":["../../src/business/responseBuilder.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Structured Prompt Generator
|
|
3
|
+
* Uses Gemini Flash to generate optimized prompts for image generation
|
|
4
|
+
* Applies 7 best practices and 3 feature perspectives through intelligent selection
|
|
5
|
+
*/
|
|
6
|
+
import type { GeminiTextClient } from '../api/geminiTextClient.js';
|
|
7
|
+
import type { Result } from '../types/result.js';
|
|
8
|
+
/**
|
|
9
|
+
* Feature flags for image generation
|
|
10
|
+
*/
|
|
11
|
+
export interface FeatureFlags {
|
|
12
|
+
maintainCharacterConsistency?: boolean;
|
|
13
|
+
blendImages?: boolean;
|
|
14
|
+
useWorldKnowledge?: boolean;
|
|
15
|
+
useGoogleSearch?: boolean;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Result of structured prompt generation
|
|
19
|
+
*/
|
|
20
|
+
export interface StructuredPromptResult {
|
|
21
|
+
originalPrompt: string;
|
|
22
|
+
structuredPrompt: string;
|
|
23
|
+
selectedPractices: string[];
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Interface for structured prompt generation
|
|
27
|
+
*/
|
|
28
|
+
export interface StructuredPromptGenerator {
|
|
29
|
+
generateStructuredPrompt(userPrompt: string, features?: FeatureFlags, inputImageData?: string, // Optional base64-encoded image for context
|
|
30
|
+
purpose?: string): Promise<Result<StructuredPromptResult, Error>>;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Implementation of StructuredPromptGenerator using Gemini Flash
|
|
34
|
+
*/
|
|
35
|
+
export declare class StructuredPromptGeneratorImpl implements StructuredPromptGenerator {
|
|
36
|
+
private readonly geminiTextClient;
|
|
37
|
+
constructor(geminiTextClient: GeminiTextClient);
|
|
38
|
+
generateStructuredPrompt(userPrompt: string, features?: FeatureFlags, inputImageData?: string, purpose?: string): Promise<Result<StructuredPromptResult, Error>>;
|
|
39
|
+
/**
|
|
40
|
+
* Build complete prompt with all optimization context
|
|
41
|
+
*/
|
|
42
|
+
private buildCompletePrompt;
|
|
43
|
+
/**
|
|
44
|
+
* Build enhanced feature context based on flags with explicit requirements
|
|
45
|
+
*/
|
|
46
|
+
private buildEnhancedFeatureContext;
|
|
47
|
+
/**
|
|
48
|
+
* Infer which best practices were selected based on the generated prompt
|
|
49
|
+
*/
|
|
50
|
+
private inferSelectedPractices;
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Factory function to create StructuredPromptGenerator
|
|
54
|
+
*/
|
|
55
|
+
export declare function createStructuredPromptGenerator(geminiTextClient: GeminiTextClient): StructuredPromptGenerator;
|
|
56
|
+
//# sourceMappingURL=structuredPromptGenerator.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"structuredPromptGenerator.d.ts","sourceRoot":"","sources":["../../src/business/structuredPromptGenerator.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,4BAA4B,CAAA;AAClE,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,oBAAoB,CAAA;AA+ChD;;GAEG;AACH,MAAM,WAAW,YAAY;IAC3B,4BAA4B,CAAC,EAAE,OAAO,CAAA;IACtC,WAAW,CAAC,EAAE,OAAO,CAAA;IACrB,iBAAiB,CAAC,EAAE,OAAO,CAAA;IAC3B,eAAe,CAAC,EAAE,OAAO,CAAA;CAC1B;AAED;;GAEG;AACH,MAAM,WAAW,sBAAsB;IACrC,cAAc,EAAE,MAAM,CAAA;IACtB,gBAAgB,EAAE,MAAM,CAAA;IACxB,iBAAiB,EAAE,MAAM,EAAE,CAAA;CAC5B;AAED;;GAEG;AACH,MAAM,WAAW,yBAAyB;IACxC,wBAAwB,CACtB,UAAU,EAAE,MAAM,EAClB,QAAQ,CAAC,EAAE,YAAY,EACvB,cAAc,CAAC,EAAE,MAAM,EAAE,4CAA4C;IACrE,OAAO,CAAC,EAAE,MAAM,GACf,OAAO,CAAC,MAAM,CAAC,sBAAsB,EAAE,KAAK,CAAC,CAAC,CAAA;CAClD;AAED;;GAEG;AACH,qBAAa,6BAA8B,YAAW,yBAAyB;IACjE,OAAO,CAAC,QAAQ,CAAC,gBAAgB;gBAAhB,gBAAgB,EAAE,gBAAgB;IAEzD,wBAAwB,CAC5B,UAAU,EAAE,MAAM,EAClB,QAAQ,GAAE,YAAiB,EAC3B,cAAc,CAAC,EAAE,MAAM,EACvB,OAAO,CAAC,EAAE,MAAM,GACf,OAAO,CAAC,MAAM,CAAC,sBAAsB,EAAE,KAAK,CAAC,CAAC;IAgDjD;;OAEG;IACH,OAAO,CAAC,mBAAmB;IAyC3B;;OAEG;IACH,OAAO,CAAC,2BAA2B;IA4BnC;;OAEG;IACH,OAAO,CAAC,sBAAsB;CAkF/B;AAED;;GAEG;AACH,wBAAgB,+BAA+B,CAC7C,gBAAgB,EAAE,gBAAgB,GACjC,yBAAyB,CAE3B"}
|